diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..978c7e086 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Enterprise"] + path = Enterprise + url = git@github.com:element-hq/element-ios-enterprise diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index b1d968e14..f13442914 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -762,6 +762,7 @@ B444F9C184A377C1B481F07F /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = E992D7B8BE54B2AB454613AF /* XCUIElement.swift */; }; B4A0C69370E6008A971463E7 /* BugReportScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C89820BB2B88D4EA28131C /* BugReportScreenViewModelProtocol.swift */; }; B4AAB3257A83B73F53FB2689 /* StateStoreViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */; }; + B50C95B6D1EABFE1CEA50959 /* AppHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B048CB133239700CD890F5D /* AppHooks.swift */; }; B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC5F5209279A752D98AAC4B2 /* CollapsibleFlowLayoutTests.swift */; }; B53D292A5CA61E371C4CD785 /* GenericCallLinkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514923AA9640C34F39E0500A /* GenericCallLinkCoordinator.swift */; }; B5479997ECC516C121E6625E /* LocationMarkerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFECCE59967018204876D0A5 /* LocationMarkerView.swift */; }; @@ -1324,6 +1325,7 @@ 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = ""; }; 2AE807361805463F5AEDD1CA /* VoiceMessagePreviewComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessagePreviewComposer.swift; sourceTree = ""; }; 2AF715D4FD4710EBB637D661 /* SettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenViewModelProtocol.swift; sourceTree = ""; }; + 2B048CB133239700CD890F5D /* AppHooks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppHooks.swift; sourceTree = ""; }; 2BB385E148DE55C85C0A02D6 /* SoftLogoutScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenModels.swift; sourceTree = ""; }; 2BDB3E65A79779EDA5D33D8A /* AudioPlayerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerState.swift; sourceTree = ""; }; 2BFDCA5A09EE70BC17F2EFA7 /* URLComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLComponents.swift; sourceTree = ""; }; @@ -3708,6 +3710,14 @@ path = Items; sourceTree = ""; }; + 769D25068533684018BA0F82 /* Hooks */ = { + isa = PBXGroup; + children = ( + 2B048CB133239700CD890F5D /* AppHooks.swift */, + ); + path = Hooks; + sourceTree = ""; + }; 7803E03F759061C948D66B7E /* AppLock */ = { isa = PBXGroup; children = ( @@ -4970,6 +4980,7 @@ C0937E3B06A8F0E2DB7C8241 /* Other */, 2ECFF6B05DAA37EB10DBF7E8 /* UITests */, 337015ADFBA3AB96660DB3A6 /* Generated */, + 769D25068533684018BA0F82 /* Hooks */, 31CE4DA53232AA534057F912 /* Mocks */, 4C826614718790C58C17117F /* UnitTests */, ); @@ -5896,6 +5907,7 @@ A021827B528F1EDC9101CA58 /* AppCoordinatorProtocol.swift in Sources */, 4FF90E2242DBD596E1ED2E27 /* AppCoordinatorStateMachine.swift in Sources */, 9D9690D2FD4CD26FF670620F /* AppDelegate.swift in Sources */, + B50C95B6D1EABFE1CEA50959 /* AppHooks.swift in Sources */, 6851B077B4C913CC12DB6E77 /* AppLockFlowCoordinator.swift in Sources */, 06F8EDF52E33A2D36BCC1161 /* AppLockScreen.swift in Sources */, 9912F9EB2D6589141A2957B4 /* AppLockScreenCoordinator.swift in Sources */, diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index f70687641..1cb8d331c 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -29,6 +29,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg private let appMediator: AppMediator private let appSettings: AppSettings private let appDelegate: AppDelegate + private let appHooks: AppHooks private let elementCallService: ElementCallServiceProtocol /// Common background task to continue long-running tasks in the background. @@ -65,10 +66,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg @Consumable private var storedAppRoute: AppRoute? init(appDelegate: AppDelegate) { + let appHooks = AppHooks() + appHooks.configure() + windowManager = WindowManager(appDelegate: appDelegate) appMediator = AppMediator(windowManager: windowManager) - let appSettings = AppSettings() + let appSettings = appHooks.runAppSettingsHook(AppSettings()) MXLog.configure(logLevel: appSettings.logLevel) @@ -83,6 +87,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg self.appDelegate = appDelegate self.appSettings = appSettings + self.appHooks = appHooks appRouteURLParser = AppRouteURLParser(appSettings: appSettings) elementCallService = ElementCallService() diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index c3f3aaaa6..2bc5a9d6f 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -74,6 +74,14 @@ final class AppSettings { store = userDefaults } + // MARK: - Hooks + + func override(defaultHomeserverAddress: String? = nil) { + if let defaultHomeserverAddress { + self.defaultHomeserverAddress = defaultHomeserverAddress + } + } + // MARK: - Application /// Whether or not the app is a development build that isn't in production. @@ -94,7 +102,7 @@ final class AppSettings { /// The default homeserver address used. This is intentionally a string without a scheme /// so that it can be passed to Rust as a ServerName for well-known discovery. - let defaultHomeserverAddress = "matrix.org" + private(set) var defaultHomeserverAddress = "matrix.org" /// An override of the homeserver's Sliding Sync proxy URL. This allows development against servers /// that don't yet have an officially trusted proxy configured in their well-known. diff --git a/ElementX/Sources/Hooks/AppHooks.swift b/ElementX/Sources/Hooks/AppHooks.swift new file mode 100644 index 000000000..f908dbe04 --- /dev/null +++ b/ElementX/Sources/Hooks/AppHooks.swift @@ -0,0 +1,45 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +// MARK: Registration + +class AppHooks: AppHooksProtocol { + private(set) var appSettingsHook: AppSettingsHookProtocol? + func registerAppSettingsHook(_ hook: AppSettingsHookProtocol) { + appSettingsHook = hook + } + + func runAppSettingsHook(_ appSettings: AppSettings) -> AppSettings { + guard let appSettingsHook else { return appSettings } + return appSettingsHook.run(appSettings: appSettings) + } +} + +protocol AppHooksProtocol { + func configure() +} + +extension AppHooksProtocol { + func configure() { } +} + +// MARK: Protocols + +protocol AppSettingsHookProtocol { + func run(appSettings: AppSettings) -> AppSettings +} diff --git a/ElementX/Sources/Mocks/PHGPostHogMock.swift b/ElementX/Sources/Mocks/PHGPostHogMock.swift index 30e6ab07e..14580b343 100644 --- a/ElementX/Sources/Mocks/PHGPostHogMock.swift +++ b/ElementX/Sources/Mocks/PHGPostHogMock.swift @@ -31,7 +31,7 @@ class MockPostHogFactory: PostHogFactory { self.mock = mock } - func createPostHog(config: PostHogConfig) -> ElementX.PHGPostHogProtocol { + func createPostHog(config: PostHogConfig) -> PHGPostHogProtocol { mock } } diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml index ce76d1dab..b307e71dc 100644 --- a/ElementX/SupportingFiles/target.yml +++ b/ElementX/SupportingFiles/target.yml @@ -118,6 +118,7 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: $(BASE_BUNDLE_IDENTIFIER) MARKETING_VERSION: $(MARKETING_VERSION) CURRENT_PROJECT_VERSION: $(CURRENT_PROJECT_VERSION) + ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon DEVELOPMENT_TEAM: $(DEVELOPMENT_TEAM) CODE_SIGN_ENTITLEMENTS: ElementX/SupportingFiles/ElementX.entitlements SWIFT_OBJC_BRIDGING_HEADER: ElementX/SupportingFiles/ElementX-Bridging-Header.h diff --git a/Enterprise b/Enterprise new file mode 160000 index 000000000..e03750f65 --- /dev/null +++ b/Enterprise @@ -0,0 +1 @@ +Subproject commit e03750f654cd3800c14b41827fb3f6ab57f7d5f0 diff --git a/app.yml b/app.yml new file mode 100644 index 000000000..89deb906e --- /dev/null +++ b/app.yml @@ -0,0 +1,7 @@ +settings: + APP_DISPLAY_NAME: Element X + PRODUCTION_APP_NAME: Element + BASE_APP_GROUP_IDENTIFIER: io.element + BASE_BUNDLE_IDENTIFIER: io.element.elementx + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: "colors/accent-color" + DEVELOPMENT_TEAM: 7J4U792NQT diff --git a/ci_scripts/ci_post_clone.sh b/ci_scripts/ci_post_clone.sh index 4b2e9a397..9d6ce0a7a 100755 --- a/ci_scripts/ci_post_clone.sh +++ b/ci_scripts/ci_post_clone.sh @@ -8,6 +8,10 @@ install_xcode_cloud_brew_dependencies if [ "$CI_WORKFLOW" = "Nightly" ]; then bundle exec fastlane config_nightly build_number:"$CI_BUILD_NUMBER" +elif [ "$CI_WORKFLOW" = "Enterprise" ]; then + # Not sure what Xcode Cloud does, might need to also + # git submodule update --init --recursive + bundle exec fastlane config_enterprise else bundle exec fastlane config_production fi diff --git a/fastlane/Fastfile b/fastlane/Fastfile index b24579d0a..2018f8610 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,6 +1,11 @@ require 'yaml' require 'semantic' +enterprise = '../Enterprise/fastlane/Fastfile' +if File.exist?(enterprise) + import enterprise +end + before_all do xcversion(version: "15.2") @@ -146,14 +151,18 @@ lane :integration_tests do ) end +lane :config_production do + config_secrets() + xcodegen(spec: "project.yml") +end + lane :config_nightly do |options| build_number = options[:build_number] UI.user_error!("Invalid build number.") unless !build_number.to_s.empty? target_file_path = "../project.yml" data = YAML.load_file target_file_path - data["settings"]["BASE_APP_GROUP_IDENTIFIER"] = "io.element.nightly" - data["settings"]["BASE_BUNDLE_IDENTIFIER"] = "io.element.elementx.nightly" + data["include"].append({ "path" => "fastlane/nightly.yml" }) config_secrets() @@ -170,11 +179,6 @@ lane :config_nightly do |options| update_app_icon(caption_text: "#{release_version}(#{build_number})", modulate: "100,20,100") end -lane :config_production do - config_secrets() - xcodegen(spec: "project.yml") -end - $sentry_retry=0 lane :upload_dsyms_to_sentry do |options| auth_token = ENV["SENTRY_AUTH_TOKEN"] @@ -302,8 +306,7 @@ end private_lane :config_xcodegen_alpha do target_file_path = "../project.yml" data = YAML.load_file target_file_path - data["settings"]["BASE_APP_GROUP_IDENTIFIER"] = "io.element.pr" - data["settings"]["BASE_BUNDLE_IDENTIFIER"] = "io.element.elementx.pr" + data["include"].append({ "path" => "fastlane/alpha.yml" }) File.open(target_file_path, 'w') { |f| YAML.dump(data, f) } xcodegen(spec: "project.yml") diff --git a/fastlane/README.md b/fastlane/README.md index bcb092d07..34919f2e2 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -45,14 +45,6 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do -### config_nightly - -```sh -[bundle exec] fastlane config_nightly -``` - - - ### config_production ```sh @@ -61,6 +53,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do +### config_nightly + +```sh +[bundle exec] fastlane config_nightly +``` + + + ### upload_dsyms_to_sentry ```sh diff --git a/fastlane/alpha.yml b/fastlane/alpha.yml new file mode 100644 index 000000000..ccbf08b55 --- /dev/null +++ b/fastlane/alpha.yml @@ -0,0 +1,3 @@ +settings: + BASE_APP_GROUP_IDENTIFIER: io.element.pr + BASE_BUNDLE_IDENTIFIER: io.element.elementx.pr diff --git a/fastlane/nightly.yml b/fastlane/nightly.yml new file mode 100644 index 000000000..8e41a3208 --- /dev/null +++ b/fastlane/nightly.yml @@ -0,0 +1,3 @@ +settings: + BASE_APP_GROUP_IDENTIFIER: io.element.nightly + BASE_BUNDLE_IDENTIFIER: io.element.elementx.nightly diff --git a/project.yml b/project.yml index 03be9cfab..579c21c66 100644 --- a/project.yml +++ b/project.yml @@ -21,21 +21,16 @@ options: settings: CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED: YES - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: "colors/accent-color" ENABLE_BITCODE: NO - BASE_APP_GROUP_IDENTIFIER: io.element APP_GROUP_IDENTIFIER: group.$(BASE_APP_GROUP_IDENTIFIER) - BASE_BUNDLE_IDENTIFIER: io.element.elementx APP_NAME: ElementX - APP_DISPLAY_NAME: Element X - PRODUCTION_APP_NAME: Element KEYCHAIN_ACCESS_GROUP_IDENTIFIER: $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER) MARKETING_VERSION: 1.6.13 CURRENT_PROJECT_VERSION: 1 - DEVELOPMENT_TEAM: 7J4U792NQT SUPPORTS_MACCATALYST: NO include: + - path: app.yml - path: ElementX/SupportingFiles/target.yml - path: UnitTests/SupportingFiles/target.yml - path: PreviewTests/SupportingFiles/target.yml