diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index eb5802c59..dcfda5940 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -187,6 +187,7 @@ B12D7A0023E2462200FACEDC /* UserVerificationStartCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12D79F823E2462200FACEDC /* UserVerificationStartCoordinatorType.swift */; }; B12D7A0123E2462200FACEDC /* UserVerificationStartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12D79F923E2462200FACEDC /* UserVerificationStartViewModel.swift */; }; B12D7A0223E2462200FACEDC /* UserVerificationStartViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12D79FA23E2462200FACEDC /* UserVerificationStartViewAction.swift */; }; + B12D7A0423E43DCC00FACEDC /* KeyVerificationKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12D7A0323E43DCC00FACEDC /* KeyVerificationKind.swift */; }; B139C21B21FE5B9200BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B139C21A21FE5B9100BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift */; }; B139C21D21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B139C21C21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift */; }; B139C21F21FE5D6600BB68EC /* KeyBackupRecoverFromPassphraseViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B139C21E21FE5D6600BB68EC /* KeyBackupRecoverFromPassphraseViewAction.swift */; }; @@ -915,6 +916,7 @@ B12D79F823E2462200FACEDC /* UserVerificationStartCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserVerificationStartCoordinatorType.swift; sourceTree = ""; }; B12D79F923E2462200FACEDC /* UserVerificationStartViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserVerificationStartViewModel.swift; sourceTree = ""; }; B12D79FA23E2462200FACEDC /* UserVerificationStartViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserVerificationStartViewAction.swift; sourceTree = ""; }; + B12D7A0323E43DCC00FACEDC /* KeyVerificationKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyVerificationKind.swift; sourceTree = ""; }; B139C21A21FE5B9100BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseViewModel.swift; sourceTree = ""; }; B139C21C21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseViewModelType.swift; sourceTree = ""; }; B139C21E21FE5D6600BB68EC /* KeyBackupRecoverFromPassphraseViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverFromPassphraseViewAction.swift; sourceTree = ""; }; @@ -1749,8 +1751,9 @@ 324A2046225FC571004FE8B0 /* Incoming */, 32891D72226728EE00C82226 /* Loading */, 3232AB96225730E100AD6A5C /* Start */, - 32891D6D2264DF7B00C82226 /* Verified */, 3232ABAC2257BE6400AD6A5C /* Verify */, + 32891D6D2264DF7B00C82226 /* Verified */, + B12D7A0323E43DCC00FACEDC /* KeyVerificationKind.swift */, 3232AB95225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift */, 3232AB9F225730E100AD6A5C /* DeviceVerificationCoordinatorBridgePresenter.swift */, 3232ABA0225730E100AD6A5C /* DeviceVerificationCoordinator.swift */, @@ -5082,6 +5085,7 @@ B1B9DEEE22EB34EF0065E677 /* ReactionHistoryViewAction.swift in Sources */, B1C543A4239E98E400DCA1FA /* KeyVerificationCellInnerContentView.swift in Sources */, 32B94DFA228EC26400716A26 /* ReactionsMenuButton.swift in Sources */, + B12D7A0423E43DCC00FACEDC /* KeyVerificationKind.swift in Sources */, B1B9DEEC22EB34EF0065E677 /* ReactionHistoryViewModelType.swift in Sources */, B157FAA523264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift in Sources */, B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */, diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift index b3ffdc89e..476cf80cd 100644 --- a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift @@ -28,12 +28,13 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { private let navigationRouter: NavigationRouterType private let session: MXSession private let otherUserId: String - private let otherDeviceId: String - + private let otherDeviceId: String + private var incomingTransaction: MXIncomingSASTransaction? private var incomingKeyVerificationRequest: MXKeyVerificationRequest? - var roomMember: MXRoomMember? + private var verificationKind: KeyVerificationKind = .device + private var roomMember: MXRoomMember? // MARK: Public @@ -56,6 +57,13 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { self.otherUserId = otherUserId self.otherDeviceId = otherDeviceId } + + init(navigationRouter: NavigationRouterType, session: MXSession, userId: String, otherDeviceId: String) { + self.navigationRouter = navigationRouter + self.session = session + self.otherUserId = userId + self.otherDeviceId = otherDeviceId + } /// Contrustor to manage an incoming SAS device verification transaction /// @@ -90,6 +98,7 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { self.otherUserId = roomMember.userId self.otherDeviceId = "" self.roomMember = roomMember + self.verificationKind = .user } // MARK: - Public methods @@ -108,8 +117,15 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { rootCoordinator.start() self.add(childCoordinator: rootCoordinator) - self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in - self?.remove(childCoordinator: rootCoordinator) + + if self.navigationRouter.modules.isEmpty == false { + self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in + self?.remove(childCoordinator: rootCoordinator) + }) + } else { + self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in + self?.remove(childCoordinator: rootCoordinator) + } } } @@ -166,7 +182,7 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { } private func showVerify(transaction: MXSASTransaction, animated: Bool) { - let coordinator = DeviceVerificationVerifyCoordinator(session: self.session, transaction: transaction) + let coordinator = DeviceVerificationVerifyCoordinator(session: self.session, transaction: transaction, verificationKind: self.verificationKind) coordinator.delegate = self coordinator.start() @@ -177,7 +193,7 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { } private func showVerified(animated: Bool) { - let viewController = DeviceVerificationVerifiedViewController.instantiate() + let viewController = DeviceVerificationVerifiedViewController.instantiate(with: self.verificationKind) viewController.delegate = self self.navigationRouter.setRootModule(viewController) } diff --git a/Riot/Modules/DeviceVerification/KeyVerificationKind.swift b/Riot/Modules/DeviceVerification/KeyVerificationKind.swift new file mode 100644 index 000000000..d9d8f29fe --- /dev/null +++ b/Riot/Modules/DeviceVerification/KeyVerificationKind.swift @@ -0,0 +1,21 @@ +/* + Copyright 2020 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 + +enum KeyVerificationKind { + case device + case user +} diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift index a21cc9f31..1d6a465ad 100644 --- a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift @@ -66,6 +66,13 @@ final class DeviceVerificationDataLoadingViewController: UIViewController { return self.theme.statusBarStyle } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // Hide back button + self.navigationItem.setHidesBackButton(true, animated: animated) + } + // MARK: - Private private func update(theme: Theme) { diff --git a/Riot/Modules/DeviceVerification/Verified/DeviceVerificationVerifiedViewController.swift b/Riot/Modules/DeviceVerification/Verified/DeviceVerificationVerifiedViewController.swift index b9ebde0b5..a583410bd 100644 --- a/Riot/Modules/DeviceVerification/Verified/DeviceVerificationVerifiedViewController.swift +++ b/Riot/Modules/DeviceVerification/Verified/DeviceVerificationVerifiedViewController.swift @@ -39,6 +39,7 @@ final class DeviceVerificationVerifiedViewController: UIViewController { // MARK: Private private var theme: Theme! + private var verificationKind: KeyVerificationKind = .user // MARK: Public @@ -46,9 +47,10 @@ final class DeviceVerificationVerifiedViewController: UIViewController { // MARK: - Setup - class func instantiate() -> DeviceVerificationVerifiedViewController { + class func instantiate(with verificationKind: KeyVerificationKind) -> DeviceVerificationVerifiedViewController { let viewController = StoryboardScene.DeviceVerificationVerifiedViewController.initialScene.instantiate() viewController.theme = ThemeService.shared().theme + viewController.verificationKind = verificationKind return viewController } @@ -59,7 +61,6 @@ final class DeviceVerificationVerifiedViewController: UIViewController { // Do any additional setup after loading the view. - self.title = VectorL10n.deviceVerificationTitle self.vc_removeBackTitle() self.setupViews() @@ -81,9 +82,28 @@ final class DeviceVerificationVerifiedViewController: UIViewController { // MARK: - Private private func setupViews() { - self.titleLabel.text = VectorL10n.deviceVerificationVerifiedTitle - self.description1Label.text = VectorL10n.deviceVerificationVerifiedDescription1 - self.description2Label.text = VectorL10n.deviceVerificationVerifiedDescription2 + let title: String + let bodyTitle: String + let descriptionTextPart1: String + let descriptionTextPart2: String + + switch self.verificationKind { + case .device: + title = VectorL10n.deviceVerificationTitle + bodyTitle = VectorL10n.deviceVerificationVerifiedTitle + descriptionTextPart1 = VectorL10n.deviceVerificationVerifiedDescription1 + descriptionTextPart2 = VectorL10n.deviceVerificationVerifiedDescription2 + case .user: + title = "Verify user" + bodyTitle = VectorL10n.deviceVerificationVerifiedTitle + descriptionTextPart1 = "You’ve successfully verified this user." + descriptionTextPart2 = "Messages with this user in this room are end-to-end encrypted and can’t be read by third parties." + } + + self.title = title + self.titleLabel.text = bodyTitle + self.description1Label.text = descriptionTextPart1 + self.description2Label.text = descriptionTextPart2 self.okButton.setTitle(VectorL10n.deviceVerificationVerifiedGotItButton, for: .normal) } @@ -103,7 +123,7 @@ final class DeviceVerificationVerifiedViewController: UIViewController { self.okButtonBackgroundView.backgroundColor = theme.backgroundColor theme.applyStyle(onButton: self.okButton) - } + } private func registerThemeServiceDidChangeThemeNotification() { NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) diff --git a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyCoordinator.swift b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyCoordinator.swift index 4b5c83580..e3793c883 100644 --- a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyCoordinator.swift +++ b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyCoordinator.swift @@ -38,10 +38,10 @@ final class DeviceVerificationVerifyCoordinator: DeviceVerificationVerifyCoordin // MARK: - Setup - init(session: MXSession, transaction: MXSASTransaction) { + init(session: MXSession, transaction: MXSASTransaction, verificationKind: KeyVerificationKind) { self.session = session - let deviceVerificationVerifyViewModel = DeviceVerificationVerifyViewModel(session: self.session, transaction: transaction) + let deviceVerificationVerifyViewModel = DeviceVerificationVerifyViewModel(session: self.session, transaction: transaction, verificationKind: verificationKind) let deviceVerificationVerifyViewController = DeviceVerificationVerifyViewController.instantiate(with: deviceVerificationVerifyViewModel) self.deviceVerificationVerifyViewModel = deviceVerificationVerifyViewModel self.deviceVerificationVerifyViewController = deviceVerificationVerifyViewController diff --git a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift index 7869f9a31..69065a751 100644 --- a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift +++ b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift @@ -59,7 +59,6 @@ final class DeviceVerificationVerifyViewController: UIViewController { // Do any additional setup after loading the view. - self.title = VectorL10n.deviceVerificationTitle self.vc_removeBackTitle() self.setupViews() @@ -123,16 +122,33 @@ final class DeviceVerificationVerifyViewController: UIViewController { self.scrollView.keyboardDismissMode = .interactive - if viewModel.emojis != nil { + let isVerificationByEmoji = viewModel.emojis != nil + + if isVerificationByEmoji { self.decimalLabel.isHidden = true - self.titleLabel.text = VectorL10n.deviceVerificationVerifyTitleEmoji } else { self.emojisCollectionView.isHidden = true - self.titleLabel.text = VectorL10n.deviceVerificationVerifyTitleNumber self.decimalLabel.text = self.viewModel.decimal } + + let title: String + let instructionText: String + let adviceText: String + + switch viewModel.verificationKind { + case .device: + title = VectorL10n.deviceVerificationTitle + instructionText = isVerificationByEmoji ? VectorL10n.deviceVerificationVerifyTitleEmoji : VectorL10n.deviceVerificationVerifyTitleNumber + adviceText = VectorL10n.deviceVerificationSecurityAdvice + case .user: + title = "Verify user" + instructionText = isVerificationByEmoji ? "Verify this user by confirming the following unique emoji appears on their screen, in the same order." : "Verify this user by confirming the following numbers appear on their screen, in the same order." + adviceText = VectorL10n.deviceVerificationSecurityAdvice + } - self.informationLabel.text = VectorL10n.deviceVerificationSecurityAdvice + self.title = title + self.titleLabel.text = instructionText + self.informationLabel.text = adviceText self.waitingPartnerLabel.text = VectorL10n.deviceVerificationVerifyWaitPartner self.waitingPartnerLabel.isHidden = true @@ -223,10 +239,8 @@ extension DeviceVerificationVerifyViewController: UICollectionViewDataSource { } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VerifyEmojiCollectionViewCell", for: indexPath) as? VerifyEmojiCollectionViewCell else { - return UICollectionViewCell() - } + + let cell = collectionView.dequeueReusableCell(for: indexPath, cellType: VerifyEmojiCollectionViewCell.self) guard let emoji = self.viewModel.emojis?[indexPath.row] else { return UICollectionViewCell() diff --git a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModel.swift b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModel.swift index 2be7640a9..86c26a7c2 100644 --- a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModel.swift +++ b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModel.swift @@ -31,16 +31,19 @@ final class DeviceVerificationVerifyViewModel: DeviceVerificationVerifyViewModel weak var viewDelegate: DeviceVerificationVerifyViewModelViewDelegate? weak var coordinatorDelegate: DeviceVerificationVerifyViewModelCoordinatorDelegate? - var emojis: [MXEmojiRepresentation]? - var decimal: String? + + let emojis: [MXEmojiRepresentation]? + let decimal: String? + let verificationKind: KeyVerificationKind // MARK: - Setup - init(session: MXSession, transaction: MXSASTransaction) { + init(session: MXSession, transaction: MXSASTransaction, verificationKind: KeyVerificationKind) { self.session = session self.transaction = transaction self.emojis = self.transaction.sasEmoji self.decimal = self.transaction.sasDecimal + self.verificationKind = verificationKind } deinit { diff --git a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModelType.swift b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModelType.swift index 8ea8aa449..9c5167f4f 100644 --- a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModelType.swift +++ b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewModelType.swift @@ -35,6 +35,7 @@ protocol DeviceVerificationVerifyViewModelType { func process(viewAction: DeviceVerificationVerifyViewAction) - var emojis: [MXEmojiRepresentation]? { get set } - var decimal: String? { get set } + var emojis: [MXEmojiRepresentation]? { get } + var decimal: String? { get } + var verificationKind: KeyVerificationKind { get } } diff --git a/Riot/Modules/DeviceVerification/Verify/Views/VerifyEmojiCollectionViewCell.swift b/Riot/Modules/DeviceVerification/Verify/Views/VerifyEmojiCollectionViewCell.swift index 7d1780062..e609f6b38 100644 --- a/Riot/Modules/DeviceVerification/Verify/Views/VerifyEmojiCollectionViewCell.swift +++ b/Riot/Modules/DeviceVerification/Verify/Views/VerifyEmojiCollectionViewCell.swift @@ -15,8 +15,9 @@ */ import UIKit +import Reusable -class VerifyEmojiCollectionViewCell: UICollectionViewCell, Themable { +class VerifyEmojiCollectionViewCell: UICollectionViewCell, Reusable, Themable { @IBOutlet weak var emoji: UILabel! @IBOutlet weak var name: UILabel!