diff --git a/CHANGES.md b/CHANGES.md index 048c6c97b..988944819 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,22 @@ +## Changes in 1.9.1 (2022-08-29) + +🙌 Improvements + +- Added Labs flag for the new App Layout. ([#6649](https://github.com/vector-im/element-ios/issues/6649)) + +🐛 Bugfixes + +- Render the PIN entry screen correctly on landscape ([#6629](https://github.com/vector-im/element-ios/pull/6629)) +- Ensure rest client async responses are processed on the main queue ([#6642](https://github.com/vector-im/element-ios/pull/6642)) +- Stop waiting for biometric unlock if disabled system wide ([#5279](https://github.com/vector-im/element-ios/issues/5279)) +- App Layout: added support for transparent avatar icons in the all chats screen ([#6556](https://github.com/vector-im/element-ios/issues/6556)) +- App Layout: fixed reactions background in timeline ([#6557](https://github.com/vector-im/element-ios/issues/6557)) +- App Layout: Removed Low Priority Rooms from Filters ([#6577](https://github.com/vector-im/element-ios/issues/6577)) +- App Layout: Updated missing image for Onboarding screen page 2 ([#6624](https://github.com/vector-im/element-ios/issues/6624)) +- App Layout: fixed limited number of invites in the All Chats screen ([#6625](https://github.com/vector-im/element-ios/issues/6625)) +- Fix notification issues for threads. ([#6628](https://github.com/vector-im/element-ios/issues/6628)) + + ## Changes in 1.9.0 (2022-08-24) 🙌 Improvements diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 05b88688a..fba787b2a 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.9.0 -CURRENT_PROJECT_VERSION = 1.9.0 +MARKETING_VERSION = 1.9.1 +CURRENT_PROJECT_VERSION = 1.9.1 diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 7315755ac..cc648923b 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -419,8 +419,11 @@ final class BuildSettings: NSObject { static let syncLocalContacts: Bool = false // MARK: - New App Layout - static let newAppLayoutEnabled = true - + static let newAppLayoutEnabled = false + + static var isSideMenuActivated: Bool = enableSideMenu + static var isNewAppLayoutActivated: Bool = newAppLayoutEnabled + // MARK: - Device manager static let deviceManagerEnabled = false diff --git a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/Contents.json b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/Contents.json index 68a004064..99aa89f84 100644 --- a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "all_chats_onboarding2.svg", + "filename" : "all_chats_onboarding2.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "all_chats_onboarding2@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "all_chats_onboarding2@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2.png b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2.png new file mode 100644 index 000000000..119903ee6 Binary files /dev/null and b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2.png differ diff --git a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2.svg b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2.svg deleted file mode 100644 index 72518cdd8..000000000 --- a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2.svg +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2@2x.png b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2@2x.png new file mode 100644 index 000000000..5e33559ac Binary files /dev/null and b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2@2x.png differ diff --git a/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2@3x.png b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2@3x.png new file mode 100644 index 000000000..b36afc879 Binary files /dev/null and b/Riot/Assets/Images.xcassets/AllChatsOnboarding/all_chats_onboarding2.imageset/all_chats_onboarding2@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Home/all_chats_edit_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/all_chats_edit_icon.imageset/Contents.json index f00e7d1d2..4716ddef7 100644 --- a/Riot/Assets/Images.xcassets/Home/all_chats_edit_icon.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/Home/all_chats_edit_icon.imageset/Contents.json @@ -2,16 +2,7 @@ "images" : [ { "filename" : "all_chats_edit_icon.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "idiom" : "universal" } ], "info" : { diff --git a/Riot/Assets/Images.xcassets/Home/all_chats_empty_list_placeholder_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/all_chats_empty_list_placeholder_icon.imageset/Contents.json index 90791b942..49e4118aa 100644 --- a/Riot/Assets/Images.xcassets/Home/all_chats_empty_list_placeholder_icon.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/Home/all_chats_empty_list_placeholder_icon.imageset/Contents.json @@ -2,16 +2,7 @@ "images" : [ { "filename" : "all_chats_empty_list_placeholder_icon.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "idiom" : "universal" } ], "info" : { diff --git a/Riot/Assets/Images.xcassets/Home/all_chats_spaces_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/all_chats_spaces_icon.imageset/Contents.json index 20c13cc1f..d29454793 100644 --- a/Riot/Assets/Images.xcassets/Home/all_chats_spaces_icon.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/Home/all_chats_spaces_icon.imageset/Contents.json @@ -2,16 +2,7 @@ "images" : [ { "filename" : "all_chats_spaces_icon.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "idiom" : "universal" } ], "info" : { diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 90fbf058d..f642e3993 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -761,6 +761,7 @@ Tap the + to start adding people."; "settings_labs_enable_auto_report_decryption_errors" = "Auto Report Decryption Errors"; "settings_labs_use_only_latest_user_avatar_and_name" = "Show latest avatar and name for users in message history"; "settings_labs_enable_live_location_sharing" = "Live location sharing - share current location (active development, and temporarily, locations persist in room history)"; +"settings_labs_enable_new_app_layout" = "New Application Layout"; "settings_version" = "Version %@"; "settings_olm_version" = "Olm Version %@"; diff --git a/Riot/Categories/MXRestClient+Async.swift b/Riot/Categories/MXRestClient+Async.swift index 6d13c798f..d72bb9ce1 100644 --- a/Riot/Categories/MXRestClient+Async.swift +++ b/Riot/Categories/MXRestClient+Async.swift @@ -158,6 +158,7 @@ extension MXRestClient { // MARK: - Private + @MainActor private func getResponse(_ callback: (@escaping (MXResponse) -> Void) -> MXHTTPOperation) async throws -> T { try await withCheckedThrowingContinuation { continuation in _ = callback { response in @@ -171,6 +172,7 @@ extension MXRestClient { } } + @MainActor private func getResponse(_ callback: (@escaping (T?) -> Void, @escaping (Error?) -> Void) -> MXHTTPOperation) async throws -> T { try await withCheckedThrowingContinuation { continuation in _ = callback { response in @@ -186,6 +188,7 @@ extension MXRestClient { } } + @MainActor private func getResponse(_ callback: (@escaping (T?, U?, V?) -> Void, @escaping (Error?) -> Void) -> MXHTTPOperation) async throws -> (T?, U?, V?) { try await withCheckedThrowingContinuation { continuation in _ = callback { arg1, arg2, arg3 in diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 086139eec..1a079a716 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -7351,6 +7351,10 @@ public class VectorL10n: NSObject { public static var settingsLabsEnableLiveLocationSharing: String { return VectorL10n.tr("Vector", "settings_labs_enable_live_location_sharing") } + /// New Application Layout + public static var settingsLabsEnableNewAppLayout: String { + return VectorL10n.tr("Vector", "settings_labs_enable_new_app_layout") + } /// Ring for group calls public static var settingsLabsEnableRingingForGroupCalls: String { return VectorL10n.tr("Vector", "settings_labs_enable_ringing_for_group_calls") diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index c3732c144..240c04a3c 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -46,6 +46,8 @@ final class RiotSettings: NSObject { private override init() { super.init() + BuildSettings.isSideMenuActivated = BuildSettings.enableSideMenu && !newAppLayoutBetaEnabled + BuildSettings.isNewAppLayoutActivated = BuildSettings.newAppLayoutEnabled || newAppLayoutBetaEnabled } /// Indicate if UserDefaults suite has been migrated once. @@ -381,9 +383,21 @@ final class RiotSettings: NSObject { @UserDefault(key: "allChatsOnboardingHasBeenDisplayed", defaultValue: false, storage: defaults) var allChatsOnboardingHasBeenDisplayed + + // MARK: - New App Layout + @UserDefault(key: "newAppLayoutBetaEnabled", defaultValue: false, storage: defaults) + var newAppLayoutBetaEnabled { + didSet { + BuildSettings.isSideMenuActivated = BuildSettings.enableSideMenu && !newAppLayoutBetaEnabled + BuildSettings.isNewAppLayoutActivated = BuildSettings.newAppLayoutEnabled || newAppLayoutBetaEnabled + NotificationCenter.default.post(name: RiotSettings.newAppLayoutBetaToggleDidChange, object: self) + } + } + } // MARK: - RiotSettings notification constants extension RiotSettings { public static let didUpdateLiveLocationSharingActivation = Notification.Name("RiotSettingsDidUpdateLiveLocationSharingActivation") + public static let newAppLayoutBetaToggleDidChange = Notification.Name("RiotSettingsNewAppLayoutBetaToggleDidChange") } diff --git a/Riot/Managers/Theme/Themes/BlackTheme.swift b/Riot/Managers/Theme/Themes/BlackTheme.swift index d0ff58cd9..c05964236 100644 --- a/Riot/Managers/Theme/Themes/BlackTheme.swift +++ b/Riot/Managers/Theme/Themes/BlackTheme.swift @@ -22,8 +22,14 @@ class BlackTheme: DarkTheme { super.init() self.identifier = ThemeIdentifier.black.rawValue self.backgroundColor = UIColor(rgb: 0x000000) - self.baseColor = UIColor(rgb: 0x000000) - self.headerBackgroundColor = UIColor(rgb: 0x000000) self.headerBorderColor = UIColor(rgb: 0x15191E) } + + override var baseColor: UIColor { + UIColor(rgb: 0x000000) + } + + override var headerBackgroundColor: UIColor { + UIColor(rgb: 0x000000) + } } diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift index 35651e6b1..dc4e89f1b 100644 --- a/Riot/Managers/Theme/Themes/DarkTheme.swift +++ b/Riot/Managers/Theme/Themes/DarkTheme.swift @@ -26,7 +26,9 @@ class DarkTheme: NSObject, Theme { var backgroundColor: UIColor = UIColor(rgb: 0x15191E) - var baseColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0x15191E) : UIColor(rgb: 0x21262C) + var baseColor: UIColor { + BuildSettings.isNewAppLayoutActivated ? UIColor(rgb: 0x15191E) : UIColor(rgb: 0x21262C) + } var baseIconPrimaryColor: UIColor = UIColor(rgb: 0xEDF3FF) var baseTextPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF) var baseTextSecondaryColor: UIColor = UIColor(rgb: 0xA9B2BC) @@ -35,7 +37,9 @@ class DarkTheme: NSObject, Theme { var searchPlaceholderColor: UIColor = UIColor(rgb: 0xA9B2BC) var searchResultHighlightColor: UIColor = UIColor(rgb: 0xFCC639).withAlphaComponent(0.3) - var headerBackgroundColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0x15191E) : UIColor(rgb: 0x21262C) + var headerBackgroundColor: UIColor { + BuildSettings.isNewAppLayoutActivated ? UIColor(rgb: 0x15191E) : UIColor(rgb: 0x21262C) + } var headerBorderColor: UIColor = UIColor(rgb: 0x15191E) var headerTextPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF) var headerTextSecondaryColor: UIColor = UIColor(rgb: 0xA9B2BC) diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift index 412390a47..d58a1a6d0 100644 --- a/Riot/Managers/Theme/Themes/DefaultTheme.swift +++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift @@ -26,7 +26,9 @@ class DefaultTheme: NSObject, Theme { var backgroundColor: UIColor = UIColor(rgb: 0xFFFFFF) - var baseColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0xFFFFFF) : UIColor(rgb: 0xF5F7FA) + var baseColor: UIColor { + BuildSettings.isNewAppLayoutActivated ? UIColor(rgb: 0xFFFFFF) : UIColor(rgb: 0xF5F7FA) + } var baseIconPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF) var baseTextPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF) var baseTextSecondaryColor: UIColor = UIColor(rgb: 0x8F97A3) @@ -35,7 +37,9 @@ class DefaultTheme: NSObject, Theme { var searchPlaceholderColor: UIColor = UIColor(rgb: 0x8F97A3) var searchResultHighlightColor: UIColor = UIColor(rgb: 0xFCC639).withAlphaComponent(0.2) - var headerBackgroundColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0xFFFFFF) : UIColor(rgb: 0xF5F7FA) + var headerBackgroundColor: UIColor { + BuildSettings.isNewAppLayoutActivated ? UIColor(rgb: 0xFFFFFF) : UIColor(rgb: 0xF5F7FA) + } var headerBorderColor: UIColor = UIColor(rgb: 0xE9EDF1) var headerTextPrimaryColor: UIColor = UIColor(rgb: 0x17191C) var headerTextSecondaryColor: UIColor = UIColor(rgb: 0x737D8C) @@ -169,7 +173,7 @@ class DefaultTheme: NSObject, Theme { searchBar.backgroundImage = UIImage() // Remove top and bottom shadow searchBar.tintColor = self.tintColor - guard !BuildSettings.newAppLayoutEnabled else { + guard !BuildSettings.isNewAppLayoutActivated else { return } diff --git a/Riot/Modules/Analytics/SentryMonitoringClient.swift b/Riot/Modules/Analytics/SentryMonitoringClient.swift index b848c02a9..38b91960b 100644 --- a/Riot/Modules/Analytics/SentryMonitoringClient.swift +++ b/Riot/Modules/Analytics/SentryMonitoringClient.swift @@ -34,6 +34,7 @@ struct SentryMonitoringClient { options.dsn = Self.sentryDSN // Collecting only 10% of all events + options.sampleRate = 0.1 options.tracesSampleRate = 0.1 options.beforeSend = { event in diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift index 202e698a0..3553148f3 100755 --- a/Riot/Modules/Application/AppCoordinator.swift +++ b/Riot/Modules/Application/AppCoordinator.swift @@ -91,7 +91,7 @@ final class AppCoordinator: NSObject, AppCoordinatorType { // Setup user location services _ = UserLocationServiceProvider.shared - if BuildSettings.enableSideMenu { + if BuildSettings.isSideMenuActivated { self.addSideMenu() } @@ -105,6 +105,8 @@ final class AppCoordinator: NSObject, AppCoordinatorType { } } + NotificationCenter.default.addObserver(self, selector: #selector(self.newAppLayoutToggleDidChange(notification:)), name: RiotSettings.newAppLayoutBetaToggleDidChange, object: nil) + // NOTE: When split view is shown there can be no Matrix sessions ready. Keep this behavior or use a loading screen before showing the split view. self.showSplitView() MXLog.debug("[AppCoordinator] Showed split view") @@ -160,6 +162,12 @@ final class AppCoordinator: NSObject, AppCoordinatorType { ThemePublisher.shared.republish(themeIdPublisher: themeIdPublisher) } + @objc private func newAppLayoutToggleDidChange(notification: Notification) { + if BuildSettings.isSideMenuActivated { + self.addSideMenu() + } + } + private func excludeAllItemsFromBackup() { let manager = FileManager.default diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 8a8545a4c..1b3ce1db7 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1114,21 +1114,66 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni threadId:(NSString *)threadId sender:(NSString *)userId { - if (roomId) - { - MXRoom *room = [self.mxSessions.firstObject roomWithRoomId:roomId]; - if (room.summary.membership != MXMembershipJoin) + void(^sessionReadyBlock)(MXSession*) = ^(MXSession *session){ + if (roomId) { - Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerNotification; + MXRoom *room = [session roomWithRoomId:roomId]; + if (room.summary.membership != MXMembershipJoin) + { + Analytics.shared.joinedRoomTrigger = AnalyticsJoinedRoomTriggerNotification; + } + else + { + Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerNotification; + } + } + + self.lastNavigatedRoomIdFromPush = roomId; + + if (threadId) + { + if(![[MXKRoomDataSourceManager sharedManagerForMatrixSession:session] hasRoomDataSourceForRoom:roomId]) + { + // the room having this thread probably was not opened before, paginate room messages to build threads + MXRoom *room = [session roomWithRoomId:roomId]; + [room liveTimeline:^(id liveTimeline) { + [liveTimeline resetPagination]; + [liveTimeline paginate:NSUIntegerMax direction:MXTimelineDirectionBackwards onlyFromStore:YES complete:^{ + [liveTimeline resetPagination]; + [self navigateToRoomById:roomId threadId:threadId sender:userId]; + } failure:^(NSError * _Nonnull error) { + [self navigateToRoomById:roomId threadId:threadId sender:userId]; + }]; + }]; + } + else + { + // the room has been opened before, we should be ok to continue + [self navigateToRoomById:roomId threadId:threadId sender:userId]; + } } else { - Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerNotification; + [self navigateToRoomById:roomId threadId:threadId sender:userId]; } - } + }; - _lastNavigatedRoomIdFromPush = roomId; - [self navigateToRoomById:roomId threadId:threadId sender:userId]; + MXSession *mxSession = self.mxSessions.firstObject; + if (mxSession.state >= MXSessionStateSyncInProgress) + { + sessionReadyBlock(mxSession); + } + else + { + // wait for session state to be sync in progress + __block id sessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:mxSession queue:nil usingBlock:^(NSNotification * _Nonnull note) { + if (mxSession.state >= MXSessionStateSyncInProgress) + { + [[NSNotificationCenter defaultCenter] removeObserver:sessionStateObserver]; + sessionReadyBlock(mxSession); + } + }]; + } } #pragma mark - Badge Count @@ -4212,7 +4257,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni } // Need to set `showAllRoomsInHomeSpace` to `true` for the new App Layout - if (BuildSettings.newAppLayoutEnabled) + if (BuildSettings.isNewAppLayoutActivated) { RiotSettings.shared.showAllRoomsInHomeSpace = YES; } diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index 18ea65eca..228751d31 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -84,7 +84,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou _crossSigningBannerDisplay = CrossSigningBannerDisplayNone; _secureBackupBannerDisplay = SecureBackupBannerDisplayNone; - _areSectionsShrinkable = !BuildSettings.newAppLayoutEnabled; + _areSectionsShrinkable = !BuildSettings.isNewAppLayoutActivated; shrinkedSectionsBitMask = 0; roomTagsListenerByUserId = [[NSMutableDictionary alloc] init]; @@ -758,7 +758,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou } - if (count && !(sectionType == RecentsDataSourceSectionTypeInvites) && !BuildSettings.newAppLayoutEnabled) + if (count && !(sectionType == RecentsDataSourceSectionTypeInvites) && !BuildSettings.isNewAppLayoutActivated) { NSString *roomCount = [NSString stringWithFormat:@" %tu", count]; @@ -987,7 +987,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou sectionHeader.bottomView = nil; } - if (!BuildSettings.newAppLayoutEnabled || !sectionHeader.bottomView) + if (!BuildSettings.isNewAppLayoutActivated || !sectionHeader.bottomView) { // Add label frame.size.height = RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT - 10; @@ -1101,7 +1101,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou { RecentsInvitesTableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:[RecentsInvitesTableViewCell defaultReuseIdentifier]]; - tableViewCell.invitesCount = self.recentsListService.invitedRoomListData.counts.numberOfRooms; + tableViewCell.invitesCount = self.recentsListService.invitedRoomListData.counts.total.numberOfRooms; return tableViewCell; } diff --git a/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift b/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift index 7370f0f94..74effcd99 100644 --- a/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift +++ b/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift @@ -132,7 +132,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol { if let fetcher = conversationRoomListDataFetcherForRooms, fetcherTypes.contains(.conversationRooms) { result.append(fetcher) } - if let fetcher = lowPriorityRoomListDataFetcher, fetcherTypes.contains(.lowPriority) { + if let fetcher = lowPriorityRoomListDataFetcher, fetcherTypes.contains(.lowPriority), shouldShowLowPriority { result.append(fetcher) } if let fetcher = serverNoticeRoomListDataFetcher, fetcherTypes.contains(.serverNotice) { @@ -482,7 +482,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol { } private var shouldShowLowPriority: Bool { - return fetcherTypesForMode[mode]?.contains(.lowPriority) ?? false + return ((mode != .allChats) || !AllChatsLayoutSettingsManager.shared.hasAnActiveFilter) && fetcherTypesForMode[mode]?.contains(.lowPriority) ?? false } private var shouldShowServerNotice: Bool { diff --git a/Riot/Modules/ContextMenu/ContextMenuProviders/PublicRoomContextMenuProvider.swift b/Riot/Modules/ContextMenu/ContextMenuProviders/PublicRoomContextMenuProvider.swift index da2502668..d30594110 100644 --- a/Riot/Modules/ContextMenu/ContextMenuProviders/PublicRoomContextMenuProvider.swift +++ b/Riot/Modules/ContextMenu/ContextMenuProviders/PublicRoomContextMenuProvider.swift @@ -37,7 +37,7 @@ class PublicRoomContextMenuProvider: NSObject { } roomViewController.isContextPreview = true - RoomPreviewDataSource.load(withRoomId: room.roomId, andMatrixSession: session) { [weak roomViewController] roomDataSource in + RoomPreviewDataSource.load(withRoomId: room.roomId, threadId: nil, andMatrixSession: session) { [weak roomViewController] roomDataSource in guard let dataSource = roomDataSource as? RoomPreviewDataSource else { return } diff --git a/Riot/Modules/ContextMenu/ContextMenuProviders/RecentCellContextMenuProvider.swift b/Riot/Modules/ContextMenu/ContextMenuProviders/RecentCellContextMenuProvider.swift index a748b7649..c696932db 100644 --- a/Riot/Modules/ContextMenu/ContextMenuProviders/RecentCellContextMenuProvider.swift +++ b/Riot/Modules/ContextMenu/ContextMenuProviders/RecentCellContextMenuProvider.swift @@ -57,7 +57,7 @@ class RecentCellContextMenuProvider: NSObject { } roomViewController.isContextPreview = true - RoomPreviewDataSource.load(withRoomId: room.roomId, andMatrixSession: session) { [weak roomViewController] roomDataSource in + RoomPreviewDataSource.load(withRoomId: room.roomId, threadId: nil, andMatrixSession: session) { [weak roomViewController] roomDataSource in guard let dataSource = roomDataSource as? RoomPreviewDataSource else { return } diff --git a/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m b/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m index 8703623bb..fb27ec4b4 100644 --- a/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m +++ b/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m @@ -146,7 +146,7 @@ [self updateSearch]; - if (BuildSettings.newAppLayoutEnabled) + if (BuildSettings.isNewAppLayoutActivated) { [self.searchBar vc_searchTextField].backgroundColor = nil; [self vc_setLargeTitleDisplayMode: UINavigationItemLargeTitleDisplayModeAutomatic]; diff --git a/Riot/Modules/Home/AllChats/AllChatsLayoutSettingsManager.swift b/Riot/Modules/Home/AllChats/AllChatsLayoutSettingsManager.swift index 065c54cb3..33b1ee335 100644 --- a/Riot/Modules/Home/AllChats/AllChatsLayoutSettingsManager.swift +++ b/Riot/Modules/Home/AllChats/AllChatsLayoutSettingsManager.swift @@ -105,6 +105,11 @@ final class AllChatsLayoutSettingsManager: NSObject { } } + /// `true` if filters are activated in the All Chats Layout screen and a filter other than `.all` is active + var hasAnActiveFilter: Bool { + return !allChatLayoutSettings.filters.isEmpty && !activeFilters.isEmpty && activeFilters != .all + } + // MARK: - Private private func track(activeFilters: AllChatsLayoutFilterType?) { diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index 0ef4f7c48..c46e9d577 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -80,6 +80,11 @@ { [super viewDidLoad]; + if (!BuildSettings.isNewAppLayoutActivated) + { + [self.tabBarController vc_setLargeTitleDisplayMode:UINavigationItemLargeTitleDisplayModeNever]; + } + self.roomListDataReady = NO; self.view.accessibilityIdentifier = @"HomeVCView"; diff --git a/Riot/Modules/KeyVerification/User/SessionsStatus/UserVerificationSessionStatusCell.swift b/Riot/Modules/KeyVerification/User/SessionsStatus/UserVerificationSessionStatusCell.swift index d0b6de6e7..548ce70b0 100644 --- a/Riot/Modules/KeyVerification/User/SessionsStatus/UserVerificationSessionStatusCell.swift +++ b/Riot/Modules/KeyVerification/User/SessionsStatus/UserVerificationSessionStatusCell.swift @@ -63,7 +63,7 @@ final class UserVerificationSessionStatusCell: UITableViewCell, NibReusable, The func update(theme: Theme) { self.theme = theme - self.backgroundColor = theme.headerBackgroundColor + self.backgroundColor = theme.colors.system self.sessionNameLabel.textColor = theme.textPrimaryColor self.updateStatusTextColor() } diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h index a5c542880..d7c4b2db2 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h @@ -261,10 +261,11 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey; the room data source is created. @param roomId the id of the room to get data from. + @param threadId the id of the thread to load. If provided, thread data source will be loaded from the room specified with `roomId`. @param mxSession the Matrix session to get data from. @param onComplete a block providing the newly created instance. */ -+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete; ++ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete; /** Asynchronously create adata source to serve data corresponding to an event in the @@ -306,10 +307,11 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey; Initialise the data source to serve data corresponding to the passed room. @param roomId the id of the room to get data from. + @param threadId the id of the thread to initialize. If provided, thread data source will be initialized from the room specified with `roomId`. @param mxSession the Matrix session to get data from. @return the newly created instance. */ -- (instancetype)initWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession; +- (instancetype)initWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession threadId:(NSString*)threadId; /** Initialise the data source to serve data corresponding to an event in the diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m index 5872eee2d..7770efd89 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m @@ -208,9 +208,9 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { @implementation MXKRoomDataSource -+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete ++ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete { - MXKRoomDataSource *roomDataSource = [[self alloc] initWithRoomId:roomId andMatrixSession:mxSession]; + MXKRoomDataSource *roomDataSource = [[self alloc] initWithRoomId:roomId andMatrixSession:mxSession threadId:threadId]; [self ensureSessionStateForDataSource:roomDataSource initialEventId:nil andMatrixSession:mxSession onComplete:onComplete]; } @@ -284,7 +284,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { } } -- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession +- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession threadId:(NSString *)threadId { self = [super initWithMatrixSession:matrixSession]; if (self) @@ -292,6 +292,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { MXLogVerbose(@"[MXKRoomDataSource][%p] initWithRoomId: %@", self, roomId); _roomId = roomId; + _threadId = threadId; _secondaryRoomEventTypes = @[ kMXEventTypeStringCallInvite, kMXEventTypeStringCallCandidates, @@ -368,7 +369,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { - (instancetype)initWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId2 threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession { - self = [self initWithRoomId:roomId andMatrixSession:mxSession]; + self = [self initWithRoomId:roomId andMatrixSession:mxSession threadId:threadId]; if (self) { if (initialEventId2) @@ -376,7 +377,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { initialEventId = initialEventId2; _isLive = NO; } - _threadId = threadId; } return self; @@ -553,6 +553,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { } self.room = nil; + self.thread = nil; self.secondaryRoom = nil; } @@ -584,7 +585,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { - (void)destroy { - MXLogDebug(@"[MXKRoomDataSource][%p] Destroy - room id: %@", self, _roomId); + MXLogDebug(@"[MXKRoomDataSource][%p] Destroy - room id: %@ - thread id: %@", self, _roomId, _threadId); [self unregisterScanManagerNotifications]; [self unregisterReactionsChangeListener]; @@ -2848,11 +2849,14 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { - (void)setState:(MXKDataSourceState)newState { - self->state = newState; - - if (self.delegate && [self.delegate respondsToSelector:@selector(dataSource:didStateChange:)]) + if (self->state != newState) { - [self.delegate dataSource:self didStateChange:self->state]; + self->state = newState; + + if (self.delegate && [self.delegate respondsToSelector:@selector(dataSource:didStateChange:)]) + { + [self.delegate dataSource:self didStateChange:self->state]; + } } } diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.h index 46f6709da..28a62e80e 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.h @@ -78,6 +78,13 @@ typedef enum : NSUInteger { */ - (void)reset; +/** + Flag indicating the manager has a room data source for a given room id. + + @param roomId the room id to check. + */ +- (BOOL)hasRoomDataSourceForRoom:(NSString*)roomId; + /** Get a room data source corresponding to a room id. diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.m index fd4e54c8a..181552e53 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSourceManager.m @@ -191,6 +191,11 @@ static Class _roomDataSourceClass; } } +- (BOOL)hasRoomDataSourceForRoom:(NSString *)roomId +{ + return roomDataSources[roomId] != nil; +} + - (void)roomDataSourceForRoom:(NSString *)roomId create:(BOOL)create onComplete:(void (^)(MXKRoomDataSource *roomDataSource))onComplete { NSParameterAssert(roomId); @@ -200,7 +205,7 @@ static Class _roomDataSourceClass; if (!roomDataSource && create && roomId) { - [_roomDataSourceClass loadRoomDataSourceWithRoomId:roomId andMatrixSession:mxSession onComplete:^(id roomDataSource) { + [_roomDataSourceClass loadRoomDataSourceWithRoomId:roomId threadId:nil andMatrixSession:mxSession onComplete:^(id roomDataSource) { [self addRoomDataSource:roomDataSource]; onComplete(roomDataSource); }]; diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift index b539368c3..b72b31ac0 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift @@ -73,8 +73,8 @@ final class ReactionsMenuView: UIView, Themable, NibLoadable { // MARK: - Public func update(theme: Theme) { - self.reactionsBackgroundView.backgroundColor = theme.headerBackgroundColor - self.moreReactionsBackgroundView.backgroundColor = theme.headerBackgroundColor + self.reactionsBackgroundView.backgroundColor = theme.colors.system + self.moreReactionsBackgroundView.backgroundColor = theme.colors.system self.moreReactionsButton.tintColor = theme.tintColor } diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 958403acc..ed48741db 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -68,9 +68,9 @@ const CGFloat kTypingCellHeight = 24; @implementation RoomDataSource -- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession +- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession threadId:(NSString *)threadId { - self = [super initWithRoomId:roomId andMatrixSession:matrixSession]; + self = [super initWithRoomId:roomId andMatrixSession:matrixSession threadId:threadId]; if (self) { // Replace default Cell data class diff --git a/Riot/Modules/Room/DataSources/ThreadDataSource.swift b/Riot/Modules/Room/DataSources/ThreadDataSource.swift index 4c46a1f42..3f69f7a04 100644 --- a/Riot/Modules/Room/DataSources/ThreadDataSource.swift +++ b/Riot/Modules/Room/DataSources/ThreadDataSource.swift @@ -15,15 +15,31 @@ // import Foundation +import UIKit @objcMembers public class ThreadDataSource: RoomDataSource { + + private typealias ThreadID = String + + /// Map of cached data sources. Keys are thread identifiers. + private static var dataSourceCache: [ThreadID: ThreadDataSource] = [:] public override func finalizeInitialization() { super.finalizeInitialization() showReadMarker = false showBubbleReceipts = false showTypingRow = false + + NotificationCenter.default.addObserver(self, + selector: #selector(didReceiveMemoryWarning), + name: UIApplication.didReceiveMemoryWarningNotification, + object: nil) + + NotificationCenter.default.addObserver(self, + selector: #selector(didLeaveRoom(_:)), + name: .mxSessionDidLeaveRoom, + object: nil) } public override var showReadMarker: Bool { @@ -41,5 +57,47 @@ public class ThreadDataSource: RoomDataSource { _ = newValue } } + + public override class func load(withRoomId roomId: String!, + initialEventId: String!, + threadId: String!, + andMatrixSession mxSession: MXSession!, + onComplete: ((Any?) -> Void)!) { + if let dataSource = dataSourceCache[threadId] { + onComplete(dataSource) + return + } + super.load(withRoomId: roomId, initialEventId: initialEventId, threadId: threadId, andMatrixSession: mxSession) { dataSource in + if let dataSource = dataSource as? ThreadDataSource { + Self.dataSourceCache[threadId] = dataSource + } + onComplete(dataSource) + } + } + + @objc + private func didReceiveMemoryWarning() { + MXLog.debug("[ThreadDataSource] didReceiveMemoryWarning. Will reload not active data sources in cache.") + + Self.dataSourceCache.forEach { + if $1.delegate == nil { + $1.reload() + } + } + } + + @objc + private func didLeaveRoom(_ notification: Notification) { + MXLog.debug("[ThreadDataSource] didReceiveMemoryWarning. Will reload not active data sources in cache.") + + guard let session = notification.object as? MXSession, + session == mxSession, + let roomId = notification.userInfo?[kMXSessionNotificationRoomIdKey] as? String else { + return + } + + let threadIds = Array(Self.dataSourceCache.filter { $1.roomId == roomId }.keys) + threadIds.forEach { Self.dataSourceCache.removeValue(forKey: $0) } + } } diff --git a/Riot/Modules/Room/MXKRoomViewController.m b/Riot/Modules/Room/MXKRoomViewController.m index 2002d7344..e007b8595 100644 --- a/Riot/Modules/Room/MXKRoomViewController.m +++ b/Riot/Modules/Room/MXKRoomViewController.m @@ -291,6 +291,8 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + + [self.navigationController setToolbarHidden:YES animated:NO]; // Observe server sync process at room data source level too [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMatrixSessionChange) name:kMXKRoomDataSourceSyncStatusChanged object:nil]; @@ -339,7 +341,7 @@ _bubblesTableView.hidden = NO; } - if (BuildSettings.newAppLayoutEnabled) + if (BuildSettings.isNewAppLayoutActivated) { [self vc_setLargeTitleDisplayMode: UINavigationItemLargeTitleDisplayModeNever]; } diff --git a/Riot/Modules/Room/RoomCoordinator.swift b/Riot/Modules/Room/RoomCoordinator.swift index 1728aac21..643cd803e 100644 --- a/Riot/Modules/Room/RoomCoordinator.swift +++ b/Riot/Modules/Room/RoomCoordinator.swift @@ -67,7 +67,10 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol { var canReleaseRoomDataSource: Bool { // If the displayed data is not a preview, let the manager release the room data source // (except if the view controller has the room data source ownership). - return self.parameters.previewData == nil && self.roomViewController.roomDataSource != nil && self.roomViewController.hasRoomDataSourceOwnership == false + return self.parameters.previewData == nil + && self.roomViewController.roomDataSource != nil + && self.roomViewController.roomDataSource.threadId == nil + && self.roomViewController.hasRoomDataSourceOwnership == false } // MARK: - Setup @@ -238,7 +241,7 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol { self.roomViewController.displayRoom(threadDataSource) // Give the data source ownership to the room view controller. - self.roomViewController.hasRoomDataSourceOwnership = true + self.roomViewController.hasRoomDataSourceOwnership = false self.mxSession?.updateBreadcrumbsWithRoom(withId: roomId, success: nil, failure: nil) diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index 5d75ed1b8..44ddb735b 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -47,7 +47,7 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { let files = RoomFilesViewController() files.finalizeInit() files.screenTracker = AnalyticsScreenTracker(screen: .roomUploads) - MXKRoomDataSource.load(withRoomId: self.room.roomId, andMatrixSession: self.session) { (dataSource) in + MXKRoomDataSource.load(withRoomId: self.room.roomId, threadId: nil, andMatrixSession: self.session) { (dataSource) in guard let dataSource = dataSource as? MXKRoomDataSource else { return } dataSource.filterMessagesWithURL = true dataSource.finalizeInitialization() diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 1c9114ab1..7d3da462f 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -5687,6 +5687,7 @@ static CGSize kThreadListBarButtonItemImageSize; if (self.isContextPreview) { [RoomPreviewDataSource loadRoomDataSourceWithRoomId:self.roomDataSource.roomId + threadId:nil andMatrixSession:self.mainSession onComplete:^(RoomPreviewDataSource *roomDataSource) { diff --git a/Riot/Modules/Room/TimelineCells/KeyVerification/KeyVerificationCellInnerContentView.swift b/Riot/Modules/Room/TimelineCells/KeyVerification/KeyVerificationCellInnerContentView.swift index cac389332..62bc9b7e6 100644 --- a/Riot/Modules/Room/TimelineCells/KeyVerification/KeyVerificationCellInnerContentView.swift +++ b/Riot/Modules/Room/TimelineCells/KeyVerification/KeyVerificationCellInnerContentView.swift @@ -130,7 +130,7 @@ final class KeyVerificationCellInnerContentView: UIView, NibLoadable { // MARK: - Public func update(theme: Theme) { - self.backgroundColor = theme.headerBackgroundColor + self.backgroundColor = theme.colors.system self.titleLabel.textColor = theme.textPrimaryColor self.otherUserInformationLabel.textColor = theme.textSecondaryColor diff --git a/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.swift b/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.swift index 9b966de0f..433401bca 100644 --- a/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.swift +++ b/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.swift @@ -87,6 +87,6 @@ final class RoomReactionActionViewCell: UICollectionViewCell, NibReusable, Thema self.actionLabel.textColor = self.theme?.textSecondaryColor self.reactionBackgroundView.layer.borderWidth = 0.0 - self.reactionBackgroundView.backgroundColor = self.theme?.headerBackgroundColor + self.reactionBackgroundView.backgroundColor = self.theme?.colors.system } } diff --git a/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionImageViewCell.swift b/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionImageViewCell.swift index a063db721..454822478 100644 --- a/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionImageViewCell.swift +++ b/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionImageViewCell.swift @@ -79,6 +79,6 @@ final class RoomReactionImageViewCell: UICollectionViewCell, NibReusable, Themab self.imageView.tintColor = self.theme?.textSecondaryColor self.reactionBackgroundView.layer.borderWidth = 0.0 - self.reactionBackgroundView.backgroundColor = self.theme?.headerBackgroundColor + self.reactionBackgroundView.backgroundColor = self.theme?.colors.system } } diff --git a/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionViewCell.swift b/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionViewCell.swift index 7e509e923..1e530b126 100644 --- a/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionViewCell.swift +++ b/Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionViewCell.swift @@ -97,7 +97,7 @@ final class RoomReactionViewCell: UICollectionViewCell, NibReusable, Themable { reactionBackgroundColor = self.theme?.tintBackgroundColor reactionBackgroundBorderWidth = Constants.selectedBorderWidth } else { - reactionBackgroundColor = self.theme?.headerBackgroundColor + reactionBackgroundColor = self.theme?.colors.system reactionBackgroundBorderWidth = 0.0 } diff --git a/Riot/Modules/SetPinCode/PinCodePreferences.swift b/Riot/Modules/SetPinCode/PinCodePreferences.swift index 386dc26a0..a55530f1f 100644 --- a/Riot/Modules/SetPinCode/PinCodePreferences.swift +++ b/Riot/Modules/SetPinCode/PinCodePreferences.swift @@ -127,6 +127,10 @@ final class PinCodePreferences: NSObject { var canUseBiometricsToUnlock: Bool? { get { + guard isBiometricsAvailable == true else { + return false + } + do { return try store.bool(forKey: StoreKeys.canUseBiometricsToUnlock) } catch let error { diff --git a/Riot/Modules/SetPinCode/SetPinCoordinatorBridgePresenter.swift b/Riot/Modules/SetPinCode/SetPinCoordinatorBridgePresenter.swift index 2351e5f61..c381b76eb 100644 --- a/Riot/Modules/SetPinCode/SetPinCoordinatorBridgePresenter.swift +++ b/Riot/Modules/SetPinCode/SetPinCoordinatorBridgePresenter.swift @@ -95,13 +95,8 @@ final class SetPinCoordinatorBridgePresenter: NSObject { let setPinCoordinator = SetPinCoordinator(session: self.session, viewMode: self.viewMode, pinCodePreferences: .shared) setPinCoordinator.delegate = self - guard let view = setPinCoordinator.toPresentable().view else { return } - pinCoordinatorWindow.addSubview(view) - view.leadingAnchor.constraint(equalTo: pinCoordinatorWindow.leadingAnchor, constant: 0).isActive = true - view.trailingAnchor.constraint(equalTo: pinCoordinatorWindow.trailingAnchor, constant: 0).isActive = true - view.topAnchor.constraint(equalTo: pinCoordinatorWindow.topAnchor, constant: 0).isActive = true - view.bottomAnchor.constraint(equalTo: pinCoordinatorWindow.bottomAnchor, constant: 0).isActive = true + pinCoordinatorWindow.rootViewController = setPinCoordinator.toPresentable() pinCoordinatorWindow.makeKeyAndVisible() setPinCoordinator.start() diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index 6b9a19f97..2da06cdf9 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -172,7 +172,8 @@ typedef NS_ENUM(NSUInteger, LABS_ENABLE) LABS_ENABLE_RINGING_FOR_GROUP_CALLS_INDEX = 0, LABS_ENABLE_THREADS_INDEX, LABS_ENABLE_AUTO_REPORT_DECRYPTION_ERRORS, - LABS_ENABLE_LIVE_LOCATION_SHARING + LABS_ENABLE_LIVE_LOCATION_SHARING, + LABS_ENABLE_NEW_APP_LAYOUT }; typedef NS_ENUM(NSUInteger, SECURITY) @@ -595,6 +596,7 @@ ChangePasswordCoordinatorBridgePresenterDelegate> { [sectionLabs addRowWithTag:LABS_ENABLE_LIVE_LOCATION_SHARING]; } + [sectionLabs addRowWithTag:LABS_ENABLE_NEW_APP_LAYOUT]; sectionLabs.headerTitle = [VectorL10n settingsLabs]; if (sectionLabs.hasAnyRows) { @@ -1497,6 +1499,21 @@ ChangePasswordCoordinatorBridgePresenterDelegate> return labelAndSwitchCell; } +- (UITableViewCell *)buildNewAppLayoutCellForTableView:(UITableView*)tableView + atIndexPath:(NSIndexPath*)indexPath +{ + MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; + + labelAndSwitchCell.mxkLabel.text = [VectorL10n settingsLabsEnableNewAppLayout]; + + labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.newAppLayoutBetaEnabled; + labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor; + labelAndSwitchCell.mxkSwitch.enabled = YES; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableNewAppLayout:) forControlEvents:UIControlEventTouchUpInside]; + + return labelAndSwitchCell; +} + #pragma mark - 3Pid Add - (void)showAuthenticationIfNeededForAdding:(MX3PIDMedium)medium withSession:(MXSession*)session completion:(void (^)(NSDictionary* authParams))completion @@ -2532,6 +2549,10 @@ ChangePasswordCoordinatorBridgePresenterDelegate> { cell = [self buildLiveLocationSharingCellForTableView:tableView atIndexPath:indexPath]; } + else if (row == LABS_ENABLE_NEW_APP_LAYOUT) + { + cell = [self buildNewAppLayoutCellForTableView:tableView atIndexPath:indexPath]; + } } else if (section == SECTION_TAG_SECURITY) { @@ -3971,6 +3992,15 @@ ChangePasswordCoordinatorBridgePresenterDelegate> RiotSettings.shared.enableLiveLocationSharing = sender.isOn; } +- (void)toggleEnableNewAppLayout:(UISwitch *)sender +{ + if (sender.isOn) + { + RiotSettings.shared.showAllRoomsInHomeSpace = YES; + } + RiotSettings.shared.newAppLayoutBetaEnabled = sender.isOn; +} + #pragma mark - TextField listener - (IBAction)textFieldDidChange:(id)sender diff --git a/Riot/Modules/SplitView/SplitViewCoordinator.swift b/Riot/Modules/SplitView/SplitViewCoordinator.swift index eff81d0e5..a3de10ee5 100644 --- a/Riot/Modules/SplitView/SplitViewCoordinator.swift +++ b/Riot/Modules/SplitView/SplitViewCoordinator.swift @@ -227,7 +227,7 @@ final class SplitViewCoordinator: NSObject, SplitViewCoordinatorType { } let existingRoomCoordinatorWithSameRoomId = self.detailModules.first { presentable -> Bool in - if let currentRoomCoordinator = presentable as? RoomCoordinatorProtocol { + if let currentRoomCoordinator = presentable as? RoomCoordinatorProtocol, currentRoomCoordinator.threadId == nil { return currentRoomCoordinator.roomId == roomCoordinator.roomId } return false diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index b9f926407..96cc0880f 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -156,7 +156,7 @@ [self userInterfaceThemeDidChange]; } - self.tabBar.hidden = BuildSettings.newAppLayoutEnabled; + self.tabBar.hidden = BuildSettings.isNewAppLayoutActivated; } - (void)viewDidAppear:(BOOL)animated @@ -213,8 +213,8 @@ } [[AppDelegate theDelegate] checkAppVersion]; - - if (BuildSettings.newAppLayoutEnabled && !RiotSettings.shared.allChatsOnboardingHasBeenDisplayed) + + if (BuildSettings.isNewAppLayoutActivated && !RiotSettings.shared.allChatsOnboardingHasBeenDisplayed) { [self showAllChatsOnboardingScreen]; } @@ -633,7 +633,7 @@ { if (roomParentId) { NSString *parentName = [mxSession roomSummaryWithRoomId:roomParentId].displayname; - if (!BuildSettings.newAppLayoutEnabled) + if (!BuildSettings.isNewAppLayoutActivated) { NSMutableArray *breadcrumbs = [[NSMutableArray alloc] initWithObjects:parentName, nil]; @@ -649,7 +649,7 @@ } else { - if (!BuildSettings.newAppLayoutEnabled) + if (!BuildSettings.isNewAppLayoutActivated) { titleView.breadcrumbView.breadcrumbs = @[]; } @@ -661,7 +661,7 @@ - (void)updateSideMenuNotifcationIcon { - if (BuildSettings.newAppLayoutEnabled) { return; } + if (BuildSettings.isNewAppLayoutActivated) { return; } BOOL displayNotification = NO; @@ -693,7 +693,7 @@ -(void)setupTitleView { - if (!BuildSettings.newAppLayoutEnabled) + if (!BuildSettings.isNewAppLayoutActivated) { titleView = [MainTitleView new]; self.navigationItem.titleView = titleView; diff --git a/Riot/Modules/TabBar/TabBarCoordinator.swift b/Riot/Modules/TabBar/TabBarCoordinator.swift index d059aa5d3..711e1e1cf 100644 --- a/Riot/Modules/TabBar/TabBarCoordinator.swift +++ b/Riot/Modules/TabBar/TabBarCoordinator.swift @@ -116,13 +116,15 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { self.addMatrixSessionToMasterTabBarController(userSession.matrixSession) } - if BuildSettings.enableSideMenu { + if BuildSettings.isSideMenuActivated { self.setupSideMenuGestures() } self.registerUserSessionsServiceNotifications() self.registerSessionChange() + NotificationCenter.default.addObserver(self, selector: #selector(self.newAppLayoutToggleDidChange(notification:)), name: RiotSettings.newAppLayoutBetaToggleDidChange, object: nil) + self.updateMasterTabBarController(with: spaceId, forceReload: true) } else { self.updateMasterTabBarController(with: spaceId) @@ -239,6 +241,15 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { // MARK: - Private methods + @objc private func newAppLayoutToggleDidChange(notification: Notification) { + self.masterTabBarController = nil + start() +// updateMasterTabBarController(with: self.currentSpaceId, forceReload: true) +// createLeftButtonItem(for: self.masterTabBarController) +// createRightButtonItem(for: self.masterTabBarController) +// popToHome(animated: true, completion: nil) + } + private func createMasterTabBarController() -> MasterTabBarController { let tabBarController = MasterTabBarController() @@ -367,10 +378,10 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { private func updateTabControllers(for tabBarController: MasterTabBarController, showCommunities: Bool) { var viewControllers: [UIViewController] = [] - let homeViewController = BuildSettings.newAppLayoutEnabled ? self.createAllChatsViewController() : self.createHomeViewController() + let homeViewController = BuildSettings.isNewAppLayoutActivated ? self.createAllChatsViewController() : self.createHomeViewController() viewControllers.append(homeViewController) - if !BuildSettings.newAppLayoutEnabled { + if !BuildSettings.isNewAppLayoutActivated { if RiotSettings.shared.homeScreenShowFavouritesTab { let favouritesViewController = self.createFavouritesViewController() viewControllers.append(favouritesViewController) @@ -703,14 +714,15 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { // MARK: Navigation bar items management private weak var rightMenuAvatarView: AvatarView? + private weak var rightMenuButton: UIButton? private func createLeftButtonItem(for viewController: UIViewController) { - guard !BuildSettings.newAppLayoutEnabled else { + guard !BuildSettings.isNewAppLayoutActivated else { createAvatarButtonItem(for: viewController) return } - guard BuildSettings.enableSideMenu else { + guard BuildSettings.isSideMenuActivated else { let settingsBarButtonItem: MXKBarButtonItem = MXKBarButtonItem(image: Asset.Images.settingsIcon.image, style: .plain) { [weak self] in self?.showSettings() } @@ -729,7 +741,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { } private func createRightButtonItem(for viewController: UIViewController) { - guard !BuildSettings.newAppLayoutEnabled else { + guard !BuildSettings.isNewAppLayoutActivated else { return } @@ -776,6 +788,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { button.showsMenuAsPrimaryAction = true button.autoresizingMask = [.flexibleHeight, .flexibleWidth] view.addSubview(button) + self.rightMenuButton = button let avatarView = UserAvatarView(frame: view.bounds.inset(by: UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7))) avatarView.isUserInteractionEnabled = false @@ -786,16 +799,18 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { if let avatar = userAvatarViewData(from: currentMatrixSession) { avatarView.fill(with: avatar) + button.setImage(nil, for: .normal) } viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: view) } private func updateAvatarButtonItem() { - guard let avatarView = rightMenuAvatarView, let avatar = userAvatarViewData(from: currentMatrixSession) else { + guard let avatarView = rightMenuAvatarView, let button = rightMenuButton, let avatar = userAvatarViewData(from: currentMatrixSession) else { return } + button.setImage(nil, for: .normal) avatarView.fill(with: avatar) } @@ -890,7 +905,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { private var windowOverlay: WindowOverlayPresenter? func showCoachMessageIfNeeded(with session: MXSession) { - guard !BuildSettings.newAppLayoutEnabled else { + guard !BuildSettings.isNewAppLayoutActivated else { // Showing coach message makes no sense with the new App Layout return } @@ -937,7 +952,7 @@ extension TabBarCoordinator: MasterTabBarControllerDelegate { } func masterTabBarController(_ masterTabBarController: MasterTabBarController!, needsSideMenuIconWithNotification displayNotification: Bool) { - guard BuildSettings.enableSideMenu else { + guard BuildSettings.isSideMenuActivated else { return } diff --git a/RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift b/RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift index ce8a3d44e..cd7f8db15 100644 --- a/RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift +++ b/RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift @@ -93,7 +93,7 @@ private final class StubMXKRoomDataSource: MXKRoomDataSource { private final class FakeMXKRoomDataSource: MXKRoomDataSource { class func make() throws -> FakeMXKRoomDataSource { - let dataSource = try XCTUnwrap(FakeMXKRoomDataSource(roomId: "!foofoofoofoofoofoo:matrix.org", andMatrixSession: nil)) + let dataSource = try XCTUnwrap(FakeMXKRoomDataSource(roomId: "!foofoofoofoofoofoo:matrix.org", andMatrixSession: nil, threadId: nil)) dataSource.registerCellDataClass(CollapsibleBubbleCellData.self, forCellIdentifier: kMXKRoomBubbleCellDataIdentifier) dataSource.eventFormatter = CountingEventFormatter(matrixSession: nil) return dataSource