From ab53de3770ab8f86d4262ff9161052d44813c032 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Wed, 4 Mar 2026 20:28:26 +0100 Subject: [PATCH 1/8] Add assets (strings and images) --- .../Localizations/fr.lproj/Tchap.strings | 7 ++++++ .../NextTchapLogo.imageset/Contents.json | 23 ++++++++++++++++++ .../next_tchap_logo@1x.png | Bin 0 -> 8158 bytes .../next_tchap_logo@2x.png | Bin 0 -> 18294 bytes .../next_tchap_logo@3x.png | Bin 0 -> 29419 bytes .../MigrateToNewTchapCoordinatorType.swift | 8 ++++++ .../MigrateToNewTchapView.swift | 18 ++++++++++++++ 7 files changed, 56 insertions(+) create mode 100644 Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/Contents.json create mode 100644 Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@1x.png create mode 100644 Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@2x.png create mode 100644 Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@3x.png create mode 100644 Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift create mode 100644 Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift diff --git a/Tchap/Assets/Localizations/fr.lproj/Tchap.strings b/Tchap/Assets/Localizations/fr.lproj/Tchap.strings index 3b0273229d..3037362749 100644 --- a/Tchap/Assets/Localizations/fr.lproj/Tchap.strings +++ b/Tchap/Assets/Localizations/fr.lproj/Tchap.strings @@ -379,3 +379,10 @@ // Chat participants "room_participants_leave_not_allowed_for_last_owner_msg" = "Vous ne pouvez pas quitter ce salon car vous êtes le seul administrateur."; +//////////////////////////////////////////////////////////////////////////////// +// MARK: Migrate to New Tchap +"migrate_to_new_tchap_title" = "Tchap évolue !"; +"migrate_to_new_tchap_message" = "Une nouvelle application est disponible pour iPhone. Veuillez la télécharger pour accéder à de nouvelles fonctionnalités."; +"migrate_to_new_tchap_warning" = "L'ancienne application sera bientôt abandonnée. Pour migrer, installez la nouvelle application, connectez-vous en vérifiant votre identité, puis supprimez l'ancienne."; +"migrate_to_new_tchap_action_accept_title" = "Télécharger"; +"migrate_to_new_tchap_action_help_title" = "Aide à la migration"; diff --git a/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/Contents.json b/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/Contents.json new file mode 100644 index 0000000000..174c29427c --- /dev/null +++ b/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "next_tchap_logo@1x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "next_tchap_logo@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "next_tchap_logo@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@1x.png b/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..9f045ac8baa50de3983abe9734576c1f58bba4ce GIT binary patch literal 8158 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 FngCTLS7QJG literal 0 HcmV?d00001 diff --git a/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@3x.png b/Tchap/Assets/SharedImages.xcassets/NextTchapLogo.imageset/next_tchap_logo@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..4bad19b26b53573428c2ef8fd3626d115911df17 GIT binary patch literal 29419 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 Y^_jxoyteHDKL-X;QP7aDlr;_gKX?F9QUCw| literal 0 HcmV?d00001 diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift new file mode 100644 index 0000000000..da27731e20 --- /dev/null +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift @@ -0,0 +1,8 @@ +// +// Copyright 2026 New Vector Ltd +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import Foundation diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift new file mode 100644 index 0000000000..3baa1ed65a --- /dev/null +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift @@ -0,0 +1,18 @@ +// +// Copyright 2026 New Vector Ltd +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import SwiftUI + +struct MigrateToNewTchapView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + MigrateToNewTchapView() +} From cda2e72bd4fb37d3913a04fda6bec6b44b6c1018 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Wed, 4 Mar 2026 20:28:50 +0100 Subject: [PATCH 2/8] Add `MigrateToNewTchap` module --- .../MigrateToNewTchapCoordinator.swift | 70 ++++++++++ .../MigrateToNewTchapCoordinatorType.swift | 30 +++- .../MigrateToNewTchapView.swift | 131 +++++++++++++++++- .../MigrateToNewTchapViewController.swift | 77 ++++++++++ .../MigrateToNewTchapViewModel.swift | 36 +++++ Tchap/target.yml | 1 + 6 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift create mode 100644 Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewController.swift create mode 100644 Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewModel.swift diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift new file mode 100644 index 0000000000..968a49db85 --- /dev/null +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift @@ -0,0 +1,70 @@ +/* + Copyright 2019 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 UIKit + +final class MigrateToNewTchapCoordinator: MigrateToNewTchapCoordinatorType { + + // MARK: Constant + + private enum Constants { + static let nextTchapAppStoreAppURL = "https://apps.apple.com/fr/app/tchap-x/id6736991029" + static let nextTchapHelpURL = "https://app.crisp.chat/website/6dacc68e-de3a-4511-8177-1339616098de/helpdesk/articles/fr/45a1de71-1093-4392-ab09-c88a6338c181/" + } + + // MARK: - Properties + + // MARK: Private + + private let rootRouter: RootRouterType + + // MARK: Public + + var childCoordinators: [Coordinator] = [] + + weak var delegate: MigrateToNewTchapCoordinatorDelegate? + + // MARK: - Setup + + init(rootRouter: RootRouterType) { + self.rootRouter = rootRouter + } + + // MARK: - Public methods + + func start() { + let migrateToNewTchapViewModel = MigrateToNewTchapViewModel( + appStoreAppUrl: URL(string: Constants.nextTchapAppStoreAppURL)!, // swiftlint:disable:this force_unwrapping + helpArticleUrl: URL(string: Constants.nextTchapHelpURL)!, // swiftlint:disable:this force_unwrapping + actionCancel: { [weak self] in + self?.migrateToNewTchapViewControllerDidTapSkipAction() + }) + + let migrateToNewTchapViewController = MigrateToNewTchapViewController.instantiate(with: migrateToNewTchapViewModel) + + self.rootRouter.presentModule(migrateToNewTchapViewController, animated: true, completion: nil) + } +} + +// MARK: - delegate +extension MigrateToNewTchapCoordinator { + + func migrateToNewTchapViewControllerDidTapSkipAction() { + self.rootRouter.dismissModule(animated: true) { + self.delegate?.migrateToNewTchapCoordinatorDidCancel(self) + } + } +} diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift index da27731e20..9d960a7e48 100644 --- a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift @@ -1,8 +1,26 @@ -// -// Copyright 2026 New Vector Ltd -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// +/* + Copyright 2019 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 + +protocol MigrateToNewTchapCoordinatorDelegate: AnyObject { + func migrateToNewTchapCoordinatorDidCancel(_ coordinator: MigrateToNewTchapCoordinatorType) +} + +/// `AppVersionUpdateCoordinatorType` is a protocol describing a Coordinator that handle application version update navigation flow. +protocol MigrateToNewTchapCoordinatorType: Coordinator { + var delegate: MigrateToNewTchapCoordinatorDelegate? { get set } +} diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift index 3baa1ed65a..5b23302d05 100644 --- a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapView.swift @@ -8,11 +8,138 @@ import SwiftUI struct MigrateToNewTchapView: View { + @Environment(\.openURL) private var openURL + + @ObservedObject var viewModel: MigrateToNewTchapViewModel + + private func openAppStoreAction() { + openURL(viewModel.appStoreAppUrl) + } + + private func presentHelpAction() { + viewModel.shouldPresentHelp = true + } + + var iconsHeader: some View { + HStack(spacing: 0.0) { + Image(uiImage: Asset.SharedImages.tchapLogo.image) + .resizable() + .scaledToFit() + .padding(.vertical, 8.0) + Image(systemName: "arrow.right") + .font(.title) + .foregroundStyle(Color(uiColor: viewModel.theme.textSecondaryColor)) + .padding(.horizontal, 16.0) + Image(uiImage: Asset_tchap.SharedImages.nextTchapLogo.image) + .resizable() + .scaledToFit() + } + } + + var title: some View { + Text(TchapL10n.migrateToNewTchapTitle) + .font(.title2) + .bold() + .foregroundStyle(Color(uiColor: viewModel.theme.textPrimaryColor)) + } + + var message: some View { + Text(TchapL10n.migrateToNewTchapMessage) + .font(.callout) + .multilineTextAlignment(.center) + .foregroundStyle(Color(uiColor: viewModel.theme.textSecondaryColor)) + } + + var warning: some View { + HStack(alignment: .top, spacing: 12.0) { + Image(systemName: "exclamationmark.triangle") + .foregroundStyle(Color(uiColor: viewModel.theme.warningColor)) + Text(TchapL10n.migrateToNewTchapWarning) + .font(.callout) + .foregroundStyle(Color(uiColor: viewModel.theme.textPrimaryColor)) + } + .padding() + .background( + RoundedRectangle(cornerRadius: 8.0) + .fill(Color(uiColor: UIColor(rgb: viewModel.isCurrentThemeDark ? 0x440505 : 0xFFEFED))) + ) + } + + var appStoreButton: some View { + Button { + openAppStoreAction() + } label: { + Text(TchapL10n.migrateToNewTchapActionAcceptTitle) + .font(.callout) + .bold() + .padding() + .frame(maxWidth: .infinity) + .background(Color(uiColor: viewModel.theme.tintColor)) + .cornerRadius(4.0) + .foregroundColor(.white) + } + } + + var helpButton: some View { + Button { + presentHelpAction() + } label: { + Text(TchapL10n.migrateToNewTchapActionHelpTitle) + .font(.callout) + .bold() + .padding() + .frame(maxWidth: .infinity) + .foregroundColor(Color(uiColor: viewModel.theme.textSecondaryColor)) + } + } + + @ToolbarContentBuilder + var toolbar: some ToolbarContent { + ToolbarItem { + Button { + viewModel.actionCancel() + } label: { + Text(VectorL10n.skip) + } + } + } + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + NavigationView { + VStack { + iconsHeader + .frame(height: 96.0) + .padding(.bottom, 32.0) + + title + .padding(.bottom, 8.0) + + message + .padding(.bottom, 16.0) + + warning + .padding(.bottom, 32.0) + + appStoreButton + + helpButton + + } + .padding(32.0) + .background(Color(uiColor:.systemBackground)) + + .toolbar { + toolbar + } + } + .sheet(isPresented: $viewModel.shouldPresentHelp) { + WebSheetView(targetUrl: viewModel.helpArticleUrl) + } } } #Preview { - MigrateToNewTchapView() + MigrateToNewTchapView(viewModel: MigrateToNewTchapViewModel(appStoreAppUrl: URL(string: "https://apple.com")!, // swiftlint:disable:this force_unwrapping + helpArticleUrl: URL(string: "https://www.tchap.gouv.fr")!, // swiftlint:disable:this force_unwrapping + actionCancel: {})) } diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewController.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewController.swift new file mode 100644 index 0000000000..08eb9e7a41 --- /dev/null +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewController.swift @@ -0,0 +1,77 @@ +/* + Copyright 2019 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 UIKit +import SwiftUI + +@preconcurrency final class MigrateToNewTchapViewController: UIHostingController { + + // MARK: - Properties + + // MARK: Private + + private var viewModel: MigrateToNewTchapViewModel! + + // MARK: Public + + // MARK: - Setup + + static func instantiate(with viewModel: MigrateToNewTchapViewModel) -> MigrateToNewTchapViewController { + let view = MigrateToNewTchapView(viewModel: viewModel) + let viewController = MigrateToNewTchapViewController(rootView: view) + viewController.viewModel = viewModel + return viewController + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + registerThemeServiceDidChangeThemeNotification() + + // Do any additional setup after loading the view. + + self.setupViews() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.themeDidChange() + } + + // MARK: - Private + + private func updateTheme() { + self.viewModel.theme = ThemeService.shared().theme + } + + @objc private func themeDidChange() { + self.updateTheme() + } + + private func setupViews() { + } + + func presentHelp() { + viewModel.shouldPresentHelp = true + } +} diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewModel.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewModel.swift new file mode 100644 index 0000000000..c7912038cb --- /dev/null +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapViewModel.swift @@ -0,0 +1,36 @@ +/* + Copyright 2019 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 + +final class MigrateToNewTchapViewModel: ObservableObject { + @Published var theme: Theme + var isCurrentThemeDark: Bool { ThemeService.shared().isCurrentThemeDark() } + @Published var shouldPresentHelp = false + let appStoreAppUrl: URL + let helpArticleUrl: URL + + let actionCancel: () -> Void + + init(appStoreAppUrl: URL, + helpArticleUrl: URL, + actionCancel: @escaping () -> Void) { + theme = ThemeService.shared().theme + self.appStoreAppUrl = appStoreAppUrl + self.helpArticleUrl = helpArticleUrl + self.actionCancel = actionCancel + } +} diff --git a/Tchap/target.yml b/Tchap/target.yml index 0d1da67ad9..1c899a5304 100644 --- a/Tchap/target.yml +++ b/Tchap/target.yml @@ -117,6 +117,7 @@ targetTemplates: - path: ../Tchap/Generated/Strings.swift - path: ../Tchap/Modules/Application/VersionUpdate - path: ../Tchap/Modules/Room/Views/BubbleCells/Antivirus + - path: ../Tchap/Modules/Application/MigrateToNewTchap # Add separately localizable files From 63f0b103b975d66ddef9b681240c884f78393192 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Fri, 13 Mar 2026 18:55:25 +0100 Subject: [PATCH 3/8] Make wellKnown() method public --- .../Common/Service/MatrixSDK/AuthenticationService.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift index 496f250eb7..2e19d3d561 100644 --- a/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift +++ b/RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift @@ -320,7 +320,9 @@ class AuthenticationService: NSObject { } /// Perform a well-known request on the specified homeserver URL. - private func wellKnown(for homeserverURL: URL) async throws -> MXWellKnown { + // Tchap: make wellknown() method available outside (needed in AllChatsCoordinator to check the existence of new Tchap application). + // private func wellKnown(for homeserverURL: URL) async throws -> MXWellKnown { + func wellKnown(for homeserverURL: URL) async throws -> MXWellKnown { let wellKnownClient = clientType.init(homeServer: homeserverURL, unrecognizedCertificateHandler: nil) // The .well-known/matrix/client API is often just a static file returned with no content type. From bee4acd7c55c1986a1a0659eff07e5c7a8809103 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Fri, 13 Mar 2026 18:56:23 +0100 Subject: [PATCH 4/8] Clean MigrateToNewTchap module --- .../MigrateToNewTchapCoordinator.swift | 33 ++++++------------- .../MigrateToNewTchapCoordinatorType.swift | 2 +- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift index 968a49db85..889b75eb32 100644 --- a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinator.swift @@ -20,8 +20,7 @@ final class MigrateToNewTchapCoordinator: MigrateToNewTchapCoordinatorType { // MARK: Constant - private enum Constants { - static let nextTchapAppStoreAppURL = "https://apps.apple.com/fr/app/tchap-x/id6736991029" + private enum Constants { static let nextTchapHelpURL = "https://app.crisp.chat/website/6dacc68e-de3a-4511-8177-1339616098de/helpdesk/articles/fr/45a1de71-1093-4392-ab09-c88a6338c181/" } @@ -29,7 +28,7 @@ final class MigrateToNewTchapCoordinator: MigrateToNewTchapCoordinatorType { // MARK: Private - private let rootRouter: RootRouterType + private(set) var migrateToNewTchapViewController: MigrateToNewTchapViewController! // MARK: Public @@ -39,32 +38,20 @@ final class MigrateToNewTchapCoordinator: MigrateToNewTchapCoordinatorType { // MARK: - Setup - init(rootRouter: RootRouterType) { - self.rootRouter = rootRouter + init(appStoreUrl: URL, cancelAction: @escaping () -> Void) { + let migrateToNewTchapViewModel = MigrateToNewTchapViewModel( + appStoreAppUrl: appStoreUrl, + helpArticleUrl: URL(string: Constants.nextTchapHelpURL)!, // swiftlint:disable:this force_unwrapping + actionCancel: cancelAction) + migrateToNewTchapViewController = MigrateToNewTchapViewController.instantiate(with: migrateToNewTchapViewModel) } // MARK: - Public methods func start() { - let migrateToNewTchapViewModel = MigrateToNewTchapViewModel( - appStoreAppUrl: URL(string: Constants.nextTchapAppStoreAppURL)!, // swiftlint:disable:this force_unwrapping - helpArticleUrl: URL(string: Constants.nextTchapHelpURL)!, // swiftlint:disable:this force_unwrapping - actionCancel: { [weak self] in - self?.migrateToNewTchapViewControllerDidTapSkipAction() - }) - - let migrateToNewTchapViewController = MigrateToNewTchapViewController.instantiate(with: migrateToNewTchapViewModel) - - self.rootRouter.presentModule(migrateToNewTchapViewController, animated: true, completion: nil) } -} - -// MARK: - delegate -extension MigrateToNewTchapCoordinator { - func migrateToNewTchapViewControllerDidTapSkipAction() { - self.rootRouter.dismissModule(animated: true) { - self.delegate?.migrateToNewTchapCoordinatorDidCancel(self) - } + func toPresentable() -> UIViewController { + return self.migrateToNewTchapViewController } } diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift index 9d960a7e48..c43e5c0f03 100644 --- a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift @@ -21,6 +21,6 @@ protocol MigrateToNewTchapCoordinatorDelegate: AnyObject { } /// `AppVersionUpdateCoordinatorType` is a protocol describing a Coordinator that handle application version update navigation flow. -protocol MigrateToNewTchapCoordinatorType: Coordinator { +protocol MigrateToNewTchapCoordinatorType: Coordinator, Presentable { var delegate: MigrateToNewTchapCoordinatorDelegate? { get set } } From 19d04efc0b32335c6c3c802da787d027d5428246 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Fri, 13 Mar 2026 18:56:56 +0100 Subject: [PATCH 5/8] Display MigrateToNewTchap after user's session is inited --- .../Home/AllChats/AllChatsCoordinator.swift | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift index ef8784c4f7..22ad6b00d9 100644 --- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift +++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift @@ -270,6 +270,24 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { self.addMatrixSessionToAllChatsController(userSession.matrixSession) // Tchap: Add external account management self.createLeftButtonItem(for: allChatsViewController) + + // Tchap: check for new Tchap advertizing in wellknown. + Task { + if let homeServerName = MXTools.serverName(inMatrixIdentifier: userSession.userId), + let newTchapAppStoreUrl = await newTchapAppStoreUrl(for: homeServerName) { + let checkMigrateToNewTchapCoordinator = MigrateToNewTchapCoordinator(appStoreUrl: newTchapAppStoreUrl) { [weak self] in + self?.navigationRouter.dismissModule(animated: true, completion: nil) + } + Task { @MainActor in + checkMigrateToNewTchapCoordinator.start() + // If any coordinator is already present, we can dismiss it by default before presenting our coordinator. +// navigationRouter.dismissModule(animated: true) { [weak self] in +// self?.navigationRouter.present(checkMigrateToNewTchapCoordinator, animated: true) +// } + navigationRouter.present(checkMigrateToNewTchapCoordinator, animated: true) + } + } + } } @objc private func userSessionsServiceWillRemoveUserSession(_ notification: Notification) { @@ -702,6 +720,33 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { viewController.loadViewIfNeeded() return viewController } + + + // Tchap: check advertizing of new Tchap in returned wellknown + // + // Tchap: the key "fr.gouv.tchap.tchapx" is present in the payload if the homeserver advertizes the new Tchap. + // Check matrix/client wellknown content for "fr.gouv.tchap.tchapx" key. + // + // The awaited content is the urls of the applications on the application stores. + // + // "fr.gouv.tchap.tchapx": { + // "android": "https://store.tchapx.android", + // "ios": "https://apps.apple.com/fr/app/tchap-x/id6736991029" + // } + // + // Returns the new Tchap appStore URL if found in well-known. + private func newTchapAppStoreUrl(for homeserverName: String) async -> URL? { + let homeserverAddress = HomeserverAddress.sanitized(homeserverName) + guard let homeserverURL = URL(string: homeserverAddress), + let wellknown = try? await AuthenticationService.shared.wellKnown(for: homeserverURL), + let wellknownEntries = wellknown.jsonDictionary() as? [String: Any], + let newTchapEntry = wellknownEntries["fr.gouv.tchap.tchapx"] as? [String: String], + let newTchapIosEntry = newTchapEntry["ios"], + let appStoreUrl = URL(string: newTchapIosEntry) else { + return nil + } + return appStoreUrl + } } extension AllChatsCoordinator: SignOutFlowPresenterDelegate { From 64a7010b40512fd7b4776d83d1986bc816c785aa Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Mon, 16 Mar 2026 16:10:12 +0100 Subject: [PATCH 6/8] Present Migration pop-up in right controller or coordinator --- .../Home/AllChats/AllChatsCoordinator.swift | 42 +++++++++++++++---- Riot/Routers/NavigationRouter.swift | 7 ++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift index 22ad6b00d9..2cc1ac5731 100644 --- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift +++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift @@ -270,21 +270,45 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { self.addMatrixSessionToAllChatsController(userSession.matrixSession) // Tchap: Add external account management self.createLeftButtonItem(for: allChatsViewController) - + + // Tchap: check if Migration to new Tchap View should be presented to user. + tchapCheckMigration(userSession: userSession) + } + + // Tchap: check if Migration to new Tchap View should be presented to user. + private func tchapCheckMigration(userSession: UserSession) { // Tchap: check for new Tchap advertizing in wellknown. Task { + // Wait a moment to let "Verifiy device" view pop-up if necessary. + try? await Task.sleep(nanoseconds: 1_000_000_000) + if let homeServerName = MXTools.serverName(inMatrixIdentifier: userSession.userId), let newTchapAppStoreUrl = await newTchapAppStoreUrl(for: homeServerName) { - let checkMigrateToNewTchapCoordinator = MigrateToNewTchapCoordinator(appStoreUrl: newTchapAppStoreUrl) { [weak self] in - self?.navigationRouter.dismissModule(animated: true, completion: nil) - } + + // Check if a ViewController is already presented. If so, present our Migration view from this presented view controller. Task { @MainActor in + + let presentingViewController = (navigationRouter as? NavigationRouter)?.presentedViewController() + + // Prepare Coordinator + let checkMigrateToNewTchapCoordinator = MigrateToNewTchapCoordinator(appStoreUrl: newTchapAppStoreUrl) { [weak self] in + // Dismiss Migration to new Tchap View from right context. + if let presentingViewController { + presentingViewController.dismiss(animated: true, completion: nil) + } else { + self?.navigationRouter.dismissModule(animated: true, completion: nil) + } + } + + // Start Coordinator checkMigrateToNewTchapCoordinator.start() - // If any coordinator is already present, we can dismiss it by default before presenting our coordinator. -// navigationRouter.dismissModule(animated: true) { [weak self] in -// self?.navigationRouter.present(checkMigrateToNewTchapCoordinator, animated: true) -// } - navigationRouter.present(checkMigrateToNewTchapCoordinator, animated: true) + + // Present Coordinator in right context. + if let presentingViewController { + presentingViewController.present(checkMigrateToNewTchapCoordinator.toPresentable(), animated: true) + } else { + navigationRouter.present(checkMigrateToNewTchapCoordinator, animated: true) + } } } } diff --git a/Riot/Routers/NavigationRouter.swift b/Riot/Routers/NavigationRouter.swift index 8ecc707f7e..a3bbb83c1e 100755 --- a/Riot/Routers/NavigationRouter.swift +++ b/Riot/Routers/NavigationRouter.swift @@ -403,3 +403,10 @@ extension NavigationRouter { static let navigationController = "navigationController" } } + +// Tchap: Used to know from which controller or coordinator to present New Tchap Migration View. +extension NavigationRouter { + func presentedViewController() -> UIViewController? { + navigationController.presentedViewController + } +} From cd296d0d0f57f00e9bd5f6e964784abf5fd5c764 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Mon, 16 Mar 2026 17:31:41 +0100 Subject: [PATCH 7/8] Present Migration alert when AllChats view appeared, ans no more than once every 24h --- Riot/Managers/Settings/RiotSettings.swift | 7 +++++- .../Home/AllChats/AllChatsCoordinator.swift | 22 ++++++++++++++----- .../AllChats/AllChatsViewController.swift | 6 ++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 424d5e004b..a305eca352 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -426,10 +426,15 @@ final class RiotSettings: NSObject { var tchapSecureBackupNextDisplayDate // Tchap has tried to automatically activate cross-signing. - // This automatic activation must be tried only once because if it fails, it could pro;pt user each time the application is activated. + // This automatic activation must be tried only once because if it fails, it could prompt user each time the application is activated. @UserDefault(key: "tchapCrossSigningAutoActivationTried", defaultValue: false, storage: defaults) var tchapCrossSigningAutoActivationTried + // Tchap migrate to new Tchap last display. + // Register the last time the new Tchap Migration alert was displayed to decide if enough time has spent before showing the alert again. + @UserDefault(key: "tchapNewTchapMigrationAlertLastPresentationDate", defaultValue: Date.distantPast, storage: defaults) + var tchapNewTchapMigrationAlertLastPresentationDate + } // MARK: - RiotSettings notification constants diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift index 2cc1ac5731..08a1f396aa 100644 --- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift +++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift @@ -270,17 +270,19 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { self.addMatrixSessionToAllChatsController(userSession.matrixSession) // Tchap: Add external account management self.createLeftButtonItem(for: allChatsViewController) - - // Tchap: check if Migration to new Tchap View should be presented to user. - tchapCheckMigration(userSession: userSession) } // Tchap: check if Migration to new Tchap View should be presented to user. private func tchapCheckMigration(userSession: UserSession) { // Tchap: check for new Tchap advertizing in wellknown. Task { - // Wait a moment to let "Verifiy device" view pop-up if necessary. - try? await Task.sleep(nanoseconds: 1_000_000_000) + + // Don't present alert more than once a day. + guard Date.now.timeIntervalSince(RiotSettings.shared.tchapNewTchapMigrationAlertLastPresentationDate) > 86400 else { + return + } + + RiotSettings.shared.tchapNewTchapMigrationAlertLastPresentationDate = .now if let homeServerName = MXTools.serverName(inMatrixIdentifier: userSession.userId), let newTchapAppStoreUrl = await newTchapAppStoreUrl(for: homeServerName) { @@ -835,6 +837,16 @@ extension AllChatsCoordinator: AllChatsViewControllerDelegate { self.navigationRouter.present(router, animated: true) } + + // Tchap: new Tchap migration + func allChatsViewControllerShouldShowNewTchapMigration(_ allChatsViewController: AllChatsViewController) { + // This method can be called by `viewDidAppear` before device is verified. + // In this case, userSession will be nil. + guard let userSession = self.parameters.userSessionsService.mainUserSession else { + return + } + tchapCheckMigration(userSession: userSession) + } } // MARK: - RoomCoordinatorDelegate diff --git a/Riot/Modules/Home/AllChats/AllChatsViewController.swift b/Riot/Modules/Home/AllChats/AllChatsViewController.swift index 4cba34df28..4f644a35c2 100644 --- a/Riot/Modules/Home/AllChats/AllChatsViewController.swift +++ b/Riot/Modules/Home/AllChats/AllChatsViewController.swift @@ -18,6 +18,7 @@ protocol AllChatsViewControllerDelegate: AnyObject { // Tchap: Add methods to use Tchap specific flows. func allChatsViewControllerShouldOpenRoomCreation(_ allChatsViewController: AllChatsViewController) func allChatsViewControllerShouldOpenRoomList(_ allChatsViewController: AllChatsViewController) + func allChatsViewControllerShouldShowNewTchapMigration(_ allChatsViewController: AllChatsViewController) } class AllChatsViewController: HomeViewController { @@ -178,7 +179,10 @@ class AllChatsViewController: HomeViewController { return } - AppDelegate.theDelegate().checkAppVersion() + // Tchap: Tchap doesn't check for version update anymore. +// AppDelegate.theDelegate().checkAppVersion() + + allChatsDelegate?.allChatsViewControllerShouldShowNewTchapMigration(self) if BuildSettings.newAppLayoutEnabled && !RiotSettings.shared.allChatsOnboardingHasBeenDisplayed { // Tchap: Disable new layout tutorials. Wait for an updated tutorials before show it. From 111ce237e652b0a51c488de89d3a7b44ad5428fc Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Mon, 16 Mar 2026 19:04:15 +0100 Subject: [PATCH 8/8] Remove useless comment --- .../MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift index c43e5c0f03..de3d3d5788 100644 --- a/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift +++ b/Tchap/Modules/Application/MigrateToNewTchap/MigrateToNewTchapCoordinatorType.swift @@ -20,7 +20,6 @@ protocol MigrateToNewTchapCoordinatorDelegate: AnyObject { func migrateToNewTchapCoordinatorDidCancel(_ coordinator: MigrateToNewTchapCoordinatorType) } -/// `AppVersionUpdateCoordinatorType` is a protocol describing a Coordinator that handle application version update navigation flow. protocol MigrateToNewTchapCoordinatorType: Coordinator, Presentable { var delegate: MigrateToNewTchapCoordinatorDelegate? { get set } }