mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge remote-tracking branch 'origin/complete_security_allow_device_verification_retry' into complete_security_allow_device_verification_retry
This commit is contained in:
commit
e31cc51416
26 changed files with 1076 additions and 363 deletions
45
CHANGES.rst
45
CHANGES.rst
|
@ -2,52 +2,53 @@ Changes to be released in next version
|
|||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
*
|
||||
|
||||
🙌 Improvements
|
||||
* Pin: Implement not allowed PINs feature. There is no restriction by default.
|
||||
* Room: New Room Settings screen.
|
||||
* Complete Security: Come back to the root screen if device verification is cancelled.
|
||||
* Architecture: Use coordinator pattern for legacy screen flows (#3597).
|
||||
|
||||
🐛 Bugfix
|
||||
* Timeline: Hide encrypted history (pre-invite) (#3660).
|
||||
* Fix floating action buttons' images.
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
*
|
||||
*
|
||||
|
||||
Others
|
||||
*
|
||||
*
|
||||
|
||||
Changes in 1.0.12 (2020-09-16)
|
||||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
*
|
||||
|
||||
🙌 Improvements
|
||||
*
|
||||
*
|
||||
|
||||
🐛 Bugfix
|
||||
*
|
||||
*
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
*
|
||||
*
|
||||
|
||||
Others
|
||||
*
|
||||
*
|
||||
|
||||
Improvements:
|
||||
* Upgrade MatrixKit version ([v0.12.20](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.20)).
|
||||
|
@ -56,10 +57,10 @@ Changes in 1.0.11 (2020-09-15)
|
|||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
*
|
||||
|
||||
🙌 Improvements
|
||||
* Room: Collapse state messages on room creation (#3629).
|
||||
* Room: Collapse state messages on room creation (#3629).
|
||||
* AuthVC: Make force PIN working for registration as well.
|
||||
* AppDelegate: Do not show incoming key verification requests while authenticating.
|
||||
|
||||
|
@ -68,13 +69,13 @@ Changes in 1.0.11 (2020-09-15)
|
|||
* Loading animation: Fix the bug where, after authentication, the animation disappeared too early and made auth screen flashed.
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
*
|
||||
*
|
||||
|
||||
Others
|
||||
* buildRelease.sh: Pass a `git_tag` parameter to fastlane because fastlane `git_branch` method can fail.
|
||||
|
@ -86,28 +87,28 @@ Changes in 1.0.10 (2020-09-08)
|
|||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
*
|
||||
|
||||
🙌 Improvements
|
||||
* AppDelegate: Convert to Swift (#3594).
|
||||
* Contextualize floating button actions per tab (#3627).
|
||||
|
||||
🐛 Bugfix
|
||||
* Show pin code screen on every foreground (#3620).
|
||||
* Show pin code screen on every foreground (#3620).
|
||||
* Close keyboard on pin code screen (#3622).
|
||||
* Fix content leakage on pin code protection (#3624).
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
* buildRelease.sh: Make sure it works for both branches and tags
|
||||
|
||||
Others
|
||||
*
|
||||
*
|
||||
|
||||
Improvements:
|
||||
* Upgrade MatrixKit version ([v0.12.18](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.12.18)).
|
||||
|
|
|
@ -186,6 +186,13 @@
|
|||
B10A3E8E24FE4368007C380F /* ElementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8B24FE4367007C380F /* ElementView.swift */; };
|
||||
B10A3E8F24FE4368007C380F /* Timeline_1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8C24FE4367007C380F /* Timeline_1.swift */; };
|
||||
B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E8D24FE4367007C380F /* ElementViewController.swift */; };
|
||||
B10A3E9324FE8254007C380F /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9124FE8254007C380F /* AppCoordinator.swift */; };
|
||||
B10A3E9424FE8254007C380F /* AppCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9224FE8254007C380F /* AppCoordinatorType.swift */; };
|
||||
B10A3E9824FE86AF007C380F /* SplitViewCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9624FE86AE007C380F /* SplitViewCoordinatorType.swift */; };
|
||||
B10A3E9924FE86AF007C380F /* SplitViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9724FE86AF007C380F /* SplitViewCoordinator.swift */; };
|
||||
B10A3E9C24FE88CB007C380F /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9A24FE88CA007C380F /* RootRouter.swift */; };
|
||||
B10A3E9D24FE88CB007C380F /* RootRouterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9B24FE88CB007C380F /* RootRouterType.swift */; };
|
||||
B10A3E9F24FFC3E6007C380F /* PlaceholderDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10A3E9E24FFC3E5007C380F /* PlaceholderDetailViewController.swift */; };
|
||||
B10CFBC32268D99D00A5842E /* JitsiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10CFBC22268D99D00A5842E /* JitsiService.swift */; };
|
||||
B1107EC82200B0720038014B /* KeyBackupRecoverSuccessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1107EC72200B0720038014B /* KeyBackupRecoverSuccessViewController.swift */; };
|
||||
B1107ECA2200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1107EC92200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard */; };
|
||||
|
@ -653,6 +660,9 @@
|
|||
B1C562E5228C7C8D0037F12A /* RoomContextualMenuViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1C562E0228C7C8C0037F12A /* RoomContextualMenuViewController.storyboard */; };
|
||||
B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C562E6228C7CF10037F12A /* ContextualMenuItemView.swift */; };
|
||||
B1C562E9228C7CF20037F12A /* ContextualMenuItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1C562E7228C7CF20037F12A /* ContextualMenuItemView.xib */; };
|
||||
B1C7822F2500EAF500337EB9 /* TabBarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C7822D2500EAF400337EB9 /* TabBarCoordinator.swift */; };
|
||||
B1C782302500EAF500337EB9 /* TabBarCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C7822E2500EAF500337EB9 /* TabBarCoordinatorType.swift */; };
|
||||
B1C782322500F96700337EB9 /* SplitViewPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1C782312500F96600337EB9 /* SplitViewPresentable.swift */; };
|
||||
B1CA3A2721EF6914000D1D89 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2621EF6913000D1D89 /* UIViewController.swift */; };
|
||||
B1CA3A2921EF692B000D1D89 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2821EF692B000D1D89 /* UIView.swift */; };
|
||||
B1CE83B62422812100D07506 /* KeyVerificationCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CE83B52422812000D07506 /* KeyVerificationCoordinatorBridgePresenter.swift */; };
|
||||
|
@ -1188,6 +1198,13 @@
|
|||
B10A3E8B24FE4367007C380F /* ElementView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementView.swift; sourceTree = "<group>"; };
|
||||
B10A3E8C24FE4367007C380F /* Timeline_1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timeline_1.swift; sourceTree = "<group>"; };
|
||||
B10A3E8D24FE4367007C380F /* ElementViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementViewController.swift; sourceTree = "<group>"; };
|
||||
B10A3E9124FE8254007C380F /* AppCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
|
||||
B10A3E9224FE8254007C380F /* AppCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinatorType.swift; sourceTree = "<group>"; };
|
||||
B10A3E9624FE86AE007C380F /* SplitViewCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewCoordinatorType.swift; sourceTree = "<group>"; };
|
||||
B10A3E9724FE86AF007C380F /* SplitViewCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewCoordinator.swift; sourceTree = "<group>"; };
|
||||
B10A3E9A24FE88CA007C380F /* RootRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootRouter.swift; sourceTree = "<group>"; };
|
||||
B10A3E9B24FE88CB007C380F /* RootRouterType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootRouterType.swift; sourceTree = "<group>"; };
|
||||
B10A3E9E24FFC3E5007C380F /* PlaceholderDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderDetailViewController.swift; sourceTree = "<group>"; };
|
||||
B10CFBC22268D99D00A5842E /* JitsiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiService.swift; sourceTree = "<group>"; };
|
||||
B1107EC72200B0720038014B /* KeyBackupRecoverSuccessViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverSuccessViewController.swift; sourceTree = "<group>"; };
|
||||
B1107EC92200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = KeyBackupRecoverSuccessViewController.storyboard; sourceTree = "<group>"; };
|
||||
|
@ -1847,6 +1864,9 @@
|
|||
B1C6FFE723954CE70055347B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
B1C6FFE823954D3B0055347B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
B1C6FFE923954D4B0055347B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Vector.strings; sourceTree = "<group>"; };
|
||||
B1C7822D2500EAF400337EB9 /* TabBarCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarCoordinator.swift; sourceTree = "<group>"; };
|
||||
B1C7822E2500EAF500337EB9 /* TabBarCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarCoordinatorType.swift; sourceTree = "<group>"; };
|
||||
B1C782312500F96600337EB9 /* SplitViewPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitViewPresentable.swift; sourceTree = "<group>"; };
|
||||
B1CA3A2621EF6913000D1D89 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
|
||||
B1CA3A2821EF692B000D1D89 /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
|
||||
B1CE83B52422812000D07506 /* KeyVerificationCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyVerificationCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
|
||||
|
@ -2690,6 +2710,8 @@
|
|||
B1098C0B21ED07E4000DDA48 /* Presentable.swift */,
|
||||
B1098C0C21ED07E4000DDA48 /* NavigationRouterType.swift */,
|
||||
B1098C0821ED07E4000DDA48 /* NavigationRouter.swift */,
|
||||
B10A3E9B24FE88CB007C380F /* RootRouterType.swift */,
|
||||
B10A3E9A24FE88CA007C380F /* RootRouter.swift */,
|
||||
);
|
||||
path = Routers;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2704,6 +2726,19 @@
|
|||
path = LoadingAnimation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B10A3E9524FE86AE007C380F /* SplitView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B10A3E9624FE86AE007C380F /* SplitViewCoordinatorType.swift */,
|
||||
B10A3E9724FE86AF007C380F /* SplitViewCoordinator.swift */,
|
||||
B1B556EC20EE6C4C00210D55 /* RiotSplitViewController.h */,
|
||||
B1B556EB20EE6C4C00210D55 /* RiotSplitViewController.m */,
|
||||
B10A3E9E24FFC3E5007C380F /* PlaceholderDetailViewController.swift */,
|
||||
B1C782312500F96600337EB9 /* SplitViewPresentable.swift */,
|
||||
);
|
||||
path = SplitView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B1107EC62200B0190038014B /* Success */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3308,12 +3343,12 @@
|
|||
children = (
|
||||
ECF57A3725090C23004BBF9D /* CreateRoom */,
|
||||
B1BB648724FD07B3008238AE /* Application */,
|
||||
B10A3E9524FE86AE007C380F /* SplitView */,
|
||||
EC1CA84F24C1DEC400DE9EBF /* SetPinCode */,
|
||||
EC3B066324AC6ADD000DF9BF /* CrossSigning */,
|
||||
EC711BB424A63C11008F830C /* AuthenticatedSession */,
|
||||
EC711B9A24A63B58008F830C /* SecureBackup */,
|
||||
EC711B4724A63B36008F830C /* Secrets */,
|
||||
B1B556EA20EE6C4C00210D55 /* Main */,
|
||||
B1560DA024B65A9500490F50 /* LaunchLoading */,
|
||||
B1B556CA20EE6C4C00210D55 /* TabBar */,
|
||||
B1B556F920EE6C4C00210D55 /* Authentication */,
|
||||
|
@ -3614,6 +3649,8 @@
|
|||
B1B556CA20EE6C4C00210D55 /* TabBar */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1C7822E2500EAF500337EB9 /* TabBarCoordinatorType.swift */,
|
||||
B1C7822D2500EAF400337EB9 /* TabBarCoordinator.swift */,
|
||||
B1B556CB20EE6C4C00210D55 /* MasterTabBarController.h */,
|
||||
B1B556CC20EE6C4C00210D55 /* MasterTabBarController.m */,
|
||||
);
|
||||
|
@ -3722,15 +3759,6 @@
|
|||
path = People;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B1B556EA20EE6C4C00210D55 /* Main */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1B556EC20EE6C4C00210D55 /* RiotSplitViewController.h */,
|
||||
B1B556EB20EE6C4C00210D55 /* RiotSplitViewController.m */,
|
||||
);
|
||||
path = Main;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B1B556ED20EE6C4C00210D55 /* MediaPicker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -4509,6 +4537,8 @@
|
|||
B1BB649224FD428A008238AE /* AppDelegate.swift */,
|
||||
F083BB0C1E7009EC00A9B29C /* LegacyAppDelegate.h */,
|
||||
F083BB0D1E7009EC00A9B29C /* LegacyAppDelegate.m */,
|
||||
B10A3E9224FE8254007C380F /* AppCoordinatorType.swift */,
|
||||
B10A3E9124FE8254007C380F /* AppCoordinator.swift */,
|
||||
);
|
||||
path = Application;
|
||||
sourceTree = "<group>";
|
||||
|
@ -6206,12 +6236,14 @@
|
|||
B1B5572F20EE6C4D00210D55 /* ReadReceiptsViewController.m in Sources */,
|
||||
B1BD71BC238E8F9600BA92E2 /* WidgetPermissionViewController.swift in Sources */,
|
||||
B1B558CB20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
|
||||
B10A3E9824FE86AF007C380F /* SplitViewCoordinatorType.swift in Sources */,
|
||||
B11291EA238D35590077B478 /* SlidingModalPresentable.swift in Sources */,
|
||||
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 */,
|
||||
B10A3E9424FE8254007C380F /* AppCoordinatorType.swift in Sources */,
|
||||
B108931F23AB80EF00802670 /* KeyVerificationIncomingRequestApprovalBubbleCell.swift in Sources */,
|
||||
EC51E7922510C0A500AAE7DB /* SpanningSlidingModalContainerView.swift in Sources */,
|
||||
B1CE83D42422817200D07506 /* KeyVerificationVerifiedViewController.swift in Sources */,
|
||||
|
@ -6219,6 +6251,7 @@
|
|||
B14F143422144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewAction.swift in Sources */,
|
||||
B1098BF621ECFE65000DDA48 /* KeyBackupSetupPassphraseCoordinator.swift in Sources */,
|
||||
B1B558C320EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.m in Sources */,
|
||||
B10A3E9D24FE88CB007C380F /* RootRouterType.swift in Sources */,
|
||||
B1B9DEDC22E9B7440065E677 /* SerializationServiceType.swift in Sources */,
|
||||
B110872521F098F0003554A5 /* ActivityIndicatorPresenter.swift in Sources */,
|
||||
32242F1521E8FBA900725742 /* DarkTheme.swift in Sources */,
|
||||
|
@ -6249,6 +6282,8 @@
|
|||
3291DC8D23E0BFF10009732F /* SecurityViewController.m in Sources */,
|
||||
B18DEDD4243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewModelType.swift in Sources */,
|
||||
B1C45A88232A8C2600165425 /* SettingsIdentityServerViewState.swift in Sources */,
|
||||
B1C782302500EAF500337EB9 /* TabBarCoordinatorType.swift in Sources */,
|
||||
B1C782322500F96700337EB9 /* SplitViewPresentable.swift in Sources */,
|
||||
B14F142F22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift in Sources */,
|
||||
32DB557822FDADE50016329E /* ServiceTermsModalScreenViewState.swift in Sources */,
|
||||
B1B558E120EF768F00210D55 /* RoomMembershipCollapsedBubbleCell.m in Sources */,
|
||||
|
@ -6355,6 +6390,7 @@
|
|||
B142317A22CCFA2000FFA96A /* EditHistoryCell.swift in Sources */,
|
||||
ECF57A50250913E4004BBF9D /* MXKTableViewCellWithLabelAndSwitch.swift in Sources */,
|
||||
B1DCC62622E60CC600625807 /* EmojiItem.swift in Sources */,
|
||||
B10A3E9324FE8254007C380F /* AppCoordinator.swift in Sources */,
|
||||
B1B5572A20EE6C4D00210D55 /* RoomMemberDetailsViewController.m in Sources */,
|
||||
EC3B066C24AC6ADE000DF9BF /* CrossSigningSetupBannerCell.swift in Sources */,
|
||||
ECF57A4E25090C23004BBF9D /* EnterNewRoomDetailsViewModelType.swift in Sources */,
|
||||
|
@ -6441,8 +6477,10 @@
|
|||
B1DCC63722E8541700625807 /* EmojiStore.swift in Sources */,
|
||||
3232ABA6225730E100AD6A5C /* DeviceVerificationStartViewController.swift in Sources */,
|
||||
B16932EA20F3C39000746532 /* UnifiedSearchRecentsDataSource.m in Sources */,
|
||||
B10A3E9924FE86AF007C380F /* SplitViewCoordinator.swift in Sources */,
|
||||
B1BEE72A23DF38B20003A4CB /* UserVerificationSessionStatusCell.swift in Sources */,
|
||||
B1C45A8A232A8C2600165425 /* SettingsIdentityServerCoordinatorBridgePresenter.swift in Sources */,
|
||||
B1C7822F2500EAF500337EB9 /* TabBarCoordinator.swift in Sources */,
|
||||
B1B557DE20EF5FBB00210D55 /* FilesSearchTableViewCell.m in Sources */,
|
||||
B1B5574020EE6C4D00210D55 /* SegmentedViewController.m in Sources */,
|
||||
ECF57A4C25090C23004BBF9D /* EnterNewRoomDetailsViewAction.swift in Sources */,
|
||||
|
@ -6656,6 +6694,7 @@
|
|||
B1C3360322F1ED600021BA8D /* MediaPickerCoordinator.swift in Sources */,
|
||||
B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */,
|
||||
EC711B8924A63B37008F830C /* SecretsRecoveryWithPassphraseViewModel.swift in Sources */,
|
||||
B10A3E9F24FFC3E6007C380F /* PlaceholderDetailViewController.swift in Sources */,
|
||||
B1963B3822933BC800CBA17F /* AutosizedCollectionView.swift in Sources */,
|
||||
EC711B7A24A63B37008F830C /* SecretsSetupRecoveryKeyViewAction.swift in Sources */,
|
||||
B12D79FB23E2462200FACEDC /* UserVerificationStartCoordinator.swift in Sources */,
|
||||
|
@ -6761,6 +6800,7 @@
|
|||
B1B9DEEC22EB34EF0065E677 /* ReactionHistoryViewModelType.swift in Sources */,
|
||||
B157FAA523264AE900EBFBD4 /* SettingsDiscoveryThreePidDetailsViewModel.swift in Sources */,
|
||||
EC711B8624A63B37008F830C /* SecretsRecoveryWithPassphraseCoordinatorType.swift in Sources */,
|
||||
B10A3E9C24FE88CB007C380F /* RootRouter.swift in Sources */,
|
||||
B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */,
|
||||
B14F143022144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift in Sources */,
|
||||
B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
|
@ -261,7 +261,7 @@
|
|||
<!--Master Tab Bar Controller-->
|
||||
<scene sceneID="iBe-Y5-gBt">
|
||||
<objects>
|
||||
<tabBarController id="xaQ-tG-rlO" customClass="MasterTabBarController" sceneMemberID="viewController">
|
||||
<tabBarController storyboardIdentifier="MasterTabBarController" id="xaQ-tG-rlO" customClass="MasterTabBarController" sceneMemberID="viewController">
|
||||
<navigationItem key="navigationItem" id="m6O-wq-yrc">
|
||||
<barButtonItem key="leftBarButtonItem" image="settings_icon" id="QSE-cg-V2m">
|
||||
<userDefinedRuntimeAttributes>
|
||||
|
@ -288,15 +288,12 @@
|
|||
<connections>
|
||||
<outlet property="searchBarButtonIem" destination="pud-Fh-Usd" id="DiH-Re-nZE"/>
|
||||
<outlet property="settingsBarButtonItem" destination="QSE-cg-V2m" id="N6b-Ju-w9g"/>
|
||||
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showRoomDetails" id="tk8-vF-K4T"/>
|
||||
<segue destination="ZlD-EU-ncw" kind="presentation" identifier="showAuth" modalPresentationStyle="fullScreen" id="fpJ-zM-Qpo"/>
|
||||
<segue destination="pBa-To-3YT" kind="relationship" relationship="viewControllers" id="Sfs-mh-GOz"/>
|
||||
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showContactDetails" id="p4M-yR-DLA"/>
|
||||
<segue destination="HnD-LA-psC" kind="relationship" relationship="viewControllers" id="zON-Qp-EVq"/>
|
||||
<segue destination="IGB-jr-yFz" kind="relationship" relationship="viewControllers" id="CeF-yL-aO0"/>
|
||||
<segue destination="HPQ-zg-lZR" kind="relationship" relationship="viewControllers" id="y12-eg-vhO"/>
|
||||
<segue destination="SLx-Wj-p7E" kind="relationship" relationship="viewControllers" id="MLn-VT-30W"/>
|
||||
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showGroupDetails" id="fIR-e3-ssz"/>
|
||||
</connections>
|
||||
</tabBarController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="k1S-FF-3Zu" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
@ -342,7 +339,7 @@
|
|||
<!--RecentsSplitVC-->
|
||||
<scene sceneID="Nki-YV-4Qg">
|
||||
<objects>
|
||||
<splitViewController title="RecentsSplitVC" id="H1p-Uh-vWS" customClass="RiotSplitViewController" sceneMemberID="viewController">
|
||||
<splitViewController storyboardIdentifier="RiotSplitViewController" title="RecentsSplitVC" id="H1p-Uh-vWS" customClass="RiotSplitViewController" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationItem key="navigationItem" id="EB5-8V-irH"/>
|
||||
<connections>
|
||||
|
@ -422,10 +419,10 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="-1375" y="-1121"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<!--Placeholder Detail View Controller-->
|
||||
<scene sceneID="2wP-Cu-Wca">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="EmptyDetailsViewControllerStoryboardId" id="Cpr-Tz-Az0" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="EmptyDetailsViewControllerStoryboardId" id="Cpr-Tz-Az0" customClass="PlaceholderDetailViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="yS4-RU-AsN"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="VKG-pW-vMU"/>
|
||||
|
@ -434,8 +431,12 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo" translatesAutoresizingMaskIntoConstraints="NO" id="6LG-qc-7jf">
|
||||
<rect key="frame" x="127.5" y="283" width="120" height="101"/>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo" translatesAutoresizingMaskIntoConstraints="NO" id="6LG-qc-7jf">
|
||||
<rect key="frame" x="127.5" y="273.5" width="120" height="120"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="6LG-qc-7jf" secondAttribute="height" multiplier="1:1" id="4Qy-7P-CuE"/>
|
||||
<constraint firstAttribute="width" constant="120" id="E2Y-gX-itg"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
@ -445,6 +446,9 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="c9s-dM-eEg"/>
|
||||
<connections>
|
||||
<outlet property="logoImageView" destination="6LG-qc-7jf" id="vLR-KE-0aH"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="pZm-ap-zdK" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
@ -590,15 +594,14 @@
|
|||
</scene>
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="Tfl-tq-LQp"/>
|
||||
<segue reference="fIR-e3-ssz"/>
|
||||
<segue reference="mhb-l9-pM3"/>
|
||||
<segue reference="f5u-Y1-7nt"/>
|
||||
<segue reference="vCz-dl-6xQ"/>
|
||||
<segue reference="cUw-vU-gJq"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<resources>
|
||||
<image name="integrations_icon" width="24" height="24"/>
|
||||
<image name="logo" width="120" height="101"/>
|
||||
<image name="launch_screen_logo" width="240" height="240"/>
|
||||
<image name="search_icon" width="24" height="24"/>
|
||||
<image name="settings_icon" width="24" height="24"/>
|
||||
<image name="tab_favourites" width="24" height="24"/>
|
||||
|
|
|
@ -35,7 +35,6 @@ internal enum InfoPlist {
|
|||
internal static let nsSiriUsageDescription: String = _document["NSSiriUsageDescription"]
|
||||
internal static let uiBackgroundModes: [String] = _document["UIBackgroundModes"]
|
||||
internal static let uiLaunchStoryboardName: String = _document["UILaunchStoryboardName"]
|
||||
internal static let uiMainStoryboardFile: String = _document["UIMainStoryboardFile"]
|
||||
internal static let uiRequiredDeviceCapabilities: [String] = _document["UIRequiredDeviceCapabilities"]
|
||||
internal static let uiStatusBarHidden: Bool = _document["UIStatusBarHidden"]
|
||||
internal static let uiStatusBarTintParameters: [String: Any] = _document["UIStatusBarTintParameters"]
|
||||
|
|
|
@ -115,6 +115,8 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan
|
|||
// Observe "Invert Colours" settings changes (available since iOS 11)
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessibilityInvertColorsStatusDidChange) name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
[self reEvaluateTheme];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
109
Riot/Modules/Application/AppCoordinator.swift
Executable file
109
Riot/Modules/Application/AppCoordinator.swift
Executable file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
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 Intents
|
||||
|
||||
/// The AppCoordinator is responsible of screen navigation and data injection at root application level. It decides if authentication or home screen should be shown and inject data needed for these flows, it changes the navigation stack on deep link, displays global warning.
|
||||
/// This class should avoid to contain too many data management code not related to screen navigation logic. For example `MXSession` or push notification management should be handled in dedicated classes and report only navigation changes to the AppCoordinator.
|
||||
final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let rootRouter: RootRouterType
|
||||
// swiftlint:disable weak_delegate
|
||||
private let legacyAppDelegate: LegacyAppDelegate = AppDelegate.theDelegate()
|
||||
// swiftlint:enable weak_delegate
|
||||
|
||||
private weak var splitViewCoordinator: SplitViewCoordinatorType?
|
||||
|
||||
// TODO: Use a dedicated class to handle Matrix sessions
|
||||
/// Main user Matrix session
|
||||
private var mainSession: MXSession? {
|
||||
return MXKAccountManager.shared().activeAccounts.first?.mxSession
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
|
||||
var childCoordinators: [Coordinator] = []
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(router: RootRouterType) {
|
||||
self.rootRouter = router
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
self.showSplitView(session: self.mainSession)
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func showAuthentication() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private func showLoading() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private func showPinCode() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private func showSplitView(session: MXSession?) {
|
||||
let splitViewCoordinator = SplitViewCoordinator(router: self.rootRouter, session: session)
|
||||
splitViewCoordinator.delegate = self
|
||||
splitViewCoordinator.start()
|
||||
self.add(childCoordinator: splitViewCoordinator)
|
||||
self.splitViewCoordinator = splitViewCoordinator
|
||||
}
|
||||
|
||||
private func checkAppVersion() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private func showError(_ error: Error) {
|
||||
// FIXME: Present an error on coordinator.toPresentable()
|
||||
self.legacyAppDelegate.showError(asAlert: error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - LegacyAppDelegateDelegate
|
||||
extension AppCoordinator: LegacyAppDelegateDelegate {
|
||||
|
||||
func legacyAppDelegate(_ legacyAppDelegate: LegacyAppDelegate!, wantsToPopToHomeViewControllerAnimated animated: Bool, completion: (() -> Void)!) {
|
||||
|
||||
self.splitViewCoordinator?.popToHome(animated: animated, completion: completion)
|
||||
}
|
||||
|
||||
func legacyAppDelegateRestoreEmptyDetailsViewController(_ legacyAppDelegate: LegacyAppDelegate!) {
|
||||
self.splitViewCoordinator?.restorePlaceholderDetails()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SplitViewCoordinatorDelegate
|
||||
extension AppCoordinator: SplitViewCoordinatorDelegate {
|
||||
func splitViewCoordinatorDidCompleteAuthentication(_ coordinator: SplitViewCoordinatorType) {
|
||||
self.legacyAppDelegate.authenticationDidComplete()
|
||||
}
|
||||
}
|
21
Riot/Modules/Application/AppCoordinatorType.swift
Normal file
21
Riot/Modules/Application/AppCoordinatorType.swift
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 2020 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
/// `AppCoordinatorType` is a protocol describing a Coordinator that handles application navigation flow.
|
||||
protocol AppCoordinatorType: Coordinator {
|
||||
}
|
|
@ -21,9 +21,12 @@ import PushKit
|
|||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
|
||||
private var appCoordinator: AppCoordinatorType!
|
||||
private var rootRouter: RootRouterType!
|
||||
|
||||
private var legacyAppDelegate: LegacyAppDelegate {
|
||||
return AppDelegate.theDelegate()
|
||||
}
|
||||
|
@ -54,6 +57,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
|
||||
// Setup window
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
self.window = window
|
||||
|
||||
// Create AppCoordinator
|
||||
self.rootRouter = RootRouter(window: window)
|
||||
|
||||
let appCoordinator = AppCoordinator(router: self.rootRouter)
|
||||
appCoordinator.start()
|
||||
self.legacyAppDelegate.delegate = appCoordinator
|
||||
|
||||
self.appCoordinator = appCoordinator
|
||||
|
||||
// Call legacy AppDelegate
|
||||
self.legacyAppDelegate.window = window
|
||||
self.legacyAppDelegate.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#import "UniversalLink.h"
|
||||
|
||||
@protocol Configurable;
|
||||
|
||||
@protocol LegacyAppDelegateDelegate;
|
||||
|
||||
#pragma mark - Notifications
|
||||
/**
|
||||
|
@ -56,6 +56,8 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification;
|
|||
void (^_completionHandler)(UIBackgroundFetchResult);
|
||||
}
|
||||
|
||||
@property (weak, nonatomic) id<LegacyAppDelegateDelegate> delegate;
|
||||
|
||||
/**
|
||||
Application main view controller
|
||||
*/
|
||||
|
@ -176,6 +178,8 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification;
|
|||
|
||||
- (void)configureCallManagerIfRequiredForSession:(MXSession *)mxSession;
|
||||
|
||||
- (void)authenticationDidComplete;
|
||||
|
||||
#pragma mark - Matrix Accounts handling
|
||||
|
||||
- (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection;
|
||||
|
@ -234,3 +238,10 @@ extern NSString *const AppDelegateUniversalLinkDidChangeNotification;
|
|||
- (void)checkAppVersion;
|
||||
|
||||
@end
|
||||
|
||||
@protocol LegacyAppDelegateDelegate <NSObject>
|
||||
|
||||
- (void)legacyAppDelegate:(LegacyAppDelegate*)legacyAppDelegate wantsToPopToHomeViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion;
|
||||
- (void)legacyAppDelegateRestoreEmptyDetailsViewController:(LegacyAppDelegate*)legacyAppDelegate;
|
||||
|
||||
@end
|
||||
|
|
|
@ -89,7 +89,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
|
|||
|
||||
NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUniversalLinkDidChangeNotification";
|
||||
|
||||
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate, MasterTabBarControllerDelegate>
|
||||
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate>
|
||||
{
|
||||
/**
|
||||
Reachability observer
|
||||
|
@ -176,11 +176,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
*/
|
||||
BOOL isErrorNotificationSuspended;
|
||||
|
||||
/**
|
||||
Completion block called when [self popToHomeViewControllerAnimated:] has been
|
||||
completed.
|
||||
*/
|
||||
void (^popToHomeViewControllerCompletion)(void);
|
||||
|
||||
/**
|
||||
The listeners to call events.
|
||||
|
@ -375,27 +370,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
}
|
||||
}
|
||||
|
||||
- (UINavigationController*)secondaryNavigationController
|
||||
{
|
||||
UIViewController* rootViewController = self.window.rootViewController;
|
||||
|
||||
if ([rootViewController isKindOfClass:[UISplitViewController class]])
|
||||
{
|
||||
UISplitViewController *splitViewController = (UISplitViewController *)rootViewController;
|
||||
if (splitViewController.viewControllers.count == 2)
|
||||
{
|
||||
UIViewController *secondViewController = [splitViewController.viewControllers lastObject];
|
||||
|
||||
if ([secondViewController isKindOfClass:[UINavigationController class]])
|
||||
{
|
||||
return (UINavigationController*)secondViewController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - UIApplicationDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions
|
||||
|
@ -466,28 +440,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
|
||||
// To simplify navigation into the app, we retrieve here the main navigation controller and the tab bar controller.
|
||||
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
|
||||
splitViewController.delegate = self;
|
||||
|
||||
_masterNavigationController = splitViewController.viewControllers[0];
|
||||
_masterTabBarController = _masterNavigationController.viewControllers.firstObject;
|
||||
|
||||
// Force the background color of the fake view controller displayed when there is no details.
|
||||
UINavigationController *secondNavController = self.secondaryNavigationController;
|
||||
if (secondNavController)
|
||||
{
|
||||
[ThemeService.shared.theme applyStyleOnNavigationBar:secondNavController.navigationBar];
|
||||
secondNavController.topViewController.view.backgroundColor = ThemeService.shared.theme.backgroundColor;
|
||||
}
|
||||
|
||||
// on IOS 8 iPad devices, force to display the primary and the secondary viewcontroller
|
||||
// to avoid empty room View Controller in portrait orientation
|
||||
// else, the user cannot select a room
|
||||
// shouldHideViewController delegate method is also implemented
|
||||
if ([(NSString*)[UIDevice currentDevice].model hasPrefix:@"iPad"])
|
||||
{
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
NSAssert(_masterTabBarController, @"Something wrong in Main.storyboard");
|
||||
|
||||
|
@ -938,32 +894,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
|
||||
- (void)restoreEmptyDetailsViewController
|
||||
{
|
||||
UIViewController* rootViewController = self.window.rootViewController;
|
||||
|
||||
if ([rootViewController isKindOfClass:[UISplitViewController class]])
|
||||
{
|
||||
UISplitViewController *splitViewController = (UISplitViewController *)rootViewController;
|
||||
|
||||
// Be sure that the primary is then visible too.
|
||||
if (splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryHidden)
|
||||
{
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
|
||||
}
|
||||
|
||||
if (splitViewController.viewControllers.count == 2)
|
||||
{
|
||||
UIViewController *mainViewController = splitViewController.viewControllers[0];
|
||||
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
UIViewController *emptyDetailsViewController = [storyboard instantiateViewControllerWithIdentifier:@"EmptyDetailsViewControllerStoryboardId"];
|
||||
emptyDetailsViewController.view.backgroundColor = ThemeService.shared.theme.backgroundColor;
|
||||
|
||||
splitViewController.viewControllers = @[mainViewController, emptyDetailsViewController];
|
||||
}
|
||||
}
|
||||
|
||||
// Release the current selected item (room/contact/group...).
|
||||
[_masterTabBarController releaseSelectedItem];
|
||||
[self.delegate legacyAppDelegateRestoreEmptyDetailsViewController:self];
|
||||
}
|
||||
|
||||
- (UIAlertController*)showErrorAsAlert:(NSError*)error
|
||||
|
@ -1136,61 +1067,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
|
||||
- (void)popToHomeViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
|
||||
{
|
||||
UINavigationController *secondNavController = self.secondaryNavigationController;
|
||||
if (secondNavController)
|
||||
{
|
||||
[secondNavController popToRootViewControllerAnimated:animated];
|
||||
}
|
||||
|
||||
// Force back to the main screen if this is not the one that is displayed
|
||||
if (_masterTabBarController && _masterTabBarController != _masterNavigationController.visibleViewController)
|
||||
{
|
||||
// Listen to the masterNavigationController changes
|
||||
// We need to be sure that masterTabBarController is back to the screen
|
||||
popToHomeViewControllerCompletion = completion;
|
||||
_masterNavigationController.delegate = self;
|
||||
|
||||
[_masterNavigationController popToViewController:_masterTabBarController animated:animated];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select the Home tab
|
||||
_masterTabBarController.selectedIndex = TABBAR_HOME_INDEX;
|
||||
|
||||
if (completion)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UINavigationController delegate
|
||||
|
||||
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
if (viewController == _masterTabBarController)
|
||||
{
|
||||
_masterNavigationController.delegate = nil;
|
||||
|
||||
// For unknown reason, the navigation bar is not restored correctly by [popToViewController:animated:]
|
||||
// when a ViewController has hidden it (see MXKAttachmentsViewController).
|
||||
// Patch: restore navigation bar by default here.
|
||||
_masterNavigationController.navigationBarHidden = NO;
|
||||
|
||||
// Release the current selected item (room/contact/...).
|
||||
[_masterTabBarController releaseSelectedItem];
|
||||
|
||||
if (popToHomeViewControllerCompletion)
|
||||
{
|
||||
void (^popToHomeViewControllerCompletion2)(void) = popToHomeViewControllerCompletion;
|
||||
popToHomeViewControllerCompletion = nil;
|
||||
|
||||
// Dispatch the completion in order to let navigation stack refresh itself.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
popToHomeViewControllerCompletion2();
|
||||
});
|
||||
}
|
||||
}
|
||||
[self.delegate legacyAppDelegate:self wantsToPopToHomeViewControllerAnimated:animated completion:completion];
|
||||
}
|
||||
|
||||
#pragma mark - Crash handling
|
||||
|
@ -2448,8 +2325,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
NSLog(@"[AppDelegate] handleLaunchAnimation: Authentication still in progress");
|
||||
|
||||
// Wait for the return of masterTabBarControllerDidCompleteAuthentication
|
||||
isLaunching = YES;
|
||||
_masterTabBarController.masterVCDelegate = self;
|
||||
isLaunching = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2621,6 +2497,11 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
}
|
||||
}
|
||||
|
||||
- (void)authenticationDidComplete
|
||||
{
|
||||
[self handleLaunchAnimation];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/**
|
||||
|
@ -3613,50 +3494,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
[rootController.view setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark - SplitViewController delegate
|
||||
|
||||
- (nullable UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
|
||||
{
|
||||
// Return the top view controller of the master navigation controller, if it is a navigation controller itself.
|
||||
UIViewController *topViewController = _masterNavigationController.topViewController;
|
||||
if ([topViewController isKindOfClass:UINavigationController.class])
|
||||
{
|
||||
return topViewController;
|
||||
}
|
||||
|
||||
// Else return the default empty details view controller from the storyboard.
|
||||
// Be sure that the primary is then visible too.
|
||||
if (splitViewController.displayMode == UISplitViewControllerDisplayModePrimaryHidden)
|
||||
{
|
||||
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
|
||||
}
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
UIViewController *emptyDetailsViewController = [storyboard instantiateViewControllerWithIdentifier:@"EmptyDetailsViewControllerStoryboardId"];
|
||||
emptyDetailsViewController.view.backgroundColor = ThemeService.shared.theme.backgroundColor;
|
||||
return emptyDetailsViewController;
|
||||
}
|
||||
|
||||
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
|
||||
{
|
||||
if (!self.masterTabBarController.currentRoomViewController && !self.masterTabBarController.currentContactDetailViewController && !self.masterTabBarController.currentGroupDetailViewController)
|
||||
{
|
||||
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
|
||||
{
|
||||
// oniPad devices, force to display the primary and the secondary viewcontroller
|
||||
// to avoid empty room View Controller in portrait orientation
|
||||
// else, the user cannot select a room
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Status Bar Tap handling
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
|
@ -4710,11 +4547,4 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
|||
[self logoutWithConfirmation:NO completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - MasterTabBarControllerDelegate
|
||||
|
||||
- (void)masterTabBarControllerDidCompleteAuthentication:(MasterTabBarController *)masterTabBarController
|
||||
{
|
||||
[self handleLaunchAnimation];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -96,7 +96,7 @@ class PlaceholderedTextView: UITextView {
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(textViewTextChanged(_:)), name: UITextView.textDidChangeNotification, object: self)
|
||||
kvoLineFragmentPadding = observe(\.textContainer.lineFragmentPadding, options: [.new]) { [weak self] (_, change) in
|
||||
guard let self = self else { return }
|
||||
let newValue = change.newValue ?? 0
|
||||
let newValue = change.newValue ?? 0
|
||||
self.placeholderTextView.textContainer.lineFragmentPadding = newValue
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ final class KeyVerificationCoordinator: KeyVerificationCoordinatorType {
|
|||
private let session: MXSession
|
||||
private let verificationFlow: KeyVerificationFlow
|
||||
private let verificationKind: KeyVerificationKind
|
||||
private var completeSecurityCoordinator: KeyVerificationSelfVerifyWaitCoordinatorType?
|
||||
private weak var completeSecurityCoordinator: KeyVerificationSelfVerifyWaitCoordinatorType?
|
||||
|
||||
private var otherUserId: String {
|
||||
|
||||
|
|
81
Riot/Modules/SplitView/PlaceholderDetailViewController.swift
Normal file
81
Riot/Modules/SplitView/PlaceholderDetailViewController.swift
Normal file
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// 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
|
||||
|
||||
/// Used as a placeholder for UISplitViewController detail view controller
|
||||
final class PlaceholderDetailViewController: UIViewController, Themable {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var logoImageView: UIImageView!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var theme: Theme!
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
self.setupViews()
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
self.update(theme: self.theme)
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
// TODO: Extract Storyboard and use SwiftGen
|
||||
class func instantiate() -> PlaceholderDetailViewController {
|
||||
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
|
||||
guard let emptyDetailsViewController = storyboard.instantiateViewController(withIdentifier: "EmptyDetailsViewControllerStoryboardId") as? PlaceholderDetailViewController else {
|
||||
fatalError("[PlaceholderDetailViewController] Fail to load view controller from storyboard")
|
||||
}
|
||||
emptyDetailsViewController.theme = ThemeService.shared().theme
|
||||
return emptyDetailsViewController
|
||||
}
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.view.backgroundColor = theme.backgroundColor
|
||||
self.logoImageView.tintColor = theme.tintColor
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
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() {
|
||||
self.logoImageView.image = Asset.Images.launchScreenLogo.image
|
||||
}
|
||||
}
|
172
Riot/Modules/SplitView/SplitViewCoordinator.swift
Normal file
172
Riot/Modules/SplitView/SplitViewCoordinator.swift
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
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 SplitViewCoordinator: NSObject, SplitViewCoordinatorType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let rootRouter: RootRouterType
|
||||
private var session: MXSession?
|
||||
|
||||
private let splitViewController: UISplitViewController
|
||||
|
||||
private weak var masterPresentable: SplitViewMasterPresentable?
|
||||
private weak var detailNavigationController: UINavigationController?
|
||||
|
||||
private weak var tabBarCoordinator: TabBarCoordinatorType?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
var childCoordinators: [Coordinator] = []
|
||||
|
||||
weak var delegate: SplitViewCoordinatorDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
// TODO: Improve sessions injection
|
||||
// at the moment the session is not used, see TabBarCoordinator `init`.
|
||||
init(router: RootRouterType, session: MXSession?) {
|
||||
self.rootRouter = router
|
||||
self.session = session
|
||||
|
||||
let splitViewController = UISplitViewController()
|
||||
splitViewController.preferredDisplayMode = .allVisible
|
||||
self.splitViewController = splitViewController
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
self.splitViewController.delegate = self
|
||||
|
||||
let tabBarCoordinator = self.createTabBarCoordinator()
|
||||
tabBarCoordinator.delegate = self
|
||||
tabBarCoordinator.splitViewMasterPresentableDelegate = self
|
||||
tabBarCoordinator.start()
|
||||
|
||||
let detailNavigationController = self.createDetailNavigationController()
|
||||
|
||||
self.splitViewController.viewControllers = [tabBarCoordinator.toPresentable(), detailNavigationController]
|
||||
|
||||
self.add(childCoordinator: tabBarCoordinator)
|
||||
|
||||
self.tabBarCoordinator = tabBarCoordinator
|
||||
self.masterPresentable = tabBarCoordinator
|
||||
self.detailNavigationController = detailNavigationController
|
||||
|
||||
self.rootRouter.setRootModule(self.splitViewController)
|
||||
}
|
||||
|
||||
func update(with session: MXSession) {
|
||||
self.session = session
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.splitViewController
|
||||
}
|
||||
|
||||
// TODO: Do not expose publicly this method
|
||||
func restorePlaceholderDetails() {
|
||||
// Be sure that the primary is then visible too.
|
||||
if splitViewController.displayMode == .primaryHidden {
|
||||
splitViewController.preferredDisplayMode = .allVisible
|
||||
}
|
||||
|
||||
if splitViewController.viewControllers.count == 2 {
|
||||
let mainViewController = splitViewController.viewControllers[0]
|
||||
|
||||
let emptyDetailsViewController = self.createPlaceholderDetailsViewController()
|
||||
|
||||
splitViewController.viewControllers = [mainViewController, emptyDetailsViewController]
|
||||
}
|
||||
|
||||
// Release the current selected item (room/contact/group...).
|
||||
self.tabBarCoordinator?.releaseSelectedItems()
|
||||
}
|
||||
|
||||
func popToHome(animated: Bool, completion: (() -> Void)?) {
|
||||
if let secondNavController = self.detailNavigationController {
|
||||
secondNavController.popToRootViewController(animated: animated)
|
||||
}
|
||||
|
||||
// Force back to the main screen if this is not the one that is displayed
|
||||
self.tabBarCoordinator?.popToHome(animated: animated, completion: completion)
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func createPlaceholderDetailsViewController() -> UIViewController {
|
||||
return PlaceholderDetailViewController.instantiate()
|
||||
}
|
||||
|
||||
private func createTabBarCoordinator() -> TabBarCoordinator {
|
||||
let tabBarCoordinator = TabBarCoordinator(session: self.session)
|
||||
tabBarCoordinator.delegate = self
|
||||
return tabBarCoordinator
|
||||
}
|
||||
|
||||
private func createDetailNavigationController() -> UINavigationController {
|
||||
let placeholderDetailViewController = self.createPlaceholderDetailsViewController()
|
||||
let detailNavigationController = RiotNavigationController(rootViewController: placeholderDetailViewController)
|
||||
return detailNavigationController
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UISplitViewControllerDelegate
|
||||
extension SplitViewCoordinator: UISplitViewControllerDelegate {
|
||||
|
||||
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
|
||||
|
||||
if let detailViewController = self.masterPresentable?.secondViewControllerWhenSeparatedFromPrimary() {
|
||||
return detailViewController
|
||||
}
|
||||
|
||||
// Else return the default empty details view controller from the storyboard.
|
||||
// Be sure that the primary is then visible too.
|
||||
if splitViewController.displayMode == .primaryHidden {
|
||||
splitViewController.preferredDisplayMode = .allVisible
|
||||
}
|
||||
|
||||
return self.createPlaceholderDetailsViewController()
|
||||
}
|
||||
|
||||
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
|
||||
return self.masterPresentable?.collapseDetailViewController ?? false
|
||||
}
|
||||
}
|
||||
|
||||
/// MARK: - UINavigationControllerDelegate
|
||||
extension SplitViewCoordinator: TabBarCoordinatorDelegate {
|
||||
func tabBarCoordinatorDidCompleteAuthentication(_ coordinator: TabBarCoordinatorType) {
|
||||
self.delegate?.splitViewCoordinatorDidCompleteAuthentication(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// MARK: - SplitViewMasterPresentableDelegate
|
||||
extension SplitViewCoordinator: SplitViewMasterPresentableDelegate {
|
||||
func splitViewMasterPresentable(_ presentable: Presentable, wantsToDisplay detailPresentable: Presentable) {
|
||||
guard let detailNavigationController = self.detailNavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
detailNavigationController.viewControllers = [detailPresentable.toPresentable()]
|
||||
self.splitViewController.showDetailViewController(detailNavigationController, sender: nil)
|
||||
}
|
||||
}
|
33
Riot/Modules/SplitView/SplitViewCoordinatorType.swift
Normal file
33
Riot/Modules/SplitView/SplitViewCoordinatorType.swift
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
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 SplitViewCoordinatorDelegate: class {
|
||||
// TODO: Remove this method, authentication should not be handled by SplitViewCoordinator
|
||||
func splitViewCoordinatorDidCompleteAuthentication(_ coordinator: SplitViewCoordinatorType)
|
||||
}
|
||||
|
||||
/// `SplitViewCoordinatorType` is a protocol describing a Coordinator that handles split view navigation flow.
|
||||
protocol SplitViewCoordinatorType: Coordinator, Presentable {
|
||||
|
||||
var delegate: SplitViewCoordinatorDelegate? { get }
|
||||
|
||||
func popToHome(animated: Bool, completion: (() -> Void)?)
|
||||
|
||||
// TODO: Do not expose publicly this method
|
||||
func restorePlaceholderDetails()
|
||||
}
|
33
Riot/Modules/SplitView/SplitViewPresentable.swift
Normal file
33
Riot/Modules/SplitView/SplitViewPresentable.swift
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// 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
|
||||
|
||||
protocol SplitViewMasterPresentableDelegate: class {
|
||||
func splitViewMasterPresentable(_ presentable: Presentable, wantsToDisplay detailPresentable: Presentable)
|
||||
}
|
||||
|
||||
/// Protocol used by the master view presentable of a UISplitViewController
|
||||
protocol SplitViewMasterPresentable: class, Presentable {
|
||||
|
||||
var splitViewMasterPresentableDelegate: SplitViewMasterPresentableDelegate? { get set }
|
||||
|
||||
/// Indicate true if the detail can be collapsed
|
||||
var collapseDetailViewController: Bool { get }
|
||||
|
||||
/// Return the detail view controller to display when the detail is separated from the master view controller
|
||||
func secondViewControllerWhenSeparatedFromPrimary() -> UIViewController?
|
||||
}
|
|
@ -42,6 +42,9 @@
|
|||
|
||||
@interface MasterTabBarController : UITabBarController
|
||||
|
||||
// UITabBarController already have a `delegate` property
|
||||
@property (weak, nonatomic) id<MasterTabBarControllerDelegate> masterTabBarDelegate;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *settingsBarButtonItem;
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *searchBarButtonIem;
|
||||
|
||||
|
@ -141,7 +144,6 @@
|
|||
*/
|
||||
- (void)refreshTabBarBadges;
|
||||
|
||||
@property (nonatomic, weak) id<MasterTabBarControllerDelegate> masterVCDelegate;
|
||||
|
||||
// Reference to the current auth VC. It is not nil only when the auth screen is displayed.
|
||||
@property (nonatomic, readonly) AuthenticationViewController *authViewController;
|
||||
|
@ -178,5 +180,6 @@
|
|||
@protocol MasterTabBarControllerDelegate <NSObject>
|
||||
|
||||
- (void)masterTabBarControllerDidCompleteAuthentication:(MasterTabBarController *)masterTabBarController;
|
||||
- (void)masterTabBarController:(MasterTabBarController*)masterTabBarController wantsToDisplayDetailViewController:(UIViewController*)detailViewController;
|
||||
|
||||
@end;
|
||||
@end
|
||||
|
|
|
@ -477,6 +477,60 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)showRoomDetails
|
||||
{
|
||||
[self releaseCurrentDetailsViewController];
|
||||
|
||||
if (_selectedRoomPreviewData)
|
||||
{
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
[self.masterTabBarDelegate masterTabBarController:self wantsToDisplayDetailViewController:_currentRoomViewController];
|
||||
|
||||
[_currentRoomViewController displayRoomPreview:_selectedRoomPreviewData];
|
||||
_selectedRoomPreviewData = nil;
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXWeakify(self);
|
||||
void (^openRoomDataSource)(MXKRoomDataSource *roomDataSource) = ^(MXKRoomDataSource *roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
self->_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
[self.masterTabBarDelegate masterTabBarController:self wantsToDisplayDetailViewController:self.currentRoomViewController];
|
||||
|
||||
[self.currentRoomViewController displayRoom:roomDataSource];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
|
||||
};
|
||||
|
||||
if (_selectedRoomDataSource)
|
||||
{
|
||||
// If the room data source is already loaded, display it
|
||||
openRoomDataSource(_selectedRoomDataSource);
|
||||
_selectedRoomDataSource = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else, load it. The user may see the EmptyDetailsViewControllerStoryboardId
|
||||
// screen in this case
|
||||
[self dataSourceOfRoomToDisplay:^(MXKRoomDataSource *roomDataSource) {
|
||||
openRoomDataSource(roomDataSource);
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession
|
||||
{
|
||||
[self selectRoomWithId:roomId andEventId:eventId inMatrixSession:matrixSession completion:nil];
|
||||
|
@ -509,7 +563,7 @@
|
|||
|
||||
self->_selectedRoomDataSource = roomDataSource;
|
||||
|
||||
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
|
||||
[self showRoomDetails];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
|
@ -533,14 +587,28 @@
|
|||
_selectedRoomId = roomPreviewData.roomId;
|
||||
_selectedRoomSession = roomPreviewData.mxSession;
|
||||
|
||||
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
|
||||
[self showRoomDetails];
|
||||
}
|
||||
|
||||
- (void)selectContact:(MXKContact*)contact
|
||||
{
|
||||
_selectedContact = contact;
|
||||
|
||||
[self performSegueWithIdentifier:@"showContactDetails" sender:self];
|
||||
[self showContactDetails];
|
||||
}
|
||||
|
||||
- (void)showContactDetails
|
||||
{
|
||||
[self releaseCurrentDetailsViewController];
|
||||
|
||||
// Replace the rootviewcontroller with a contact details view controller
|
||||
_currentContactDetailViewController = [ContactDetailsViewController contactDetailsViewController];
|
||||
_currentContactDetailViewController.enableVoipCall = NO;
|
||||
_currentContactDetailViewController.contact = _selectedContact;
|
||||
|
||||
[self.masterTabBarDelegate masterTabBarController:self wantsToDisplayDetailViewController:_currentContactDetailViewController];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
|
||||
- (void)selectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession
|
||||
|
@ -548,7 +616,20 @@
|
|||
_selectedGroup = group;
|
||||
_selectedGroupSession = matrixSession;
|
||||
|
||||
[self performSegueWithIdentifier:@"showGroupDetails" sender:self];
|
||||
[self showGroupDetails];
|
||||
}
|
||||
|
||||
- (void)showGroupDetails
|
||||
{
|
||||
[self releaseCurrentDetailsViewController];
|
||||
|
||||
// Replace the rootviewcontroller with a group details view controller
|
||||
_currentGroupDetailViewController = [GroupDetailsViewController groupDetailsViewController];
|
||||
[_currentGroupDetailViewController setGroup:_selectedGroup withMatrixSession:_selectedGroupSession];
|
||||
|
||||
[self.masterTabBarDelegate masterTabBarController:self wantsToDisplayDetailViewController:_currentGroupDetailViewController];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
|
||||
- (void)releaseSelectedItem
|
||||
|
@ -608,137 +689,55 @@
|
|||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
|
||||
{
|
||||
if ([[segue identifier] isEqualToString:@"showRoomDetails"] || [[segue identifier] isEqualToString:@"showContactDetails"] || [[segue identifier] isEqualToString:@"showGroupDetails"])
|
||||
// Keep ref on destinationViewController
|
||||
[childViewControllers addObject:segue.destinationViewController];
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showAuth"])
|
||||
{
|
||||
UINavigationController *navigationController = [segue destinationViewController];
|
||||
// Keep ref on the authentification view controller while it is displayed
|
||||
// ie until we get the notification about a new account
|
||||
_authViewController = segue.destinationViewController;
|
||||
isAuthViewControllerPreparing = NO;
|
||||
|
||||
[self releaseCurrentDetailsViewController];
|
||||
// Listen to the end of the authentication flow
|
||||
_authViewController.authVCDelegate = self;
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showRoomDetails"])
|
||||
{
|
||||
if (_selectedRoomPreviewData)
|
||||
{
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
navigationController.viewControllers = @[_currentRoomViewController];
|
||||
|
||||
[_currentRoomViewController displayRoomPreview:_selectedRoomPreviewData];
|
||||
_selectedRoomPreviewData = nil;
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXWeakify(self);
|
||||
void (^openRoomDataSource)(MXKRoomDataSource *roomDataSource) = ^(MXKRoomDataSource *roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
self->_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
navigationController.viewControllers = @[self.currentRoomViewController];
|
||||
|
||||
[self.currentRoomViewController displayRoom:roomDataSource];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
|
||||
};
|
||||
|
||||
if (_selectedRoomDataSource)
|
||||
{
|
||||
// If the room data source is already loaded, display it
|
||||
openRoomDataSource(_selectedRoomDataSource);
|
||||
_selectedRoomDataSource = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else, load it. The user may see the EmptyDetailsViewControllerStoryboardId
|
||||
// screen in this case
|
||||
[self dataSourceOfRoomToDisplay:^(MXKRoomDataSource *roomDataSource) {
|
||||
openRoomDataSource(roomDataSource);
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([[segue identifier] isEqualToString:@"showContactDetails"])
|
||||
{
|
||||
// Replace the rootviewcontroller with a contact details view controller
|
||||
_currentContactDetailViewController = [ContactDetailsViewController contactDetailsViewController];
|
||||
_currentContactDetailViewController.enableVoipCall = NO;
|
||||
_currentContactDetailViewController.contact = _selectedContact;
|
||||
authViewControllerObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
navigationController.viewControllers = @[_currentContactDetailViewController];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace the rootviewcontroller with a group details view controller
|
||||
_currentGroupDetailViewController = [GroupDetailsViewController groupDetailsViewController];
|
||||
[_currentGroupDetailViewController setGroup:_selectedGroup withMatrixSession:_selectedGroupSession];
|
||||
_authViewController = nil;
|
||||
|
||||
navigationController.viewControllers = @[_currentGroupDetailViewController];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:authViewControllerObserver];
|
||||
authViewControllerObserver = nil;
|
||||
}];
|
||||
|
||||
authViewRemovedAccountObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidRemoveAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
// The user has cleared data for their soft logged out account
|
||||
_authViewController = nil;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:authViewRemovedAccountObserver];
|
||||
authViewRemovedAccountObserver = nil;
|
||||
}];
|
||||
|
||||
// Forward parameters if any
|
||||
if (authViewControllerRegistrationParameters)
|
||||
{
|
||||
_authViewController.externalRegistrationParameters = authViewControllerRegistrationParameters;
|
||||
authViewControllerRegistrationParameters = nil;
|
||||
}
|
||||
if (softLogoutCredentials)
|
||||
{
|
||||
_authViewController.softLogoutCredentials = softLogoutCredentials;
|
||||
softLogoutCredentials = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ([[segue identifier] isEqualToString:@"showUnifiedSearch"])
|
||||
{
|
||||
// Keep ref on destinationViewController
|
||||
[childViewControllers addObject:segue.destinationViewController];
|
||||
unifiedSearchViewController= segue.destinationViewController;
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showAuth"])
|
||||
for (MXSession *session in mxSessionArray)
|
||||
{
|
||||
// Keep ref on the authentification view controller while it is displayed
|
||||
// ie until we get the notification about a new account
|
||||
_authViewController = segue.destinationViewController;
|
||||
isAuthViewControllerPreparing = NO;
|
||||
|
||||
// Listen to the end of the authentication flow
|
||||
_authViewController.authVCDelegate = self;
|
||||
|
||||
authViewControllerObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
_authViewController = nil;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:authViewControllerObserver];
|
||||
authViewControllerObserver = nil;
|
||||
}];
|
||||
|
||||
authViewRemovedAccountObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidRemoveAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
// The user has cleared data for their soft logged out account
|
||||
_authViewController = nil;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:authViewRemovedAccountObserver];
|
||||
authViewRemovedAccountObserver = nil;
|
||||
}];
|
||||
|
||||
// Forward parameters if any
|
||||
if (authViewControllerRegistrationParameters)
|
||||
{
|
||||
_authViewController.externalRegistrationParameters = authViewControllerRegistrationParameters;
|
||||
authViewControllerRegistrationParameters = nil;
|
||||
}
|
||||
if (softLogoutCredentials)
|
||||
{
|
||||
_authViewController.softLogoutCredentials = softLogoutCredentials;
|
||||
softLogoutCredentials = nil;
|
||||
}
|
||||
}
|
||||
else if ([[segue identifier] isEqualToString:@"showUnifiedSearch"])
|
||||
{
|
||||
unifiedSearchViewController= segue.destinationViewController;
|
||||
|
||||
for (MXSession *session in mxSessionArray)
|
||||
{
|
||||
[unifiedSearchViewController addMatrixSession:session];
|
||||
}
|
||||
[unifiedSearchViewController addMatrixSession:session];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1175,10 +1174,7 @@
|
|||
- (void)authenticationViewControllerDidDismiss:(AuthenticationViewController *)authenticationViewController
|
||||
{
|
||||
_authenticationInProgress = NO;
|
||||
if (self.masterVCDelegate)
|
||||
{
|
||||
[self.masterVCDelegate masterTabBarControllerDidCompleteAuthentication:self];
|
||||
}
|
||||
[self.masterTabBarDelegate masterTabBarControllerDidCompleteAuthentication:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
192
Riot/Modules/TabBar/TabBarCoordinator.swift
Normal file
192
Riot/Modules/TabBar/TabBarCoordinator.swift
Normal file
|
@ -0,0 +1,192 @@
|
|||
// File created from FlowTemplate
|
||||
// $ createRootCoordinator.sh TabBar TabBar
|
||||
/*
|
||||
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 TabBarCoordinator: NSObject, TabBarCoordinatorType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var session: MXSession?
|
||||
|
||||
/// Completion called when `popToHomeAnimated:` has been completed.
|
||||
private var popToHomeViewControllerCompletion: (() -> Void)?
|
||||
|
||||
// TODO: Move MasterTabBarController navigation code here
|
||||
// and if possible use a simple: `private let tabBarController: UITabBarController`
|
||||
private var masterTabBarController: MasterTabBarController!
|
||||
|
||||
// TODO: Embed UINavigationController in each tab like recommended by Apple and remove these properties. UITabBarViewController shoud not be embed in a UINavigationController (https://github.com/vector-im/riot-ios/issues/3086).
|
||||
private let navigationRouter: NavigationRouterType
|
||||
private let masterNavigationController: UINavigationController
|
||||
|
||||
// MARK: Public
|
||||
|
||||
// Must be used only internally
|
||||
var childCoordinators: [Coordinator] = []
|
||||
|
||||
weak var delegate: TabBarCoordinatorDelegate?
|
||||
|
||||
weak var splitViewMasterPresentableDelegate: SplitViewMasterPresentableDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
// TODO: Improve sessions injection
|
||||
// at the moment Matrix session is injected to MasterTabBarController via LegacyAppDelegate
|
||||
init(session: MXSession?) {
|
||||
let masterNavigationController = RiotNavigationController()
|
||||
self.navigationRouter = NavigationRouter(navigationController: masterNavigationController)
|
||||
self.masterNavigationController = masterNavigationController
|
||||
self.session = session
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
let masterTabBarController = self.createMasterTabBarController()
|
||||
masterTabBarController.masterTabBarDelegate = self
|
||||
self.masterTabBarController = masterTabBarController
|
||||
self.navigationRouter.setRootModule(masterTabBarController)
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.navigationRouter.toPresentable()
|
||||
}
|
||||
|
||||
func releaseSelectedItems() {
|
||||
self.masterTabBarController.releaseSelectedItem()
|
||||
}
|
||||
|
||||
func popToHome(animated: Bool, completion: (() -> Void)?) {
|
||||
// Force back to the main screen if this is not the one that is displayed
|
||||
if masterTabBarController != masterNavigationController.visibleViewController {
|
||||
// Listen to the masterNavigationController changes
|
||||
// We need to be sure that masterTabBarController is back to the screen
|
||||
popToHomeViewControllerCompletion = completion
|
||||
masterNavigationController.delegate = self
|
||||
|
||||
masterNavigationController.popToViewController(masterTabBarController, animated: animated)
|
||||
} else {
|
||||
// Select the Home tab
|
||||
masterTabBarController.selectedIndex = Int(TABBAR_HOME_INDEX)
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SplitViewMasterPresentable
|
||||
|
||||
var collapseDetailViewController: Bool {
|
||||
if (masterTabBarController.currentRoomViewController == nil) && (masterTabBarController.currentContactDetailViewController == nil) && (masterTabBarController.currentGroupDetailViewController == nil) {
|
||||
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func secondViewControllerWhenSeparatedFromPrimary() -> UIViewController? {
|
||||
// Return the top view controller of the master navigation controller, if it is a navigation controller itself.
|
||||
if let topViewController = masterNavigationController.topViewController as? UINavigationController {
|
||||
// Keep the detail scene
|
||||
return topViewController
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func createMasterTabBarController() -> MasterTabBarController {
|
||||
let storyboard = UIStoryboard(name: "Main", bundle: nil)
|
||||
guard let masterTabBarController = storyboard.instantiateViewController(withIdentifier: "MasterTabBarController") as? MasterTabBarController else {
|
||||
fatalError("[TabBarCoordinator] Can't load MasterTabBarController")
|
||||
}
|
||||
return masterTabBarController
|
||||
}
|
||||
|
||||
// MARK: Navigation
|
||||
|
||||
// FIXME: Should be displayed per tab.
|
||||
private func showSettings() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
// FIXME: Should be displayed per tab.
|
||||
private func showUnifiedSearch() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
// FIXME: Should be displayed from a tab.
|
||||
private func showContactDetails() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
// FIXME: Should be displayed from a tab.
|
||||
private func showRoomDetails() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
// FIXME: Should be displayed from a tab.
|
||||
private func showGroupDetails() {
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UINavigationControllerDelegate
|
||||
extension TabBarCoordinator: UINavigationControllerDelegate {
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
|
||||
|
||||
if viewController == masterTabBarController {
|
||||
masterNavigationController.delegate = nil
|
||||
|
||||
// For unknown reason, the navigation bar is not restored correctly by [popToViewController:animated:]
|
||||
// when a ViewController has hidden it (see MXKAttachmentsViewController).
|
||||
// Patch: restore navigation bar by default here.
|
||||
masterNavigationController.isNavigationBarHidden = false
|
||||
|
||||
// Release the current selected item (room/contact/...).
|
||||
masterTabBarController.releaseSelectedItem()
|
||||
|
||||
if let popToHomeViewControllerCompletion = self.popToHomeViewControllerCompletion {
|
||||
let popToHomeViewControllerCompletion2: (() -> Void)? = popToHomeViewControllerCompletion
|
||||
self.popToHomeViewControllerCompletion = nil
|
||||
|
||||
DispatchQueue.main.async {
|
||||
popToHomeViewControllerCompletion2?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MasterTabBarControllerDelegate
|
||||
extension TabBarCoordinator: MasterTabBarControllerDelegate {
|
||||
|
||||
func masterTabBarControllerDidCompleteAuthentication(_ masterTabBarController: MasterTabBarController!) {
|
||||
self.delegate?.tabBarCoordinatorDidCompleteAuthentication(self)
|
||||
}
|
||||
|
||||
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, wantsToDisplayDetailViewController detailViewController: UIViewController!) {
|
||||
|
||||
self.splitViewMasterPresentableDelegate?.splitViewMasterPresentable(self, wantsToDisplay: detailViewController)
|
||||
}
|
||||
}
|
36
Riot/Modules/TabBar/TabBarCoordinatorType.swift
Normal file
36
Riot/Modules/TabBar/TabBarCoordinatorType.swift
Normal file
|
@ -0,0 +1,36 @@
|
|||
// File created from FlowTemplate
|
||||
// $ createRootCoordinator.sh TabBar TabBar
|
||||
/*
|
||||
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 TabBarCoordinatorDelegate: class {
|
||||
// TODO: Remove this method, authentication should not be handled by TabBarCoordinator
|
||||
func tabBarCoordinatorDidCompleteAuthentication(_ coordinator: TabBarCoordinatorType)
|
||||
}
|
||||
|
||||
/// `TabBarCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
|
||||
protocol TabBarCoordinatorType: Coordinator, SplitViewMasterPresentable {
|
||||
|
||||
var delegate: TabBarCoordinatorDelegate? { get }
|
||||
|
||||
func popToHome(animated: Bool, completion: (() -> Void)?)
|
||||
|
||||
// TODO: Remove this method, this implementation detail should not be exposed
|
||||
// Release the current selected item (room/contact/group...).
|
||||
func releaseSelectedItems()
|
||||
}
|
87
Riot/Routers/RootRouter.swift
Executable file
87
Riot/Routers/RootRouter.swift
Executable file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
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
|
||||
|
||||
/// `RootRouter` is a concrete implementation of RootRouterType.
|
||||
final class RootRouter: RootRouterType {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
// `rootViewController` animation constants
|
||||
private enum RootViewControllerUpdateAnimation {
|
||||
static let duration: TimeInterval = 0.3
|
||||
static let options: UIView.AnimationOptions = .transitionCrossDissolve
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
private var presentedModule: Presentable?
|
||||
|
||||
let window: UIWindow
|
||||
|
||||
/// The root view controller currently presented
|
||||
var rootViewController: UIViewController? {
|
||||
return self.window.rootViewController
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(window: UIWindow) {
|
||||
self.window = window
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func setRootModule(_ module: Presentable) {
|
||||
self.updateRootViewController(rootViewController: module.toPresentable(), animated: false, completion: nil)
|
||||
self.window.makeKeyAndVisible()
|
||||
}
|
||||
|
||||
func dismissRootModule(animated: Bool, completion: (() -> Void)?) {
|
||||
self.updateRootViewController(rootViewController: nil, animated: animated, completion: completion)
|
||||
}
|
||||
|
||||
func presentModule(_ module: Presentable, animated: Bool, completion: (() -> Void)?) {
|
||||
let viewControllerPresenter = self.rootViewController?.presentedViewController ?? self.rootViewController
|
||||
|
||||
viewControllerPresenter?.present(module.toPresentable(), animated: animated, completion: completion)
|
||||
self.presentedModule = module
|
||||
}
|
||||
|
||||
func dismissModule(animated: Bool, completion: (() -> Void)?) {
|
||||
self.presentedModule?.toPresentable().dismiss(animated: animated, completion: completion)
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func updateRootViewController(rootViewController: UIViewController?, animated: Bool, completion: (() -> Void)?) {
|
||||
|
||||
if animated {
|
||||
UIView.transition(with: window, duration: RootViewControllerUpdateAnimation.duration, options: RootViewControllerUpdateAnimation.options, animations: {
|
||||
let oldState: Bool = UIView.areAnimationsEnabled
|
||||
UIView.setAnimationsEnabled(false)
|
||||
self.window.rootViewController = rootViewController
|
||||
UIView.setAnimationsEnabled(oldState)
|
||||
}, completion: { (finished: Bool) -> Void in
|
||||
completion?()
|
||||
})
|
||||
} else {
|
||||
self.window.rootViewController = rootViewController
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
}
|
49
Riot/Routers/RootRouterType.swift
Executable file
49
Riot/Routers/RootRouterType.swift
Executable file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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
|
||||
|
||||
/// Protocol describing a router that wraps the root navigation of the application.
|
||||
/// Routers are used to be passed between coordinators. They handles only `physical` navigation.
|
||||
protocol RootRouterType: class {
|
||||
|
||||
/// Update the root view controller
|
||||
///
|
||||
/// - Parameter module: The new root view controller to set
|
||||
func setRootModule(_ module: Presentable)
|
||||
|
||||
/// Dismiss the root view controller
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - animated: Specify true to animate the transition.
|
||||
/// - completion: The closure executed after the view controller is dismissed.
|
||||
func dismissRootModule(animated: Bool, completion: (() -> Void)?)
|
||||
|
||||
/// Present modally a view controller on the root view controller
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - module: Specify true to animate the transition.
|
||||
/// - animated: Specify true to animate the transition.
|
||||
/// - completion: Animation completion.
|
||||
func presentModule(_ module: Presentable, animated: Bool, completion: (() -> Void)?)
|
||||
|
||||
/// Dismiss modally presented view controller from root view controller
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - animated: Specify true to animate the transition.
|
||||
/// - completion: Animation completion.
|
||||
func dismissModule(animated: Bool, completion: (() -> Void)?)
|
||||
}
|
|
@ -55,8 +55,6 @@
|
|||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
|
|
|
@ -22,6 +22,7 @@ import Foundation
|
|||
|
||||
/// FlowTemplateCoordinatorBridgePresenter enables to start FlowTemplateCoordinator from a view controller.
|
||||
/// This bridge is used while waiting for global usage of coordinator pattern.
|
||||
/// It breaks the Coordinator abstraction and it has been introduced for Objective-C compatibility (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
|
||||
@objcMembers
|
||||
final class FlowTemplateCoordinatorBridgePresenter: NSObject {
|
||||
|
||||
|
|
Loading…
Reference in a new issue