diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 4655b4bb9..9b7a4d65e 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -74,6 +74,8 @@ 32891D6C2264CBA300C82226 /* SimpleScreenTemplateViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32891D6A2264CBA300C82226 /* SimpleScreenTemplateViewController.storyboard */; }; 32891D702264DF7B00C82226 /* DeviceVerificationVerifiedViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32891D6E2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.storyboard */; }; 32891D712264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D6F2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift */; }; + 32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */; }; + 32891D76226728EF00C82226 /* DeviceVerificationDataLoadingViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */; }; 32B1FEDB21A46F2C00637127 /* TermsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32B1FEDA21A46F2C00637127 /* TermsView.xib */; }; 32BF994F21FA29A400698084 /* SettingsKeyBackupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF994E21FA29A400698084 /* SettingsKeyBackupViewModel.swift */; }; 32BF995121FA29DC00698084 /* SettingsKeyBackupViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF995021FA29DC00698084 /* SettingsKeyBackupViewModelType.swift */; }; @@ -579,6 +581,8 @@ 32891D6A2264CBA300C82226 /* SimpleScreenTemplateViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SimpleScreenTemplateViewController.storyboard; sourceTree = ""; }; 32891D6E2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DeviceVerificationVerifiedViewController.storyboard; sourceTree = ""; }; 32891D6F2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationVerifiedViewController.swift; sourceTree = ""; }; + 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationDataLoadingViewController.swift; sourceTree = ""; }; + 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DeviceVerificationDataLoadingViewController.storyboard; sourceTree = ""; }; 32B1FEDA21A46F2C00637127 /* TermsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TermsView.xib; sourceTree = ""; }; 32BDC9A1211C2C870064AF51 /* zh_Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hant; path = zh_Hant.lproj/InfoPlist.strings; sourceTree = ""; }; 32BDC9A2211C2C870064AF51 /* zh_Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hant; path = zh_Hant.lproj/Localizable.strings; sourceTree = ""; }; @@ -1338,6 +1342,7 @@ isa = PBXGroup; children = ( 324A2046225FC571004FE8B0 /* Incoming */, + 32891D72226728EE00C82226 /* Loading */, 3232AB96225730E100AD6A5C /* Start */, 32891D6D2264DF7B00C82226 /* Verified */, 3232ABAC2257BE6400AD6A5C /* Verify */, @@ -1436,6 +1441,15 @@ path = Verified; sourceTree = ""; }; + 32891D72226728EE00C82226 /* Loading */ = { + isa = PBXGroup; + children = ( + 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */, + 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */, + ); + path = Loading; + sourceTree = ""; + }; 32935CB21F628B98006888C8 /* js */ = { isa = PBXGroup; children = ( @@ -3523,6 +3537,7 @@ B1B557A220EF58AD00210D55 /* ContactTableViewCell.xib in Resources */, B1B558EB20EF768F00210D55 /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib in Resources */, B10B3B5C2201DD740072C76B /* KeyBackupBannerCell.xib in Resources */, + 32891D76226728EF00C82226 /* DeviceVerificationDataLoadingViewController.storyboard in Resources */, B1B5581820EF625800210D55 /* PreviewRoomTitleView.xib in Resources */, B1B5583020EF66BA00210D55 /* RoomIdOrAliasTableViewCell.xib in Resources */, B1B558BF20EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.xib in Resources */, @@ -3824,6 +3839,7 @@ 3232ABBC2257BE6500AD6A5C /* DeviceVerificationVerifyViewAction.swift in Sources */, F05927C91FDED836009F2A68 /* MXGroup+Riot.m in Sources */, B1B5594520EF7BD000210D55 /* TableViewCellWithCollectionView.m in Sources */, + 32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */, 32891D712264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift in Sources */, F083BDEF1E7009ED00A9B29C /* UINavigationController+Riot.m in Sources */, B1B5581F20EF625800210D55 /* SimpleRoomTitleView.m in Sources */, diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index a5276d40e..c57be644c 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -797,6 +797,7 @@ "device_verification_title" = "Verify device"; "device_verification_security_advice" = "For maximum security, we recommend you do this in person or use another trusted means of communication"; "device_verification_cancelled" = "The other party cancelled the verification."; +"device_verification_error_cannot_load_device" = "Cannot load device information."; // Mark: Incoming "device_verification_incoming_title" = "Incoming Verification Request"; diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index 0fc7a7d0f..5db46ea18 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -12,6 +12,11 @@ import UIKit // swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name internal enum StoryboardScene { + internal enum DeviceVerificationDataLoadingViewController: StoryboardType { + internal static let storyboardName = "DeviceVerificationDataLoadingViewController" + + internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationDataLoadingViewController.self) + } internal enum DeviceVerificationIncomingViewController: StoryboardType { internal static let storyboardName = "DeviceVerificationIncomingViewController" diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index fdb177bd5..c37b9c9a6 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -686,6 +686,10 @@ internal enum VectorL10n { internal static var deviceVerificationEmojiUnicorn: String { return VectorL10n.tr("Vector", "device_verification_emoji_unicorn") } + /// Cannot load device information. + internal static var deviceVerificationErrorCannotLoadDevice: String { + return VectorL10n.tr("Vector", "device_verification_error_cannot_load_device") + } /// Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages. internal static var deviceVerificationIncomingDescription1: String { return VectorL10n.tr("Vector", "device_verification_incoming_description_1") diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift index 67efd8eec..278d8d95d 100644 --- a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift @@ -69,45 +69,10 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { // MARK: - Public methods func start() { - - guard let otherUser = self.session.user(withUserId: otherUserId) else { - return // TODO - } - - // Before starting make sure we have device crypto informatino - self.session.crypto?.downloadKeys([self.otherUserId], forceDownload: false, success: { [weak self] (usersDevicesMap) in - guard let sself = self else { - return - } - - guard let otherDevice = usersDevicesMap?.object(forDevice: sself.otherDeviceId, forUser: sself.otherUserId) else { - return // TODO - } - - var rootCoordinator: Coordinator & Presentable - if let incomingTransaction = sself.incomingTransaction { - let coordinator = sself.createDeviceVerificationIncomingCoordinator(otherUser: otherUser, transaction: incomingTransaction) - coordinator.delegate = self - rootCoordinator = coordinator - } else { - let coordinator = sself.createDeviceVerificationStartCoordinator(otherUser: otherUser, otherDevice: otherDevice) - coordinator.delegate = self - rootCoordinator = coordinator - } - - // TODO: To remove. Only for dev - //rootCoordinator = DeviceVerificationVerifyCoordinator(session: sself.session) - //rootCoordinator.delegate = self - - rootCoordinator.start() - - sself.add(childCoordinator: rootCoordinator) - sself.navigationRouter.setRootModule(rootCoordinator) - - }, failure: { (error) in - // TODO - }) - } + let rootViewController = self.createDataLoadingViewController() + rootViewController.delegate = self + self.navigationRouter.setRootModule(rootViewController) + } func toPresentable() -> UIViewController { return self.navigationRouter.toPresentable() @@ -115,16 +80,28 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { // MARK: - Private methods - private func createDeviceVerificationStartCoordinator(otherUser: MXUser, otherDevice: MXDeviceInfo) -> DeviceVerificationStartCoordinator { - let coordinator = DeviceVerificationStartCoordinator(session: self.session, otherUser: otherUser, otherDevice: otherDevice) - coordinator.delegate = self - return coordinator + private func createDataLoadingViewController() -> DeviceVerificationDataLoadingViewController { + let viewController = DeviceVerificationDataLoadingViewController.instantiate(session: self.session, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId) + viewController.delegate = self + return viewController } - private func createDeviceVerificationIncomingCoordinator(otherUser: MXUser, transaction: MXIncomingSASTransaction) -> DeviceVerificationIncomingCoordinator { + private func showStart(otherUser: MXUser, otherDevice: MXDeviceInfo) { + let coordinator = DeviceVerificationStartCoordinator(session: self.session, otherUser: otherUser, otherDevice: otherDevice) + coordinator.delegate = self + coordinator.start() + + self.add(childCoordinator: coordinator) + self.navigationRouter.setRootModule(coordinator) + } + + private func showIncoming(otherUser: MXUser, transaction: MXIncomingSASTransaction) { let coordinator = DeviceVerificationIncomingCoordinator(session: self.session, otherUser: otherUser, transaction: transaction) coordinator.delegate = self - return coordinator + coordinator.start() + + self.add(childCoordinator: coordinator) + self.navigationRouter.setRootModule(coordinator) } private func showVerify(transaction: MXSASTransaction, animated: Bool) { @@ -145,6 +122,21 @@ final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { } } +extension DeviceVerificationCoordinator: DeviceVerificationDataLoadingViewControllerDelegate { + func deviceVerificationDataLoadingViewControllerDidLoadData(_ viewController: DeviceVerificationDataLoadingViewController, user: MXUser, device: MXDeviceInfo) { + + if let incomingTransaction = self.incomingTransaction { + self.showIncoming(otherUser: user, transaction: incomingTransaction) + } else { + self.showStart(otherUser: user, otherDevice: device) + } + } + + func deviceVerificationDataLoadingViewControllerDidCancel(_ viewController: DeviceVerificationDataLoadingViewController) { + self.delegate?.deviceVerificationCoordinatorDidComplete(self, otherUserId: self.otherUserId, otherDeviceId: self.otherDeviceId) + } +} + extension DeviceVerificationCoordinator: DeviceVerificationStartCoordinatorDelegate { func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didCompleteWithOutgoingTransaction transaction: MXSASTransaction) { self.showVerify(transaction: transaction, animated: true) diff --git a/Riot/Modules/DeviceVerification/Incoming/DeviceVerificationIncomingViewController.swift b/Riot/Modules/DeviceVerification/Incoming/DeviceVerificationIncomingViewController.swift index 2972e81a2..55348b673 100644 --- a/Riot/Modules/DeviceVerification/Incoming/DeviceVerificationIncomingViewController.swift +++ b/Riot/Modules/DeviceVerification/Incoming/DeviceVerificationIncomingViewController.swift @@ -69,6 +69,7 @@ final class DeviceVerificationIncomingViewController: UIViewController { // Do any additional setup after loading the view. self.title = VectorL10n.deviceVerificationTitle + self.vc_removeBackTitle() self.setupViews() self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView) diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.storyboard b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.storyboard new file mode 100644 index 000000000..5140d7bfd --- /dev/null +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.storyboard @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift new file mode 100644 index 000000000..90c35bdb4 --- /dev/null +++ b/Riot/Modules/DeviceVerification/Loading/DeviceVerificationDataLoadingViewController.swift @@ -0,0 +1,147 @@ +// File created from simpleScreenTemplate +// $ createSimpleScreen.sh DeviceVerification/Loading DeviceVerificationDataLoading +/* + 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 + +protocol DeviceVerificationDataLoadingViewControllerDelegate: class { + func deviceVerificationDataLoadingViewControllerDidLoadData(_ viewController: DeviceVerificationDataLoadingViewController, user: MXUser, device: MXDeviceInfo) + func deviceVerificationDataLoadingViewControllerDidCancel(_ viewController: DeviceVerificationDataLoadingViewController) +} + +final class DeviceVerificationDataLoadingViewController: UIViewController { + + // MARK: - Properties + + // MARK: Outlets + + // MARK: Private + + private var session: MXSession! + private var otherUserId: String! + private var otherDeviceId: String! + + private var theme: Theme! + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + // MARK: Public + + weak var delegate: DeviceVerificationDataLoadingViewControllerDelegate? + + // MARK: - Setup + + class func instantiate(session: MXSession, otherUserId: String, otherDeviceId: String) -> DeviceVerificationDataLoadingViewController { + let viewController = StoryboardScene.DeviceVerificationDataLoadingViewController.initialScene.instantiate() + viewController.session = session + viewController.otherUserId = otherUserId + viewController.otherDeviceId = otherDeviceId + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = VectorL10n.deviceVerificationTitle + self.vc_removeBackTitle() + + self.setupViews() + + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + self.loadData() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func setupViews() { + } + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + private func loadData() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + + if let otherUser = self.session.user(withUserId: otherUserId) { + self.session.crypto?.downloadKeys([self.otherUserId], forceDownload: false, success: { [weak self] (usersDevicesMap) in + guard let sself = self else { + return + } + + sself.activityPresenter.removeCurrentActivityIndicator(animated: true) + + if let otherDevice = usersDevicesMap?.object(forDevice: sself.otherDeviceId, forUser: sself.otherUserId) { + sself.delegate?.deviceVerificationDataLoadingViewControllerDidLoadData(sself, user: otherUser, device: otherDevice) + } else { + sself.errorPresenter.presentError(from: sself, title: "", message: VectorL10n.deviceVerificationErrorCannotLoadDevice, animated: true, handler: { + sself.delegate?.deviceVerificationDataLoadingViewControllerDidCancel(sself) + }) + } + + }, failure: { [weak self] (error) in + guard let sself = self else { + return + } + + sself.activityPresenter.removeCurrentActivityIndicator(animated: true) + sself.errorPresenter.presentError(from: sself, forError: error, animated: true, handler: { + sself.delegate?.deviceVerificationDataLoadingViewControllerDidCancel(sself) + }) + }) + + } else { + self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationErrorCannotLoadDevice, animated: true, handler: { + self.delegate?.deviceVerificationDataLoadingViewControllerDidCancel(self) + }) + } + } + + // MARK: - Actions + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func cancelButtonAction() { + self.delegate?.deviceVerificationDataLoadingViewControllerDidCancel(self) + } +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift index 3aba22e80..4cffdbdbd 100644 --- a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift @@ -65,6 +65,7 @@ final class DeviceVerificationStartViewController: UIViewController { // Do any additional setup after loading the view. self.title = VectorL10n.deviceVerificationTitle + self.vc_removeBackTitle() self.setupViews() self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView) diff --git a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift index b15eef975..188686776 100644 --- a/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift +++ b/Riot/Modules/DeviceVerification/Verify/DeviceVerificationVerifyViewController.swift @@ -64,6 +64,7 @@ final class DeviceVerificationVerifyViewController: UIViewController { // Do any additional setup after loading the view. self.title = VectorL10n.deviceVerificationTitle + self.vc_removeBackTitle() self.setupViews() self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView)