diff --git a/CHANGES.rst b/CHANGES.rst index 2273f045b..ab0379f42 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,16 +2,17 @@ Changes to be released in next version ================================================= ✨ Features - * + * Added blur background support for iPhone and iPad (#3842) 🙌 Improvements * Room History: Remove the report option for outgoing messages. + * Empty views: Add empty screen when there is nothing to display on home, people, favourites and rooms screen (#3836). 🐛 Bugfix * ⚠️ API Changes - * + * Slight API changes for SlidingModalPresenter to avoid race conditions while sharing a presenter. (#3842) 🗣 Translations * @@ -63,6 +64,7 @@ Changes in 1.1.0 (2020-11-17) * MXProfiler: Use this new module to track launch animation time reliably. * KeyValueStore improvements. * Jitsi: Support authenticated Jitsi widgets (#3655). + * Room invites: Allow to accept a room invite without preview. 🐛 Bugfix * Fix analytics in order to track performance improvements. diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index b710761d6..d3cdcaf96 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -203,9 +203,9 @@ B110872621F098F0003554A5 /* ActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B110872221F098F0003554A5 /* ActivityIndicatorView.swift */; }; B11291EA238D35590077B478 /* SlidingModalPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11291E9238D35590077B478 /* SlidingModalPresentable.swift */; }; B11291EC238D704C0077B478 /* FloatingPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11291EB238D704C0077B478 /* FloatingPoint.swift */; }; - B11F4D1C25680010009F1586 /* HomeEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B11F4D1A25680010009F1586 /* HomeEmptyView.xib */; }; - B11F4D1D25680010009F1586 /* HomeEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11F4D1B25680010009F1586 /* HomeEmptyView.swift */; }; + B113DD3D255E876A0022942A /* JitsiWellKnown.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5EF9C2541C06000E8A883 /* JitsiWellKnown.swift */; }; B120863722EF375F001F89E0 /* ReactionHistoryBridgeCoordinatorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B120863622EF375F001F89E0 /* ReactionHistoryBridgeCoordinatorPresenter.swift */; }; + B124BBD725645F3F0028996D /* RoomIdComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = B124BBD625645F3F0028996D /* RoomIdComponents.swift */; }; B125FE1B231D5BF200B72806 /* SettingsDiscoveryTableViewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B125FE1A231D5BF200B72806 /* SettingsDiscoveryTableViewSection.swift */; }; B125FE1D231D5DE400B72806 /* SettingsDiscoveryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B125FE1C231D5DE400B72806 /* SettingsDiscoveryViewModel.swift */; }; B125FE1F231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B125FE1E231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift */; }; @@ -333,7 +333,6 @@ B190F55922CE356800AEB493 /* EditHistoryHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B190F55822CE356800AEB493 /* EditHistoryHeaderView.swift */; }; B190F55B22CE35FD00AEB493 /* EditHistoryHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B190F55A22CE35FD00AEB493 /* EditHistoryHeaderView.xib */; }; B190F55D22CE5A9700AEB493 /* EditHistorySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B190F55C22CE5A9600AEB493 /* EditHistorySection.swift */; }; - B1920713255068B300F5062F /* RoomIdComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1920712255068B200F5062F /* RoomIdComponents.swift */; }; B1963B2B228F1C4900CBA17F /* BubbleReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */; }; B1963B2C228F1C4900CBA17F /* BubbleReactionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1963B26228F1C4800CBA17F /* BubbleReactionViewCell.xib */; }; B1963B2D228F1C4900CBA17F /* BubbleReactionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */; }; @@ -346,6 +345,8 @@ B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B19EFA3821F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift */; }; B19EFA3B21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B19EFA3A21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift */; }; B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A5B33D227ADF2A004CBA85 /* UIImage.swift */; }; + B1A67946257559CF00BB0C69 /* RootTabEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11F4D2025681500009F1586 /* RootTabEmptyView.swift */; }; + B1A67947257559D500BB0C69 /* RootTabEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B11F4D1E256814E5009F1586 /* RootTabEmptyView.xib */; }; B1A6805424B7C65200E312CC /* MajorUpdateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A6805324B7C65200E312CC /* MajorUpdateManager.swift */; }; B1A68593229E807A00D6C09A /* RoomBubbleCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A68592229E807800D6C09A /* RoomBubbleCellLayout.swift */; }; B1A6C10723881EF2002882FD /* SlidingModalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A6C10623881EF2002882FD /* SlidingModalPresenter.swift */; }; @@ -752,7 +753,8 @@ B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5368821FB1E20001F3AFF /* UIButton.swift */; }; B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5368C21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift */; }; B1E5368F21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1E5368E21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard */; }; - B1E5EF9D2541C06000E8A883 /* JitsiWellKnown.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5EF9C2541C06000E8A883 /* JitsiWellKnown.swift */; }; + B1F9072D255CDA1200DD14E5 /* RecentsViewController+RoomInvite.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F9072C255CDA1200DD14E5 /* RecentsViewController+RoomInvite.swift */; }; + B1F9072F255CE06000DD14E5 /* InviteRecentTableViewCell+ButtonViewsUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F9072E255CE06000DD14E5 /* InviteRecentTableViewCell+ButtonViewsUpdate.swift */; }; B1FDF56021F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FDF55F21F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift */; }; DB1392A2332C3CAF6C9962EF /* Pods_RiotPods_RiotNSE.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4D418D054E4032F2CFA8B51 /* Pods_RiotPods_RiotNSE.framework */; }; EC1CA85F24C1DEC400DE9EBF /* EnterPinCodeViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1CA85124C1DEC400DE9EBF /* EnterPinCodeViewModelType.swift */; }; @@ -1242,9 +1244,10 @@ B110872221F098F0003554A5 /* ActivityIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorView.swift; sourceTree = ""; }; B11291E9238D35590077B478 /* SlidingModalPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlidingModalPresentable.swift; sourceTree = ""; }; B11291EB238D704C0077B478 /* FloatingPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPoint.swift; sourceTree = ""; }; - B11F4D1A25680010009F1586 /* HomeEmptyView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HomeEmptyView.xib; sourceTree = ""; }; - B11F4D1B25680010009F1586 /* HomeEmptyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeEmptyView.swift; sourceTree = ""; }; + B11F4D1E256814E5009F1586 /* RootTabEmptyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RootTabEmptyView.xib; sourceTree = ""; }; + B11F4D2025681500009F1586 /* RootTabEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootTabEmptyView.swift; sourceTree = ""; }; B120863622EF375F001F89E0 /* ReactionHistoryBridgeCoordinatorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionHistoryBridgeCoordinatorPresenter.swift; sourceTree = ""; }; + B124BBD625645F3F0028996D /* RoomIdComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomIdComponents.swift; sourceTree = ""; }; B125FE1A231D5BF200B72806 /* SettingsDiscoveryTableViewSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryTableViewSection.swift; sourceTree = ""; }; B125FE1C231D5DE400B72806 /* SettingsDiscoveryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryViewModel.swift; sourceTree = ""; }; B125FE1E231D5DF700B72806 /* SettingsDiscoveryViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiscoveryViewModelType.swift; sourceTree = ""; }; @@ -1422,7 +1425,6 @@ B190F55822CE356800AEB493 /* EditHistoryHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditHistoryHeaderView.swift; sourceTree = ""; }; B190F55A22CE35FD00AEB493 /* EditHistoryHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EditHistoryHeaderView.xib; sourceTree = ""; }; B190F55C22CE5A9600AEB493 /* EditHistorySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditHistorySection.swift; sourceTree = ""; }; - B1920712255068B200F5062F /* RoomIdComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomIdComponents.swift; sourceTree = ""; }; B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionsView.swift; sourceTree = ""; }; B1963B26228F1C4800CBA17F /* BubbleReactionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BubbleReactionViewCell.xib; sourceTree = ""; }; B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionsViewModel.swift; sourceTree = ""; }; @@ -1984,6 +1986,8 @@ B1EDFDF32525E9690020EEFF /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Vector.strings; sourceTree = ""; }; B1EDFDF42525E9690020EEFF /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/InfoPlist.strings; sourceTree = ""; }; B1EDFDF52525E96A0020EEFF /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = ""; }; + B1F9072C255CDA1200DD14E5 /* RecentsViewController+RoomInvite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RecentsViewController+RoomInvite.swift"; sourceTree = ""; }; + B1F9072E255CE06000DD14E5 /* InviteRecentTableViewCell+ButtonViewsUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InviteRecentTableViewCell+ButtonViewsUpdate.swift"; sourceTree = ""; }; B1FDF55F21F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupSetupPassphraseViewAction.swift; sourceTree = ""; }; B43DC75D1590BB8A4243BD4D /* Pods-RiotPods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-Riot.release.xcconfig"; path = "Target Support Files/Pods-RiotPods-Riot/Pods-RiotPods-Riot.release.xcconfig"; sourceTree = ""; }; BABB6681FBD79219B1213D6C /* Pods-RiotTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotTests.debug.xcconfig"; path = "Target Support Files/Pods-RiotTests/Pods-RiotTests.debug.xcconfig"; sourceTree = ""; }; @@ -3233,6 +3237,14 @@ path = OnBoarding; sourceTree = ""; }; + B180A645255DF59800F5E6FF /* Room */ = { + isa = PBXGroup; + children = ( + B124BBD625645F3F0028996D /* RoomIdComponents.swift */, + ); + path = Room; + sourceTree = ""; + }; B183226923F59F3E0035B2E8 /* Buttons */ = { isa = PBXGroup; children = ( @@ -3273,14 +3285,6 @@ path = SelfVerifyWait; sourceTree = ""; }; - B19207112550683500F5062F /* Room */ = { - isa = PBXGroup; - children = ( - B1920712255068B200F5062F /* RoomIdComponents.swift */, - ); - path = Room; - sourceTree = ""; - }; B1963B24228F1C4800CBA17F /* BubbleReactions */ = { isa = PBXGroup; children = ( @@ -3785,6 +3789,7 @@ B1B556DB20EE6C4C00210D55 /* RecentsViewController.h */, B1B556D920EE6C4C00210D55 /* RecentsViewController.m */, B1B556DA20EE6C4C00210D55 /* RecentsViewController.xib */, + B1F9072C255CDA1200DD14E5 /* RecentsViewController+RoomInvite.swift */, B16932F320F3C4B800746532 /* DataSources */, B16932F420F3C4C000746532 /* CellData */, B1B5594E20EF9A8600210D55 /* Views */, @@ -4460,8 +4465,6 @@ B1B5594320EF7BD000210D55 /* TableViewCellWithCollectionView.h */, B1B5594020EF7BD000210D55 /* TableViewCellWithCollectionView.m */, B1B5593F20EF7BD000210D55 /* TableViewCellWithCollectionView.xib */, - B11F4D1B25680010009F1586 /* HomeEmptyView.swift */, - B11F4D1A25680010009F1586 /* HomeEmptyView.xib */, ); path = Views; sourceTree = ""; @@ -4474,6 +4477,8 @@ B1B5594F20EF9A8600210D55 /* RecentTableViewCell.h */, B1B5595020EF9A8600210D55 /* RecentTableViewCell.m */, B1B5595120EF9A8600210D55 /* RecentTableViewCell.xib */, + B11F4D2025681500009F1586 /* RootTabEmptyView.swift */, + B11F4D1E256814E5009F1586 /* RootTabEmptyView.xib */, ); path = Views; sourceTree = ""; @@ -4502,6 +4507,7 @@ isa = PBXGroup; children = ( B1B5597420EFB02900210D55 /* InviteRecentTableViewCell.h */, + B1F9072E255CE06000DD14E5 /* InviteRecentTableViewCell+ButtonViewsUpdate.swift */, B1B5597220EFB02900210D55 /* InviteRecentTableViewCell.m */, B1B5597320EFB02900210D55 /* InviteRecentTableViewCell.xib */, ); @@ -4524,7 +4530,7 @@ B1B5598A20EFC42100210D55 /* Settings */, 32242F0B21E8FBA900725742 /* Theme */, B1B5598020EFC3DF00210D55 /* Widgets */, - B19207112550683500F5062F /* Room */, + B180A645255DF59800F5E6FF /* Room */, ); path = Managers; sourceTree = ""; @@ -5935,12 +5941,12 @@ B1B558BB20EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib in Resources */, B1B557A720EF5A1B00210D55 /* DeviceTableViewCell.xib in Resources */, B14084C823BF76CB0010F692 /* BubbleCellContentView.xib in Resources */, + B1A67947257559D500BB0C69 /* RootTabEmptyView.xib in Resources */, B1B557D220EF5E3500210D55 /* MediaAlbumTableCell.xib in Resources */, B1B558C520EF768F00210D55 /* RoomOutgoingEncryptedTextMsgBubbleCell.xib in Resources */, B1B5582B20EF666100210D55 /* DirectoryRecentTableViewCell.xib in Resources */, B105778F2213052A00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.storyboard in Resources */, EC1CA89924C9C9A200DE9EBF /* SetupBiometricsViewController.storyboard in Resources */, - B11F4D1C25680010009F1586 /* HomeEmptyView.xib in Resources */, B1B5590F20EF782800210D55 /* TableViewCellWithPhoneNumberTextField.xib in Resources */, B1B5578520EF564900210D55 /* GroupTableViewCellWithSwitch.xib in Resources */, B1B557B320EF5AEF00210D55 /* EventDetailsView.xib in Resources */, @@ -6233,6 +6239,7 @@ buildActionMask = 2147483647; files = ( EC711B7B24A63B37008F830C /* SecretsSetupRecoveryKeyCoordinator.swift in Sources */, + B1F9072D255CDA1200DD14E5 /* RecentsViewController+RoomInvite.swift in Sources */, B1B557D120EF5E3500210D55 /* MediaAlbumTableCell.m in Sources */, 32607D71243E0A55006674CC /* KeyBackupRecoverFromPrivateKeyViewState.swift in Sources */, EC51E7A92514D2E100AAE7DB /* RoomInfoListViewModelType.swift in Sources */, @@ -6350,6 +6357,7 @@ B157FAA823264BED00EBFBD4 /* SettingsDiscoveryThreePidDetailsCoordinatorBridgePresenter.swift in Sources */, B169330B20F3CA3A00746532 /* Contact.m in Sources */, B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */, + B113DD3D255E876A0022942A /* JitsiWellKnown.swift in Sources */, EC51E7AC2514D2E100AAE7DB /* RoomInfoListCoordinatorType.swift in Sources */, B1D4752A21EE52B10067973F /* KeyBackupSetupIntroViewController.swift in Sources */, B10A3E9424FE8254007C380F /* AppCoordinatorType.swift in Sources */, @@ -6508,6 +6516,7 @@ 32F6B96B2270623100BBA352 /* KeyVerificationDataLoadingViewAction.swift in Sources */, B1B558C920EF768F00210D55 /* RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */, B1B5571B20EE6C4D00210D55 /* DeactivateAccountViewController.m in Sources */, + B1A67946257559CF00BB0C69 /* RootTabEmptyView.swift in Sources */, B1DCC63922E85E9A00625807 /* EmojiMartStore.swift in Sources */, B10A3E9024FE4368007C380F /* ElementViewController.swift in Sources */, B1B5590620EF768F00210D55 /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m in Sources */, @@ -6527,6 +6536,7 @@ B126768A2523E4D100BE6B98 /* SecretsResetViewModel.swift in Sources */, B1DCC62422E60CA900625807 /* EmojiPickerCategoryViewData.swift in Sources */, B1550FCB2420E8F500CE097B /* QRCodeReaderViewController.swift in Sources */, + B124BBD725645F3F0028996D /* RoomIdComponents.swift in Sources */, 324A2056225FC571004FE8B0 /* DeviceVerificationIncomingCoordinator.swift in Sources */, B16932F720F3C50E00746532 /* RecentsDataSource.m in Sources */, B1DCC63B22E85EF800625807 /* EmojiMartCategory.swift in Sources */, @@ -6689,7 +6699,6 @@ EC51E7A62514D2E100AAE7DB /* RoomInfoCoordinatorBridgePresenter.swift in Sources */, EC1CA87524C8259700DE9EBF /* KeychainStore.swift in Sources */, B1B5575220EE6C4D00210D55 /* RoomKeyRequestViewController.m in Sources */, - B1920713255068B300F5062F /* RoomIdComponents.swift in Sources */, 32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */, F083BD1E1E7009ED00A9B29C /* LegacyAppDelegate.m in Sources */, B1B558E620EF768F00210D55 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, @@ -6703,6 +6712,7 @@ B18DEDD9243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewController.swift in Sources */, EC1CA89524C9C9A200DE9EBF /* SetupBiometricsViewController.swift in Sources */, 324A2052225FC571004FE8B0 /* DeviceVerificationIncomingViewAction.swift in Sources */, + B1F9072F255CE06000DD14E5 /* InviteRecentTableViewCell+ButtonViewsUpdate.swift in Sources */, EC85D72C2477DCF2002C44C9 /* KeyVerificationManuallyVerifyViewState.swift in Sources */, EC1CA86E24C5BA4500DE9EBF /* PinCodePreferences.swift in Sources */, B105778D2213051E00334B1E /* KeyBackupSetupSuccessFromRecoveryKeyViewController.swift in Sources */, @@ -6887,7 +6897,6 @@ B18DEDD5243377C10075FEF7 /* KeyVerificationSelfVerifyWaitViewModel.swift in Sources */, EC711B8B24A63B37008F830C /* SecretsRecoveryWithPassphraseViewState.swift in Sources */, ECAE7AE524EC0E01002FA813 /* TableViewSections.swift in Sources */, - B1E5EF9D2541C06000E8A883 /* JitsiWellKnown.swift in Sources */, B1CE83DA2422817200D07506 /* KeyVerificationVerifyByScanningViewModel.swift in Sources */, 32242F0921E8B05F00725742 /* UIColor.swift in Sources */, B16932E720F3C37100746532 /* HomeMessagesSearchDataSource.m in Sources */, @@ -6925,7 +6934,6 @@ B10A3E9C24FE88CB007C380F /* RootRouter.swift in Sources */, B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */, B14F143022144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift in Sources */, - B11F4D1D25680010009F1586 /* HomeEmptyView.swift in Sources */, B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */, B1DCC63422E72C1B00625807 /* UISearchBar.swift in Sources */, 32A6001622C661100042C1D9 /* EditHistoryViewState.swift in Sources */, diff --git a/Riot/Assets/Images.xcassets/Contents.json b/Riot/Assets/Images.xcassets/Contents.json index da4a164c9..73c00596a 100644 --- a/Riot/Assets/Images.xcassets/Contents.json +++ b/Riot/Assets/Images.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Riot/Assets/Images.xcassets/Favourites/Contents.json b/Riot/Assets/Images.xcassets/Favourites/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Riot/Assets/Images.xcassets/Favourites/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/Contents.json b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/Contents.json new file mode 100644 index 000000000..915cb0de0 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "favourites_empty_screen_artwork.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "favourites_empty_screen_artwork@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "favourites_empty_screen_artwork@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork.png b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork.png new file mode 100644 index 000000000..f30212c8d Binary files /dev/null and b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork.png differ diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork@2x.png b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork@2x.png new file mode 100644 index 000000000..2c5863043 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork@3x.png b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork@3x.png new file mode 100644 index 000000000..440238122 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork.imageset/favourites_empty_screen_artwork@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/Contents.json new file mode 100644 index 000000000..0146dee1b --- /dev/null +++ b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "favourites_empty_screen_artwork_dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "favourites_empty_screen_artwork_dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "favourites_empty_screen_artwork_dark@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark.png b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark.png new file mode 100644 index 000000000..96dede29e Binary files /dev/null and b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark.png differ diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark@2x.png b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark@2x.png new file mode 100644 index 000000000..1a7c5b4ef Binary files /dev/null and b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark@3x.png b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark@3x.png new file mode 100644 index 000000000..db3cdf08c Binary files /dev/null and b/Riot/Assets/Images.xcassets/Favourites/favourites_empty_screen_artwork_dark.imageset/favourites_empty_screen_artwork_dark@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/Contents.json similarity index 62% rename from Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/Contents.json rename to Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/Contents.json index 7e47ef7db..16df39dfa 100644 --- a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "home_placeholder_artwork.png", + "filename" : "home_empty_screen_artwork.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "home_placeholder_artwork@2x.png", + "filename" : "home_empty_screen_artwork@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "home_placeholder_artwork@3x.png", + "filename" : "home_empty_screen_artwork@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork.png b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork.png new file mode 100644 index 000000000..3e286dffe Binary files /dev/null and b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork@2x.png b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork@2x.png new file mode 100644 index 000000000..7b093d968 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork@3x.png b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork@3x.png new file mode 100644 index 000000000..25debf8cf Binary files /dev/null and b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork.imageset/home_empty_screen_artwork@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/Contents.json new file mode 100644 index 000000000..3f602142e --- /dev/null +++ b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "home_empty_screen_artwork_dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "home_empty_screen_artwork_dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "home_empty_screen_artwork_dark@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark.png b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark.png new file mode 100644 index 000000000..7f82490f2 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark@2x.png b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark@2x.png new file mode 100644 index 000000000..e83d6a04f Binary files /dev/null and b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark@3x.png b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark@3x.png new file mode 100644 index 000000000..91f37eae7 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Home/home_empty_screen_artwork_dark.imageset/home_empty_screen_artwork_dark@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork.png b/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork.png deleted file mode 100644 index 5c737cc1d..000000000 Binary files a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork@2x.png b/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork@2x.png deleted file mode 100644 index 7aec3e024..000000000 Binary files a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork@2x.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork@3x.png b/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork@3x.png deleted file mode 100644 index 9c6862c3c..000000000 Binary files a/Riot/Assets/Images.xcassets/Home/home_placeholder_artwork.imageset/home_placeholder_artwork@3x.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/Contents.json b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/Contents.json new file mode 100644 index 000000000..cde9a91d7 --- /dev/null +++ b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "people_empty_screen_artwork.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "people_empty_screen_artwork@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "people_empty_screen_artwork@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork.png b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork.png new file mode 100644 index 000000000..18457d376 Binary files /dev/null and b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork.png differ diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork@2x.png b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork@2x.png new file mode 100644 index 000000000..a19ce9944 Binary files /dev/null and b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork@2x.png differ diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork@3x.png b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork@3x.png new file mode 100644 index 000000000..34e0d105d Binary files /dev/null and b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork.imageset/people_empty_screen_artwork@3x.png differ diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/Contents.json new file mode 100644 index 000000000..07de45802 --- /dev/null +++ b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "people_empty_screen_artwork_dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "people_empty_screen_artwork_dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "people_empty_screen_artwork_dark@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark.png b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark.png new file mode 100644 index 000000000..4d74ca25d Binary files /dev/null and b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark.png differ diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark@2x.png b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark@2x.png new file mode 100644 index 000000000..51db7608c Binary files /dev/null and b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark@2x.png differ diff --git a/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark@3x.png b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark@3x.png new file mode 100644 index 000000000..8a35ba227 Binary files /dev/null and b/Riot/Assets/Images.xcassets/People/people_empty_screen_artwork_dark.imageset/people_empty_screen_artwork_dark@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/Contents.json b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/Contents.json new file mode 100644 index 000000000..a3832a835 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "rooms_empty_screen_artwork.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "rooms_empty_screen_artwork@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "rooms_empty_screen_artwork@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork.png b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork.png new file mode 100644 index 000000000..38d2099db Binary files /dev/null and b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork.png differ diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork@2x.png b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork@2x.png new file mode 100644 index 000000000..bb8124f37 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork@3x.png b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork@3x.png new file mode 100644 index 000000000..fb8273933 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork.imageset/rooms_empty_screen_artwork@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/Contents.json new file mode 100644 index 000000000..a70c9cb51 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "rooms_empty_screen_artwork_dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "rooms_empty_screen_artwork_dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "rooms_empty_screen_artwork_dark@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark.png b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark.png new file mode 100644 index 000000000..1e1e2b8f7 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark.png differ diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark@2x.png b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark@2x.png new file mode 100644 index 000000000..122a2efc1 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark@3x.png b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark@3x.png new file mode 100644 index 000000000..9656a1a4c Binary files /dev/null and b/Riot/Assets/Images.xcassets/Rooms/rooms_empty_screen_artwork_dark.imageset/rooms_empty_screen_artwork_dark@3x.png differ diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index dc81d4ede..dc29d77fc 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -181,9 +181,16 @@ "people_conversation_section" = "CONVERSATIONS"; "people_no_conversation" = "No conversations"; +"people_empty_view_title" = "People"; +"people_empty_view_information" = "Chat securely with anyone. +Tap the + to start adding people."; + // Rooms tab "room_directory_no_public_room" = "No public rooms available"; +"rooms_empty_view_title" = "Rooms"; +"rooms_empty_view_information" = "Rooms are great for any group chat, private or public. Tap the + to find existing rooms, or make new ones."; + // Groups tab "group_invite_section" = "INVITES"; "group_section" = "COMMUNITIES"; @@ -1519,5 +1526,10 @@ // MARK: - Home -"home_empty_view_title" = "Welcome to Element,\n%@"; -"home_empty_view_information" = "The all-in-one secure chat app for teams, friends and organisations. Tap the \"+\" button below to add people and rooms."; +"home_empty_view_title" = "Welcome to %@,\n%@"; +"home_empty_view_information" = "The all-in-one secure chat app for teams, friends and organisations. Tap the + button below to add people and rooms."; + +// MARK: - Favourites + +"favourites_empty_view_title" = "Favourite rooms and people"; +"favourites_empty_view_information" = "You can favourite a few ways - the quickest is just to press and hold. Tap the star and they’ll automatically appear here for safe keeping."; diff --git a/Riot/Categories/UITableViewCell.swift b/Riot/Categories/UITableViewCell.swift index 359b02134..e9ea1f8ba 100644 --- a/Riot/Categories/UITableViewCell.swift +++ b/Riot/Categories/UITableViewCell.swift @@ -18,6 +18,10 @@ import Foundation extension UITableViewCell { + + private enum AccessoryImageAlpha { + static let highlighted: CGFloat = 0.3 + } /// Returns safe area insetted separator inset. Should only be used when custom constraints on custom table view cells are being set according to separator insets. @objc var vc_separatorInset: UIEdgeInsets { @@ -30,8 +34,10 @@ extension UITableViewCell { } @objc func vc_setAccessoryDisclosureIndicator(withTintColor tintColor: UIColor) { - let disclosureImageView = UIImageView(image: Asset.Images.disclosureIcon.image) + let disclosureImage = Asset.Images.disclosureIcon.image.withRenderingMode(.alwaysTemplate) + let disclosureImageView = UIImageView(image: disclosureImage) disclosureImageView.tintColor = tintColor + disclosureImageView.highlightedImage = disclosureImage.vc_withAlpha(AccessoryImageAlpha.highlighted) self.accessoryView = disclosureImageView } diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index d8a8f46f1..d2c1f1a7e 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -59,13 +59,16 @@ internal enum Asset { internal static let encryptionNormal = ImageAsset(name: "encryption_normal") internal static let encryptionTrusted = ImageAsset(name: "encryption_trusted") internal static let encryptionWarning = ImageAsset(name: "encryption_warning") + internal static let favouritesEmptyScreenArtwork = ImageAsset(name: "favourites_empty_screen_artwork") + internal static let favouritesEmptyScreenArtworkDark = ImageAsset(name: "favourites_empty_screen_artwork_dark") internal static let roomActionDirectChat = ImageAsset(name: "room_action_direct_chat") internal static let roomActionFavourite = ImageAsset(name: "room_action_favourite") internal static let roomActionLeave = ImageAsset(name: "room_action_leave") internal static let roomActionNotification = ImageAsset(name: "room_action_notification") internal static let roomActionPriorityHigh = ImageAsset(name: "room_action_priority_high") internal static let roomActionPriorityLow = ImageAsset(name: "room_action_priority_low") - internal static let homePlaceholderArtwork = ImageAsset(name: "home_placeholder_artwork") + internal static let homeEmptyScreenArtwork = ImageAsset(name: "home_empty_screen_artwork") + internal static let homeEmptyScreenArtworkDark = ImageAsset(name: "home_empty_screen_artwork_dark") internal static let plusFloatingAction = ImageAsset(name: "plus_floating_action") internal static let closeBanner = ImageAsset(name: "close_banner") internal static let importFilesButton = ImageAsset(name: "import_files_button") @@ -77,6 +80,8 @@ internal enum Asset { internal static let cameraStop = ImageAsset(name: "camera_stop") internal static let cameraVideoCapture = ImageAsset(name: "camera_video_capture") internal static let videoIcon = ImageAsset(name: "video_icon") + internal static let peopleEmptyScreenArtwork = ImageAsset(name: "people_empty_screen_artwork") + internal static let peopleEmptyScreenArtworkDark = ImageAsset(name: "people_empty_screen_artwork_dark") internal static let peopleFloatingAction = ImageAsset(name: "people_floating_action") internal static let error = ImageAsset(name: "error") internal static let scrolldown = ImageAsset(name: "scrolldown") @@ -98,6 +103,8 @@ internal enum Asset { internal static let modIcon = ImageAsset(name: "mod_icon") internal static let moreReactions = ImageAsset(name: "more_reactions") internal static let scrollup = ImageAsset(name: "scrollup") + internal static let roomsEmptyScreenArtwork = ImageAsset(name: "rooms_empty_screen_artwork") + internal static let roomsEmptyScreenArtworkDark = ImageAsset(name: "rooms_empty_screen_artwork_dark") internal static let roomsFloatingAction = ImageAsset(name: "rooms_floating_action") internal static let userIcon = ImageAsset(name: "user_icon") internal static let fileDocIcon = ImageAsset(name: "file_doc_icon") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 32fb6bf15..46934e2a6 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1230,6 +1230,14 @@ internal enum VectorL10n { internal static var externalLinkConfirmationTitle: String { return VectorL10n.tr("Vector", "external_link_confirmation_title") } + /// You can favourite a few ways - the quickest is just to press and hold. Tap the star and they’ll automatically appear here for safe keeping. + internal static var favouritesEmptyViewInformation: String { + return VectorL10n.tr("Vector", "favourites_empty_view_information") + } + /// Favourite rooms and people + internal static var favouritesEmptyViewTitle: String { + return VectorL10n.tr("Vector", "favourites_empty_view_title") + } /// File upload internal static var fileUploadErrorTitle: String { return VectorL10n.tr("Vector", "file_upload_error_title") @@ -1346,13 +1354,13 @@ internal enum VectorL10n { internal static var groupSection: String { return VectorL10n.tr("Vector", "group_section") } - /// The all-in-one secure chat app for teams, friends and organisations. Tap the "+" button below to add people and rooms. + /// The all-in-one secure chat app for teams, friends and organisations. Tap the + button below to add people and rooms. internal static var homeEmptyViewInformation: String { return VectorL10n.tr("Vector", "home_empty_view_information") } - /// Welcome to Element,\n%@ - internal static func homeEmptyViewTitle(_ p1: String) -> String { - return VectorL10n.tr("Vector", "home_empty_view_title", p1) + /// Welcome to %@,\n%@ + internal static func homeEmptyViewTitle(_ p1: String, _ p2: String) -> String { + return VectorL10n.tr("Vector", "home_empty_view_title", p1, p2) } /// Could not connect to the homeserver. internal static var homeserverConnectionLost: String { @@ -2018,6 +2026,14 @@ internal enum VectorL10n { internal static var peopleConversationSection: String { return VectorL10n.tr("Vector", "people_conversation_section") } + /// Chat securely with anyone.\nTap the + to start adding people. + internal static var peopleEmptyViewInformation: String { + return VectorL10n.tr("Vector", "people_empty_view_information") + } + /// People + internal static var peopleEmptyViewTitle: String { + return VectorL10n.tr("Vector", "people_empty_view_title") + } /// INVITES internal static var peopleInvitesSection: String { return VectorL10n.tr("Vector", "people_invites_section") @@ -3202,6 +3218,14 @@ internal enum VectorL10n { internal static var roomWidgetPermissionWidgetIdPermission: String { return VectorL10n.tr("Vector", "room_widget_permission_widget_id_permission") } + /// Rooms are great for any group chat, private or public. Tap the + to find existing rooms, or make new ones. + internal static var roomsEmptyViewInformation: String { + return VectorL10n.tr("Vector", "rooms_empty_view_information") + } + /// Rooms + internal static var roomsEmptyViewTitle: String { + return VectorL10n.tr("Vector", "rooms_empty_view_title") + } /// Save internal static var save: String { return VectorL10n.tr("Vector", "save") diff --git a/Riot/Managers/Theme/ThemeService.h b/Riot/Managers/Theme/ThemeService.h index b10e6cb7f..7fcaff121 100644 --- a/Riot/Managers/Theme/ThemeService.h +++ b/Riot/Managers/Theme/ThemeService.h @@ -59,6 +59,10 @@ extern NSString *const kThemeServiceDidChangeThemeNotification; */ - (id)themeWithThemeId:(NSString*)themeId; + +/// Retrun YES if the current is Dark or Black +- (BOOL)isCurrentThemeDark; + #pragma mark - Riot Colors not yet themeable @property (nonatomic, readonly) UIColor *riotColorCuriousBlue; diff --git a/Riot/Managers/Theme/ThemeService.m b/Riot/Managers/Theme/ThemeService.m index de494bb23..f29dbcaab 100644 --- a/Riot/Managers/Theme/ThemeService.m +++ b/Riot/Managers/Theme/ThemeService.m @@ -95,6 +95,16 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan return theme; } +- (BOOL)isCurrentThemeDark +{ + if ([self.theme.identifier isEqualToString:@"dark"] || [self.theme.identifier isEqualToString:@"black"]) + { + return YES; + } + + return NO; +} + #pragma mark - Private methods - (instancetype)init diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 613b9aa03..096482692 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1765,7 +1765,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [self configureCallManagerIfRequiredForSession:mxSession]; - [self.configuration setupSettingsFor:mxSession]; + [self.configuration setupSettingsFor:mxSession]; } else if (mxSession.state == MXSessionStateStoreDataReady) { diff --git a/Riot/Modules/Common/Recents/RecentsViewController+RoomInvite.swift b/Riot/Modules/Common/Recents/RecentsViewController+RoomInvite.swift new file mode 100644 index 000000000..4c9eb0288 --- /dev/null +++ b/Riot/Modules/Common/Recents/RecentsViewController+RoomInvite.swift @@ -0,0 +1,38 @@ +// +// 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 + +extension RecentsViewController { + + @objc func canShowRoomPreview(for room: MXRoom) -> Bool { + // Do not show room preview if room is not direct + guard room.isDirect else { + return false + } + + let membershipTransitionState = room.summary.membershipTransitionState + + // NOTE: For the moment do not offer the possibility to show room preview when invitation action is in progress + + switch membershipTransitionState { + case .failedJoining, .failedLeaving: + return false + default: + return true + } + } +} diff --git a/Riot/Modules/Common/Recents/RecentsViewController.h b/Riot/Modules/Common/Recents/RecentsViewController.h index c79d3441b..ec0d613fe 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.h +++ b/Riot/Modules/Common/Recents/RecentsViewController.h @@ -17,6 +17,8 @@ #import +@class RootTabEmptyView; + @interface RecentsViewController : MXKRecentListViewController { @protected @@ -83,6 +85,11 @@ */ @property (nonatomic) NSString *screenName; +/** + Empty view to display when there is no item to show on the screen. + */ +@property (nonatomic, weak) RootTabEmptyView *emptyView; + /** Return the sticky header for the specified section of the table view @@ -177,5 +184,17 @@ - (void)didTapOnSectionHeader:(UIGestureRecognizer*)gestureRecognizer; - (void)didSwipeOnSectionHeader:(UISwipeGestureRecognizer*)gestureRecognizer; +#pragma mark - Empty view + +/** + Overrides this method to fill the empty view with data. + */ +- (void)updateEmptyView; + +/** + Overrides this method to indicate if empty view should be shown. Returns NO by default. + */ +- (BOOL)shouldShowEmptyView; + @end diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 336275581..3cdcc85bc 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -153,7 +153,7 @@ }]; self.recentsSearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone; - self.recentsSearchBar.placeholder = NSLocalizedStringFromTable(@"search_default_placeholder", @"Vector", nil); + self.recentsSearchBar.placeholder = NSLocalizedStringFromTable(@"search_default_placeholder", @"Vector", nil); // Observe user interface theme change. kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { @@ -184,6 +184,8 @@ // Force table refresh [self cancelEditionMode:YES]; } + + [self.emptyView updateWithTheme:ThemeService.shared.theme]; [self setNeedsStatusBarAppearanceUpdate]; } @@ -452,6 +454,79 @@ } } +- (void)joinRoom:(MXRoom*)room completion:(void(^)(BOOL succeed))completion +{ + [room join:^{ + // `recentsTableView` will be reloaded `roomChangeMembershipStateDataSourceDidChangeRoomMembershipState` function + + if (completion) + { + completion(YES); + } + + } failure:^(NSError * _Nonnull error) { + NSLog(@"[RecentsViewController] Failed to join an invited room (%@)", room.roomId); + [self presentRoomJoinFailedAlertForError:error completion:^{ + if (completion) + { + completion(NO); + } + }]; + }]; +} + +- (void)leaveRoom:(MXRoom*)room completion:(void(^)(BOOL succeed))completion +{ + // Decline the invitation + [room leave:^{ + + // `recentsTableView` will be reloaded `roomChangeMembershipStateDataSourceDidChangeRoomMembershipState` function + + if (completion) + { + completion(YES); + } + } failure:^(NSError * _Nonnull error) { + NSLog(@"[RecentsViewController] Failed to reject an invited room (%@)", room.roomId); + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + if (completion) + { + completion(NO); + } + }]; +} + +- (void)presentRoomJoinFailedAlertForError:(NSError*)error completion:(void(^)(void))completion +{ + MXWeakify(self); + NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; + if ([msg isEqualToString:@"No known servers"]) + { + // minging kludge until https://matrix.org/jira/browse/SYN-678 is fixed + // 'Error when trying to join an empty room should be more explicit' + msg = [NSBundle mxk_localizedStringForKey:@"room_error_join_failed_empty_room"]; + } + + [self->currentAlert dismissViewControllerAnimated:NO completion:nil]; + + self->currentAlert = [UIAlertController alertControllerWithTitle:[NSBundle mxk_localizedStringForKey:@"room_error_join_failed_title"] message:msg preferredStyle:UIAlertControllerStyleAlert]; + + [self->currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + + if (completion) + { + completion(); + } + }]]; + + [self presentViewController:self->currentAlert animated:YES completion:nil]; +} + #pragma mark - Sticky Headers - (void)setEnableStickyHeaders:(BOOL)enableStickyHeaders @@ -820,23 +895,23 @@ // Display the room preview [self dispayRoomWithRoomId:invitedRoom.roomId inMatrixSession:invitedRoom.mxSession]; } - else if ([actionIdentifier isEqualToString:kInviteRecentTableViewCellDeclineButtonPressed]) + else if ([actionIdentifier isEqualToString:kInviteRecentTableViewCellAcceptButtonPressed]) { // Retrieve the invited room MXRoom *invitedRoom = userInfo[kInviteRecentTableViewCellRoomKey]; + // Accept invitation + [self joinRoom:invitedRoom completion:nil]; + } + else if ([actionIdentifier isEqualToString:kInviteRecentTableViewCellDeclineButtonPressed]) + { + // Retrieve the invited room + MXRoom *invitedRoom = userInfo[kInviteRecentTableViewCellRoomKey]; + [self cancelEditionMode:isRefreshPending]; // Decline the invitation - [invitedRoom leave:^{ - - [self.recentsTableView reloadData]; - - } failure:^(NSError *error) { - - NSLog(@"[RecentsViewController] Failed to reject an invited room (%@)", invitedRoom.roomId); - - }]; + [self leaveRoom:invitedRoom completion:nil]; } else { @@ -848,6 +923,13 @@ } } +- (void)dataSource:(MXKDataSource *)dataSource didCellChange:(id)changes +{ + [super dataSource:dataSource didCellChange:changes]; + + [self showEmptyViewIfNeeded]; +} + #pragma mark - Swipe actions - (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath @@ -1271,8 +1353,21 @@ if ([cell isKindOfClass:[InviteRecentTableViewCell class]]) { - // hide the selection - [tableView deselectRowAtIndexPath:indexPath animated:NO]; + id cellData = [self.dataSource cellDataAtIndexPath:indexPath]; + + // Retrieve the invited room + MXRoom* invitedRoom = cellData.roomSummary.room; + + // Check if can show preview for the invited room + if ([self canShowRoomPreviewFor:invitedRoom]) + { + // Display the room preview + [self dispayRoomWithRoomId:invitedRoom.roomId inMatrixSession:invitedRoom.mxSession]; + } + else + { + [tableView deselectRowAtIndexPath:indexPath animated:NO]; + } } else if ([cell isKindOfClass:[DirectoryRecentTableViewCell class]]) { @@ -1871,4 +1966,90 @@ coordinatorBridgePresenter = nil; } +#pragma mark - Empty view management + +- (void)showEmptyViewIfNeeded +{ + [self showEmptyView:[self shouldShowEmptyView]]; +} + +- (void)showEmptyView:(BOOL)show +{ + if (!self.viewIfLoaded) + { + return; + } + + if (show && !self.emptyView) + { + RootTabEmptyView *emptyView = [RootTabEmptyView instantiate]; + [emptyView updateWithTheme:ThemeService.shared.theme]; + [self addEmptyView:emptyView]; + + self.emptyView = emptyView; + + [self updateEmptyView]; + } + else if (!show) + { + [self.emptyView removeFromSuperview]; + } + + self.recentsTableView.hidden = show; + self.stickyHeadersTopContainer.hidden = show; + self.stickyHeadersBottomContainer.hidden = show; +} + +- (void)updateEmptyView +{ + +} + +- (void)addEmptyView:(RootTabEmptyView*)emptyView +{ + if (!self.isViewLoaded) + { + return; + } + + NSLayoutConstraint *emptyViewBottomConstraint; + NSLayoutConstraint *contentViewBottomConstraint; + + if (plusButtonImageView && plusButtonImageView.isHidden == NO) + { + [self.view insertSubview:emptyView belowSubview:plusButtonImageView]; + + contentViewBottomConstraint = [NSLayoutConstraint constraintWithItem:emptyView.contentView + attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationLessThanOrEqual toItem:plusButtonImageView + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:0]; + } + else + { + [self.view addSubview:emptyView]; + } + + emptyViewBottomConstraint = [emptyView.bottomAnchor constraintEqualToAnchor:emptyView.superview.bottomAnchor]; + + emptyView.translatesAutoresizingMaskIntoConstraints = NO; + + [NSLayoutConstraint activateConstraints:@[ + [emptyView.topAnchor constraintEqualToAnchor:emptyView.superview.topAnchor], + [emptyView.leftAnchor constraintEqualToAnchor:emptyView.superview.leftAnchor], + [emptyView.rightAnchor constraintEqualToAnchor:emptyView.superview.rightAnchor], + emptyViewBottomConstraint + ]]; + + if (contentViewBottomConstraint) + { + contentViewBottomConstraint.active = YES; + } +} + +- (BOOL)shouldShowEmptyView +{ + return NO; +} + @end diff --git a/Riot/Modules/Home/Views/HomeEmptyView.swift b/Riot/Modules/Common/Recents/Views/RootTabEmptyView.swift similarity index 71% rename from Riot/Modules/Home/Views/HomeEmptyView.swift rename to Riot/Modules/Common/Recents/Views/RootTabEmptyView.swift index 7a37058a0..9bda2067c 100644 --- a/Riot/Modules/Home/Views/HomeEmptyView.swift +++ b/Riot/Modules/Common/Recents/Views/RootTabEmptyView.swift @@ -1,4 +1,4 @@ -// +// // Copyright 2020 New Vector Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,15 +17,18 @@ import Foundation import Reusable +/// `RootTabEmptyView` is a view to display when there is no UI item to display on a screen. @objcMembers -final class HomeEmptyView: UIView, NibLoadable { +final class RootTabEmptyView: UIView, NibLoadable { // MARK: - Properties // MARK: Outlets - + + @IBOutlet private weak var imageView: UIImageView! @IBOutlet private weak var titleLabel: UILabel! @IBOutlet private weak var informationLabel: UILabel! + @IBOutlet private(set) weak var contentView: UIView! // MARK: Private @@ -35,8 +38,8 @@ final class HomeEmptyView: UIView, NibLoadable { // MARK: - Setup - class func instantiate() -> HomeEmptyView { - let view = HomeEmptyView.loadFromNib() + class func instantiate() -> RootTabEmptyView { + let view = RootTabEmptyView.loadFromNib() view.theme = ThemeService.shared().theme return view } @@ -51,13 +54,15 @@ final class HomeEmptyView: UIView, NibLoadable { // MARK: - Public - func fill(with displayName: String) { - self.titleLabel.text = VectorL10n.homeEmptyViewTitle(displayName) + func fill(with image: UIImage, title: String, informationText: String) { + self.imageView.image = image + self.titleLabel.text = title + self.informationLabel.text = informationText } } // MARK: - Themable -extension HomeEmptyView: Themable { +extension RootTabEmptyView: Themable { func update(theme: Theme) { self.theme = theme diff --git a/Riot/Modules/Common/Recents/Views/RootTabEmptyView.xib b/Riot/Modules/Common/Recents/Views/RootTabEmptyView.xib new file mode 100644 index 000000000..fc840087c --- /dev/null +++ b/Riot/Modules/Common/Recents/Views/RootTabEmptyView.xib @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Favorites/FavouritesViewController.m b/Riot/Modules/Favorites/FavouritesViewController.m index 80b129cf7..608ed6d47 100644 --- a/Riot/Modules/Favorites/FavouritesViewController.m +++ b/Riot/Modules/Favorites/FavouritesViewController.m @@ -114,4 +114,42 @@ return 0.0f; } +#pragma mark - Empty view management + +- (void)updateEmptyView +{ + [self.emptyView fillWith:[self emptyViewArtwork] + title:NSLocalizedStringFromTable(@"favourites_empty_view_title", @"Vector", nil) + informationText:NSLocalizedStringFromTable(@"favourites_empty_view_information", @"Vector", nil)]; +} + +- (UIImage*)emptyViewArtwork +{ + if (ThemeService.shared.isCurrentThemeDark) + { + return [UIImage imageNamed:@"favourites_empty_screen_artwork_dark"]; + } + else + { + return [UIImage imageNamed:@"favourites_empty_screen_artwork"]; + } +} + +- (BOOL)shouldShowEmptyView +{ + // Do not present empty screen while searching + if (recentsDataSource.searchPatternsList.count) + { + return NO; + } + + return [self totalItemCounts] == 0; +} + +// Total items to display on the screen +- (NSUInteger)totalItemCounts +{ + return recentsDataSource.favoriteCellDataArray.count; +} + @end diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index 069c24efc..95bc66b7a 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -46,8 +46,6 @@ @property (nonatomic, strong) CrossSigningSetupBannerCell *keyVerificationSetupBannerPrototypeCell; @property (nonatomic, strong) AuthenticatedSessionViewControllerFactory *authenticatedSessionViewControllerFactory; -@property (nonatomic, weak) HomeEmptyView *homeEmptyView; - @end @implementation HomeViewController @@ -101,9 +99,7 @@ // Take the lead on the shared data source. recentsDataSource.areSectionsShrinkable = NO; [recentsDataSource setDelegate:self andRecentsDataSourceMode:RecentsDataSourceModeHome]; - } - - [self updateEmptyViewDisplayName]; + } [self moveAllCollectionsToLeft]; } @@ -281,28 +277,15 @@ { [super onMatrixSessionChange]; - [self updateEmptyViewDisplayName]; -} - -- (void)userInterfaceThemeDidChange -{ - [super userInterfaceThemeDidChange]; - - [self.homeEmptyView updateWithTheme:ThemeService.shared.theme]; + [self updateEmptyView]; } #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - NSInteger numberOfSections = [recentsDataSource numberOfSectionsInTableView:tableView]; - - BOOL showEmptyView = [self shouldShowEmptyView]; - - [self showEmptyView:showEmptyView]; - // Return the actual number of sections prepared in recents dataSource. - return numberOfSections; + return [recentsDataSource numberOfSectionsInTableView:tableView]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section @@ -819,51 +802,40 @@ #pragma mark - Empty view management -- (void)showEmptyView:(BOOL)show -{ - if (show && !self.homeEmptyView) - { - HomeEmptyView *homeEmptyView = [HomeEmptyView instantiate]; - [homeEmptyView updateWithTheme:ThemeService.shared.theme]; - [self addEmptyView:homeEmptyView]; - - self.homeEmptyView = homeEmptyView; - - [self updateEmptyViewDisplayName]; - } - else if (!show) - { - [self.homeEmptyView removeFromSuperview]; - } - - self.recentsTableView.hidden = show; -} - -- (void)updateEmptyViewDisplayName +- (void)updateEmptyView { MXUser *myUser = self.mainSession.myUser; NSString *displayName = myUser.displayname ?: myUser.userId; + displayName = displayName ?: @""; - [self.homeEmptyView fillWith:displayName ?: @""]; + NSString *appName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"]; + NSString *title = [NSString stringWithFormat:NSLocalizedStringFromTable(@"home_empty_view_title", @"Vector", nil), appName, displayName]; + + [self.emptyView fillWith:[self emptyViewArtwork] + title:title + informationText:NSLocalizedStringFromTable(@"home_empty_view_information", @"Vector", nil)]; } -- (void)addEmptyView:(UIView*)emptyView +- (UIImage*)emptyViewArtwork { - [self.view insertSubview:emptyView belowSubview:plusButtonImageView]; - - emptyView.translatesAutoresizingMaskIntoConstraints = NO; - - [NSLayoutConstraint activateConstraints:@[ - [emptyView.topAnchor constraintEqualToAnchor:emptyView.superview.topAnchor], - [emptyView.leftAnchor constraintEqualToAnchor:emptyView.superview.leftAnchor], - [emptyView.rightAnchor constraintEqualToAnchor:emptyView.superview.rightAnchor], - [emptyView.bottomAnchor constraintEqualToAnchor:plusButtonImageView.topAnchor] - ]]; + if (ThemeService.shared.isCurrentThemeDark) + { + return [UIImage imageNamed:@"home_empty_screen_artwork_dark"]; + } + else + { + return [UIImage imageNamed:@"home_empty_screen_artwork"]; + } } -// By default on fresh account - (BOOL)shouldShowEmptyView { + // Do not present empty screen while searching + if (recentsDataSource.searchPatternsList.count) + { + return NO; + } + // Check if some banners should be displayed if (recentsDataSource.secureBackupBannerSection != -1 || recentsDataSource.crossSigningBannerSection != -1) { diff --git a/Riot/Modules/Home/Views/HomeEmptyView.xib b/Riot/Modules/Home/Views/HomeEmptyView.xib deleted file mode 100644 index cd6740b1c..000000000 --- a/Riot/Modules/Home/Views/HomeEmptyView.xib +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Riot/Modules/People/PeopleViewController.m b/Riot/Modules/People/PeopleViewController.m index 0193efaec..fa9657d0a 100644 --- a/Riot/Modules/People/PeopleViewController.m +++ b/Riot/Modules/People/PeopleViewController.m @@ -461,4 +461,71 @@ [super searchBarCancelButtonClicked:searchBar]; } +#pragma mark - Empty view management + +- (void)updateEmptyView +{ + [self.emptyView fillWith:[self emptyViewArtwork] + title:NSLocalizedStringFromTable(@"people_empty_view_title", @"Vector", nil) + informationText:NSLocalizedStringFromTable(@"people_empty_view_information", @"Vector", nil)]; +} + +- (UIImage*)emptyViewArtwork +{ + if (ThemeService.shared.isCurrentThemeDark) + { + return [UIImage imageNamed:@"people_empty_screen_artwork_dark"]; + } + else + { + return [UIImage imageNamed:@"people_empty_screen_artwork"]; + } +} + +- (BOOL)shouldShowEmptyView +{ + // Do not present empty screen while searching + if (recentsDataSource.searchPatternsList.count) + { + return NO; + } + + return [self totalItemCounts] == 0; +} + +// Total items to display on the screen +- (NSUInteger)totalItemCounts +{ + return recentsDataSource.invitesCellDataArray.count + + recentsDataSource.conversationCellDataArray.count + + recentsDataSource.peopleCellDataArray.count + + [self numberOfContactsInContactsDataSource]; +} + +- (NSUInteger)numberOfContactsInContactsDataSource +{ + BOOL areLocalContactsAccessAuthorized = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized; + + NSInteger nbOfItemsInContactDataSource = 0; + + for (NSInteger i = 0; i < contactsSectionNumber; i++) + { + nbOfItemsInContactDataSource += [contactsDataSource tableView:self.recentsTableView numberOfRowsInSection:i]; + } + + NSInteger numberOfContactsInContactsDataSource; + + // No local contacts to show and no search in directory + if (!areLocalContactsAccessAuthorized && contactsSectionNumber == 1 && nbOfItemsInContactDataSource <= 1) + { + numberOfContactsInContactsDataSource = 0; + } + else + { + numberOfContactsInContactsDataSource = nbOfItemsInContactDataSource; + } + + return numberOfContactsInContactsDataSource; +} + @end diff --git a/Riot/Modules/People/Views/InviteRecentTableViewCell+ButtonViewsUpdate.swift b/Riot/Modules/People/Views/InviteRecentTableViewCell+ButtonViewsUpdate.swift new file mode 100644 index 000000000..7c5ce4825 --- /dev/null +++ b/Riot/Modules/People/Views/InviteRecentTableViewCell+ButtonViewsUpdate.swift @@ -0,0 +1,61 @@ +// +// 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 + +extension InviteRecentTableViewCell { + + @objc func resetButtonViews() { + self.leftButton.isEnabled = true + self.rightButton.isEnabled = true + self.leftButtonActivityIndicator.stopAnimating() + self.rightButtonActivityIndicator.stopAnimating() + } + + /// Update buttons according to current MXMembershipChangeState of the room + @objc func updateButtonViews(with room: MXRoom) { + let membershipTransitionState = room.summary.membershipTransitionState + + var joinButtonIsLoading = false + var leaveButtonIsLoading = false + + switch membershipTransitionState { + case .joining: + joinButtonIsLoading = true + case .leaving: + leaveButtonIsLoading = true + default: + break + } + + let areButtonsEnabled = !(joinButtonIsLoading || leaveButtonIsLoading) + + self.leftButton.isEnabled = areButtonsEnabled + self.rightButton.isEnabled = areButtonsEnabled + + if leaveButtonIsLoading { + self.leftButtonActivityIndicator.startAnimating() + } else { + self.leftButtonActivityIndicator.stopAnimating() + } + + if joinButtonIsLoading { + self.rightButtonActivityIndicator.startAnimating() + } else { + self.rightButtonActivityIndicator.stopAnimating() + } + } +} diff --git a/Riot/Modules/People/Views/InviteRecentTableViewCell.h b/Riot/Modules/People/Views/InviteRecentTableViewCell.h index 1b4ca9d93..314f7f7e8 100644 --- a/Riot/Modules/People/Views/InviteRecentTableViewCell.h +++ b/Riot/Modules/People/Views/InviteRecentTableViewCell.h @@ -25,6 +25,13 @@ */ extern NSString *const kInviteRecentTableViewCellPreviewButtonPressed; +/** + Action identifier used when the user pressed 'accept' button displayed on room invitation. + + The `userInfo` dictionary contains an `MXRoom` object under the `kInviteRecentTableViewCellRoomKey` key, representing the room of the invitation. + */ +extern NSString *const kInviteRecentTableViewCellAcceptButtonPressed; + /** Action identifier used when the user pressed 'decline' button displayed on room invitation. @@ -45,6 +52,9 @@ extern NSString *const kInviteRecentTableViewCellRoomKey; @property (weak, nonatomic) IBOutlet UIButton *leftButton; @property (weak, nonatomic) IBOutlet UIButton *rightButton; +@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *leftButtonActivityIndicator; +@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *rightButtonActivityIndicator; + @property (weak, nonatomic) IBOutlet UIView *noticeBadgeView; diff --git a/Riot/Modules/People/Views/InviteRecentTableViewCell.m b/Riot/Modules/People/Views/InviteRecentTableViewCell.m index b9a7de18b..25567576d 100644 --- a/Riot/Modules/People/Views/InviteRecentTableViewCell.m +++ b/Riot/Modules/People/Views/InviteRecentTableViewCell.m @@ -26,6 +26,7 @@ #pragma mark - Constant definitions +NSString *const kInviteRecentTableViewCellAcceptButtonPressed = @"kInviteRecentTableViewCellAcceptButtonPressed"; NSString *const kInviteRecentTableViewCellPreviewButtonPressed = @"kInviteRecentTableViewCellPreviewButtonPressed"; NSString *const kInviteRecentTableViewCellDeclineButtonPressed = @"kInviteRecentTableViewCellDeclineButtonPressed"; @@ -42,14 +43,12 @@ NSString *const kInviteRecentTableViewCellRoomKey = @"kInviteRecentTableViewCell [self.leftButton.layer setCornerRadius:5]; self.leftButton.clipsToBounds = YES; [self.leftButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateNormal]; - [self.leftButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateHighlighted]; [self.leftButton addTarget:self action:@selector(onDeclinePressed:) forControlEvents:UIControlEventTouchUpInside]; [self.rightButton.layer setCornerRadius:5]; self.rightButton.clipsToBounds = YES; - [self.rightButton setTitle:NSLocalizedStringFromTable(@"preview", @"Vector", nil) forState:UIControlStateNormal]; - [self.rightButton setTitle:NSLocalizedStringFromTable(@"preview", @"Vector", nil) forState:UIControlStateHighlighted]; - [self.rightButton addTarget:self action:@selector(onPreviewPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.rightButton setTitle:NSLocalizedStringFromTable(@"accept", @"Vector", nil) forState:UIControlStateNormal]; + [self.rightButton addTarget:self action:@selector(onRightButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; [self.noticeBadgeView.layer setCornerRadius:10]; @@ -66,20 +65,29 @@ NSString *const kInviteRecentTableViewCellRoomKey = @"kInviteRecentTableViewCell self.noticeBadgeView.backgroundColor = ThemeService.shared.theme.noticeColor; } -- (void)onDeclinePressed:(id)sender +- (void)prepareForReuse { - if (self.delegate) - { - MXRoom *room = roomCellData.roomSummary.room; - - if (room) - { - [self.delegate cell:self didRecognizeAction:kInviteRecentTableViewCellDeclineButtonPressed userInfo:@{kInviteRecentTableViewCellRoomKey:room}]; - } - } + [super prepareForReuse]; + + [self resetButtonViews]; + self.accessoryView = nil; } -- (void)onPreviewPressed:(id)sender +- (void)onDeclinePressed:(id)sender +{ + [self notifyDelegateWithActionIdentifier:kInviteRecentTableViewCellDeclineButtonPressed]; +} + +- (void)onRightButtonPressed:(id)sender +{ + MXRoom *room = roomCellData.roomSummary.room; + + NSString *actionIdentifier = room.isDirect ? kInviteRecentTableViewCellAcceptButtonPressed : kInviteRecentTableViewCellPreviewButtonPressed; + + [self notifyDelegateWithActionIdentifier:actionIdentifier]; +} + +- (void)notifyDelegateWithActionIdentifier:(NSString*)actionIdentifier { if (self.delegate) { @@ -87,7 +95,7 @@ NSString *const kInviteRecentTableViewCellRoomKey = @"kInviteRecentTableViewCell if (room) { - [self.delegate cell:self didRecognizeAction:kInviteRecentTableViewCellPreviewButtonPressed userInfo:@{kInviteRecentTableViewCellRoomKey:room}]; + [self.delegate cell:self didRecognizeAction:actionIdentifier userInfo:@{kInviteRecentTableViewCellRoomKey:room}]; } } } @@ -95,6 +103,33 @@ NSString *const kInviteRecentTableViewCellRoomKey = @"kInviteRecentTableViewCell - (void)render:(MXKCellData *)cellData { [super render:cellData]; + + MXRoom *room = roomCellData.roomSummary.room; + + if (room.roomId) + { + [self updateViewsWithRoom:room showPreviewButton:NO]; + } +} + +- (void)updateViewsWithRoom:(MXRoom*)room showPreviewButton:(BOOL)showPreviewButton +{ + NSString *rightButtonTitle; + + if (!showPreviewButton) + { + rightButtonTitle = NSLocalizedStringFromTable(@"accept", @"Vector", nil); + [self vc_setAccessoryDisclosureIndicatorWithCurrentTheme]; + } + else + { + rightButtonTitle = NSLocalizedStringFromTable(@"preview", @"Vector", nil); + self.accessoryView = nil; + } + + [self.rightButton setTitle:rightButtonTitle forState:UIControlStateNormal]; + + [self updateButtonViewsWith:room]; } + (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth diff --git a/Riot/Modules/People/Views/InviteRecentTableViewCell.xib b/Riot/Modules/People/Views/InviteRecentTableViewCell.xib index 5b756ca84..f1ecf7116 100644 --- a/Riot/Modules/People/Views/InviteRecentTableViewCell.xib +++ b/Riot/Modules/People/Views/InviteRecentTableViewCell.xib @@ -1,12 +1,9 @@ - - - - + + - - + @@ -16,7 +13,7 @@ - + @@ -33,7 +30,7 @@ diff --git a/Riot/Modules/Room/CreationModal/RoomCreationModalCoordinatorBridgePresenter.swift b/Riot/Modules/Room/CreationModal/RoomCreationModalCoordinatorBridgePresenter.swift index 55bcacf9a..660a2a2a7 100644 --- a/Riot/Modules/Room/CreationModal/RoomCreationModalCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/CreationModal/RoomCreationModalCoordinatorBridgePresenter.swift @@ -36,9 +36,7 @@ final class RoomCreationModalCoordinatorBridgePresenter: NSObject { private let bubbleData: MXKRoomBubbleCellDataStoring private var coordinator: RoomCreationEventsModalCoordinator? private lazy var slidingModalPresenter: SlidingModalPresenter = { - let presenter = SlidingModalPresenter() - presenter.isSpanning = true - return presenter + return SlidingModalPresenter() }() // MARK: Public @@ -64,6 +62,7 @@ final class RoomCreationModalCoordinatorBridgePresenter: NSObject { slidingModalPresenter.present(roomCreationEventsModalCoordinator.toSlidingModalPresentable(), from: viewController, animated: animated, + options: .spanning, completion: nil) roomCreationEventsModalCoordinator.start() diff --git a/Riot/Modules/Rooms/RoomsViewController.m b/Riot/Modules/Rooms/RoomsViewController.m index 6908a61a1..ee58b242e 100644 --- a/Riot/Modules/Rooms/RoomsViewController.m +++ b/Riot/Modules/Rooms/RoomsViewController.m @@ -375,4 +375,45 @@ self.roomsDirectoryCoordinatorBridgePresenter = nil; } +#pragma mark - Empty view management + +- (void)updateEmptyView +{ + [self.emptyView fillWith:[self emptyViewArtwork] + title:NSLocalizedStringFromTable(@"rooms_empty_view_title", @"Vector", nil) + informationText:NSLocalizedStringFromTable(@"rooms_empty_view_information", @"Vector", nil)]; +} + +- (UIImage*)emptyViewArtwork +{ + if (ThemeService.shared.isCurrentThemeDark) + { + return [UIImage imageNamed:@"rooms_empty_screen_artwork_dark"]; + } + else + { + return [UIImage imageNamed:@"rooms_empty_screen_artwork"]; + } +} + +- (BOOL)shouldShowEmptyView +{ + // Do not present empty screen while searching + if (recentsDataSource.searchPatternsList.count) + { + return NO; + } + + // Otherwise check the number of items to display + return [self totalItemCounts] == 0; +} + +// Total items to display on the screen +- (NSUInteger)totalItemCounts +{ + return recentsDataSource.conversationCellDataArray.count + + recentsDataSource.publicRoomsDirectoryDataSource.roomsCount + + recentsDataSource.invitesCellDataArray.count; +} + @end diff --git a/Riot/Modules/SlidingModal/SlidingModalContainerView.swift b/Riot/Modules/SlidingModal/SlidingModalContainerView.swift index 528c860a2..aa781543f 100644 --- a/Riot/Modules/SlidingModal/SlidingModalContainerView.swift +++ b/Riot/Modules/SlidingModal/SlidingModalContainerView.swift @@ -39,6 +39,23 @@ class SlidingModalContainerView: UIView, Themable, NibLoadable { // MARK: - Properties + private weak var blurView: UIVisualEffectView? + var blurBackground: Bool = false { + didSet { + if blurBackground { + let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + blurView.frame = self.dimmingView.bounds + blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.dimmingView.addSubview(blurView) + self.blurView = blurView + self.dimmingView.backgroundColor = .clear + } else { + self.blurView?.removeFromSuperview() + self.dimmingView.backgroundColor = UIColor.black.withAlphaComponent(Constants.dimmingColorAlpha) + } + } + } + // MARK: Outlets @IBOutlet private weak var dimmingView: UIView! @@ -61,6 +78,9 @@ class SlidingModalContainerView: UIView, Themable, NibLoadable { return -(self.contentViewHeightConstraint.constant + bottomSafeAreaHeight) } + // used to avoid changing constraint during animations + private var lastBounds: CGRect? + // MARK: Public var contentViewFrame: CGRect { @@ -92,12 +112,26 @@ class SlidingModalContainerView: UIView, Themable, NibLoadable { super.layoutSubviews() self.contentView.layer.cornerRadius = Constants.cornerRadius + + guard lastBounds != nil else { + lastBounds = bounds + return + } + + if UIDevice.current.userInterfaceIdiom == .pad && lastBounds != bounds { + lastBounds = bounds + self.contentViewBottomConstraint.constant = (UIScreen.main.bounds.height + self.dismissContentViewBottomConstant) / 2 + } } // MARK: - Public func preparePresentAnimation() { - self.contentViewBottomConstraint.constant = 0 + if UIDevice.current.userInterfaceIdiom == .pad { + self.contentViewBottomConstraint.constant = (UIScreen.main.bounds.height + self.dismissContentViewBottomConstant) / 2 + } else { + self.contentViewBottomConstraint.constant = 0 + } } func prepareDismissAnimation() { diff --git a/Riot/Modules/SlidingModal/SlidingModalPresentationAnimator.swift b/Riot/Modules/SlidingModal/SlidingModalPresentationAnimator.swift index 1e8c30479..d50cc4909 100644 --- a/Riot/Modules/SlidingModal/SlidingModalPresentationAnimator.swift +++ b/Riot/Modules/SlidingModal/SlidingModalPresentationAnimator.swift @@ -30,6 +30,7 @@ final class SlidingModalPresentationAnimator: NSObject { private let isPresenting: Bool private let isSpanning: Bool + private let blurBackground: Bool // MARK: - Setup @@ -37,9 +38,10 @@ final class SlidingModalPresentationAnimator: NSObject { /// /// - Parameter isPresenting: true to animate presentation or false to animate dismissal /// - Parameter isSpanning: true to remove left, bottom and right spaces between the screen edges and the content view - required public init(isPresenting: Bool, isSpanning: Bool) { + required public init(isPresenting: Bool, isSpanning: Bool, blurBackground: Bool) { self.isPresenting = isPresenting self.isSpanning = isSpanning + self.blurBackground = blurBackground super.init() } @@ -58,7 +60,9 @@ final class SlidingModalPresentationAnimator: NSObject { let containerView = transitionContext.containerView - let slidingModalContainerView = isSpanning ? SpanningSlidingModalContainerView.instantiate() : SlidingModalContainerView.instantiate() + // Spanning not available for iPad + let slidingModalContainerView = isSpanning && UIDevice.current.userInterfaceIdiom != .pad ? SpanningSlidingModalContainerView.instantiate() : SlidingModalContainerView.instantiate() + slidingModalContainerView.blurBackground = self.blurBackground slidingModalContainerView.alpha = 0 slidingModalContainerView.updateDimmingViewAlpha(0.0) diff --git a/Riot/Modules/SlidingModal/SlidingModalPresentationDelegate.swift b/Riot/Modules/SlidingModal/SlidingModalPresentationDelegate.swift index a3412e54d..e6efdcf28 100644 --- a/Riot/Modules/SlidingModal/SlidingModalPresentationDelegate.swift +++ b/Riot/Modules/SlidingModal/SlidingModalPresentationDelegate.swift @@ -19,9 +19,11 @@ import Foundation /// `SlidingModalPresentationDelegate` handle a custom sliding UIViewController transition. public class SlidingModalPresentationDelegate: NSObject { private let isSpanning: Bool + private let blurBackground: Bool - public init(isSpanning: Bool) { + public init(isSpanning: Bool, blurBackground: Bool) { self.isSpanning = isSpanning + self.blurBackground = blurBackground super.init() } } @@ -30,11 +32,11 @@ public class SlidingModalPresentationDelegate: NSObject { extension SlidingModalPresentationDelegate: UIViewControllerTransitioningDelegate { public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return SlidingModalPresentationAnimator(isPresenting: true, isSpanning: isSpanning) + return SlidingModalPresentationAnimator(isPresenting: true, isSpanning: isSpanning, blurBackground: blurBackground) } public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return SlidingModalPresentationAnimator(isPresenting: false, isSpanning: isSpanning) + return SlidingModalPresentationAnimator(isPresenting: false, isSpanning: isSpanning, blurBackground: blurBackground) } public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { diff --git a/Riot/Modules/SlidingModal/SlidingModalPresenter.swift b/Riot/Modules/SlidingModal/SlidingModalPresenter.swift index b5173ab6d..4b4e3b663 100644 --- a/Riot/Modules/SlidingModal/SlidingModalPresenter.swift +++ b/Riot/Modules/SlidingModal/SlidingModalPresenter.swift @@ -16,6 +16,16 @@ import UIKit +/// Availbale options for present method +struct SlidingModalOption: OptionSet { + let rawValue: UInt32 + + /// Is content view spanning the screen width and to the bottom + static let spanning = SlidingModalOption(rawValue: 1 << 0) + /// the background is blurred in order to obfuscate the view behind the popup + static let blurBackground = SlidingModalOption(rawValue: 1 << 1) +} + /// `SlidingModalPresenter` allows to present a custom UIViewController or UIView conforming to `SlidingModalPresentable` as a modal with a vertical sliding animation from a UIViewController. final class SlidingModalPresenter: NSObject { @@ -28,38 +38,41 @@ final class SlidingModalPresenter: NSObject { } // MARK: - Properties - + // swiftlint:disable weak_delegate private var transitionDelegate: SlidingModalPresentationDelegate? // swiftlint:enable weak_delegate private weak var presentingViewController: UIViewController? - /// Is content view spanning the screen width and to the bottom - var isSpanning: Bool = false - + // MARK: - Presentation options + + @objc static let NoOption: UInt32 = 0 + @objc static let SpanningOption: UInt32 = SlidingModalOption.spanning.rawValue + @objc static let BlurBackgroungOption: UInt32 = SlidingModalOption.blurBackground.rawValue + // MARK: - Public @objc func present(_ viewController: SlidingModalPresentable.ViewControllerType, from presentingViewController: UIViewController, animated: Bool, completion: (() -> Void)?) { + self.present(viewController, from: presentingViewController, animated: animated, options: [], completion: completion) + } + + @objc func present(_ viewController: SlidingModalPresentable.ViewControllerType, from presentingViewController: UIViewController, animated: Bool, options: UInt32, completion: (() -> Void)?) { + self.present(viewController, from: presentingViewController, animated: animated, options: SlidingModalOption(rawValue: options), completion: completion) + } + + func present(_ viewController: SlidingModalPresentable.ViewControllerType, from presentingViewController: UIViewController, animated: Bool, options: SlidingModalOption, completion: (() -> Void)?) { NSLog("[SlidingModalPresenter] present \(type(of: viewController))") - if UIDevice.current.userInterfaceIdiom == .pad { - viewController.modalPresentationStyle = .formSheet - - let preferredHeight = viewController.layoutHeightFittingWidth(TabletContentSize.preferred.width).clamped(to: TabletContentSize.minHeight...TabletContentSize.maxHeight) - - viewController.preferredContentSize = CGSize(width: TabletContentSize.preferred.width, height: preferredHeight) - } else { - let transitionDelegate = SlidingModalPresentationDelegate(isSpanning: isSpanning) - - viewController.modalPresentationStyle = .custom - viewController.transitioningDelegate = transitionDelegate - - // Presented view controller does not affect the statusbar appearance - viewController.modalPresentationCapturesStatusBarAppearance = false - - self.transitionDelegate = transitionDelegate - } + let transitionDelegate = SlidingModalPresentationDelegate(isSpanning: options.contains(.spanning), blurBackground: options.contains(.blurBackground)) + + viewController.modalPresentationStyle = .custom + viewController.transitioningDelegate = transitionDelegate + + // Presented view controller does not affect the statusbar appearance + viewController.modalPresentationCapturesStatusBarAppearance = false + + self.transitionDelegate = transitionDelegate presentingViewController.present(viewController, animated: animated, completion: completion) diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h index 26bf83cda..b3f520b1f 100644 --- a/Riot/SupportingFiles/Riot-Bridging-Header.h +++ b/Riot/SupportingFiles/Riot-Bridging-Header.h @@ -25,3 +25,4 @@ #import "RoomFilesViewController.h" #import "RoomSettingsViewController.h" #import "JitsiWidgetData.h" +#import "InviteRecentTableViewCell.h"