diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index c3bdde714..7240bade9 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -764,6 +764,17 @@ EC51E7902510B7C700AAE7DB /* AutosizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E78F2510B7C700AAE7DB /* AutosizedTableView.swift */; }; EC51E7922510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7912510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift */; }; EC51E7942510C0D000AAE7DB /* SpanningSlidingModalContainerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC51E7932510C0D000AAE7DB /* SpanningSlidingModalContainerView.xib */; }; + EC51E7A62514D2E100AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79A2514D2E000AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift */; }; + EC51E7A72514D2E100AAE7DB /* RoomInfoCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79B2514D2E000AAE7DB /* RoomInfoCoordinator.swift */; }; + EC51E7A82514D2E100AAE7DB /* RoomInfoListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79D2514D2E100AAE7DB /* RoomInfoListViewController.swift */; }; + EC51E7A92514D2E100AAE7DB /* RoomInfoListViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E79E2514D2E100AAE7DB /* RoomInfoListViewModelType.swift */; }; + EC51E7AA2514D2E100AAE7DB /* RoomInfoListViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC51E79F2514D2E100AAE7DB /* RoomInfoListViewController.storyboard */; }; + EC51E7AB2514D2E100AAE7DB /* RoomInfoListViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A02514D2E100AAE7DB /* RoomInfoListViewState.swift */; }; + EC51E7AC2514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A12514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift */; }; + EC51E7AD2514D2E100AAE7DB /* RoomInfoListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A22514D2E100AAE7DB /* RoomInfoListCoordinator.swift */; }; + EC51E7AE2514D2E100AAE7DB /* RoomInfoListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A32514D2E100AAE7DB /* RoomInfoListViewModel.swift */; }; + EC51E7AF2514D2E100AAE7DB /* RoomInfoListViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A42514D2E100AAE7DB /* RoomInfoListViewAction.swift */; }; + EC51E7B02514D2E100AAE7DB /* RoomInfoCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC51E7A52514D2E100AAE7DB /* RoomInfoCoordinatorType.swift */; }; EC619C1924DAD96000663A80 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC619C1824DAD96000663A80 /* UIScrollView.swift */; }; EC711B4624A63B13008F830C /* MXRecoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4524A63B13008F830C /* MXRecoveryService.swift */; }; EC711B7424A63B37008F830C /* SecretsSetupRecoveryKeyViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC711B4A24A63B36008F830C /* SecretsSetupRecoveryKeyViewModelType.swift */; }; @@ -1951,6 +1962,17 @@ EC51E78F2510B7C700AAE7DB /* AutosizedTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutosizedTableView.swift; sourceTree = ""; }; EC51E7912510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanningSlidingModalContainerView.swift; sourceTree = ""; }; EC51E7932510C0D000AAE7DB /* SpanningSlidingModalContainerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SpanningSlidingModalContainerView.xib; sourceTree = ""; }; + EC51E79A2514D2E000AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoCoordinatorBridgePresenter.swift; sourceTree = ""; }; + EC51E79B2514D2E000AAE7DB /* RoomInfoCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoCoordinator.swift; sourceTree = ""; }; + EC51E79D2514D2E100AAE7DB /* RoomInfoListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewController.swift; sourceTree = ""; }; + EC51E79E2514D2E100AAE7DB /* RoomInfoListViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewModelType.swift; sourceTree = ""; }; + EC51E79F2514D2E100AAE7DB /* RoomInfoListViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RoomInfoListViewController.storyboard; sourceTree = ""; }; + EC51E7A02514D2E100AAE7DB /* RoomInfoListViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewState.swift; sourceTree = ""; }; + EC51E7A12514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListCoordinatorType.swift; sourceTree = ""; }; + EC51E7A22514D2E100AAE7DB /* RoomInfoListCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListCoordinator.swift; sourceTree = ""; }; + EC51E7A32514D2E100AAE7DB /* RoomInfoListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewModel.swift; sourceTree = ""; }; + EC51E7A42514D2E100AAE7DB /* RoomInfoListViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoListViewAction.swift; sourceTree = ""; }; + EC51E7A52514D2E100AAE7DB /* RoomInfoCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfoCoordinatorType.swift; sourceTree = ""; }; EC619C1824DAD96000663A80 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = ""; }; EC711B4524A63B13008F830C /* MXRecoveryService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MXRecoveryService.swift; sourceTree = ""; }; EC711B4A24A63B36008F830C /* SecretsSetupRecoveryKeyViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsSetupRecoveryKeyViewModelType.swift; sourceTree = ""; }; @@ -3392,6 +3414,7 @@ B1B5568E20EE6C4C00210D55 /* Room */ = { isa = PBXGroup; children = ( + EC51E7B12514D34200AAE7DB /* RoomInfo */, ECFBD605250FA98900DD5F5A /* CreationModal */, 32A6000C22C661100042C1D9 /* EditHistory */, B1B5568F20EE6C4C00210D55 /* RoomViewController.h */, @@ -4800,6 +4823,32 @@ path = TableView; sourceTree = ""; }; + EC51E79C2514D2E100AAE7DB /* RoomInfoList */ = { + isa = PBXGroup; + children = ( + EC51E79D2514D2E100AAE7DB /* RoomInfoListViewController.swift */, + EC51E79E2514D2E100AAE7DB /* RoomInfoListViewModelType.swift */, + EC51E79F2514D2E100AAE7DB /* RoomInfoListViewController.storyboard */, + EC51E7A02514D2E100AAE7DB /* RoomInfoListViewState.swift */, + EC51E7A12514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift */, + EC51E7A22514D2E100AAE7DB /* RoomInfoListCoordinator.swift */, + EC51E7A32514D2E100AAE7DB /* RoomInfoListViewModel.swift */, + EC51E7A42514D2E100AAE7DB /* RoomInfoListViewAction.swift */, + ); + path = RoomInfoList; + sourceTree = ""; + }; + EC51E7B12514D34200AAE7DB /* RoomInfo */ = { + isa = PBXGroup; + children = ( + EC51E79B2514D2E000AAE7DB /* RoomInfoCoordinator.swift */, + EC51E79A2514D2E000AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift */, + EC51E7A52514D2E100AAE7DB /* RoomInfoCoordinatorType.swift */, + EC51E79C2514D2E100AAE7DB /* RoomInfoList */, + ); + path = RoomInfo; + sourceTree = ""; + }; EC711B4724A63B36008F830C /* Secrets */ = { isa = PBXGroup; children = ( @@ -5594,6 +5643,7 @@ B1CE83D32422817200D07506 /* KeyVerificationVerifiedViewController.storyboard in Resources */, B1B5590020EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.xib in Resources */, B1B5597020EFA85D00210D55 /* EncryptionInfoView.xib in Resources */, + EC51E7AA2514D2E100AAE7DB /* RoomInfoListViewController.storyboard in Resources */, B1B558BC20EF768F00210D55 /* RoomMembershipBubbleCell.xib in Resources */, B1B5571F20EE6C4D00210D55 /* ContactDetailsViewController.xib in Resources */, B157FAA423264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewController.storyboard in Resources */, @@ -6029,6 +6079,7 @@ EC711B7B24A63B37008F830C /* SecretsSetupRecoveryKeyCoordinator.swift in Sources */, B1B557D120EF5E3500210D55 /* MediaAlbumTableCell.m in Sources */, 32607D71243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift in Sources */, + EC51E7A92514D2E100AAE7DB /* RoomInfoListViewModelType.swift in Sources */, 324A2053225FC571004FE8B0 /* DeviceVerificationIncomingViewModel.swift in Sources */, B1B557A120EF58AD00210D55 /* ContactTableViewCell.m in Sources */, B1CE83DE2422817200D07506 /* KeyVerificationVerifyBySASViewModelType.swift in Sources */, @@ -6137,6 +6188,7 @@ B157FAA823264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift in Sources */, B169330B20F3CA3A00746532 /* Contact.m in Sources */, B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */, + EC51E7AC2514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift in Sources */, B1D4752A21EE52B10067973F /* KeyBackupSetupIntroViewController.swift in Sources */, B108931F23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift in Sources */, EC51E7922510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift in Sources */, @@ -6178,6 +6230,7 @@ B14F142F22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift in Sources */, 32DB557822FDADE50016329E /* ServiceTermsModalScreenViewState.swift in Sources */, B1B558E120EF768F00210D55 /* RoomMembershipCollapsedBubbleCell.m in Sources */, + EC51E7AB2514D2E100AAE7DB /* RoomInfoListViewState.swift in Sources */, B1B5571A20EE6C4D00210D55 /* SettingsViewController.m in Sources */, B1CE9EFD22148703000FAE6A /* SignOutAlertPresenter.swift in Sources */, 32F6B9692270623100BBA352 /* KeyVerificationDataLoadingCoordinator.swift in Sources */, @@ -6248,6 +6301,7 @@ B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */, B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */, B1D1BDA622BBAFB500831367 /* ReactionsMenuView.swift in Sources */, + EC51E7AD2514D2E100AAE7DB /* RoomInfoListCoordinator.swift in Sources */, EC711B4624A63B13008F830C /* MXRecoveryService.swift in Sources */, EC1CA86C24C1DEC400DE9EBF /* SetPinCoordinatorType.swift in Sources */, EC1CA86324C1DEC400DE9EBF /* EnterPinCodeCoordinatorType.swift in Sources */, @@ -6287,6 +6341,7 @@ B1DCC63922E85E9A00625807 /* EmojiMartStore.swift in Sources */, B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */, B1B5590620EF768F00210D55 /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m in Sources */, + EC51E7AE2514D2E100AAE7DB /* RoomInfoListViewModel.swift in Sources */, B139C21D21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift in Sources */, B157FA9F23264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinator.swift in Sources */, B1CE83D92422817200D07506 /* KeyVerificationVerifyByScanningViewAction.swift in Sources */, @@ -6330,6 +6385,7 @@ B1B5596F20EFA85D00210D55 /* EncryptionInfoView.m in Sources */, ECFBD5D1250A7AAF00DD5F5A /* ShowDirectoryViewController.swift in Sources */, B1B5573820EE6C4D00210D55 /* GroupParticipantsViewController.m in Sources */, + EC51E7B02514D2E100AAE7DB /* RoomInfoCoordinatorType.swift in Sources */, 3232ABAB225730E100AD6A5C /* KeyVerificationCoordinator.swift in Sources */, B1BEE73B23DF44A60003A4CB /* UserVerificationSessionsStatusCoordinator.swift in Sources */, B1B5583E20EF6E7F00210D55 /* GroupRoomTableViewCell.m in Sources */, @@ -6344,6 +6400,7 @@ B1B9DEDA22E9B7350065E677 /* SerializationService.swift in Sources */, B1B5572520EE6C4D00210D55 /* RoomMessagesSearchViewController.m in Sources */, B197B7C6243DE947005ABBF3 /* EncryptionTrustLevelBadgeImageHelper.swift in Sources */, + EC51E7A82514D2E100AAE7DB /* RoomInfoListViewController.swift in Sources */, B12D79FD23E2462200FACEDC /* UserVerificationStartViewModelType.swift in Sources */, B1C543AE23A286A000DCA1FA /* KeyVerificationRequestStatusBubbleCell.swift in Sources */, B139C22121FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift in Sources */, @@ -6397,6 +6454,7 @@ ECDC15F224AF41D2003437CF /* FormattedBodyParser.swift in Sources */, B1B5577E20EE84BF00210D55 /* IncomingCallView.m in Sources */, B1CE83E22422817200D07506 /* KeyVerificationVerifyBySASViewState.swift in Sources */, + EC51E7AF2514D2E100AAE7DB /* RoomInfoListViewAction.swift in Sources */, B1DCC62822E60CE300625807 /* EmojiCategory.swift in Sources */, B14084CC23BF9DE90010F692 /* KeyVerificationConclusionWithPaginationTitleBubbleCell.swift in Sources */, B1CE83D62422817200D07506 /* KeyVerificationVerifyByScanningCoordinator.swift in Sources */, @@ -6449,6 +6507,7 @@ EC1CA89A24C9C9A200DE9EBF /* SetupBiometricsCoordinatorType.swift in Sources */, 32A6001722C661100042C1D9 /* EditHistoryViewController.swift in Sources */, B1098BFA21ECFE65000DDA48 /* KeyBackupSetupPassphraseViewModel.swift in Sources */, + EC51E7A62514D2E100AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift in Sources */, EC1CA87524C8259700DE9EBF /* KeychainStore.swift in Sources */, B1B5575220EE6C4D00210D55 /* RoomKeyRequestViewController.m in Sources */, 32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */, @@ -6592,6 +6651,7 @@ B1B558D320EF768F00210D55 /* RoomOutgoingEncryptedTextMsgBubbleCell.m in Sources */, B1B5576F20EE702800210D55 /* IntegrationManagerViewController.m in Sources */, 32FD756424D2AD5100BA7B37 /* BuildSettings.swift in Sources */, + EC51E7A72514D2E100AAE7DB /* RoomInfoCoordinator.swift in Sources */, B1B557AC20EF5A6D00210D55 /* DeviceView.m in Sources */, 3281BCF72201FA4200F4A383 /* UIControl.swift in Sources */, B16932EE20F3C3C900746532 /* FilesSearchCellData.m in Sources */, diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index d93451da9..0511af4f1 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -147,6 +147,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: RoomCreationEventsModalViewController.self) } + internal enum RoomInfoListViewController: StoryboardType { + internal static let storyboardName = "RoomInfoListViewController" + + internal static let initialScene = InitialSceneType(storyboard: RoomInfoListViewController.self) + } internal enum SecretsRecoveryWithKeyViewController: StoryboardType { internal static let storyboardName = "SecretsRecoveryWithKeyViewController" diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift new file mode 100644 index 000000000..e1d70ba03 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -0,0 +1,80 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh Room2 RoomInfo RoomInfoList +/* + 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 UIKit + +@objcMembers +final class RoomInfoCoordinator: RoomInfoCoordinatorType { + + // 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: RoomInfoCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController()) + self.session = session + } + + // MARK: - Public methods + + func start() { + + let rootCoordinator = self.createRoomInfoListCoordinator() + + rootCoordinator.start() + + self.add(childCoordinator: rootCoordinator) + + self.navigationRouter.setRootModule(rootCoordinator) + } + + func toPresentable() -> UIViewController { + return self.navigationRouter.toPresentable() + } + + // MARK: - Private methods + + private func createRoomInfoListCoordinator() -> RoomInfoListCoordinator { + let coordinator = RoomInfoListCoordinator(session: self.session) + coordinator.delegate = self + return coordinator + } +} + +// MARK: - RoomInfoListCoordinatorDelegate +extension RoomInfoCoordinator: RoomInfoListCoordinatorDelegate { + func roomInfoListCoordinator(_ coordinator: RoomInfoListCoordinatorType, didCompleteWithUserDisplayName userDisplayName: String?) { + self.delegate?.roomInfoCoordinatorDidComplete(self) + } + + func roomInfoListCoordinatorDidCancel(_ coordinator: RoomInfoListCoordinatorType) { + self.delegate?.roomInfoCoordinatorDidComplete(self) + } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift new file mode 100644 index 000000000..b1e476eed --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift @@ -0,0 +1,83 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh Room2 RoomInfo RoomInfoList +/* + 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 + +@objc protocol RoomInfoCoordinatorBridgePresenterDelegate { + func roomInfoCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter) +} + +/// RoomInfoCoordinatorBridgePresenter enables to start RoomInfoCoordinator from a view controller. +/// This bridge is used while waiting for global usage of coordinator pattern. +@objcMembers +final class RoomInfoCoordinatorBridgePresenter: NSObject { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var coordinator: RoomInfoCoordinator? + + // MARK: Public + + weak var delegate: RoomInfoCoordinatorBridgePresenterDelegate? + + // 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 roomInfoCoordinator = RoomInfoCoordinator(session: self.session) + roomInfoCoordinator.delegate = self + viewController.present(roomInfoCoordinator.toPresentable(), animated: animated, completion: nil) + roomInfoCoordinator.start() + + self.coordinator = roomInfoCoordinator + } + + func dismiss(animated: Bool, completion: (() -> Void)?) { + guard let coordinator = self.coordinator else { + return + } + coordinator.toPresentable().dismiss(animated: animated) { + self.coordinator = nil + + if let completion = completion { + completion() + } + } + } +} + +// MARK: - RoomInfoCoordinatorDelegate +extension RoomInfoCoordinatorBridgePresenter: RoomInfoCoordinatorDelegate { + func roomInfoCoordinatorDidComplete(_ coordinator: RoomInfoCoordinatorType) { + self.delegate?.roomInfoCoordinatorBridgePresenterDelegateDidComplete(self) + } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift new file mode 100644 index 000000000..c98c7a751 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift @@ -0,0 +1,28 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh Room2 RoomInfo RoomInfoList +/* + 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 + +protocol RoomInfoCoordinatorDelegate: class { + func roomInfoCoordinatorDidComplete(_ coordinator: RoomInfoCoordinatorType) +} + +/// `RoomInfoCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. +protocol RoomInfoCoordinatorType: Coordinator, Presentable { + var delegate: RoomInfoCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift new file mode 100644 index 000000000..f8fc63e63 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift @@ -0,0 +1,71 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 +import UIKit + +final class RoomInfoListCoordinator: RoomInfoListCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var roomInfoListViewModel: RoomInfoListViewModelType + private let roomInfoListViewController: RoomInfoListViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: RoomInfoListCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + + let roomInfoListViewModel = RoomInfoListViewModel(session: self.session) + let roomInfoListViewController = RoomInfoListViewController.instantiate(with: roomInfoListViewModel) + self.roomInfoListViewModel = roomInfoListViewModel + self.roomInfoListViewController = roomInfoListViewController + } + + // MARK: - Public methods + + func start() { + self.roomInfoListViewModel.coordinatorDelegate = self + } + + func toPresentable() -> UIViewController { + return self.roomInfoListViewController + } +} + +// MARK: - RoomInfoListViewModelCoordinatorDelegate +extension RoomInfoListCoordinator: RoomInfoListViewModelCoordinatorDelegate { + + func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, didCompleteWithUserDisplayName userDisplayName: String?) { + self.delegate?.roomInfoListCoordinator(self, didCompleteWithUserDisplayName: userDisplayName) + } + + func roomInfoListViewModelDidCancel(_ viewModel: RoomInfoListViewModelType) { + self.delegate?.roomInfoListCoordinatorDidCancel(self) + } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift new file mode 100644 index 000000000..0d3babf54 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift @@ -0,0 +1,29 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 + +protocol RoomInfoListCoordinatorDelegate: class { + func roomInfoListCoordinator(_ coordinator: RoomInfoListCoordinatorType, didCompleteWithUserDisplayName userDisplayName: String?) + func roomInfoListCoordinatorDidCancel(_ coordinator: RoomInfoListCoordinatorType) +} + +/// `RoomInfoListCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +protocol RoomInfoListCoordinatorType: Coordinator, Presentable { + var delegate: RoomInfoListCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift new file mode 100644 index 000000000..2879faddb --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 + +/// RoomInfoListViewController view actions exposed to view model +enum RoomInfoListViewAction { + case loadData + case complete + case cancel +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.storyboard b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.storyboard new file mode 100644 index 000000000..a9d93521e --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.storyboard @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift new file mode 100644 index 000000000..1370420b4 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -0,0 +1,178 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 UIKit + +final class RoomInfoListViewController: 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 informationLabel: UILabel! + @IBOutlet private weak var doneButton: UIButton! + + // MARK: Private + + private var viewModel: RoomInfoListViewModelType! + private var theme: Theme! + private var keyboardAvoider: KeyboardAvoider? + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + // MARK: - Setup + + class func instantiate(with viewModel: RoomInfoListViewModelType) -> RoomInfoListViewController { + let viewController = StoryboardScene.RoomInfoListViewController.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.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: .loadData) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.keyboardAvoider?.startAvoiding() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + self.keyboardAvoider?.stopAvoiding() + } + + 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: Set view colors here + self.informationLabel.textColor = theme.textPrimaryColor + + self.doneButton.backgroundColor = theme.backgroundColor + theme.applyStyle(onButton: self.doneButton) + } + + 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.title = "Template" + + self.scrollView.keyboardDismissMode = .interactive + + self.informationLabel.text = "VectorL10n.roomInfoListTitle" + } + + private func render(viewState: RoomInfoListViewState) { + switch viewState { + case .loading: + self.renderLoading() + case .loaded(let displayName): + self.renderLoaded(displayName: displayName) + case .error(let error): + self.render(error: error) + } + } + + private func renderLoading() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + self.informationLabel.text = "Fetch display name" + } + + private func renderLoaded(displayName: String) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + + self.informationLabel.text = "You display name: \(displayName)" + } + + 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 doneButtonAction(_ sender: Any) { + self.viewModel.process(viewAction: .complete) + } + + private func cancelButtonAction() { + self.viewModel.process(viewAction: .cancel) + } +} + + +// MARK: - RoomInfoListViewModelViewDelegate +extension RoomInfoListViewController: RoomInfoListViewModelViewDelegate { + + func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, didUpdateViewState viewSate: RoomInfoListViewState) { + self.render(viewState: viewSate) + } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift new file mode 100644 index 000000000..0a085830d --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift @@ -0,0 +1,91 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 + +final class RoomInfoListViewModel: RoomInfoListViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + + private var currentOperation: MXHTTPOperation? + private var userDisplayName: String? + + // MARK: Public + + weak var viewDelegate: RoomInfoListViewModelViewDelegate? + weak var coordinatorDelegate: RoomInfoListViewModelCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + } + + deinit { + self.cancelOperations() + } + + // MARK: - Public + + func process(viewAction: RoomInfoListViewAction) { + switch viewAction { + case .loadData: + self.loadData() + case .complete: + self.coordinatorDelegate?.roomInfoListViewModel(self, didCompleteWithUserDisplayName: self.userDisplayName) + case .cancel: + self.cancelOperations() + self.coordinatorDelegate?.roomInfoListViewModelDidCancel(self) + } + } + + // MARK: - Private + + private func loadData() { + + self.update(viewState: .loading) + + // Check first that the user homeserver is federated with the Riot-bot homeserver + self.currentOperation = self.session.matrixRestClient.displayName(forUser: self.session.myUser.userId) { [weak self] (response) in + + guard let self = self else { + return + } + + switch response { + case .success(let userDisplayName): + self.update(viewState: .loaded(userDisplayName)) + self.userDisplayName = userDisplayName + case .failure(let error): + self.update(viewState: .error(error)) + } + } + } + + private func update(viewState: RoomInfoListViewState) { + self.viewDelegate?.roomInfoListViewModel(self, didUpdateViewState: viewState) + } + + private func cancelOperations() { + self.currentOperation?.cancel() + } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift new file mode 100644 index 000000000..e7a4f2797 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift @@ -0,0 +1,37 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 + +protocol RoomInfoListViewModelViewDelegate: class { + func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, didUpdateViewState viewSate: RoomInfoListViewState) +} + +protocol RoomInfoListViewModelCoordinatorDelegate: class { + func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, didCompleteWithUserDisplayName userDisplayName: String?) + func roomInfoListViewModelDidCancel(_ viewModel: RoomInfoListViewModelType) +} + +/// Protocol describing the view model used by `RoomInfoListViewController` +protocol RoomInfoListViewModelType { + + var viewDelegate: RoomInfoListViewModelViewDelegate? { get set } + var coordinatorDelegate: RoomInfoListViewModelCoordinatorDelegate? { get set } + + func process(viewAction: RoomInfoListViewAction) +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewState.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewState.swift new file mode 100644 index 000000000..186900275 --- /dev/null +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewState.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room2/RoomInfo RoomInfoList +/* + 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 + +/// RoomInfoListViewController view state +enum RoomInfoListViewState { + case loading + case loaded(_ displayName: String) + case error(Error) +}