diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a67b28178..202fe0f96 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -36,6 +36,9 @@ 2D45E5BF25C9549700A6D639 /* PublicTimelineViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D45E5BE25C9549700A6D639 /* PublicTimelineViewModel+State.swift */; }; 2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */; }; 2D46976425C2A71500CF4AA9 /* UIIamge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46976325C2A71500CF4AA9 /* UIIamge.swift */; }; + 2D59819B25E4A581000FB903 /* MastodonConfirmEmailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */; }; + 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */; }; + 2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */ = {isa = PBXBuildFile; productRef = 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */; }; 2D5A3D0325CF8742002347D6 /* ControlContainableScrollViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */; }; 2D5A3D1125CF87AA002347D6 /* AvatarBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */; }; 2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */; }; @@ -218,6 +221,8 @@ 2D45E5BE25C9549700A6D639 /* PublicTimelineViewModel+State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewModel+State.swift"; sourceTree = ""; }; 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraint.swift; sourceTree = ""; }; 2D46976325C2A71500CF4AA9 /* UIIamge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIIamge.swift; sourceTree = ""; }; + 2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonConfirmEmailViewController.swift; sourceTree = ""; }; + 2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonConfirmEmailViewModel.swift; sourceTree = ""; }; 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlContainableScrollViews.swift; sourceTree = ""; }; 2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = ""; }; 2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewModel+Diffable.swift"; sourceTree = ""; }; @@ -346,6 +351,7 @@ DB5086B825CC0D6400C2C187 /* Kingfisher in Frameworks */, 2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */, DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */, + 2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */, 45B49097460EDE530AD5AA72 /* Pods_Mastodon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -466,6 +472,15 @@ path = Button; sourceTree = ""; }; + 2D59819925E4A55C000FB903 /* ConfirmEmail */ = { + isa = PBXGroup; + children = ( + 2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */, + 2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */, + ); + path = ConfirmEmail; + sourceTree = ""; + }; 2D5A3D0125CF8640002347D6 /* Vender */ = { isa = PBXGroup; children = ( @@ -596,6 +611,7 @@ DB01409B25C40BB600F9F3CF /* Authentication */ = { isa = PBXGroup; children = ( + 2D59819925E4A55C000FB903 /* ConfirmEmail */, DB0140A625C40C0900F9F3CF /* PinBased */, DBE0821A25CD382900FD6BBD /* Register */, DB72602125E36A2500235243 /* ServerRules */, @@ -947,6 +963,7 @@ 2D42FF6025C8177C004A627A /* ActiveLabel */, DB0140BC25C40D7500F9F3CF /* CommonOSLog */, DB5086B725CC0D6400C2C187 /* Kingfisher */, + 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -1074,6 +1091,7 @@ 2D42FF5F25C8177C004A627A /* XCRemoteSwiftPackageReference "ActiveLabel" */, DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */, DB5086B625CC0D6400C2C187 /* XCRemoteSwiftPackageReference "Kingfisher" */, + 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */, ); productRefGroup = DB427DD325BAA00100D1B89D /* Products */; projectDirPath = ""; @@ -1258,6 +1276,7 @@ files = ( DB98337125C9443200AD9700 /* APIService+Authentication.swift in Sources */, 0FAA0FDF25E0B57E0017CCDE /* WelcomeViewController.swift in Sources */, + 2D59819B25E4A581000FB903 /* MastodonConfirmEmailViewController.swift in Sources */, DB45FB1D25CA9D23005A8AC7 /* APIService+HomeTimeline.swift in Sources */, 2D7631B325C159F700929FB9 /* Item.swift in Sources */, 2D61335E25C1894B00CAE157 /* APIService.swift in Sources */, @@ -1302,6 +1321,7 @@ 2DF75BA125D0E29D00694EC8 /* StatusProvider+TimelinePostTableViewCellDelegate.swift in Sources */, 2D42FF7E25C82218004A627A /* ActionToolBarContainer.swift in Sources */, DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */, + 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */, 2D38F1C625CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift in Sources */, DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */, @@ -1875,6 +1895,14 @@ minimumVersion = 4.0.0; }; }; + 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/vtourraine/ThirdPartyMailer.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.7.1; + }; + }; 2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Alamofire/AlamofireNetworkActivityIndicator"; @@ -1915,6 +1943,11 @@ package = 2D42FF5F25C8177C004A627A /* XCRemoteSwiftPackageReference "ActiveLabel" */; productName = ActiveLabel; }; + 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */ = { + isa = XCSwiftPackageProductDependency; + package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */; + productName = ThirdPartyMailer; + }; 2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */ = { isa = XCSwiftPackageProductDependency; package = 2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */; diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index bbf66235a..456a6e967 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -81,6 +81,15 @@ "revision": "2b6054efa051565954e1d2b9da831680026cd768", "version": "5.0.0" } + }, + { + "package": "ThirdPartyMailer", + "repositoryURL": "https://github.com/vtourraine/ThirdPartyMailer.git", + "state": { + "branch": null, + "revision": "923c60ee7588da47db8cfc4e0f5b96e5e605ef84", + "version": "1.7.1" + } } ] }, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 833e2a51a..02689f102 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -43,6 +43,7 @@ extension SceneCoordinator { case mastodonPinBasedAuthentication(viewModel: MastodonPinBasedAuthenticationViewModel) case mastodonRegister(viewModel: MastodonRegisterViewModel) case mastodonServerRules(viewModel: MastodonServerRulesViewModel) + case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel) case alertController(alertController: UIAlertController) } @@ -151,6 +152,10 @@ private extension SceneCoordinator { let _viewController = MastodonServerRulesViewController() _viewController.viewModel = viewModel viewController = _viewController + case .mastodonConfirmEmail(let viewModel): + let _viewController = MastodonConfirmEmailViewController() + _viewController.viewModel = viewModel + viewController = _viewController case .alertController(let alertController): if let popoverPresentationController = alertController.popoverPresentationController { assert( diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift index 6042012d1..6b5cfb186 100644 --- a/Mastodon/Generated/Strings.swift +++ b/Mastodon/Generated/Strings.swift @@ -68,6 +68,32 @@ internal enum L10n { } internal enum Scene { + internal enum ConfirmEmail { + /// We just sent an email to %@,\ntap the link to confirm your account. + internal static func subtitle(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.ConfirmEmail.Subtitle", String(describing: p1)) + } + /// One last thing. + internal static let title = L10n.tr("Localizable", "Scene.ConfirmEmail.Title") + internal enum Button { + /// I never got an email + internal static let dontReceiveEmail = L10n.tr("Localizable", "Scene.ConfirmEmail.Button.DontReceiveEmail") + /// Open email app + internal static let openEmailApp = L10n.tr("Localizable", "Scene.ConfirmEmail.Button.OpenEmailApp") + } + internal enum DontReceiveEmail { + /// Give our servers another n seconds before sending another email.\n\nCheck if your email address is correct as well as your junk folder if you haven’t. + internal static let alertDescription = L10n.tr("Localizable", "Scene.ConfirmEmail.DontReceiveEmail.alertDescription") + /// It’s too soon to tell. + internal static let alertTitle = L10n.tr("Localizable", "Scene.ConfirmEmail.DontReceiveEmail.alertTitle") + } + internal enum OpenEmailApp { + /// We just sent you another email. Check your junk folder if you haven’t. + internal static let alertDescription = L10n.tr("Localizable", "Scene.ConfirmEmail.OpenEmailApp.alertDescription") + /// Check your inbox. + internal static let alertTitle = L10n.tr("Localizable", "Scene.ConfirmEmail.OpenEmailApp.alertTitle") + } + } internal enum HomeTimeline { /// Home internal static let title = L10n.tr("Localizable", "Scene.HomeTimeline.Title") diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 3455e6836..26ce99d70 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -66,5 +66,16 @@ Dark UIViewControllerBasedStatusBarAppearance + LSApplicationQueriesSchemes + + sparrow + googlegmail + x-dispatch + readdle-spark + airmail + ms-outlook + ymail + fastmail + diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings index 9ef824361..47a1cf0bf 100644 --- a/Mastodon/Resources/en.lproj/Localizable.strings +++ b/Mastodon/Resources/en.lproj/Localizable.strings @@ -29,6 +29,7 @@ "Scene.Register.Input.Username.DuplicatePrompt" = "This username is taken."; "Scene.Register.Input.Username.Placeholder" = "username"; "Scene.Register.Title" = "Tell us about you."; + "Scene.ServerPicker.Input.Placeholder" = "Find a server or join your own..."; "Scene.ServerPicker.Title" = "Pick a Server, any server."; @@ -36,5 +37,22 @@ any server."; "Scene.ServerRules.Prompt" = "By continuing, you're subject to the terms of service and privacy policy for %@."; "Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@."; "Scene.ServerRules.Title" = "Some ground rules."; + "Scene.Welcome.Slogan" = "Social networking back in your hands."; + +"Scene.ConfirmEmail.Title" = "One last thing."; +"Scene.ConfirmEmail.Subtitle" = "We just sent an email to %@, +tap the link to confirm your account."; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Open email app"; + +"Scene.ConfirmEmail.Button.DontReceiveEmail" = "I never got an email"; + +"Scene.ConfirmEmail.DontReceiveEmail.alertTitle" = "It’s too soon to tell."; +"Scene.ConfirmEmail.DontReceiveEmail.alertDescription" = "Give our servers another n seconds before sending another email. + +Check if your email address is correct as well as your junk folder if you haven’t."; +"Scene.ConfirmEmail.OpenEmailApp.alertTitle" = "Check your inbox."; +"Scene.ConfirmEmail.OpenEmailApp.alertDescription" = "We just sent you another email. Check your junk folder if you haven’t."; + + diff --git a/Mastodon/Scene/Authentication/ConfirmEmail/MastodonConfirmEmailViewController.swift b/Mastodon/Scene/Authentication/ConfirmEmail/MastodonConfirmEmailViewController.swift new file mode 100644 index 000000000..0c45a0220 --- /dev/null +++ b/Mastodon/Scene/Authentication/ConfirmEmail/MastodonConfirmEmailViewController.swift @@ -0,0 +1,144 @@ +// +// MastodonConfirmEmailViewController.swift +// Mastodon +// +// Created by sxiaojian on 2021/2/23. +// + +import Combine +import ThirdPartyMailer +import UIKit + +final class MastodonConfirmEmailViewController: UIViewController, NeedsDependency { + var disposeBag = Set() + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var viewModel: MastodonConfirmEmailViewModel! + + let largeTitleLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.boldSystemFont(ofSize: 34)) + label.textColor = .label + label.text = L10n.Scene.ConfirmEmail.title + return label + }() + + private(set) lazy var subtitleLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: UIFont.systemFont(ofSize: 20)) + label.textColor = .secondaryLabel + label.text = L10n.Scene.ConfirmEmail.subtitle(viewModel.email) + label.numberOfLines = 0 + return label + }() + + let openEmailButton: UIButton = { + let button = UIButton(type: .system) + button.titleLabel?.font = .preferredFont(forTextStyle: .headline) + button.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.lightBrandBlue.color), for: .normal) + button.setTitleColor(.white, for: .normal) + button.setTitle(L10n.Scene.ConfirmEmail.Button.openEmailApp, for: .normal) + button.layer.masksToBounds = true + button.layer.cornerRadius = 8 + button.layer.cornerCurve = .continuous + button.addTarget(self, action: #selector(openEmailButtonPressed(_:)), for: UIControl.Event.touchUpInside) + return button + }() + + let dontReceiveButton: UIButton = { + let button = UIButton(type: .system) + button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: UIFont.boldSystemFont(ofSize: 15)) + button.setTitleColor(Asset.Colors.lightBrandBlue.color, for: .normal) + button.setTitle(L10n.Scene.ConfirmEmail.Button.dontReceiveEmail, for: .normal) + button.addTarget(self, action: #selector(dontReceiveButtonPressed(_:)), for: UIControl.Event.touchUpInside) + return button + }() +} + +extension MastodonConfirmEmailViewController { + override func viewDidLoad() { + overrideUserInterfaceStyle = .light + view.backgroundColor = Asset.Colors.Background.onboardingBackground.color + // set navigationBar transparent + self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarPosition.any, barMetrics: .default) + self.navigationController?.navigationBar.shadowImage = UIImage() + self.navigationController?.navigationBar.topItem?.title = "Back" + + // resizedView + let resizedView = UIView() + resizedView.translatesAutoresizingMaskIntoConstraints = false + resizedView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical) + + // stackView + let stackView = UIStackView() + stackView.axis = .vertical + stackView.distribution = .fill + stackView.spacing = 10 + stackView.layoutMargins = UIEdgeInsets(top: 10, left: 0, bottom: 23, right: 0) + stackView.isLayoutMarginsRelativeArrangement = true + stackView.addArrangedSubview(self.largeTitleLabel) + stackView.addArrangedSubview(self.subtitleLabel) + stackView.addArrangedSubview(resizedView) + stackView.addArrangedSubview(self.openEmailButton) + stackView.addArrangedSubview(self.dontReceiveButton) + + view.addSubview(stackView) + stackView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + stackView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor), + stackView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor), + stackView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor), + ]) + NSLayoutConstraint.activate([ + self.openEmailButton.heightAnchor.constraint(equalToConstant: 46), + ]) + } +} + +extension MastodonConfirmEmailViewController { + @objc private func openEmailButtonPressed(_ sender: UIButton) { + let alertController = UIAlertController(title: L10n.Scene.ConfirmEmail.OpenEmailApp.alertTitle, message: L10n.Scene.ConfirmEmail.OpenEmailApp.alertDescription, preferredStyle: .alert) + let openEmailAction = UIAlertAction(title: L10n.Scene.ConfirmEmail.Button.openEmailApp, style: .default) { [weak self] _ in + guard let self = self else { return } + self.showEmailAppAlert() + } + let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel, handler: nil) + alertController.addAction(openEmailAction) + alertController.addAction(cancelAction) + + self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil)) + } + + @objc private func dontReceiveButtonPressed(_ sender: UIButton) { + let alertController = UIAlertController(title: L10n.Scene.ConfirmEmail.DontReceiveEmail.alertTitle, message: L10n.Scene.ConfirmEmail.DontReceiveEmail.alertDescription, preferredStyle: .alert) + let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { _ in } + alertController.addAction(okAction) + self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil)) + } + + func showEmailAppAlert() { + let clients = ThirdPartyMailClient.clients() + let application = UIApplication.shared + let avaliableClients = clients.filter { client -> Bool in + ThirdPartyMailer.application(application, isMailClientAvailable: client) + } + let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + let alertAction = UIAlertAction(title: "Mail", style: .default) { _ in + UIApplication.shared.open(URL(string: "message://")!, options: [:], completionHandler: nil) + } + alertController.addAction(alertAction) + _ = avaliableClients.compactMap { client -> UIAlertAction in + let alertAction = UIAlertAction(title: client.name, style: .default) { _ in + _ = ThirdPartyMailer.application(application, openMailClient: client, recipient: nil, subject: nil, body: nil) + } + alertController.addAction(alertAction) + return alertAction + } + let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel, handler: nil) + alertController.addAction(cancelAction) + self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil)) + } +} diff --git a/Mastodon/Scene/Authentication/ConfirmEmail/MastodonConfirmEmailViewModel.swift b/Mastodon/Scene/Authentication/ConfirmEmail/MastodonConfirmEmailViewModel.swift new file mode 100644 index 000000000..8da02d8ed --- /dev/null +++ b/Mastodon/Scene/Authentication/ConfirmEmail/MastodonConfirmEmailViewModel.swift @@ -0,0 +1,21 @@ +// +// MastodonConfirmEmailViewModel.swift +// Mastodon +// +// Created by sxiaojian on 2021/2/23. +// + +import Combine + +final class MastodonConfirmEmailViewModel { + var disposeBag = Set() + + let context: AppContext + var email: String + + init(context: AppContext, email: String) { + self.context = context + self.email = email + } +} + diff --git a/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift index 98f876c3d..dd29d10bf 100644 --- a/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift @@ -572,7 +572,8 @@ extension MastodonRegisterViewController { let alertController = UIAlertController(title: "Success", message: "Regsiter request sent. Please check your email.\n(Auto sign in not implement yet.)", preferredStyle: .alert) let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default) { [weak self] _ in guard let self = self else { return } - self.navigationController?.popViewController(animated: true) + let viewModel = MastodonConfirmEmailViewModel(context: self.context, email: email) + self.coordinator.present(scene: .mastodonConfirmEmail(viewModel: viewModel), from: self, transition: .show) } alertController.addAction(okAction) self.coordinator.present(scene: .alertController(alertController: alertController), from: self, transition: .alertController(animated: true, completion: nil))