diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 13c95d8fc..abd1ef9ad 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -36,6 +36,17 @@ 3232AB502256558300AD6A5C /* TemplateScreenViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB452256558300AD6A5C /* TemplateScreenViewState.swift */; }; 3232AB512256558300AD6A5C /* TemplateScreenViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB462256558300AD6A5C /* TemplateScreenViewAction.swift */; }; 3232AB522256558300AD6A5C /* TemplateScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB472256558300AD6A5C /* TemplateScreenViewModel.swift */; }; + 3232ABA1225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB95225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift */; }; + 3232ABA2225730E100AD6A5C /* DeviceVerificationStartViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3232AB97225730E100AD6A5C /* DeviceVerificationStartViewController.storyboard */; }; + 3232ABA3225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB98225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift */; }; + 3232ABA4225730E100AD6A5C /* DeviceVerificationStartViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB99225730E100AD6A5C /* DeviceVerificationStartViewAction.swift */; }; + 3232ABA5225730E100AD6A5C /* DeviceVerificationStartViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB9A225730E100AD6A5C /* DeviceVerificationStartViewModelType.swift */; }; + 3232ABA6225730E100AD6A5C /* DeviceVerificationStartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB9B225730E100AD6A5C /* DeviceVerificationStartViewController.swift */; }; + 3232ABA7225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB9C225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift */; }; + 3232ABA8225730E100AD6A5C /* DeviceVerificationStartViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB9D225730E100AD6A5C /* DeviceVerificationStartViewState.swift */; }; + 3232ABA9225730E100AD6A5C /* DeviceVerificationStartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB9E225730E100AD6A5C /* DeviceVerificationStartViewModel.swift */; }; + 3232ABAA225730E100AD6A5C /* DeviceVerificationCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB9F225730E100AD6A5C /* DeviceVerificationCoordinatorBridgePresenter.swift */; }; + 3232ABAB225730E100AD6A5C /* DeviceVerificationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232ABA0225730E100AD6A5C /* DeviceVerificationCoordinator.swift */; }; 3233F7461F3497E2006ACA81 /* JitsiMeet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3233F7441F3497DA006ACA81 /* JitsiMeet.framework */; }; 3233F7471F3497E2006ACA81 /* JitsiMeet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3233F7441F3497DA006ACA81 /* JitsiMeet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3275FD8C21A5A2C500B9C13D /* TermsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3275FD8B21A5A2C500B9C13D /* TermsView.swift */; }; @@ -505,6 +516,17 @@ 3232AB452256558300AD6A5C /* TemplateScreenViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewState.swift; sourceTree = ""; }; 3232AB462256558300AD6A5C /* TemplateScreenViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewAction.swift; sourceTree = ""; }; 3232AB472256558300AD6A5C /* TemplateScreenViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModel.swift; sourceTree = ""; }; + 3232AB95225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationCoordinatorType.swift; sourceTree = ""; }; + 3232AB97225730E100AD6A5C /* DeviceVerificationStartViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DeviceVerificationStartViewController.storyboard; sourceTree = ""; }; + 3232AB98225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartCoordinatorType.swift; sourceTree = ""; }; + 3232AB99225730E100AD6A5C /* DeviceVerificationStartViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartViewAction.swift; sourceTree = ""; }; + 3232AB9A225730E100AD6A5C /* DeviceVerificationStartViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartViewModelType.swift; sourceTree = ""; }; + 3232AB9B225730E100AD6A5C /* DeviceVerificationStartViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartViewController.swift; sourceTree = ""; }; + 3232AB9C225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartCoordinator.swift; sourceTree = ""; }; + 3232AB9D225730E100AD6A5C /* DeviceVerificationStartViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartViewState.swift; sourceTree = ""; }; + 3232AB9E225730E100AD6A5C /* DeviceVerificationStartViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationStartViewModel.swift; sourceTree = ""; }; + 3232AB9F225730E100AD6A5C /* DeviceVerificationCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationCoordinatorBridgePresenter.swift; sourceTree = ""; }; + 3232ABA0225730E100AD6A5C /* DeviceVerificationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationCoordinator.swift; sourceTree = ""; }; 3233F7441F3497DA006ACA81 /* JitsiMeet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = ""; }; 3267EFB320E379FD00FF1CAA /* CHANGES.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.rst; sourceTree = ""; }; 3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; fileEncoding = 4; path = Podfile; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; @@ -1266,6 +1288,32 @@ path = ScreenTemplate; sourceTree = ""; }; + 3232AB94225730E100AD6A5C /* DeviceVerification */ = { + isa = PBXGroup; + children = ( + 3232AB96225730E100AD6A5C /* Start */, + 3232AB95225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift */, + 3232AB9F225730E100AD6A5C /* DeviceVerificationCoordinatorBridgePresenter.swift */, + 3232ABA0225730E100AD6A5C /* DeviceVerificationCoordinator.swift */, + ); + path = DeviceVerification; + sourceTree = ""; + }; + 3232AB96225730E100AD6A5C /* Start */ = { + isa = PBXGroup; + children = ( + 3232AB97225730E100AD6A5C /* DeviceVerificationStartViewController.storyboard */, + 3232AB98225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift */, + 3232AB99225730E100AD6A5C /* DeviceVerificationStartViewAction.swift */, + 3232AB9A225730E100AD6A5C /* DeviceVerificationStartViewModelType.swift */, + 3232AB9B225730E100AD6A5C /* DeviceVerificationStartViewController.swift */, + 3232AB9C225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift */, + 3232AB9D225730E100AD6A5C /* DeviceVerificationStartViewState.swift */, + 3232AB9E225730E100AD6A5C /* DeviceVerificationStartViewModel.swift */, + ); + path = Start; + sourceTree = ""; + }; 3233F7291F31F3B4006ACA81 /* libs */ = { isa = PBXGroup; children = ( @@ -1730,6 +1778,7 @@ B1B5567620EE6C4C00210D55 /* Modules */ = { isa = PBXGroup; children = ( + 3232AB94225730E100AD6A5C /* DeviceVerification */, B1B556EA20EE6C4C00210D55 /* Main */, B1B556CA20EE6C4C00210D55 /* TabBar */, B1B556F920EE6C4C00210D55 /* Authentication */, @@ -3359,6 +3408,7 @@ B1B558C020EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.xib in Resources */, B1B5572420EE6C4D00210D55 /* RoomViewController.xib in Resources */, B169331520F3CAFC00746532 /* PublicRoomTableViewCell.xib in Resources */, + 3232ABA2225730E100AD6A5C /* DeviceVerificationStartViewController.storyboard in Resources */, 3284A35120A07C210044F922 /* postMessageAPI.js in Resources */, B1B557A220EF58AD00210D55 /* ContactTableViewCell.xib in Resources */, B1B558EB20EF768F00210D55 /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib in Resources */, @@ -3580,6 +3630,7 @@ B16932A520F3A21C00746532 /* empty.mm in Sources */, 3232AB4A2256558300AD6A5C /* FlowTemplateCoordinator.swift in Sources */, B19EFA3B21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift in Sources */, + 3232ABA9225730E100AD6A5C /* DeviceVerificationStartViewModel.swift in Sources */, B16932FA20F3C51A00746532 /* RecentCellData.m in Sources */, B16932F220F3C49E00746532 /* GroupsDataSource.m in Sources */, B1B5581C20EF625800210D55 /* RoomAvatarTitleView.m in Sources */, @@ -3598,6 +3649,7 @@ B1B5598720EFC3E000210D55 /* Widget.m in Sources */, B1B557E320EF60B900210D55 /* MessagesSearchResultAttachmentBubbleCell.m in Sources */, B1CE9F062216FB09000FAE6A /* EncryptionKeysExportPresenter.swift in Sources */, + 3232ABAA225730E100AD6A5C /* DeviceVerificationCoordinatorBridgePresenter.swift in Sources */, B1B5574420EE6C4D00210D55 /* CallViewController.m in Sources */, B1B5572220EE6C4D00210D55 /* RoomSettingsViewController.m in Sources */, B1B5577320EE702800210D55 /* JitsiViewController.m in Sources */, @@ -3612,6 +3664,7 @@ B1B5572320EE6C4D00210D55 /* AttachmentsViewController.m in Sources */, F083BDEE1E7009ED00A9B29C /* MXRoom+Riot.m in Sources */, B1B5598620EFC3E000210D55 /* RiotSettings.swift in Sources */, + 3232ABA3225730E100AD6A5C /* DeviceVerificationStartCoordinatorType.swift in Sources */, 3232AB4D2256558300AD6A5C /* TemplateScreenCoordinatorType.swift in Sources */, B1B5581720EF625800210D55 /* PreviewRoomTitleView.m in Sources */, B1098BDF21ECE09F000DDA48 /* Strings.swift in Sources */, @@ -3631,6 +3684,7 @@ B139C21B21FE5B9200BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift in Sources */, B1B5574A20EE6C4D00210D55 /* MediaPickerViewController.m in Sources */, B1B5598520EFC3E000210D55 /* RageShakeManager.m in Sources */, + 3232ABA8225730E100AD6A5C /* DeviceVerificationStartViewState.swift in Sources */, B1B558D420EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.m in Sources */, B169331420F3CAFC00746532 /* PublicRoomTableViewCell.m in Sources */, 32BF995721FB07A400698084 /* SettingsKeyBackupTableViewSection.swift in Sources */, @@ -3663,8 +3717,10 @@ 3232AB512256558300AD6A5C /* TemplateScreenViewAction.swift in Sources */, 3232AB4E2256558300AD6A5C /* TemplateScreenViewModelType.swift in Sources */, B1B5590520EF768F00210D55 /* RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m in Sources */, + 3232ABA5225730E100AD6A5C /* DeviceVerificationStartViewModelType.swift in Sources */, B1B558DD20EF768F00210D55 /* RoomIncomingEncryptedTextMsgBubbleCell.m in Sources */, B1098BE521ECE1FC000DDA48 /* Storyboards.swift in Sources */, + 3232ABA7225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift in Sources */, B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */, B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */, B1B5573C20EE6C4D00210D55 /* MasterTabBarController.m in Sources */, @@ -3693,6 +3749,7 @@ F0D2ADA11F6AA5FD00A7097D /* MXRoomSummary+Riot.m in Sources */, B1B5596F20EFA85D00210D55 /* EncryptionInfoView.m in Sources */, B1B5573820EE6C4D00210D55 /* GroupParticipantsViewController.m in Sources */, + 3232ABAB225730E100AD6A5C /* DeviceVerificationCoordinator.swift in Sources */, B1B5583E20EF6E7F00210D55 /* GroupRoomTableViewCell.m in Sources */, B14F143522144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.swift in Sources */, B1B5574F20EE6C4D00210D55 /* RoomsViewController.m in Sources */, @@ -3702,6 +3759,7 @@ B1B5579A20EF575B00210D55 /* ForgotPasswordInputsView.m in Sources */, B1B558CC20EF768F00210D55 /* RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */, B1B5571D20EE6C4D00210D55 /* HomeViewController.m in Sources */, + 3232ABA6225730E100AD6A5C /* DeviceVerificationStartViewController.swift in Sources */, B16932EA20F3C39000746532 /* UnifiedSearchRecentsDataSource.m in Sources */, B1B557DE20EF5FBB00210D55 /* FilesSearchTableViewCell.m in Sources */, B1B5574020EE6C4D00210D55 /* SegmentedViewController.m in Sources */, @@ -3753,6 +3811,7 @@ B1B5571820EE6C4D00210D55 /* CountryPickerViewController.m in Sources */, B17982FF2119FED2001FD722 /* GDPRConsentViewController.swift in Sources */, B1098BE121ECE09F000DDA48 /* Images.swift in Sources */, + 3232ABA4225730E100AD6A5C /* DeviceVerificationStartViewAction.swift in Sources */, B1B5575A20EE6C4D00210D55 /* UnifiedSearchViewController.m in Sources */, 3232AB492256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift in Sources */, B1B5572820EE6C4D00210D55 /* RoomViewController.m in Sources */, @@ -3769,6 +3828,7 @@ B1098BFF21ECFE65000DDA48 /* PasswordStrengthView.swift in Sources */, B1B558D220EF768F00210D55 /* RoomEncryptedDataBubbleCell.m in Sources */, B1B558FA20EF768F00210D55 /* RoomMembershipBubbleCell.m in Sources */, + 3232ABA1225730E100AD6A5C /* DeviceVerificationCoordinatorType.swift in Sources */, B1B557BF20EF5B4500210D55 /* DisabledRoomInputToolbarView.m in Sources */, B1B5578620EF564900210D55 /* GroupTableViewCellWithSwitch.m in Sources */, B1098BE821ECFE52000DDA48 /* Coordinator.swift in Sources */, diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index 80f0725b6..ee9cee1c8 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 DeviceVerificationStartViewController: StoryboardType { + internal static let storyboardName = "DeviceVerificationStartViewController" + + internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationStartViewController.self) + } internal enum KeyBackupRecoverFromPassphraseViewController: StoryboardType { internal static let storyboardName = "KeyBackupRecoverFromPassphraseViewController" diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift new file mode 100644 index 000000000..5c7e27748 --- /dev/null +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinator.swift @@ -0,0 +1,80 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh DeviceVerification DeviceVerification DeviceVerificationStart +/* + 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 + +@objcMembers +final class DeviceVerificationCoordinator: DeviceVerificationCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let navigationRouter: NavigationRouterType + private let session: MXSession + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: DeviceVerificationCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController()) + self.session = session + } + + // MARK: - Public methods + + func start() { + + let rootCoordinator = self.createDeviceVerificationStartCoordinator() + + rootCoordinator.start() + + self.add(childCoordinator: rootCoordinator) + + self.navigationRouter.setRootModule(rootCoordinator) + } + + func toPresentable() -> UIViewController { + return self.navigationRouter.toPresentable() + } + + // MARK: - Private methods + + private func createDeviceVerificationStartCoordinator() -> DeviceVerificationStartCoordinator { + let coordinator = DeviceVerificationStartCoordinator(session: self.session) + coordinator.delegate = self + return coordinator + } +} + +// MARK: - DeviceVerificationStartCoordinatorDelegate +extension DeviceVerificationCoordinator: DeviceVerificationStartCoordinatorDelegate { + func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didCompleteWithMessage message: String) { + self.delegate?.deviceVerificationCoordinatorDidComplete(self) + } + + func deviceVerificationStartCoordinatorDidCancel(_ coordinator: DeviceVerificationStartCoordinatorType) { + self.delegate?.deviceVerificationCoordinatorDidComplete(self) + } +} diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift new file mode 100644 index 000000000..0c8b4fbc3 --- /dev/null +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorBridgePresenter.swift @@ -0,0 +1,79 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh DeviceVerification DeviceVerification DeviceVerificationStart +/* + 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 + +@objc protocol DeviceVerificationCoordinatorBridgePresenterDelegate { + func deviceVerificationCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: DeviceVerificationCoordinatorBridgePresenter) +} + +/// DeviceVerificationCoordinatorBridgePresenter enables to start DeviceVerificationCoordinator from a view controller. +/// This bridge is used while waiting for global usage of coordinator pattern. +@objcMembers +final class DeviceVerificationCoordinatorBridgePresenter: NSObject { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var coordinator: DeviceVerificationCoordinator? + + // MARK: Public + + weak var delegate: DeviceVerificationCoordinatorBridgePresenterDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + super.init() + } + + // MARK: - Public + + // NOTE: Default value feature is not compatible with Objective-C. + // func present(from viewController: UIViewController, animated: Bool) { + // self.present(from: viewController, animated: animated) + // } + + func present(from viewController: UIViewController, animated: Bool) { + let deviceVerificationCoordinator = DeviceVerificationCoordinator(session: self.session) + deviceVerificationCoordinator.delegate = self + viewController.present(deviceVerificationCoordinator.toPresentable(), animated: animated, completion: nil) + deviceVerificationCoordinator.start() + + self.coordinator = deviceVerificationCoordinator + } + + func dismiss(animated: Bool) { + guard let coordinator = self.coordinator else { + return + } + coordinator.toPresentable().dismiss(animated: animated) { + self.coordinator = nil + } + } +} + +// MARK: - DeviceVerificationCoordinatorDelegate +extension DeviceVerificationCoordinatorBridgePresenter: DeviceVerificationCoordinatorDelegate { + func deviceVerificationCoordinatorDidComplete(_ coordinator: DeviceVerificationCoordinatorType) { + self.delegate?.deviceVerificationCoordinatorBridgePresenterDelegateDidComplete(self) + } +} diff --git a/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorType.swift b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorType.swift new file mode 100644 index 000000000..bc925808b --- /dev/null +++ b/Riot/Modules/DeviceVerification/DeviceVerificationCoordinatorType.swift @@ -0,0 +1,28 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh DeviceVerification DeviceVerification DeviceVerificationStart +/* + 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 DeviceVerificationCoordinatorDelegate: class { + func deviceVerificationCoordinatorDidComplete(_ coordinator: DeviceVerificationCoordinatorType) +} + +/// `DeviceVerificationCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. +protocol DeviceVerificationCoordinatorType: Coordinator, Presentable { + var delegate: DeviceVerificationCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartCoordinator.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartCoordinator.swift new file mode 100644 index 000000000..9115c6d1b --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartCoordinator.swift @@ -0,0 +1,71 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 +import UIKit + +final class DeviceVerificationStartCoordinator: DeviceVerificationStartCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var deviceVerificationStartViewModel: DeviceVerificationStartViewModelType + private let deviceVerificationStartViewController: DeviceVerificationStartViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: DeviceVerificationStartCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + + let deviceVerificationStartViewModel = DeviceVerificationStartViewModel(session: self.session) + let deviceVerificationStartViewController = DeviceVerificationStartViewController.instantiate(with: deviceVerificationStartViewModel) + self.deviceVerificationStartViewModel = deviceVerificationStartViewModel + self.deviceVerificationStartViewController = deviceVerificationStartViewController + } + + // MARK: - Public methods + + func start() { + self.deviceVerificationStartViewModel.coordinatorDelegate = self + } + + func toPresentable() -> UIViewController { + return self.deviceVerificationStartViewController + } +} + +// MARK: - DeviceVerificationStartViewModelCoordinatorDelegate +extension DeviceVerificationStartCoordinator: DeviceVerificationStartViewModelCoordinatorDelegate { + + func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didCompleteWithMessage message: String) { + self.delegate?.deviceVerificationStartCoordinator(self, didCompleteWithMessage: message) + } + + func deviceVerificationStartViewModelDidCancel(_ viewModel: DeviceVerificationStartViewModelType) { + self.delegate?.deviceVerificationStartCoordinatorDidCancel(self) + } +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartCoordinatorType.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartCoordinatorType.swift new file mode 100644 index 000000000..2a82dc6ed --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartCoordinatorType.swift @@ -0,0 +1,29 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 DeviceVerificationStartCoordinatorDelegate: class { + func deviceVerificationStartCoordinator(_ coordinator: DeviceVerificationStartCoordinatorType, didCompleteWithMessage message: String) + func deviceVerificationStartCoordinatorDidCancel(_ coordinator: DeviceVerificationStartCoordinatorType) +} + +/// `DeviceVerificationStartCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +protocol DeviceVerificationStartCoordinatorType: Coordinator, Presentable { + var delegate: DeviceVerificationStartCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewAction.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewAction.swift new file mode 100644 index 000000000..5923c882d --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewAction.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 + +/// DeviceVerificationStartViewController view actions exposed to view model +enum DeviceVerificationStartViewAction { + case sayHello + case complete + case cancel +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.storyboard b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.storyboard new file mode 100644 index 000000000..8dd82b992 --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.storyboard @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift new file mode 100644 index 000000000..472da5243 --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewController.swift @@ -0,0 +1,187 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 DeviceVerificationStartViewController: UIViewController { + + // MARK: - Constants + + private enum Constants { + static let aConstant: Int = 666 + } + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var scrollView: UIScrollView! + + @IBOutlet private weak var messageLabel: UILabel! + @IBOutlet private weak var okButton: UIButton! + + // MARK: Private + + private var viewModel: DeviceVerificationStartViewModelType! + private var theme: Theme! + private var keyboardAvoider: KeyboardAvoider? + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + // MARK: - Setup + + class func instantiate(with viewModel: DeviceVerificationStartViewModelType) -> DeviceVerificationStartViewController { + let viewController = StoryboardScene.DeviceVerificationStartViewController.initialScene.instantiate() + viewController.viewModel = viewModel + 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 = "Template" + + self.setupViews() + self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView) + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + self.viewModel.viewDelegate = self + + self.viewModel.process(viewAction: .sayHello) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.keyboardAvoider?.startAvoiding() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + self.keyboardAvoider?.stopAvoiding() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + + // TODO: + self.messageLabel.textColor = theme.textPrimaryColor + + self.okButton.backgroundColor = theme.backgroundColor + theme.applyStyle(onButton: self.okButton) + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in + self?.cancelButtonAction() + } + + self.navigationItem.rightBarButtonItem = cancelBarButtonItem + + self.scrollView.keyboardDismissMode = .interactive + + self.messageLabel.text = "VectorL10n.deviceVerificationStartTitle" + self.messageLabel.isHidden = true + } + + private func render(viewState: DeviceVerificationStartViewState) { + switch viewState { + case .loading: + self.renderLoading() + case .loaded: + self.renderLoaded() + case .error(let error): + self.render(error: error) + } + } + + private func renderLoading() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + + private func renderLoaded() { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + + self.messageLabel.text = self.viewModel.message + self.messageLabel.isHidden = false + } + + private func render(error: Error) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil) + } + + + // MARK: - Actions + + @IBAction private func okButtonAction(_ sender: Any) { + self.viewModel.process(viewAction: .complete) + } + + private func cancelButtonAction() { + self.viewModel.process(viewAction: .cancel) + } +} + + +// MARK: - DeviceVerificationStartViewModelViewDelegate +extension DeviceVerificationStartViewController: DeviceVerificationStartViewModelViewDelegate { + + func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didUpdateViewState viewSate: DeviceVerificationStartViewState) { + self.render(viewState: viewSate) + } +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewModel.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewModel.swift new file mode 100644 index 000000000..dbc9cb9f1 --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewModel.swift @@ -0,0 +1,87 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 DeviceVerificationStartViewModel: DeviceVerificationStartViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + + // MARK: Public + + var message: String? + + weak var viewDelegate: DeviceVerificationStartViewModelViewDelegate? + weak var coordinatorDelegate: DeviceVerificationStartViewModelCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + self.message = nil + } + + deinit { + } + + // MARK: - Public + + func process(viewAction: DeviceVerificationStartViewAction) { + switch viewAction { + case .sayHello: + self.setupHelloMessage() + case .complete: + if let message = self.message { + self.coordinatorDelegate?.deviceVerificationStartViewModel(self, didCompleteWithMessage: message) + } + case .cancel: + self.coordinatorDelegate?.deviceVerificationStartViewModelDidCancel(self) + } + } + + // MARK: - Private + + private func setupHelloMessage() { + + self.update(viewState: .loading) + + // Check first that the user homeserver is federated with the Riot-bot homeserver + self.session.matrixRestClient.displayName(forUser: self.session.myUser.userId) { [weak self] (response) in + + guard let sself = self else { + return + } + + switch response { + case .success: + sself.message = "Hello \(response.value ?? "you")" + sself.update(viewState: .loaded) + case .failure(let error): + sself.update(viewState: .error(error)) + } + } + } + + private func update(viewState: DeviceVerificationStartViewState) { + self.viewDelegate?.deviceVerificationStartViewModel(self, didUpdateViewState: viewState) + } +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewModelType.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewModelType.swift new file mode 100644 index 000000000..866a7ddd8 --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewModelType.swift @@ -0,0 +1,39 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 DeviceVerificationStartViewModelViewDelegate: class { + func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didUpdateViewState viewSate: DeviceVerificationStartViewState) +} + +protocol DeviceVerificationStartViewModelCoordinatorDelegate: class { + func deviceVerificationStartViewModel(_ viewModel: DeviceVerificationStartViewModelType, didCompleteWithMessage message: String) + func deviceVerificationStartViewModelDidCancel(_ viewModel: DeviceVerificationStartViewModelType) +} + +/// Protocol describing the view model used by `DeviceVerificationStartViewController` +protocol DeviceVerificationStartViewModelType { + + var message: String? { get set } + + var viewDelegate: DeviceVerificationStartViewModelViewDelegate? { get set } + var coordinatorDelegate: DeviceVerificationStartViewModelCoordinatorDelegate? { get set } + + func process(viewAction: DeviceVerificationStartViewAction) +} diff --git a/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewState.swift b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewState.swift new file mode 100644 index 000000000..5536d4bf9 --- /dev/null +++ b/Riot/Modules/DeviceVerification/Start/DeviceVerificationStartViewState.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh DeviceVerification/Start DeviceVerificationStart +/* + 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 + +/// DeviceVerificationStartViewController view state +enum DeviceVerificationStartViewState { + case loading + case loaded + case error(Error) +}