From 15c3ed4781c287769e6237c59cfe76e52d76962f Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 13:24:16 +0200 Subject: [PATCH 01/17] Add config_production lane --- ElementX.xcodeproj/project.pbxproj | 2 ++ .../Sources/Application/AppSettings.swift | 2 +- ElementX/Sources/Other/InfoPlistReader.swift | 6 ++++++ ElementX/SupportingFiles/Info.plist | 2 ++ ElementX/SupportingFiles/target.yml | 1 + ci_scripts/ci_post_clone.sh | 4 +++- fastlane/Fastfile | 20 +++++++++++++++++++ fastlane/README.md | 8 ++++++++ project.yml | 1 + 9 files changed, 44 insertions(+), 2 deletions(-) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index d58c67d936..3f59e93a1c 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -4942,6 +4942,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; MACOSX_DEPLOYMENT_TARGET = 13.3; + MAPLIBRE_API_KEY = ""; MARKETING_VERSION = 1.2.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -5017,6 +5018,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; MACOSX_DEPLOYMENT_TARGET = 13.3; + MAPLIBRE_API_KEY = ""; MARKETING_VERSION = 1.2.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index b4d1fa059b..d25eb8e605 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -205,7 +205,7 @@ final class AppSettings { let darkTileMapStyleURL: URL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3" // maptiler api key - let mapTilerApiKey = "fU3vlMsMn4Jb6dnEIFsx" + let mapTilerApiKey = InfoPlistReader.main.mapLibreAPIKey // maptiler geocoding url let geocodingURLFormatString = "https://api.maptiler.com/geocoding/%f,%f.json" diff --git a/ElementX/Sources/Other/InfoPlistReader.swift b/ElementX/Sources/Other/InfoPlistReader.swift index 4e2bcc9592..a0b43c51cf 100644 --- a/ElementX/Sources/Other/InfoPlistReader.swift +++ b/ElementX/Sources/Other/InfoPlistReader.swift @@ -23,6 +23,7 @@ struct InfoPlistReader { static let keychainAccessGroupIdentifier = "keychainAccessGroupIdentifier" static let bundleShortVersion = "CFBundleShortVersionString" static let bundleDisplayName = "CFBundleDisplayName" + static let mapLibreAPIKey = "mapLibreAPIKey" } /// Info.plist reader on the bundle object that contains the current executable. @@ -76,6 +77,11 @@ struct InfoPlistReader { infoPlistStringValue(forKey: Keys.bundleDisplayName) } + /// Map Libre API Key + var mapLibreAPIKey: String { + infoPlistStringValue(forKey: Keys.mapLibreAPIKey) + } + private func infoPlistStringValue(forKey key: String) -> String { guard let result = bundle.object(forInfoDictionaryKey: key) as? String else { fatalError("Add \(key) into your target's Info.plst") diff --git a/ElementX/SupportingFiles/Info.plist b/ElementX/SupportingFiles/Info.plist index 9c7933379a..702b33e18c 100644 --- a/ElementX/SupportingFiles/Info.plist +++ b/ElementX/SupportingFiles/Info.plist @@ -60,5 +60,7 @@ $(BASE_BUNDLE_IDENTIFIER) keychainAccessGroupIdentifier $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER) + mapLibreAPIKey + $(MAPLIBRE_API_KEY) diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml index 4dde9748c9..7c19b384fb 100644 --- a/ElementX/SupportingFiles/target.yml +++ b/ElementX/SupportingFiles/target.yml @@ -76,6 +76,7 @@ targets: BGTaskSchedulerPermittedIdentifiers: [ io.element.elementx.background.refresh ] + mapLibreAPIKey: $(MAPLIBRE_API_KEY) settings: diff --git a/ci_scripts/ci_post_clone.sh b/ci_scripts/ci_post_clone.sh index 323593baa0..dc65096617 100755 --- a/ci_scripts/ci_post_clone.sh +++ b/ci_scripts/ci_post_clone.sh @@ -8,4 +8,6 @@ install_xcode_cloud_brew_dependencies if [ "$CI_WORKFLOW" = "Nightly" ]; then bundle exec fastlane config_nightly -fi \ No newline at end of file +else + bundle exec fastlane config_production +fi diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 7b3ba3bb8b..17f7ec1292 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -180,6 +180,9 @@ lane :config_nightly do 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" + + config_maplibre(yaml: data) + File.open(target_file_path, 'w') { |f| YAML.dump(data, f) } xcodegen(spec: "project.yml") @@ -193,6 +196,17 @@ lane :config_nightly do update_app_icon(caption_text: "Nightly #{release_version}", modulate: "100,20,100") end +lane :config_production do + target_file_path = "../project.yml" + data = YAML.load_file target_file_path + + config_maplibre(yaml: data) + + File.open(target_file_path, 'w') { |f| YAML.dump(data, f) } + + xcodegen(spec: "project.yml") +end + lane :upload_dsyms_to_sentry do |options| auth_token = ENV["SENTRY_AUTH_TOKEN"] UI.user_error!("Invalid Sentry Auth token.") unless !auth_token.to_s.empty? @@ -409,5 +423,11 @@ private_lane :create_simulator_if_necessary do |options| rescue sh("xcrun simctl create '#{simulator_name}' #{simulator_type}") end +end +private_lane :config_maplibre do |options| + yaml = options[:yaml] + api_key = ENV["MAPLIBRE_API_KEY"] + UI.user_error!("Invalid Map Libre API key.") unless !api_key.to_s.empty? + yaml["settings"]["MAPLIBRE_API_KEY"] = api_key end diff --git a/fastlane/README.md b/fastlane/README.md index abcda903f7..8608a7ea49 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -69,6 +69,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do +### config_production + +```sh +[bundle exec] fastlane config_production +``` + + + ### upload_dsyms_to_sentry ```sh diff --git a/project.yml b/project.yml index 44b894d29c..f467c8aa33 100644 --- a/project.yml +++ b/project.yml @@ -32,6 +32,7 @@ settings: MARKETING_VERSION: 1.2.1 CURRENT_PROJECT_VERSION: 1 DEVELOPMENT_TEAM: 7J4U792NQT + MAPLIBRE_API_KEY: "" include: - path: ElementX/SupportingFiles/target.yml From dbb18631d2db2b814d56d624ffba35b7fa31fa85 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 15:22:53 +0200 Subject: [PATCH 02/17] Add maplibre to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d965918860..0d5e0ce8f8 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ Tools/Scripts/element-android !/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.*.png !/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.*.png !/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.*.png +/.maplibre_key From 0240aa69140b6f9eca2cbe204c54a7882f8cce98 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 16:52:27 +0200 Subject: [PATCH 03/17] Add setupMapLibreKey --- Tools/Sources/SetupProject.swift | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Tools/Sources/SetupProject.swift b/Tools/Sources/SetupProject.swift index 728078e087..adc4a31fb7 100644 --- a/Tools/Sources/SetupProject.swift +++ b/Tools/Sources/SetupProject.swift @@ -1,5 +1,6 @@ import ArgumentParser import Foundation +import Yams struct SetupProject: ParsableCommand { static var configuration = CommandConfiguration(abstract: "A tool to setup the required components to efficiently run and contribute to Element X iOS") @@ -7,10 +8,22 @@ struct SetupProject: ParsableCommand { @Flag(help: "Use this only on ci to avoid installing failing packages") var ci = false + enum Error: LocalizedError { + case errorReadingProjectYAML + + var errorDescription: String? { + switch self { + case .errorReadingProjectYAML: + return "Error reading/parsing the file 'project.yml'" + } + } + } + func run() throws { try setupGitHooks() try brewBundleInstall() try mintPackagesInstall() + try setupMapLibreKey() try xcodegen() } @@ -29,6 +42,38 @@ struct SetupProject: ParsableCommand { try Utilities.zsh("mint install Asana/locheck") } + func setupMapLibreKey() throws { + guard !ci else { + return + } + + guard let maplibreAPIKey = try Utilities.zsh("cat ./.maplibre_key") else { + print("Error loading the file '.maplibre_key' ensure to have one in the project root directory") + return + } + + guard + let yamlFile = try Utilities.zsh("cat ./project.yml"), + var loadedYAML = try Yams.load(yaml: yamlFile) as? [String: Any], + var settings = loadedYAML["settings"] as? [String: Any] + else { + throw Error.errorReadingProjectYAML + } + + settings["MAPLIBRE_API_KEY"] = maplibreAPIKey + loadedYAML["settings"] = settings + + let updatedYAML = try Yams.dump(object: loadedYAML) + + try Utilities.zsh( + """ + cat << "EOF" > ./project.yml + \(updatedYAML) + EOF + """ + ) + } + func xcodegen() throws { try Utilities.zsh("xcodegen") } From 058fa5b44742d797b4a4927f40e6c379452ea332 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 17:27:17 +0200 Subject: [PATCH 04/17] Add documentation --- FORKING.md | 16 ++++++++++++++++ README.md | 4 ++++ 2 files changed, 20 insertions(+) create mode 100644 FORKING.md diff --git a/FORKING.md b/FORKING.md new file mode 100644 index 0000000000..62926f3916 --- /dev/null +++ b/FORKING.md @@ -0,0 +1,16 @@ +# Forking + +### Location Sharing + +The Location Sharing feature on Element X is currently integrated with [MapLibre](https://maplibre.org). + +The MapLibre SDK requires an API key to work, so you need to get one for yourself. + +After you got an API key, you need to configure the project following one of these steps: + +- Create a file named `.maplibre_key` in the project root directory. This file must contain the API key without spaces or newline characters. Then run `swift run tools setup-project` to generate the project. +- Paste your API key into the file `project.yml` as a value of the key `MAPLIBRE_API_KEY`. Then run `xcodegen` to generate the project. + +It’s not recommended to push your API key in your repository, since other people may get it. +We recommend to use the first method to inject your API key, since the `.maplibre_key` is already inside the `.gitignore`. +However be careful about not pushing the generated project or the `project.yml` with your API key inside. diff --git a/README.md b/README.md index 0af56be75c..4c6f88a70f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ Please see our [contribution guide](CONTRIBUTING.md). Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#element-x-ios:matrix.org). +## Forking + +Please read our [forking guide](FORKING.md). + ## Build instructions Please refer to the [setting up a development environment](CONTRIBUTING.md#setting-up-a-development-environment) section from the [contribution guide](CONTRIBUTING.md). From 7cd26f7222b8c7070638733ad5956f7cb4cca38b Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 18:18:43 +0200 Subject: [PATCH 05/17] Fix failing UTs --- .../NotificationManagerTests.swift | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index a9225071ac..dbea80fdc9 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -179,27 +179,53 @@ final class NotificationManagerTests: XCTestCase { } func test_MessageNotificationsRemoval() async throws { + let notificationPublisher = NotificationCenter.default.publisher(for: .roomMarkedAsRead).first() + let expectation1 = expectation(description: #function) + let subscription1 = notificationPublisher + .sink { _ in + expectation1.fulfill() + } + // No interaction if the object is nil or of the wrong type NotificationCenter.default.post(name: .roomMarkedAsRead, object: nil) - try await Task.sleep(for: .microseconds(200)) + await fulfillment(of: [expectation1]) XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0) XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0) + let expectation2 = expectation(description: #function) + let subscription2 = notificationPublisher + .sink { _ in + expectation2.fulfill() + } + NotificationCenter.default.post(name: .roomMarkedAsRead, object: 1) - try await Task.sleep(for: .microseconds(200)) + await fulfillment(of: [expectation2]) XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0) XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0) + let expectation3 = expectation(description: #function) + let subscription3 = notificationPublisher + .sink { _ in + expectation3.fulfill() + } + // The center calls the delivered and the removal functions when an id is passed NotificationCenter.default.post(name: .roomMarkedAsRead, object: "RoomID") - try await Task.sleep(for: .microseconds(200)) + await fulfillment(of: [expectation3]) XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 1) XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 1) } func test_InvitesNotificationsRemoval() async throws { + let notificationPublisher = NotificationCenter.default.publisher(for: .invitesScreenAppeared).first() + let expectation = expectation(description: #function) + let subscription = notificationPublisher + .sink { _ in + expectation.fulfill() + } + NotificationCenter.default.post(name: .invitesScreenAppeared, object: nil) - try await Task.sleep(for: .microseconds(200)) + await fulfillment(of: [expectation]) XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 1) XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 1) } From 73b12e3cafeb40fec79ea7cf6e2c7656eb80fcbb Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 19:44:45 +0200 Subject: [PATCH 06/17] Fix more UTs --- UnitTests/Sources/HomeScreenViewModelTests.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/UnitTests/Sources/HomeScreenViewModelTests.swift b/UnitTests/Sources/HomeScreenViewModelTests.swift index 77ef30f43c..f8950e4c5b 100644 --- a/UnitTests/Sources/HomeScreenViewModelTests.swift +++ b/UnitTests/Sources/HomeScreenViewModelTests.swift @@ -88,10 +88,9 @@ class HomeScreenViewModelTests: XCTestCase { let room: RoomProxyMock = .init(with: .init(id: mockRoomId, displayName: "Some room")) room.leaveRoomClosure = { .failure(.failedLeavingRoom) } clientProxy.roomForIdentifierMocks[mockRoomId] = room - let deferred = deferFulfillment(context.$viewState.first(), message: "viewState should be published.") context.send(viewAction: .confirmLeaveRoom(roomIdentifier: mockRoomId)) - try await deferred.fulfill() - XCTAssertNotNil(context.alertInfo) + let state = await context.nextViewState() + XCTAssertNotNil(state?.bindings.alertInfo) } func testLeaveRoomSuccess() async throws { From c1a19e0eeb201bd6c9f97540853a301e1ab20c74 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 12 Jul 2023 20:21:35 +0200 Subject: [PATCH 07/17] Cleanup --- .../NotificationManagerTests.swift | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index dbea80fdc9..6f2700ecda 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -180,35 +180,39 @@ final class NotificationManagerTests: XCTestCase { func test_MessageNotificationsRemoval() async throws { let notificationPublisher = NotificationCenter.default.publisher(for: .roomMarkedAsRead).first() + var cancellables: Set = .init() let expectation1 = expectation(description: #function) - let subscription1 = notificationPublisher + notificationPublisher .sink { _ in expectation1.fulfill() } - + .store(in: &cancellables) + // No interaction if the object is nil or of the wrong type NotificationCenter.default.post(name: .roomMarkedAsRead, object: nil) await fulfillment(of: [expectation1]) XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0) XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0) - + let expectation2 = expectation(description: #function) - let subscription2 = notificationPublisher + notificationPublisher .sink { _ in expectation2.fulfill() } - + .store(in: &cancellables) + NotificationCenter.default.post(name: .roomMarkedAsRead, object: 1) await fulfillment(of: [expectation2]) XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0) XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0) - + let expectation3 = expectation(description: #function) - let subscription3 = notificationPublisher + notificationPublisher .sink { _ in expectation3.fulfill() } - + .store(in: &cancellables) + // The center calls the delivered and the removal functions when an id is passed NotificationCenter.default.post(name: .roomMarkedAsRead, object: "RoomID") await fulfillment(of: [expectation3]) From c8a99adba9483b6c7abdd96654fdf3279205ed80 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 16:34:21 +0200 Subject: [PATCH 08/17] Add secrets.xcconfig --- ElementX/SupportingFiles/target.yml | 4 ++++ project.yml | 1 + secrets.xcconfig | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 secrets.xcconfig diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml index 7c19b384fb..09059695e8 100644 --- a/ElementX/SupportingFiles/target.yml +++ b/ElementX/SupportingFiles/target.yml @@ -45,6 +45,10 @@ targets: type: application platform: iOS + configFiles: + Debug: ../../secrets.xcconfig + Release: ../../secrets.xcconfig + info: path: ../SupportingFiles/Info.plist properties: diff --git a/project.yml b/project.yml index f467c8aa33..b8707d800b 100644 --- a/project.yml +++ b/project.yml @@ -4,6 +4,7 @@ attributes: fileGroups: - project.yml + - secrets.xcconfig options: groupSortPosition: bottom diff --git a/secrets.xcconfig b/secrets.xcconfig new file mode 100644 index 0000000000..5eb6c81379 --- /dev/null +++ b/secrets.xcconfig @@ -0,0 +1,20 @@ +// +// Copyright 2023 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. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +MAPLIBRE_API_KEY = your_key From 63ba81241a03a021f6826771195481398b3b4f0b Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 16:45:07 +0200 Subject: [PATCH 09/17] Cleanup gitignore file --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0d5e0ce8f8..d965918860 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,3 @@ Tools/Scripts/element-android !/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.*.png !/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.*.png !/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.*.png -/.maplibre_key From 88ed74c27ef86af8f04c554b70b152cc04fc2ea6 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 16:54:38 +0200 Subject: [PATCH 10/17] Update post-checkout hook --- .githooks/post-checkout | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.githooks/post-checkout b/.githooks/post-checkout index 93dc37d0db..5363630097 100755 --- a/.githooks/post-checkout +++ b/.githooks/post-checkout @@ -4,3 +4,6 @@ git lfs post-checkout "$@" #!/bin/bash export PATH="$PATH:/opt/homebrew/bin" + +# ignores updates of 'secrets.xcconfig' to avoid pushing sensitive data by mistake +git update-index --assume-unchanged secrets.xcconfig \ No newline at end of file From e2ea37931ef924ad0c3b1817c1735556205591ea Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 16:59:27 +0200 Subject: [PATCH 11/17] Cleanup SetupProject --- Tools/Sources/SetupProject.swift | 33 -------------------------------- 1 file changed, 33 deletions(-) diff --git a/Tools/Sources/SetupProject.swift b/Tools/Sources/SetupProject.swift index adc4a31fb7..6a91628df9 100644 --- a/Tools/Sources/SetupProject.swift +++ b/Tools/Sources/SetupProject.swift @@ -23,7 +23,6 @@ struct SetupProject: ParsableCommand { try setupGitHooks() try brewBundleInstall() try mintPackagesInstall() - try setupMapLibreKey() try xcodegen() } @@ -42,38 +41,6 @@ struct SetupProject: ParsableCommand { try Utilities.zsh("mint install Asana/locheck") } - func setupMapLibreKey() throws { - guard !ci else { - return - } - - guard let maplibreAPIKey = try Utilities.zsh("cat ./.maplibre_key") else { - print("Error loading the file '.maplibre_key' ensure to have one in the project root directory") - return - } - - guard - let yamlFile = try Utilities.zsh("cat ./project.yml"), - var loadedYAML = try Yams.load(yaml: yamlFile) as? [String: Any], - var settings = loadedYAML["settings"] as? [String: Any] - else { - throw Error.errorReadingProjectYAML - } - - settings["MAPLIBRE_API_KEY"] = maplibreAPIKey - loadedYAML["settings"] = settings - - let updatedYAML = try Yams.dump(object: loadedYAML) - - try Utilities.zsh( - """ - cat << "EOF" > ./project.yml - \(updatedYAML) - EOF - """ - ) - } - func xcodegen() throws { try Utilities.zsh("xcodegen") } From 041150560cf3e6382f7a6bfee114e4f059c20838 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 17:00:16 +0200 Subject: [PATCH 12/17] Update project --- ElementX.xcodeproj/project.pbxproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 3f59e93a1c..d190a7d794 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -967,6 +967,7 @@ 40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; 4132F882A984ED971338EE9D /* ReportContentScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenUITests.swift; sourceTree = ""; }; 4151163F666ED94FD959475A /* NotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationName.swift; sourceTree = ""; }; + 41553551C55AD59885840F0E /* secrets.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = secrets.xcconfig; sourceTree = ""; }; 4176C3E20C772DE8D182863C /* LegalInformationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreen.swift; sourceTree = ""; }; 421E716C521F96D24ECE69B3 /* NoticeRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItem.swift; sourceTree = ""; }; 421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -2004,6 +2005,7 @@ isa = PBXGroup; children = ( 5D26A086A8278D39B5756D6F /* project.yml */, + 41553551C55AD59885840F0E /* secrets.xcconfig */, 99B9B46F2D621380428E68F7 /* ElementX */, A4852B57D55D71EEBFCD931D /* UnitTests */, C0FAC17D4DD7D3A502822550 /* UITests */, @@ -3590,6 +3592,14 @@ path = Timeline; sourceTree = ""; }; + "TEMP_0AFD60FB-5804-4515-B772-2BAA5C727FE6" /* element-x-ios */ = { + isa = PBXGroup; + children = ( + 41553551C55AD59885840F0E /* secrets.xcconfig */, + ); + path = "element-x-ios"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -4822,6 +4832,7 @@ }; 62E1B7866DF0ED442C39A83B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 41553551C55AD59885840F0E /* secrets.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = ElementX/SupportingFiles/ElementX.entitlements; @@ -4845,6 +4856,7 @@ }; 6897D5BC19A2EA6ABD57DE7E /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 41553551C55AD59885840F0E /* secrets.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = ElementX/SupportingFiles/ElementX.entitlements; From 03b7425b9520f8dcb155813e578e265bc45283a4 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 17:02:06 +0200 Subject: [PATCH 13/17] Remove leftover in SetupProject --- Tools/Sources/SetupProject.swift | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Tools/Sources/SetupProject.swift b/Tools/Sources/SetupProject.swift index 6a91628df9..728078e087 100644 --- a/Tools/Sources/SetupProject.swift +++ b/Tools/Sources/SetupProject.swift @@ -1,6 +1,5 @@ import ArgumentParser import Foundation -import Yams struct SetupProject: ParsableCommand { static var configuration = CommandConfiguration(abstract: "A tool to setup the required components to efficiently run and contribute to Element X iOS") @@ -8,17 +7,6 @@ struct SetupProject: ParsableCommand { @Flag(help: "Use this only on ci to avoid installing failing packages") var ci = false - enum Error: LocalizedError { - case errorReadingProjectYAML - - var errorDescription: String? { - switch self { - case .errorReadingProjectYAML: - return "Error reading/parsing the file 'project.yml'" - } - } - } - func run() throws { try setupGitHooks() try brewBundleInstall() From 05f1bdee6c0681ff64ef04b3b72ba203527d6ff1 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 17:03:30 +0200 Subject: [PATCH 14/17] Cleanup project.yml --- ElementX.xcodeproj/project.pbxproj | 4 +--- project.yml | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index d190a7d794..9b81320791 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3592,7 +3592,7 @@ path = Timeline; sourceTree = ""; }; - "TEMP_0AFD60FB-5804-4515-B772-2BAA5C727FE6" /* element-x-ios */ = { + "TEMP_FFE5FDBA-B4DD-4FF7-B172-18026F248E20" /* element-x-ios */ = { isa = PBXGroup; children = ( 41553551C55AD59885840F0E /* secrets.xcconfig */, @@ -4954,7 +4954,6 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; MACOSX_DEPLOYMENT_TARGET = 13.3; - MAPLIBRE_API_KEY = ""; MARKETING_VERSION = 1.2.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -5030,7 +5029,6 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; MACOSX_DEPLOYMENT_TARGET = 13.3; - MAPLIBRE_API_KEY = ""; MARKETING_VERSION = 1.2.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; diff --git a/project.yml b/project.yml index b8707d800b..3ecc743535 100644 --- a/project.yml +++ b/project.yml @@ -33,7 +33,6 @@ settings: MARKETING_VERSION: 1.2.1 CURRENT_PROJECT_VERSION: 1 DEVELOPMENT_TEAM: 7J4U792NQT - MAPLIBRE_API_KEY: "" include: - path: ElementX/SupportingFiles/target.yml From 944663f4f6b8dfc591a8c9cc43382e5d8a7e3d9e Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 17:22:23 +0200 Subject: [PATCH 15/17] Add fastlane-plugin-xcconfig --- Gemfile.lock | 4 +++- fastlane/Fastfile | 20 +++++++++----------- fastlane/Pluginfile | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ba4ddfe0a5..42311168dd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,6 +123,7 @@ GEM rest-client (~> 2.0, >= 2.0.2) fastlane-plugin-sentry (1.15.0) os (~> 1.1, >= 1.1.4) + fastlane-plugin-xcconfig (2.0.0) fastlane-plugin-xcodegen (1.1.0) fastlane-plugin-brew (~> 0.1.1) gh_inspector (1.1.3) @@ -263,9 +264,10 @@ DEPENDENCIES fastlane-plugin-browserstack fastlane-plugin-diawi! fastlane-plugin-sentry + fastlane-plugin-xcconfig fastlane-plugin-xcodegen slather xcode-install BUNDLED WITH - 2.3.26 + 2.4.16 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 17f7ec1292..cf952d607d 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -181,7 +181,7 @@ lane :config_nightly do data["settings"]["BASE_APP_GROUP_IDENTIFIER"] = "io.element.nightly" data["settings"]["BASE_BUNDLE_IDENTIFIER"] = "io.element.elementx.nightly" - config_maplibre(yaml: data) + config_maplibre() File.open(target_file_path, 'w') { |f| YAML.dump(data, f) } @@ -197,13 +197,7 @@ lane :config_nightly do end lane :config_production do - target_file_path = "../project.yml" - data = YAML.load_file target_file_path - - config_maplibre(yaml: data) - - File.open(target_file_path, 'w') { |f| YAML.dump(data, f) } - + config_maplibre() xcodegen(spec: "project.yml") end @@ -425,9 +419,13 @@ private_lane :create_simulator_if_necessary do |options| end end -private_lane :config_maplibre do |options| - yaml = options[:yaml] +private_lane :config_maplibre do api_key = ENV["MAPLIBRE_API_KEY"] UI.user_error!("Invalid Map Libre API key.") unless !api_key.to_s.empty? - yaml["settings"]["MAPLIBRE_API_KEY"] = api_key + + set_xcconfig_value( + path: './secrets.xcconfig', + name: 'MAPLIBRE_API_KEY', + value: api_key + ) end diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile index af36e2a026..44bbc84323 100644 --- a/fastlane/Pluginfile +++ b/fastlane/Pluginfile @@ -6,3 +6,4 @@ gem 'fastlane-plugin-diawi', git: 'https://github.com/mhtranbn/fastlane-plugin-d gem 'fastlane-plugin-xcodegen' gem 'fastlane-plugin-sentry' gem 'fastlane-plugin-browserstack' +gem 'fastlane-plugin-xcconfig' From 42770be9a773a6a6e9b39c723ee8aca0d16a07c6 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Thu, 13 Jul 2023 17:26:07 +0200 Subject: [PATCH 16/17] Improve test --- .../NotificationManager/NotificationManagerTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index 6f2700ecda..2c0db99e8e 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -223,10 +223,12 @@ final class NotificationManagerTests: XCTestCase { func test_InvitesNotificationsRemoval() async throws { let notificationPublisher = NotificationCenter.default.publisher(for: .invitesScreenAppeared).first() let expectation = expectation(description: #function) - let subscription = notificationPublisher + var cancellables: Set = .init() + notificationPublisher .sink { _ in expectation.fulfill() } + .store(in: &cancellables) NotificationCenter.default.post(name: .invitesScreenAppeared, object: nil) await fulfillment(of: [expectation]) From 0bd018d0338b27aa310aaca7e0fbb2c37ce85476 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Fri, 14 Jul 2023 08:58:02 +0200 Subject: [PATCH 17/17] Update docs --- FORKING.md | 16 ---------------- README.md | 8 ++++---- docs/FORKING.md | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 20 deletions(-) delete mode 100644 FORKING.md create mode 100644 docs/FORKING.md diff --git a/FORKING.md b/FORKING.md deleted file mode 100644 index 62926f3916..0000000000 --- a/FORKING.md +++ /dev/null @@ -1,16 +0,0 @@ -# Forking - -### Location Sharing - -The Location Sharing feature on Element X is currently integrated with [MapLibre](https://maplibre.org). - -The MapLibre SDK requires an API key to work, so you need to get one for yourself. - -After you got an API key, you need to configure the project following one of these steps: - -- Create a file named `.maplibre_key` in the project root directory. This file must contain the API key without spaces or newline characters. Then run `swift run tools setup-project` to generate the project. -- Paste your API key into the file `project.yml` as a value of the key `MAPLIBRE_API_KEY`. Then run `xcodegen` to generate the project. - -It’s not recommended to push your API key in your repository, since other people may get it. -We recommend to use the first method to inject your API key, since the `.maplibre_key` is already inside the `.gitignore`. -However be careful about not pushing the generated project or the `project.yml` with your API key inside. diff --git a/README.md b/README.md index 4c6f88a70f..64df142dd3 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,6 @@ Please see our [contribution guide](CONTRIBUTING.md). Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#element-x-ios:matrix.org). -## Forking - -Please read our [forking guide](FORKING.md). - ## Build instructions Please refer to the [setting up a development environment](CONTRIBUTING.md#setting-up-a-development-environment) section from the [contribution guide](CONTRIBUTING.md). @@ -45,6 +41,10 @@ When you are experiencing an issue on ElementX iOS, please first search in [GitH and then in [#element-x-ios:matrix.org](https://matrix.to/#/#element-x-ios:matrix.org). If after your research you still have a question, ask at [#element-x-ios:matrix.org](https://matrix.to/#/#element-x-ios:matrix.org). Otherwise feel free to create a GitHub issue if you encounter a bug or a crash, by explaining clearly in detail what happened. You can also perform bug reporting (Rageshake) from the Element application by shaking your phone or going to the application settings. This is especially recommended when you encounter a crash. +## Forking + +Please read our [forking guide](docs/FORKING.md). + ## Copyright & License Copyright (c) 2022 New Vector Ltd diff --git a/docs/FORKING.md b/docs/FORKING.md new file mode 100644 index 0000000000..e616f4dee2 --- /dev/null +++ b/docs/FORKING.md @@ -0,0 +1,32 @@ +# Forking + +### Update the bundle identifier / app display name + +To change the bundle identifier and the app display name for your app, open the `project.yml` file in the project root folder and change these settings: + +``` +BASE_BUNDLE_IDENTIFIER: io.element.elementx +APP_DISPLAY_NAME: Element X +``` + +After the changes run `xcodegen` to propagate them. + +### Setup the location sharing + +The location sharing feature on Element X is currently integrated with [MapLibre](https://maplibre.org). + +The MapLibre SDK requires an API key to work, so you need to get one for yourself. + +After you get an API key, you need to configure the project by adding it inside the file `secrets.xconfig` in the project root folder. After you are done, the file should contain a setting like this: + +``` +MAPLIBRE_API_KEY = your_map_libre_key +``` + +It’s not recommended to push your API key in your repository since other people may get it. + +One way to avoid pushing the API key by mistake is running on your machine the command: +``` +git update-index assume-unchanged secrets.xcconfig +``` +this will prevent pushing any update of the file`secrets.xcconfig`. \ No newline at end of file