From 997cf15dd31163d06c4bbf238845cabaf1907f79 Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 22 Jun 2021 13:39:50 +0100 Subject: [PATCH 01/49] Add new settings notification feature flag and update ui entry point --- Config/BuildSettings.swift | 1 + Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ .../Room/RoomInfo/RoomInfoCoordinator.swift | 7 +++++- .../RoomInfoList/RoomInfoListViewAction.swift | 22 ++++++++----------- .../RoomInfoListViewController.swift | 10 +++++++-- .../Settings/RoomSettingsViewController.m | 5 ++++- 7 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 3cfcf65dc..0d5ae6dae 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -295,6 +295,7 @@ final class BuildSettings: NSObject { static let roomSettingsScreenShowFlairSettings: Bool = true static let roomSettingsScreenShowAdvancedSettings: Bool = true static let roomSettingsScreenAdvancedShowEncryptToVerifiedOption: Bool = true + static let roomSettingsScreenShowNotificationsV2: Bool = false // MARK: - Room Member Screen diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 234022cf2..d7abe10a2 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -710,6 +710,7 @@ Tap the + to start adding people."; "room_details_topic" = "Topic"; "room_details_favourite_tag" = "Favourite"; "room_details_low_priority_tag" = "Low priority"; +"room_details_notifs" = "Notifications"; "room_details_mute_notifs" = "Mute notifications"; "room_details_direct_chat" = "Direct Chat"; "room_details_access_section"="Who can access this room?"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index ba05c0233..cb5875969 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2710,6 +2710,10 @@ internal enum VectorL10n { internal static var roomDetailsNoLocalAddressesForDm: String { return VectorL10n.tr("Vector", "room_details_no_local_addresses_for_dm") } + /// Notifications + internal static var roomDetailsNotifs: String { + return VectorL10n.tr("Vector", "room_details_notifs") + } /// Members internal static var roomDetailsPeople: String { return VectorL10n.tr("Vector", "room_details_people") diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index f1efb7577..27252f4d7 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -152,8 +152,13 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { self.navigationRouter.push(search, animated: animated, popCompletion: nil) } }) + case .notifications: + break default: - segmentedViewController.selectedIndex = target.tabIndex + guard let tabIndex = target.tabIndex else { + fatalError("No settings tab index for this target.") + } + segmentedViewController.selectedIndex = tabIndex if case .settings(let roomSettingsField) = target { roomSettingsViewController?.selectedRoomSettingsField = roomSettingsField diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift index 945d2844a..c6e0c8887 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift @@ -24,25 +24,21 @@ enum RoomInfoListTarget: Equatable { case uploads case integrations case search - - var tabIndex: UInt { - let tabIndex: UInt - + case notifications + + var tabIndex: UInt? { switch self { case .members: - tabIndex = 0 + return 0 case .uploads: - tabIndex = 1 + return 1 case .settings: - tabIndex = 2 - case .integrations: - tabIndex = 3 - case .search: - tabIndex = 4 + return 2 + default: + return nil } - - return tabIndex } + } /// RoomInfoListViewController view actions exposed to view model diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift index bfc3396bf..28e1f64e8 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -150,6 +150,9 @@ final class RoomInfoListViewController: UIViewController { let rowSettings = Row(type: .default, icon: Asset.Images.settingsIcon.image, text: VectorL10n.roomDetailsSettings, accessoryType: .disclosureIndicator) { self.viewModel.process(viewAction: .navigate(target: .settings())) } + let roomNotifications = Row(type: .default, icon: Asset.Images.roomActionNotification.image, text: VectorL10n.roomDetailsNotifs, accessoryType: .disclosureIndicator) { + self.viewModel.process(viewAction: .navigate(target: .notifications)) + } let text = viewData.numberOfMembers == 1 ? VectorL10n.roomInfoListOneMember : VectorL10n.roomInfoListSeveralMembers(String(viewData.numberOfMembers)) let rowMembers = Row(type: .default, icon: Asset.Images.userIcon.image, text: text, accessoryType: .disclosureIndicator) { self.viewModel.process(viewAction: .navigate(target: .members)) @@ -165,8 +168,11 @@ final class RoomInfoListViewController: UIViewController { } var rows = [rowSettings] - if (RiotSettings.shared.roomInfoScreenShowIntegrations) - { + + if BuildSettings.roomSettingsScreenShowNotificationsV2 { + rows.append(roomNotifications) + } + if RiotSettings.shared.roomInfoScreenShowIntegrations { rows.append(rowIntegrations) } rows.append(rowMembers) diff --git a/Riot/Modules/Room/Settings/RoomSettingsViewController.m b/Riot/Modules/Room/Settings/RoomSettingsViewController.m index 634468fe8..08d18f655 100644 --- a/Riot/Modules/Room/Settings/RoomSettingsViewController.m +++ b/Riot/Modules/Room/Settings/RoomSettingsViewController.m @@ -528,7 +528,10 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT]; } - [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS]; + if (!BuildSettings.roomSettingsScreenShowNotificationsV2) + { + [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS]; + } [sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE]; [tmpSections addObject:sectionMain]; From 07f098b7bd299c8dfb6e14dd7f33faa732c38640 Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 22 Jun 2021 16:01:21 +0100 Subject: [PATCH 02/49] Add correct asset for notifications icon. --- .../Room/notifications.imageset/Contents.json | 23 ++++++++++++++++++ .../notifications.imageset/notifications.png | Bin 0 -> 451 bytes .../notifications@2x.png | Bin 0 -> 704 bytes .../notifications@3x.png | Bin 0 -> 1018 bytes Riot/Generated/Images.swift | 1 + .../RoomInfoListViewController.swift | 2 +- 6 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Riot/Assets/Images.xcassets/Room/notifications.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications.png create mode 100644 Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications@2x.png create mode 100644 Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications@3x.png diff --git a/Riot/Assets/Images.xcassets/Room/notifications.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/notifications.imageset/Contents.json new file mode 100644 index 000000000..66a053751 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/notifications.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "notifications.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "notifications@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "notifications@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications.png b/Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..6b100741dba3ec599789d048f69da4520c94f25a GIT binary patch literal 451 zcmV;!0X+VRP)E^QJJ=(}B;`N{^W{|zuxKM~{TKC+o@ZFMhpm)#BV#Q-n z?=bU0o(+?sGv?xOtpiqILFl!M$rJn*tQYM-zi6U@-NX>lZQE`7oLqwwg!<|tp*=Ui tJuqPnTF2QO0nthPO$1}4=`s8jUH}*JWhs``LO=ij002ovPDHLkV1hh%xxfGb literal 0 HcmV?d00001 diff --git a/Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications@2x.png b/Riot/Assets/Images.xcassets/Room/notifications.imageset/notifications@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..98d86c1524d37baa514d9599393ebd428b05244f GIT binary patch literal 704 zcmV;x0zdtUP)8^F3SBnt+*3bY3xSu;(t%TSncfp!g?Ams*d0&)Yg%%rg% zmS+M??WB?|*@p4AamKb{eb$pDJpnc4Lh!)&>~a8B!|3l@OnffF&FJM(e*q6P;F!rQ zXfyM4`)-J-r)0Ao{XBpN1RSH#=-oU=j4nLkB!nhG(85}F6^Q{ccXa3^pG4o3QeP!+ zrY^%Nx4_@=Zd%4=zsM}0V?B!PAV+vC85o^Bdo)E3G6}>TRW#;N@iy`zXn6eeaD;C&yb*jZ7UcH2toJZpO#uTdo~4(1SV%e$6M^*KoH-vy5HockYyVM!IlG~kpL;` zpfJc!A1IK2Ucic4ploV^vZ)2irWPohN($Iasm%mrAyet!Y*r29x!0`%dL`yFvzCUC zFkT<;70^w|viS)Gqw}e+XCJ#J_wE#k(IT!^_rT-uW%}?K4+`2|i%?o8o7y5z; zS0cRb?@B`^1me_*-|RyMctL7&kS37~p~_WWLv1CR57MqA1ay<3fz;=nRbm8d)cjbDxf>49`X^l1jn5< mO4eQ}sD~#svqo0000-;-mv%k%`z4N6Z?I6>1joq;U+x8mmlB!rEh%EwaglOM-~d)qEIu5x zh(&86mAdoJLtt+py1U-$bjDzb$^^xOL6h#HHDc7B7Uabdh5K4ubG-fG?Fm#&>4Gvb zNwfi+Z;D^nghJ3r{ETjuqDmDc>kKg%%&RqeR5!|%R;1(pSxgMC%*&CWsA1vFUjJ+p zO2&8u$&})g@FH)W(T0hXd$-zyk}xVLt2dMI3aTEWOO#|Z#jMDYaO&=VJ>P*6FeWJb z18q+3grwd6_cj>DNQ&(po~|QfE-Vek$R{sNj&4RG2pN_V-WoJHi()WHVL{W}#}+sO z0<}M9>pU|Qk08$1!7*51E}{zwlC{UB=y^cS!Q_+!3{WhB0=5Q@!fzW!X4%?;Ak&jXXF1qIO-B!<%#I1W$K!cnd*hywN;oCjM_ z5UY1J>VOxdzzb5~1u5`?6nH@jydVW$kOD7AffuB}3sT?(De!_6ctHxhAO&8K0{xC6 zk<&eC2@9ZbQ%_4!d^A`pzMZaoh_LWx1}#Bp8kD}X%Mi_?x1n?I?wD@j4R4?>APzCS zU(wx4oGXH+avE1qCq%8}_o4Q^`h_Ftj~r}44IzL77EOA2BWWQ)`$y*+K)hRr!aSdB zpLLIrPFR?bkfpq0t{@pT@}Ux^@4;&z1Rb+5-4>sIswB;Q)eCx>#l9r-F8^_euX@wSD(u_8!5GMOZ7W!mAJ0m4weJOC_X_5DHFS`UJ*SXRG)ti3{G oF$EYR;N|wm)i2=jcpf{y0nrRFH_^PjYybcN07*qoM6N<$g2(*E8vp Date: Fri, 25 Jun 2021 22:38:31 +0100 Subject: [PATCH 03/49] Add NotificationRepository, ViewModel and ViewController --- Riot/Generated/Storyboards.swift | 5 + .../RoomNotifcationsRepository.swift | 339 ++++++++++++++++++ .../RoomNotificationSettingsCoordinator.swift | 68 ++++ ...mNotificationSettingsCoordinatorType.swift | 29 ++ .../RoomNotificationSettingsViewAction.swift | 26 ++ ...ificationSettingsViewController.storyboard | 52 +++ ...omNotificationSettingsViewController.swift | 274 ++++++++++++++ .../RoomNotificationSettingsViewModel.swift | 75 ++++ ...oomNotificationSettingsViewModelType.swift | 37 ++ .../RoomNotificationSettingsViewState.swift | 30 ++ .../Room/RoomInfo/RoomInfoCoordinator.swift | 22 +- 11 files changed, 956 insertions(+), 1 deletion(-) create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.storyboard create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index c66d40f6a..0b77710ce 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -172,6 +172,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: RoomInfoListViewController.self) } + internal enum RoomNotificationSettingsViewController: StoryboardType { + internal static let storyboardName = "RoomNotificationSettingsViewController" + + internal static let initialScene = InitialSceneType(storyboard: RoomNotificationSettingsViewController.self) + } internal enum SecretsRecoveryWithKeyViewController: StoryboardType { internal static let storyboardName = "SecretsRecoveryWithKeyViewController" diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift new file mode 100644 index 000000000..ad69f504f --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift @@ -0,0 +1,339 @@ +// +// Copyright 2021 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 + +enum RoomNotificationState: CaseIterable { + case all + case mentionsOnly + case mute +} + +protocol RoomNotificationRepository { + typealias Completion = () -> Void + typealias NotificationSettingCallback = (RoomNotificationState) -> Void + + func observeNotificationState(listener: @escaping NotificationSettingCallback) + func update(state: RoomNotificationState, completion: @escaping Completion) + var notificationState: RoomNotificationState { get } +} + +final class RoomNotificationRepositoryImpl: RoomNotificationRepository { + + // MARK: - Properties + + // MARK: Private + + private let room: MXRoom + + private var notificationCenterDidUpdateObserver: NSObjectProtocol? + private var notificationCenterDidFailObserver: NSObjectProtocol? + + private var observers: [ObjectIdentifier] = [] + + // MARK: Public + + var notificationState: RoomNotificationState { + room.notificationState + } + + // MARK: - Setup + + init(room: MXRoom) { + self.room = room + } + + deinit { + observers.forEach(NotificationCenter.default.removeObserver) + } + + // MARK: - Public + + func observeNotificationState(listener: @escaping NotificationSettingCallback) { + + let observer = NotificationCenter.default.addObserver( + forName: NSNotification.Name(rawValue: kMXNotificationCenterDidUpdateRules), + object: nil, + queue: OperationQueue.main) { [weak self] _ in + guard let self = self else { return } + listener(self.room.notificationState) + } + observers += [ObjectIdentifier(observer)] + } + + + func update(state: RoomNotificationState, completion: @escaping Completion) { + switch state { + case .all: + allMessages(completion: completion) + case .mentionsOnly: + mentionsOnly(completion: completion) + case .mute: + mute(completion: completion) + } + } + + // MARK: - Private + + private func mute(completion: @escaping Completion) { + guard !room.isMuted else { + completion() + return + } + + if let rule = room.roomPushRule, room.isMentionsOnly { + removePushRule(rule: rule) { + self.mute(completion: completion) + } + return + } + + guard let rule = room.overridePushRule else { + self.addPushRuleToMute(completion: completion) + return + } + + guard notificationCenterDidUpdateObserver == nil else { + MXLog.debug("[MXRoom+Riot] Request in progress: ignore push rule update") + completion() + return + } + + // if the user defined one, use it + if rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) { + enablePushRule(rule: rule, completion: completion) + } else { + removePushRule(rule: rule) { + self.addPushRuleToMute(completion: completion) + } + } + } + + private func mentionsOnly(completion: @escaping Completion) { + guard !room.isMentionsOnly else { + completion() + return + } + + if let rule = room.overridePushRule, room.isMuted { + removePushRule(rule: rule) { + self.mentionsOnly(completion: completion) + } + return + } + + guard let rule = room.roomPushRule else { + addPushRuleToMentionOnly(completion: completion) + return + } + + guard notificationCenterDidUpdateObserver == nil else { + MXLog.debug("[MXRoom+Riot] Request in progress: ignore push rule update") + completion() + return + } + + // if the user defined one, use it + if rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) { + enablePushRule(rule: rule, completion: completion) + } else { + removePushRule(rule: rule) { + self.addPushRuleToMentionOnly(completion: completion) + } + } + + } + + private func allMessages(completion: @escaping Completion) { + if !room.isMentionsOnly && !room.isMuted { + completion() + return + } + + if let rule = room.overridePushRule, room.isMuted { + removePushRule(rule: rule) { + self.allMessages(completion: completion) + } + return + } + + if let rule = room.roomPushRule, room.isMentionsOnly { + removePushRule(rule: rule, completion: completion) + } + } + + private func addPushRuleToMentionOnly(completion: @escaping Completion) { + handleUpdateCallback(completion) { [weak self] in + guard let self = self else { return true } + return self.room.roomPushRule != nil + } + handleFailureCallback(completion) + + room.mxSession.notificationCenter.addRoomRule( + room.roomId, + notify: false, + sound: false, + highlight: false) + } + + private func addPushRuleToMute(completion: @escaping Completion) { + guard let roomId = room.roomId else { + return + } + handleUpdateCallback(completion) { [weak self] in + guard let self = self else { return true } + return self.room.overridePushRule != nil + } + handleFailureCallback(completion) + + room.mxSession.notificationCenter.addOverrideRule( + withId: roomId, + conditions: [["kind": "event_match", "key": "room_id", "pattern": roomId]], + notify: false, + sound: false, + highlight: false + ) + } + + + private func removePushRule(rule: MXPushRule, completion: @escaping Completion) { + handleUpdateCallback(completion) { [weak self] in + guard let self = self else { return true } + return self.room.mxSession.notificationCenter.rule(byId: rule.ruleId) == nil + } + handleFailureCallback(completion) + + room.mxSession.notificationCenter.removeRule(rule) + } + + private func enablePushRule(rule: MXPushRule, completion: @escaping Completion) { + handleUpdateCallback(completion) { + // No way to check whether this notification concerns the push rule. Consider the change is applied. + return true + } + handleFailureCallback(completion) + + room.mxSession.notificationCenter.enableRule(rule, isEnabled: true) + } + + private func handleUpdateCallback(_ completion: @escaping Completion, releaseCheck: @escaping () -> Bool) { + notificationCenterDidUpdateObserver = NotificationCenter.default.addObserver( + forName: NSNotification.Name(rawValue: kMXNotificationCenterDidUpdateRules), + object: nil, + queue: OperationQueue.main) { [weak self] _ in + guard let self = self else { return } + if releaseCheck() { + self.removeObservers() + completion() + } + } + } + + private func handleFailureCallback(_ completion: @escaping Completion) { + notificationCenterDidFailObserver = NotificationCenter.default.addObserver( + forName: NSNotification.Name(rawValue: kMXNotificationCenterDidFailRulesUpdate), + object: nil, + queue: OperationQueue.main) { [weak self] _ in + guard let self = self else { return } + self.removeObservers() + completion() + } + } + + func removeObservers() { + if let observer = self.notificationCenterDidUpdateObserver { + NotificationCenter.default.removeObserver(observer) + self.notificationCenterDidUpdateObserver = nil + } + + if let observer = self.notificationCenterDidFailObserver { + NotificationCenter.default.removeObserver(observer) + self.notificationCenterDidFailObserver = nil + } + } +} + +// We could move these to their own file and make available in global namespace or move to sdk but they are only used here at the moment +fileprivate extension MXRoom { + + typealias Completion = () -> Void + func getRoomRule(from rules: [Any]) -> MXPushRule? { + guard let pushRules = rules as? [MXPushRule] else { + return nil + } + + return pushRules.first(where: { self.roomId == $0.ruleId }) + } + + var overridePushRule: MXPushRule? { + getRoomRule(from: mxSession.notificationCenter.rules.global.override) + } + + var roomPushRule: MXPushRule? { + getRoomRule(from: mxSession.notificationCenter.rules.global.room) + } + + var notificationState: RoomNotificationState { + if isMuted { + return .mute + } + if isMentionsOnly { + return .mentionsOnly + } + return .all + } + + var isMuted: Bool { + // Check whether an override rule has been defined with the roomm id as rule id. + // This kind of rule is created to mute the room + guard let rule = self.overridePushRule, + rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify), + rule.conditionIsEnabled(kind: .eventMatch, for: roomId) else { + return false + } + return rule.enabled + } + + var isMentionsOnly: Bool { + // Check push rules at room level + guard let rule = roomPushRule else { return false } + return rule.enabled && rule.actionsContains(actionType: MXPushRuleActionTypeDontNotify) + } + +} + +fileprivate extension MXPushRule { + func actionsContains(actionType: MXPushRuleActionType) -> Bool { + guard let actions = actions as? [MXPushRuleAction] else { + return false + } + return actions.contains(where: { $0.actionType == actionType }) + } + + func conditionIsEnabled(kind: MXPushRuleConditionType, for roomId: String) -> Bool { + guard let conditions = conditions as? [MXPushRuleCondition] else { + return false + } + let ruleContainsCondition = conditions.contains { condition in + guard case kind = MXPushRuleConditionType(identifier: condition.kind), + let key = condition.parameters["key"] as? String, + let pattern = condition.parameters["pattern"] as? String + else { return false } + return key == "room_id" && pattern == roomId + } + return ruleContainsCondition && enabled + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift new file mode 100644 index 000000000..dca1ff315 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -0,0 +1,68 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation +import UIKit + +final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordinatorType { + + // MARK: - Properties + + // MARK: Private + private var roomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType + private let roomNotificationSettingsViewController: RoomNotificationSettingsViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: RoomNotificationSettingsCoordinatorDelegate? + + // MARK: - Setup + + init(room: MXRoom) { + let repository = RoomNotificationRepositoryImpl(room: room) + let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository) + let roomNotificationSettingsViewController = RoomNotificationSettingsViewController.instantiate(with: roomNotificationSettingsViewModel) + self.roomNotificationSettingsViewModel = roomNotificationSettingsViewModel + self.roomNotificationSettingsViewController = roomNotificationSettingsViewController + } + + // MARK: - Public methods + + func start() { + self.roomNotificationSettingsViewModel.coordinatorDelegate = self + } + + func toPresentable() -> UIViewController { + return self.roomNotificationSettingsViewController + } +} + +// MARK: - RoomNotificationSettingsViewModelCoordinatorDelegate +extension RoomNotificationSettingsCoordinator: RoomNotificationSettingsViewModelCoordinatorDelegate { + + func roomNotificationSettingsViewModelDidComplete(_ viewModel: RoomNotificationSettingsViewModelType) { + self.delegate?.roomNotificationSettingsCoordinatorDidComplete(self) + } + + func roomNotificationSettingsViewModelDidCancel(_ viewModel: RoomNotificationSettingsViewModelType) { + self.delegate?.roomNotificationSettingsCoordinatorDidCancel(self) + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift new file mode 100644 index 000000000..99e30f617 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift @@ -0,0 +1,29 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +protocol RoomNotificationSettingsCoordinatorDelegate: AnyObject { + func roomNotificationSettingsCoordinatorDidComplete(_ coordinator: RoomNotificationSettingsCoordinatorType) + func roomNotificationSettingsCoordinatorDidCancel(_ coordinator: RoomNotificationSettingsCoordinatorType) +} + +/// `RoomNotificationSettingsCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +protocol RoomNotificationSettingsCoordinatorType: Coordinator, Presentable { + var delegate: RoomNotificationSettingsCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift new file mode 100644 index 000000000..ee6539614 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + 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 +/// RoomNotificationSettingsViewController view actions exposed to view model +enum RoomNotificationSettingsViewAction { + case load + case selectNotificationState(RoomNotificationState) + case save + case cancel +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.storyboard b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.storyboard new file mode 100644 index 000000000..8d49ce878 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.storyboard @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift new file mode 100644 index 000000000..4c5282f6d --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -0,0 +1,274 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +final class RoomNotificationSettingsViewController: UIViewController { + + // MARK: - Properties + private enum Constants { + static let plainStyleCellReuseIdentifier = "plain" + static let linkToAccountSettings = "linkToAccountSettings" + } + // MARK: Outlets + + @IBOutlet private weak var mainTableView: UITableView! + + // MARK: Private + + private var viewModel: RoomNotificationSettingsViewModelType! + private var theme: Theme! + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + private enum RowType { + case plain + } + + private struct Row { + var type: RowType + var setting: RoomNotificationState + var text: String? + var accessoryType: UITableViewCell.AccessoryType = .none + var action: (() -> Void)? + } + + private struct Section { + var header: String? + var rows: [Row] + var footer: NSAttributedString? + } + + private var sections: [Section] = [] { + didSet { + mainTableView.reloadData() + } + } + + private var viewState: RoomNotificationSettingsViewState! + + // MARK: - Setup + + class func instantiate(with viewModel: RoomNotificationSettingsViewModelType) -> RoomNotificationSettingsViewController { + let viewController = StoryboardScene.RoomNotificationSettingsViewController.initialScene.instantiate() + viewController.viewModel = viewModel + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + setupViews() + activityPresenter = ActivityIndicatorPresenter() + errorPresenter = MXKErrorAlertPresentation() + + registerThemeServiceDidChangeThemeNotification() + update(theme: theme) + + viewModel.viewDelegate = self + viewModel.process(viewAction: .load) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return theme.statusBarStyle + } + + // MARK: - Private + + private func update(theme: Theme) { + self.theme = theme + + view.backgroundColor = theme.headerBackgroundColor + mainTableView.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + let doneBarButtonItem = MXKBarButtonItem(title: "Done", style: .plain) { [weak self] in + self?.viewModel.process(viewAction: .save) + } + + let cancelBarButtonItem = MXKBarButtonItem(title: "Cancel", style: .plain) { [weak self] in + self?.viewModel.process(viewAction: .cancel) + } + + if navigationController?.navigationBar.backItem == nil { + navigationItem.leftBarButtonItem = cancelBarButtonItem + } + navigationItem.rightBarButtonItem = doneBarButtonItem + } + + private func render(viewState: RoomNotificationSettingsViewState) { + + if viewState.saving { + activityPresenter.presentActivityIndicator(on: view, animated: true) + } else { + activityPresenter.removeCurrentActivityIndicator(animated: true) + } + self.viewState = viewState + updateSections() + } + + private func updateSections() { + let rows = RoomNotificationState.allCases.map({ (setting) -> Row in + return Row(type: .plain, + setting: setting, + text: setting.title, + accessoryType: viewState.notificationState == setting ? .checkmark : .none, + action: { + self.viewModel.process(viewAction: .selectNotificationState(setting)) + }) + }) + + let formatStr = "You can manage keywords in the %@" + let linkStr = "Account Settings" + let formattedStr = String(format: formatStr, arguments: [linkStr]) + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineHeightMultiple = 1.16 + let footer_0 = NSMutableAttributedString(string: formattedStr, attributes: [ + NSAttributedString.Key.kern: -0.08, + NSAttributedString.Key.paragraphStyle: paragraphStyle, + NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) + ]) + let linkRange = (footer_0.string as NSString).range(of: linkStr) + footer_0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) + let section0 = Section(header: nil, rows: rows, footer: footer_0) + + sections = [ + section0 + ] + } +} + +// MARK - UITableViewDataSource +extension RoomNotificationSettingsViewController: UITableViewDataSource { + + func numberOfSections(in tableView: UITableView) -> Int { + return sections.count + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return sections[section].rows.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let row = sections[indexPath.section].rows[indexPath.row] + + switch row.type { + case .plain: + var cell: UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: Constants.plainStyleCellReuseIdentifier) + if cell == nil { + cell = UITableViewCell(style: .value1, reuseIdentifier: Constants.plainStyleCellReuseIdentifier) + } + cell.textLabel?.font = .systemFont(ofSize: 17) + cell.detailTextLabel?.font = .systemFont(ofSize: 16) + cell.textLabel?.text = row.text + if row.accessoryType == .checkmark { + cell.accessoryView = UIImageView(image: Asset.Images.checkmark.image) + } else { + cell.accessoryView = nil + cell.accessoryType = row.accessoryType + } + cell.textLabel?.textColor = theme.textPrimaryColor + cell.detailTextLabel?.textColor = theme.textSecondaryColor + cell.backgroundColor = theme.backgroundColor + cell.contentView.backgroundColor = .clear + cell.tintColor = theme.tintColor + return cell + } + } + +} + +// MARK - UITableViewDelegate +extension RoomNotificationSettingsViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + cell.backgroundColor = theme.backgroundColor + cell.selectedBackgroundView = UIView() + cell.selectedBackgroundView?.backgroundColor = theme.selectedBackgroundColor + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return sections[section].header + } + + func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + return sections[section].footer?.string + } + +// func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { +// if sections[section].footer == nil { +// return nil +// } +// +// let view = tableView.dequeueReusableHeaderFooterView(RiotTableViewHeaderFooterView.self) +// +// view?.textView.attributedText = sections[section].footer +// view?.update(theme: theme) +// view?.delegate = self +// +// return view +// } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let row = sections[indexPath.section].rows[indexPath.row] + row.action?() + } + +} + +// MARK: - RoomNotificationSettingsViewModelViewDelegate +extension RoomNotificationSettingsViewController: RoomNotificationSettingsViewModelViewDelegate { + + func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewState) { + render(viewState: viewSate) + } +} + +extension RoomNotificationState { + var title: String { + switch self { + case .all: + return "All Messages" + case .mentionsOnly: + return "Mentions and Keywords only" + case .mute: + return "None" + } + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift new file mode 100644 index 000000000..ec59d2b70 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -0,0 +1,75 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + + +final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let roomNotificationRepository: RoomNotificationRepository + private var state: RoomNotificationSettingsViewStateImpl { + willSet { + update(viewState: newValue) + } + } + // MARK: Public + + weak var viewDelegate: RoomNotificationSettingsViewModelViewDelegate? + + weak var coordinatorDelegate: RoomNotificationSettingsViewModelCoordinatorDelegate? + + // MARK: - Setup + + init(roomNotificationRepository: RoomNotificationRepository) { + self.roomNotificationRepository = roomNotificationRepository + self.state = RoomNotificationSettingsViewStateImpl(saving: false, notificationState: roomNotificationRepository.notificationState) + self.roomNotificationRepository.observeNotificationState { state in + self.state.notificationState = state + } + } + + // MARK: - Public + + func process(viewAction: RoomNotificationSettingsViewAction) { + switch viewAction { + case .load: + update(viewState: self.state) + case .selectNotificationState(let state): + self.state.notificationState = state + case .save: + self.state.saving = true + roomNotificationRepository.update(state: state.notificationState) { [weak self] in + guard let self = self else { return } + self.state.saving = false + self.coordinatorDelegate?.roomNotificationSettingsViewModelDidComplete(self) + } + case .cancel: + coordinatorDelegate?.roomNotificationSettingsViewModelDidCancel(self) + } + } + + // MARK: - Private + + private func update(viewState: RoomNotificationSettingsViewState) { + self.viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState) + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift new file mode 100644 index 000000000..8ec944ade --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift @@ -0,0 +1,37 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +protocol RoomNotificationSettingsViewModelViewDelegate: AnyObject { + func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewState) +} + +protocol RoomNotificationSettingsViewModelCoordinatorDelegate: AnyObject { + func roomNotificationSettingsViewModelDidComplete(_ viewModel: RoomNotificationSettingsViewModelType) + func roomNotificationSettingsViewModelDidCancel(_ viewModel: RoomNotificationSettingsViewModelType) +} + +/// Protocol describing the view model used by `RoomNotificationSettingsViewController` +protocol RoomNotificationSettingsViewModelType { + + var viewDelegate: RoomNotificationSettingsViewModelViewDelegate? { get set } + var coordinatorDelegate: RoomNotificationSettingsViewModelCoordinatorDelegate? { get set } + + func process(viewAction: RoomNotificationSettingsViewAction) +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift new file mode 100644 index 000000000..3677004d4 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift @@ -0,0 +1,30 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/NotificationSettings RoomNotificationSettings +/* + 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 + +/// RoomNotificationSettingsViewController view state +struct RoomNotificationSettingsViewStateImpl: RoomNotificationSettingsViewState { + var saving: Bool + var notificationState: RoomNotificationState +} + +protocol RoomNotificationSettingsViewState { + var saving: Bool { get } + var notificationState: RoomNotificationState { get } +} diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index 27252f4d7..5776bccbd 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -137,6 +137,12 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { return coordinator } + private func createRoomNotificationSettingsCoordinator() -> RoomNotificationSettingsCoordinator { + let coordinator = RoomNotificationSettingsCoordinator(room: room) + coordinator.delegate = self + return coordinator + } + private func showRoomDetails(with target: RoomInfoListTarget, animated: Bool) { switch target { case .integrations: @@ -153,7 +159,10 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { } }) case .notifications: - break + let coordinator = createRoomNotificationSettingsCoordinator() + coordinator.start() + self.add(childCoordinator: coordinator) + self.navigationRouter.push(coordinator, animated: true, popCompletion: nil) default: guard let tabIndex = target.tabIndex else { fatalError("No settings tab index for this target.") @@ -189,3 +198,14 @@ extension RoomInfoCoordinator: RoomParticipantsViewControllerDelegate { } } + +extension RoomInfoCoordinator: RoomNotificationSettingsCoordinatorDelegate { + func roomNotificationSettingsCoordinatorDidComplete(_ coordinator: RoomNotificationSettingsCoordinatorType) { + self.navigationRouter.popModule(animated: true) + } + + func roomNotificationSettingsCoordinatorDidCancel(_ coordinator: RoomNotificationSettingsCoordinatorType) { + + } + +} From 0f10ffa7d7838bac6828f8b714b4bb32f7fba6bb Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 10:15:35 +0100 Subject: [PATCH 04/49] Add translations, footer message and room encryption handling --- Riot/Assets/en.lproj/Vector.strings | 11 ++++++ Riot/Generated/Strings.swift | 32 +++++++++++++++++ .../RoomNotifcationsRepository.swift | 1 + .../RoomNotificationSettingsCoordinator.swift | 2 +- ...omNotificationSettingsViewController.swift | 34 ++++++++++-------- .../RoomNotificationSettingsViewModel.swift | 35 ++++++++++++++++--- .../RoomNotificationSettingsViewState.swift | 10 ++++++ 7 files changed, 105 insertions(+), 20 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index d7abe10a2..7f307756d 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -773,6 +773,17 @@ Tap the + to start adding people."; "room_details_copy_room_address" = "Copy Room Address"; "room_details_copy_room_url" = "Copy Room URL"; +// Room Notification Settings +"room_notifs_settings_all_messages" = "All Messages"; +"room_notifs_settings_mentions_and_keywords" = "Mentions and Keywords only"; +"room_notifs_settings_none" = "None"; +"room_notifs_settings_done_action" = "Done"; +"room_notifs_settings_cancel_action" = "Cancel"; +"room_notifs_settings_manage_notifications" = "You can manage notifications in %@"; +"room_notifs_settings_account_settings" = "Account settings"; +"room_notifs_settings_encryed_room_notice" = "\nPlease note that mentions & keyword notifications are not available in encrypted rooms on mobile."; + + // Group Details "group_details_title" = "Community Details"; "group_details_home" = "Home"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index cb5875969..9e4f80e92 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -3022,6 +3022,38 @@ internal enum VectorL10n { internal static var roomNoPrivilegesToCreateGroupCall: String { return VectorL10n.tr("Vector", "room_no_privileges_to_create_group_call") } + /// Account settings + internal static var roomNotifsSettingsAccountSettings: String { + return VectorL10n.tr("Vector", "room_notifs_settings_account_settings") + } + /// All Messages + internal static var roomNotifsSettingsAllMessages: String { + return VectorL10n.tr("Vector", "room_notifs_settings_all_messages") + } + /// Cancel + internal static var roomNotifsSettingsCancelAction: String { + return VectorL10n.tr("Vector", "room_notifs_settings_cancel_action") + } + /// Done + internal static var roomNotifsSettingsDoneAction: String { + return VectorL10n.tr("Vector", "room_notifs_settings_done_action") + } + /// \nPlease note that mentions & keyword notifications are not available in encrypted rooms on mobile. + internal static var roomNotifsSettingsEncryedRoomNotice: String { + return VectorL10n.tr("Vector", "room_notifs_settings_encryed_room_notice") + } + /// You can manage notifications in %@ + internal static func roomNotifsSettingsManageNotifications(_ p1: String) -> String { + return VectorL10n.tr("Vector", "room_notifs_settings_manage_notifications", p1) + } + /// Mentions and Keywords only + internal static var roomNotifsSettingsMentionsAndKeywords: String { + return VectorL10n.tr("Vector", "room_notifs_settings_mentions_and_keywords") + } + /// None + internal static var roomNotifsSettingsNone: String { + return VectorL10n.tr("Vector", "room_notifs_settings_none") + } /// Connectivity to the server has been lost. internal static var roomOfflineNotification: String { return VectorL10n.tr("Vector", "room_offline_notification") diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift index ad69f504f..de7571668 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift @@ -287,6 +287,7 @@ fileprivate extension MXRoom { } var notificationState: RoomNotificationState { + if isMuted { return .mute } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift index dca1ff315..41c9d6c17 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -38,7 +38,7 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin init(room: MXRoom) { let repository = RoomNotificationRepositoryImpl(room: room) - let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository) + let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository, roomEncrypted: room.summary.isEncrypted) let roomNotificationSettingsViewController = RoomNotificationSettingsViewController.instantiate(with: roomNotificationSettingsViewModel) self.roomNotificationSettingsViewModel = roomNotificationSettingsViewModel self.roomNotificationSettingsViewController = roomNotificationSettingsViewController diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 4c5282f6d..3948bbc6b 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -115,11 +115,11 @@ final class RoomNotificationSettingsViewController: UIViewController { } private func setupViews() { - let doneBarButtonItem = MXKBarButtonItem(title: "Done", style: .plain) { [weak self] in + let doneBarButtonItem = MXKBarButtonItem(title: VectorL10n.roomNotifsSettingsDoneAction, style: .plain) { [weak self] in self?.viewModel.process(viewAction: .save) } - let cancelBarButtonItem = MXKBarButtonItem(title: "Cancel", style: .plain) { [weak self] in + let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.roomNotifsSettingsCancelAction, style: .plain) { [weak self] in self?.viewModel.process(viewAction: .cancel) } @@ -141,7 +141,7 @@ final class RoomNotificationSettingsViewController: UIViewController { } private func updateSections() { - let rows = RoomNotificationState.allCases.map({ (setting) -> Row in + let rows = viewState.notificationOptions.map({ (setting) -> Row in return Row(type: .plain, setting: setting, text: setting.title, @@ -151,20 +151,26 @@ final class RoomNotificationSettingsViewController: UIViewController { }) }) - let formatStr = "You can manage keywords in the %@" - let linkStr = "Account Settings" + let linkStr = VectorL10n.roomNotifsSettingsAccountSettings + let formatStr = VectorL10n.roomNotifsSettingsManageNotifications(linkStr) + let formattedStr = String(format: formatStr, arguments: [linkStr]) - + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1.16 - let footer_0 = NSMutableAttributedString(string: formattedStr, attributes: [ + let paragraphAttributes: [NSAttributedString.Key: Any] = [ NSAttributedString.Key.kern: -0.08, NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) - ]) - let linkRange = (footer_0.string as NSString).range(of: linkStr) - footer_0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) - let section0 = Section(header: nil, rows: rows, footer: footer_0) + ] + let footer0 = NSMutableAttributedString(string: formattedStr, attributes: paragraphAttributes) + let linkRange = (footer0.string as NSString).range(of: linkStr) + footer0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) + + if viewState.roomEncrypted { + footer0.append(NSAttributedString(string: VectorL10n.roomNotifsSettingsEncryedRoomNotice, attributes: paragraphAttributes)) + } + let section0 = Section(header: nil, rows: rows, footer: footer0) sections = [ section0 @@ -264,11 +270,11 @@ extension RoomNotificationState { var title: String { switch self { case .all: - return "All Messages" + return VectorL10n.roomNotifsSettingsAllMessages case .mentionsOnly: - return "Mentions and Keywords only" + return VectorL10n.roomNotifsSettingsMentionsAndKeywords case .mute: - return "None" + return VectorL10n.roomNotifsSettingsNone } } } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index ec59d2b70..00e90dbd0 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -39,11 +39,15 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Setup - init(roomNotificationRepository: RoomNotificationRepository) { + init(roomNotificationRepository: RoomNotificationRepository, roomEncrypted: Bool) { self.roomNotificationRepository = roomNotificationRepository - self.state = RoomNotificationSettingsViewStateImpl(saving: false, notificationState: roomNotificationRepository.notificationState) - self.roomNotificationRepository.observeNotificationState { state in - self.state.notificationState = state + + let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationRepository.notificationState) + self.state = RoomNotificationSettingsViewStateImpl(roomEncrypted: roomEncrypted, saving: false, notificationState: notificationState) + self.roomNotificationRepository.observeNotificationState { [weak self] state in + guard let self = self else { return } + + self.state.notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: state) } } @@ -57,7 +61,8 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel self.state.notificationState = state case .save: self.state.saving = true - roomNotificationRepository.update(state: state.notificationState) { [weak self] in + let updateState = Self.mapNotificationStateOnUpdate(encrypted: self.state.roomEncrypted, state: state.notificationState) + roomNotificationRepository.update(state: updateState) { [weak self] in guard let self = self else { return } self.state.saving = false self.coordinatorDelegate?.roomNotificationSettingsViewModelDidComplete(self) @@ -69,7 +74,27 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Private + private static func mapNotificationStateOnRead(encrypted: Bool, state: RoomNotificationState) -> RoomNotificationState { + if encrypted, case .mentionsOnly = state { + // Notifications not supported on encrypted rooms, map mentionsOnly to mute on read + return .mute + } else { + return state + } + } + + private static func mapNotificationStateOnUpdate(encrypted: Bool, state: RoomNotificationState) -> RoomNotificationState { + if encrypted, case .mute = state { + // Notifications not supported on encrypted rooms, map mute to mentions only on update + return .mentionsOnly + } else { + return state + } + } + private func update(viewState: RoomNotificationSettingsViewState) { self.viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState) } + + } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift index 3677004d4..782a1ad08 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift @@ -20,11 +20,21 @@ import Foundation /// RoomNotificationSettingsViewController view state struct RoomNotificationSettingsViewStateImpl: RoomNotificationSettingsViewState { + let roomEncrypted: Bool var saving: Bool var notificationState: RoomNotificationState + var notificationOptions: [RoomNotificationState] { + if roomEncrypted { + return [.all, .mute] + } else { + return RoomNotificationState.allCases + } + } } protocol RoomNotificationSettingsViewState { var saving: Bool { get } + var roomEncrypted: Bool { get } + var notificationOptions: [RoomNotificationState] { get } var notificationState: RoomNotificationState { get } } From 8b52cda3f798720296c36d74f914e738c531cf5a Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 10:30:44 +0100 Subject: [PATCH 05/49] Fix typo and don't show link to account settings until we have global notification settings. --- Podfile | 4 ++-- Riot/Assets/en.lproj/Vector.strings | 2 +- Riot/Generated/Strings.swift | 6 ++--- ...omNotificationSettingsViewController.swift | 22 +++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Podfile b/Podfile index 8c1ab9284..9bfab4274 100644 --- a/Podfile +++ b/Podfile @@ -11,8 +11,8 @@ use_frameworks! # - `{ {kit spec hash} => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for each repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixKitVersion = '= 0.15.0' -# $matrixKitVersion = :local +# $matrixKitVersion = '= 0.15.0' + $matrixKitVersion = :local # $matrixKitVersion = {'develop' => 'develop'} ######################################## diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 7f307756d..f9b75b276 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -781,7 +781,7 @@ Tap the + to start adding people."; "room_notifs_settings_cancel_action" = "Cancel"; "room_notifs_settings_manage_notifications" = "You can manage notifications in %@"; "room_notifs_settings_account_settings" = "Account settings"; -"room_notifs_settings_encryed_room_notice" = "\nPlease note that mentions & keyword notifications are not available in encrypted rooms on mobile."; +"room_notifs_settings_encrypted_room_notice" = "Please note that mentions & keyword notifications are not available in encrypted rooms on mobile."; // Group Details diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 9e4f80e92..e192f4340 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -3038,9 +3038,9 @@ internal enum VectorL10n { internal static var roomNotifsSettingsDoneAction: String { return VectorL10n.tr("Vector", "room_notifs_settings_done_action") } - /// \nPlease note that mentions & keyword notifications are not available in encrypted rooms on mobile. - internal static var roomNotifsSettingsEncryedRoomNotice: String { - return VectorL10n.tr("Vector", "room_notifs_settings_encryed_room_notice") + /// Please note that mentions & keyword notifications are not available in encrypted rooms on mobile. + internal static var roomNotifsSettingsEncryptedRoomNotice: String { + return VectorL10n.tr("Vector", "room_notifs_settings_encrypted_room_notice") } /// You can manage notifications in %@ internal static func roomNotifsSettingsManageNotifications(_ p1: String) -> String { diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 3948bbc6b..645bf9a3f 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -150,11 +150,6 @@ final class RoomNotificationSettingsViewController: UIViewController { self.viewModel.process(viewAction: .selectNotificationState(setting)) }) }) - - let linkStr = VectorL10n.roomNotifsSettingsAccountSettings - let formatStr = VectorL10n.roomNotifsSettingsManageNotifications(linkStr) - - let formattedStr = String(format: formatStr, arguments: [linkStr]) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1.16 @@ -163,15 +158,20 @@ final class RoomNotificationSettingsViewController: UIViewController { NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) ] - let footer0 = NSMutableAttributedString(string: formattedStr, attributes: paragraphAttributes) - let linkRange = (footer0.string as NSString).range(of: linkStr) - footer0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) - + + // Don't include link until global settings in place +// let linkStr = VectorL10n.roomNotifsSettingsAccountSettings +// let formatStr = VectorL10n.roomNotifsSettingsManageNotifications(linkStr) +// +// let formattedStr = String(format: formatStr, arguments: [linkStr]) +// let footer0 = NSMutableAttributedString(string: formattedStr, attributes: paragraphAttributes) +// let linkRange = (footer0.string as NSString).range(of: linkStr) +// footer0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) + var footer0: NSAttributedString? if viewState.roomEncrypted { - footer0.append(NSAttributedString(string: VectorL10n.roomNotifsSettingsEncryedRoomNotice, attributes: paragraphAttributes)) + footer0 = NSAttributedString(string: VectorL10n.roomNotifsSettingsEncryptedRoomNotice, attributes: paragraphAttributes) } let section0 = Section(header: nil, rows: rows, footer: footer0) - sections = [ section0 ] From 9c42cb1aebf05c7e6dd2a5110985ad3b7a3fb0bd Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 10:39:27 +0100 Subject: [PATCH 06/49] Fix naming of Repository -> Service, Impl -> Type --- .../RoomNotifcationsRepository.swift | 4 ++-- .../RoomNotificationSettingsCoordinator.swift | 2 +- .../RoomNotificationSettingsViewController.swift | 6 +++--- .../RoomNotificationSettingsViewModel.swift | 10 +++++----- .../RoomNotificationSettingsViewModelType.swift | 2 +- ...ift => RoomNotificationSettingsViewStateType.swift} | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) rename Riot/Modules/Room/NotificationSettings/{RoomNotificationSettingsViewState.swift => RoomNotificationSettingsViewStateType.swift} (90%) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift index de7571668..615a151cd 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift @@ -22,7 +22,7 @@ enum RoomNotificationState: CaseIterable { case mute } -protocol RoomNotificationRepository { +protocol RoomNotificationSettingsServiceType { typealias Completion = () -> Void typealias NotificationSettingCallback = (RoomNotificationState) -> Void @@ -31,7 +31,7 @@ protocol RoomNotificationRepository { var notificationState: RoomNotificationState { get } } -final class RoomNotificationRepositoryImpl: RoomNotificationRepository { +final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType { // MARK: - Properties diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift index 41c9d6c17..a377dd2b0 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -37,7 +37,7 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin // MARK: - Setup init(room: MXRoom) { - let repository = RoomNotificationRepositoryImpl(room: room) + let repository = RoomNotificationSettingsService(room: room) let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository, roomEncrypted: room.summary.isEncrypted) let roomNotificationSettingsViewController = RoomNotificationSettingsViewController.instantiate(with: roomNotificationSettingsViewModel) self.roomNotificationSettingsViewModel = roomNotificationSettingsViewModel diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 645bf9a3f..cf2bb35a0 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -60,7 +60,7 @@ final class RoomNotificationSettingsViewController: UIViewController { } } - private var viewState: RoomNotificationSettingsViewState! + private var viewState: RoomNotificationSettingsViewStateType! // MARK: - Setup @@ -129,7 +129,7 @@ final class RoomNotificationSettingsViewController: UIViewController { navigationItem.rightBarButtonItem = doneBarButtonItem } - private func render(viewState: RoomNotificationSettingsViewState) { + private func render(viewState: RoomNotificationSettingsViewStateType) { if viewState.saving { activityPresenter.presentActivityIndicator(on: view, animated: true) @@ -261,7 +261,7 @@ extension RoomNotificationSettingsViewController: UITableViewDelegate { // MARK: - RoomNotificationSettingsViewModelViewDelegate extension RoomNotificationSettingsViewController: RoomNotificationSettingsViewModelViewDelegate { - func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewState) { + func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewStateType) { render(viewState: viewSate) } } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index 00e90dbd0..961770b33 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -25,8 +25,8 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: Private - private let roomNotificationRepository: RoomNotificationRepository - private var state: RoomNotificationSettingsViewStateImpl { + private let roomNotificationRepository: RoomNotificationSettingsServiceType + private var state: RoomNotificationSettingsViewState { willSet { update(viewState: newValue) } @@ -39,11 +39,11 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Setup - init(roomNotificationRepository: RoomNotificationRepository, roomEncrypted: Bool) { + init(roomNotificationRepository: RoomNotificationSettingsServiceType, roomEncrypted: Bool) { self.roomNotificationRepository = roomNotificationRepository let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationRepository.notificationState) - self.state = RoomNotificationSettingsViewStateImpl(roomEncrypted: roomEncrypted, saving: false, notificationState: notificationState) + self.state = RoomNotificationSettingsViewState(roomEncrypted: roomEncrypted, saving: false, notificationState: notificationState) self.roomNotificationRepository.observeNotificationState { [weak self] state in guard let self = self else { return } @@ -92,7 +92,7 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel } } - private func update(viewState: RoomNotificationSettingsViewState) { + private func update(viewState: RoomNotificationSettingsViewStateType) { self.viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState) } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift index 8ec944ade..d6f470e16 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift @@ -19,7 +19,7 @@ import Foundation protocol RoomNotificationSettingsViewModelViewDelegate: AnyObject { - func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewState) + func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewStateType) } protocol RoomNotificationSettingsViewModelCoordinatorDelegate: AnyObject { diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift similarity index 90% rename from Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift rename to Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift index 782a1ad08..01bc56261 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewState.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift @@ -19,7 +19,7 @@ import Foundation /// RoomNotificationSettingsViewController view state -struct RoomNotificationSettingsViewStateImpl: RoomNotificationSettingsViewState { +struct RoomNotificationSettingsViewState: RoomNotificationSettingsViewStateType { let roomEncrypted: Bool var saving: Bool var notificationState: RoomNotificationState @@ -32,7 +32,7 @@ struct RoomNotificationSettingsViewStateImpl: RoomNotificationSettingsViewState } } -protocol RoomNotificationSettingsViewState { +protocol RoomNotificationSettingsViewStateType { var saving: Bool { get } var roomEncrypted: Bool { get } var notificationOptions: [RoomNotificationState] { get } From 28e15a371d5dd8adfcba315e6f26f4a680e66c96 Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 10:42:30 +0100 Subject: [PATCH 07/49] Remove Podfile change --- Podfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Podfile b/Podfile index 9bfab4274..8079b3e49 100644 --- a/Podfile +++ b/Podfile @@ -11,8 +11,8 @@ use_frameworks! # - `{ {kit spec hash} => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for each repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -# $matrixKitVersion = '= 0.15.0' - $matrixKitVersion = :local +$matrixKitVersion = '= 0.15.0' +# $matrixKitVersion = :local # $matrixKitVersion = {'develop' => 'develop'} ######################################## @@ -101,7 +101,7 @@ post_install do |installer| # Plus the app does not enable it config.build_settings['ENABLE_BITCODE'] = 'NO' - # Make fastlane(xcodebuild) happy by preventing it from building for arm64 simulator + # Make fastlane(xcodebuild) happy by preventing it from building for arm64 simulator config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" # Force ReadMoreTextView to use Swift 5.2 version (as there is no code changes to perform) @@ -109,7 +109,7 @@ post_install do |installer| config.build_settings['SWIFT_VERSION'] = '5.2' end - # Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods + # Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' end end From 1f316be7fa3ecfe5f5049d24a7616fd2a0c1cc9e Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 10:48:12 +0100 Subject: [PATCH 08/49] Remove Podfile change --- Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Podfile b/Podfile index 8079b3e49..8c1ab9284 100644 --- a/Podfile +++ b/Podfile @@ -101,7 +101,7 @@ post_install do |installer| # Plus the app does not enable it config.build_settings['ENABLE_BITCODE'] = 'NO' - # Make fastlane(xcodebuild) happy by preventing it from building for arm64 simulator + # Make fastlane(xcodebuild) happy by preventing it from building for arm64 simulator config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" # Force ReadMoreTextView to use Swift 5.2 version (as there is no code changes to perform) @@ -109,7 +109,7 @@ post_install do |installer| config.build_settings['SWIFT_VERSION'] = '5.2' end - # Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods + # Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' end end From ce5d53822becb79c1c31acef39d2add28091cf47 Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 16:16:54 +0100 Subject: [PATCH 09/49] Update theming and footer --- .../RoomNotificationSettingsFooter.swift | 61 +++++++++ .../RoomNotificationSettingsFooter.xib | 39 ++++++ ...omNotificationSettingsViewController.swift | 116 ++++-------------- .../RoomNotificationsSettingsCell.swift | 61 +++++++++ 4 files changed, 186 insertions(+), 91 deletions(-) create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.xib create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift new file mode 100644 index 000000000..4ccf9a124 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift @@ -0,0 +1,61 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import Reusable + +class RoomNotificationSettingsFooter: UITableViewHeaderFooterView { + + struct State { + let showEncryptedNotice: Bool + let showAccountLink: Bool + } + + @IBOutlet weak var label: UILabel! + + func update(footerState: State) { + +// let paragraphStyle = NSMutableParagraphStyle() +// paragraphStyle.lineHeightMultiple = 1.16 +// let paragraphAttributes: [NSAttributedString.Key: Any] = [ +// NSAttributedString.Key.kern: -0.08, +// NSAttributedString.Key.paragraphStyle: paragraphStyle, +// NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) +// ] + + // Don't include link until global settings in place +// let linkStr = VectorL10n.roomNotifsSettingsAccountSettings +// let formatStr = VectorL10n.roomNotifsSettingsManageNotifications(linkStr) +// +// let formattedStr = String(format: formatStr, arguments: [linkStr]) +// let footer0 = NSMutableAttributedString(string: formattedStr, attributes: paragraphAttributes) +// let linkRange = (footer0.string as NSString).range(of: linkStr) +// footer0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) + if footerState.showEncryptedNotice { + label.text = VectorL10n.roomNotifsSettingsEncryptedRoomNotice + } + } +} + + +extension RoomNotificationSettingsFooter: NibReusable {} +extension RoomNotificationSettingsFooter: Themable { + + func update(theme: Theme) { + contentView.backgroundColor = theme.headerBackgroundColor + label.textColor = theme.headerTextSecondaryColor + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.xib b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.xib new file mode 100644 index 000000000..48895dca9 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.xib @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index cf2bb35a0..31f441115 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -36,22 +36,14 @@ final class RoomNotificationSettingsViewController: UIViewController { private var errorPresenter: MXKErrorPresentation! private var activityPresenter: ActivityIndicatorPresenter! - private enum RowType { - case plain - } - private struct Row { - var type: RowType - var setting: RoomNotificationState - var text: String? - var accessoryType: UITableViewCell.AccessoryType = .none + var cellState: RoomNotificationSettingsCell.State var action: (() -> Void)? } private struct Section { - var header: String? var rows: [Row] - var footer: NSAttributedString? + var footerState: RoomNotificationSettingsFooter.State } private var sections: [Section] = [] { @@ -104,6 +96,7 @@ final class RoomNotificationSettingsViewController: UIViewController { if let navigationBar = navigationController?.navigationBar { theme.applyStyle(onNavigationBar: navigationBar) } + mainTableView.reloadData() } private func registerThemeServiceDidChangeThemeNotification() { @@ -127,6 +120,10 @@ final class RoomNotificationSettingsViewController: UIViewController { navigationItem.leftBarButtonItem = cancelBarButtonItem } navigationItem.rightBarButtonItem = doneBarButtonItem + mainTableView.register(cellType: RoomNotificationSettingsCell.self) + mainTableView.register(headerFooterViewType: RoomNotificationSettingsFooter.self) + mainTableView.sectionFooterHeight = UITableView.automaticDimension + mainTableView.estimatedSectionFooterHeight = 50 } private func render(viewState: RoomNotificationSettingsViewStateType) { @@ -142,36 +139,14 @@ final class RoomNotificationSettingsViewController: UIViewController { private func updateSections() { let rows = viewState.notificationOptions.map({ (setting) -> Row in - return Row(type: .plain, - setting: setting, - text: setting.title, - accessoryType: viewState.notificationState == setting ? .checkmark : .none, + let cellState = RoomNotificationSettingsCell.State(notificicationState: setting, selected: viewState.notificationState == setting) + return Row(cellState: cellState, action: { self.viewModel.process(viewAction: .selectNotificationState(setting)) }) }) - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineHeightMultiple = 1.16 - let paragraphAttributes: [NSAttributedString.Key: Any] = [ - NSAttributedString.Key.kern: -0.08, - NSAttributedString.Key.paragraphStyle: paragraphStyle, - NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) - ] - - // Don't include link until global settings in place -// let linkStr = VectorL10n.roomNotifsSettingsAccountSettings -// let formatStr = VectorL10n.roomNotifsSettingsManageNotifications(linkStr) -// -// let formattedStr = String(format: formatStr, arguments: [linkStr]) -// let footer0 = NSMutableAttributedString(string: formattedStr, attributes: paragraphAttributes) -// let linkRange = (footer0.string as NSString).range(of: linkStr) -// footer0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) - var footer0: NSAttributedString? - if viewState.roomEncrypted { - footer0 = NSAttributedString(string: VectorL10n.roomNotifsSettingsEncryptedRoomNotice, attributes: paragraphAttributes) - } - let section0 = Section(header: nil, rows: rows, footer: footer0) + let footerState = RoomNotificationSettingsFooter.State(showEncryptedNotice: viewState.roomEncrypted, showAccountLink: false) + let section0 = Section(rows: rows, footerState: footerState) sections = [ section0 ] @@ -191,29 +166,15 @@ extension RoomNotificationSettingsViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let row = sections[indexPath.section].rows[indexPath.row] + let cell: RoomNotificationSettingsCell = tableView.dequeueReusableCell(for: indexPath) + cell.update(state: row.cellState) + cell.update(theme: theme) + return cell + } + + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - switch row.type { - case .plain: - var cell: UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: Constants.plainStyleCellReuseIdentifier) - if cell == nil { - cell = UITableViewCell(style: .value1, reuseIdentifier: Constants.plainStyleCellReuseIdentifier) - } - cell.textLabel?.font = .systemFont(ofSize: 17) - cell.detailTextLabel?.font = .systemFont(ofSize: 16) - cell.textLabel?.text = row.text - if row.accessoryType == .checkmark { - cell.accessoryView = UIImageView(image: Asset.Images.checkmark.image) - } else { - cell.accessoryView = nil - cell.accessoryType = row.accessoryType - } - cell.textLabel?.textColor = theme.textPrimaryColor - cell.detailTextLabel?.textColor = theme.textSecondaryColor - cell.backgroundColor = theme.backgroundColor - cell.contentView.backgroundColor = .clear - cell.tintColor = theme.tintColor - return cell - } + return UITableView.automaticDimension } } @@ -227,28 +188,14 @@ extension RoomNotificationSettingsViewController: UITableViewDelegate { cell.selectedBackgroundView?.backgroundColor = theme.selectedBackgroundColor } - func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return sections[section].header + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + guard let footerView: RoomNotificationSettingsFooter = tableView.dequeueReusableHeaderFooterView() else { return nil } + let footerState = sections[section].footerState + footerView.update(footerState: footerState) + footerView.update(theme: theme) + return footerView } - func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - return sections[section].footer?.string - } - -// func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { -// if sections[section].footer == nil { -// return nil -// } -// -// let view = tableView.dequeueReusableHeaderFooterView(RiotTableViewHeaderFooterView.self) -// -// view?.textView.attributedText = sections[section].footer -// view?.update(theme: theme) -// view?.delegate = self -// -// return view -// } - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) @@ -265,16 +212,3 @@ extension RoomNotificationSettingsViewController: RoomNotificationSettingsViewMo render(viewState: viewSate) } } - -extension RoomNotificationState { - var title: String { - switch self { - case .all: - return VectorL10n.roomNotifsSettingsAllMessages - case .mentionsOnly: - return VectorL10n.roomNotifsSettingsMentionsAndKeywords - case .mute: - return VectorL10n.roomNotifsSettingsNone - } - } -} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift new file mode 100644 index 000000000..831c1ba73 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift @@ -0,0 +1,61 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import UIKit +import Reusable + +class RoomNotificationSettingsCell: UITableViewCell { + + struct State { + let notificicationState: RoomNotificationState + let selected: Bool + } + + func update(state: State) { + textLabel?.font = .systemFont(ofSize: 17) + detailTextLabel?.font = .systemFont(ofSize: 16) + textLabel?.text = state.notificicationState.title + if state.selected { + accessoryView = UIImageView(image: Asset.Images.checkmark.image) + } else { + accessoryView = nil + } + } +} + +extension RoomNotificationSettingsCell: Reusable {} + +extension RoomNotificationSettingsCell: Themable { + func update(theme: Theme) { + textLabel?.textColor = theme.textPrimaryColor + detailTextLabel?.textColor = theme.textSecondaryColor + backgroundColor = theme.backgroundColor + contentView.backgroundColor = .clear + tintColor = theme.tintColor + } +} + +fileprivate extension RoomNotificationState { + var title: String { + switch self { + case .all: + return VectorL10n.roomNotifsSettingsAllMessages + case .mentionsOnly: + return VectorL10n.roomNotifsSettingsMentionsAndKeywords + case .mute: + return VectorL10n.roomNotifsSettingsNone + } + } +} From 62abdf444f63ee02bd4f6fd04639d82c40630ced Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 2 Jul 2021 17:38:12 +0100 Subject: [PATCH 10/49] Use different title for scan button for self verification Because it's not 'their' device, it's your own device. --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++++ .../KeyVerificationVerifyByScanningViewController.swift | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 234022cf2..a0929d888 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1375,6 +1375,7 @@ Tap the + to start adding people."; "key_verification_verify_qr_code_information_other_device" = "Scan the code below to verify:"; "key_verification_verify_qr_code_emoji_information" = "Verify by comparing unique emoji."; "key_verification_verify_qr_code_scan_code_action" = "Scan their code"; +"key_verification_verify_qr_code_scan_code_other_device_action" = "Scan with this device"; "key_verification_verify_qr_code_cannot_scan_action" = "Can't scan?"; "key_verification_verify_qr_code_start_emoji_action" = "Verify by emoji"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index ba05c0233..34091e1d9 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2014,6 +2014,10 @@ internal enum VectorL10n { internal static var keyVerificationVerifyQrCodeScanCodeAction: String { return VectorL10n.tr("Vector", "key_verification_verify_qr_code_scan_code_action") } + /// Scan with this device + internal static var keyVerificationVerifyQrCodeScanCodeOtherDeviceAction: String { + return VectorL10n.tr("Vector", "key_verification_verify_qr_code_scan_code_other_device_action") + } /// QR code has been successfully validated. internal static var keyVerificationVerifyQrCodeScanOtherCodeSuccessMessage: String { return VectorL10n.tr("Vector", "key_verification_verify_qr_code_scan_other_code_success_message") diff --git a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift index fc01906da..cb8bc27f6 100644 --- a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift +++ b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift @@ -143,7 +143,9 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController { self.titleLabel.text = VectorL10n.keyVerificationVerifyQrCodeTitle self.informationLabel.text = VectorL10n.keyVerificationVerifyQrCodeInformation - self.scanCodeButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeScanCodeAction, for: .normal) + // Hide until we have the type of the verification request + self.scanCodeButton.isHidden = true + self.cannotScanButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeCannotScanAction, for: .normal) } @@ -195,10 +197,13 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController { switch viewData.verificationKind { case .user: informationText = VectorL10n.keyVerificationVerifyQrCodeInformation + self.scanCodeButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeScanCodeAction, for: .normal) default: informationText = VectorL10n.keyVerificationVerifyQrCodeInformationOtherDevice + self.scanCodeButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeScanCodeOtherDeviceAction, for: .normal) } + self.scanCodeButton.isHidden = false self.informationLabel.text = informationText } } From 1d7f6ad1275701c2e459eb8d5edb4eebd02444f2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 2 Jul 2021 17:41:40 +0100 Subject: [PATCH 11/49] changelog --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2e72d9c8e..42179b701 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,7 @@ Changes to be released in next version * 🐛 Bugfix - * + * Use different title for scan button for self verification (#4525) ⚠️ API Changes * From 3f7d45100c688acaa00baf5e5a46e79270337d01 Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 2 Jul 2021 20:19:46 +0100 Subject: [PATCH 12/49] Add entry points at long press on home view and slide on recents. --- .../Contents.json | 23 ++++ .../room_action_notification_muted.png | Bin 0 -> 508 bytes .../room_action_notification_muted@2x.png | Bin 0 -> 846 bytes .../room_action_notification_muted@3x.png | Bin 0 -> 1209 bytes Riot/Generated/Images.swift | 1 + .../Common/Recents/RecentsViewController.h | 4 +- .../Common/Recents/RecentsViewController.m | 60 +++++------ Riot/Modules/Home/HomeViewController.m | 6 +- ...ry.swift => RoomNotifcationsService.swift} | 0 ...mNotificationSettingsBridgePresenter.swift | 100 ++++++++++++++++++ ...omNotificationSettingsViewController.swift | 1 - 11 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/Contents.json create mode 100644 Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/room_action_notification_muted.png create mode 100644 Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/room_action_notification_muted@2x.png create mode 100644 Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/room_action_notification_muted@3x.png rename Riot/Modules/Room/NotificationSettings/{RoomNotifcationsRepository.swift => RoomNotifcationsService.swift} (100%) create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsBridgePresenter.swift diff --git a/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/Contents.json new file mode 100644 index 000000000..f60c4497c --- /dev/null +++ b/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "room_action_notification_muted.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "room_action_notification_muted@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "room_action_notification_muted@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/room_action_notification_muted.png b/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/room_action_notification_muted.imageset/room_action_notification_muted.png new file mode 100644 index 0000000000000000000000000000000000000000..02ca4c76f6fa6f8180d7642294aa227f1ab0e784 GIT binary patch literal 508 zcmVQiAC~9@TO7x*JF|KRdYz za%Pg5B)j*^N$#EmKub!$4to+0cZbTKc&j%Ja%}^px9Cn@SMM*L--oh*ty~R~c@Q~W zbU5%kU{FU;UFj_^fhZOhnENhAB@IMxf%@b^h-P3O9Y4S)VA#o-8vx_I^LFzQiX4b` zGf<3+aMB+q8nRZXYz16EHJZ--dnj@c$?9abyy2V;ZABE|l{jvV!R8=R>;z$*aB|uj zDTTK-00-8$UrXyl7uPRydqjn}rV(g>+IJ&8nFMj5K?7Lsun>Y!-vvN}>uiAhFa2$3GbR}XXZ$KOsW{?iHp(WUg6vs;XLhQiYNyXwu)~Nq= zFk227XBSXG%q+4^ykwj(_y^fim<$NNXxxc&U&r%AoE-Hi5ZXF0t!v&-v>|3%Iq#!o y&XWM*tTon)=^l2?fDdBzmopuSLg@8lL=u=t&Ug#0000r0<-~^NtY&W1i!O98fPB3neb^j`%N`Vv58_}({P9L6 zhZ9@tNDYbq$2+JtYH(h#%>o?>y7M^RV>}E%pM?MzhKDal&;Y(!5WYSb3n4#bYUa!d zyn_qDI8Dwu=;LGKr&rVXBQ$^&ozRNJ>RT*=dXWIm_~1>aJ%k#tvXd?)1ju*c;lUTs zgjH2=D6tT~`7;`pIv?Uy6}09=r#){nCvXip(fv?m1X3<$Gv`#CFl2}%Od^;hbAP*}mB1Y`WUPJOiq2p&|{F(iSjbPqI86Yyk9sh$}L zt>+QtIiO5)i7g8d=D%VKu_Hh@lCUR0IFPU_KvzoBCxviGD=c~ zE~qJyD?sT&zDF51N1acpA(5E_lqnMubDi5nV@_luu=UOp8j;8jA>53BT|iMHo1Mm- z4#?#IAFiK*V;Ez-Y+?CuQci5Spw9lpP6-gY5=I56aZKz4g%$3ej8xKwIub?&CO5Mf z2Xf)sK}ljt7J~w+5@vsmGFF(=b+B+z1@C2n@0O$hH2`Cf51O+B28yL#h9VHhwARCasg;=Uy zLvlcIkSxhkfaflkoTbFh<5wS+WCJ|&j0x=Sh9qg%VeB%3%du`8H#+ddxg{t`jwi5I zN#xf0RU)o`nr?gtha`J{W)UkZz{D&F=*k1yPA_mZl#_Ey(C%UDOuj|8G6>lG^x^Fy zI3PJZnL}W|?n&zKzZi!g3Hu-DOu`*GgkZ4n`=GS}PIk`La*`sf2`Bs1WgrNu)lOa} z7n1T$$N(lLAOHq};wc%JOROXct4Tvj3LAlQyPrp@M5V+%@#-M7)EBob470ZW|o<$mjEKnEE9C{q;6ORym+ z>o$y6sFjMqE~T|{n3vF;nOrchlg2tSV;Afb;W$4_4qMCM7#x;pDoLKbL_AeV%7Tc{C2JxG#@s!8$$9Fqm0qqFt6LKVF<4d-F3k=`@ zJHyhwNs`xkwk~pw1j(j#{-HeHB-MIWdf9~qWoJn7s@#Vpgvvw1DT=>Slxk0_axGnw zrD9fG5W*~IQo5v>nj zB1S=yS3yMRlDrEdLY5SSAR<&r!3ZKkloXU8A~Z?C2_iz06r>;`6iLAfB0`W9v>+mY z$;t5XI(!Qwf-gxUBZ%-bGC5+DEotNg5z3NMb4kS~4i8%A7FLWI;c|&`pF$Co>>p3~ zmP5E)qTHvDAOv*2vP%`$lC+DMoJz@-zd>NQDsEa4bS)==0C5#b$`N!!P6PpCJCc+l zXz!rCgf-rVz~vCOBWY*^Wl=*nmFTXF4**+{lq+adiqtS{NXji@SW8{3kS`S*#V!9< zgu|AAM*>BXeETM&N&7$LSJFawo$|E_MUs5`DWgfd-WbL?k zh`>XVpx2A~AH4{o=Y(*P#z0R}$c3G9hA}u|h@`WdH{*G$q^WO10yu~*(H}XGQ6)d` z$dQEQ=JcCJ_P`Z~kR;B +@interface RecentsViewController () { // Tell whether a recents refresh is pending (suspended during editing mode). BOOL isRefreshPending; @@ -74,6 +74,8 @@ @property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController; +@property (nonatomic, strong) RoomNotificationSettingsCoordinatorBridgePresenter *roomNotificationSettingsCoordinatorBridgePresenter; + @end @implementation RecentsViewController @@ -1031,12 +1033,12 @@ UIContextualAction *muteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:title handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { - [self muteEditedRoomNotifications:!isMuted]; + [self changeEditedRoomNotificationSettings]; completionHandler(YES); }]; muteAction.backgroundColor = actionBackgroundColor; - UIImage *notificationImage = [UIImage imageNamed:@"room_action_notification"]; + UIImage *notificationImage = isMuted ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; notificationImage = [notificationImage vc_tintedImageUsingColor:isMuted ? unselectedColor : selectedColor]; muteAction.image = [notificationImage vc_notRenderedImage]; @@ -1298,7 +1300,7 @@ } } -- (void)muteEditedRoomNotifications:(BOOL)mute +- (void)changeEditedRoomNotificationSettings { if (editedRoomId) { @@ -1306,36 +1308,22 @@ MXRoom *room = [self.mainSession roomWithRoomId:editedRoomId]; if (room) { - [self startActivityIndicator]; - - if (mute) - { - [room mentionsOnly:^{ - - [self stopActivityIndicator]; - - // Leave editing mode - [self cancelEditionMode:isRefreshPending]; - - }]; - } - else - { - [room allMessages:^{ - - [self stopActivityIndicator]; - - // Leave editing mode - [self cancelEditionMode:isRefreshPending]; - - }]; - } - } - else - { - // Leave editing mode - [self cancelEditionMode:isRefreshPending]; + // navigate + self.roomNotificationSettingsCoordinatorBridgePresenter = [[RoomNotificationSettingsCoordinatorBridgePresenter alloc] initWithRoom:room]; + self.roomNotificationSettingsCoordinatorBridgePresenter.delegate = self; + [self.roomNotificationSettingsCoordinatorBridgePresenter presentFrom:self animated:YES]; } + [self cancelEditionMode:isRefreshPending]; + } +} + +- (void)openNotificationsSettings +{ + if (self.mainSession) + { + self.createRoomCoordinatorBridgePresenter = [[CreateRoomCoordinatorBridgePresenter alloc] initWithSession:self.mainSession]; + self.createRoomCoordinatorBridgePresenter.delegate = self; + [self.createRoomCoordinatorBridgePresenter presentFrom:self animated:YES]; } } @@ -2219,4 +2207,10 @@ } } +-(void)roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete:(RoomNotificationSettingsCoordinatorBridgePresenter *)coordinatorBridgePresenter +{ + [coordinatorBridgePresenter dismissWithAnimated:YES completion:nil]; + self.roomsDirectoryCoordinatorBridgePresenter = nil; +} + @end diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index d8d5382fc..3f872cf2d 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -347,7 +347,8 @@ tableViewCell.notificationsButton.tag = room.isMute || room.isMentionsOnly; [tableViewCell.notificationsButton addTarget:self action:@selector(onNotificationsButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - tableViewCell.notificationsImageView.image = [UIImage imageNamed:@"room_action_notification"]; + tableViewCell.notificationsImageView.image = tableViewCell.notificationsButton.tag ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + tableViewCell.notificationsImageView.tintColor = tableViewCell.notificationsButton.tag ? unselectedColor : selectedColor; // Get the room tag (use only the first one). @@ -663,8 +664,7 @@ MXRoom *room = [self.mainSession roomWithRoomId:editedRoomId]; if (room) { - UIButton *button = (UIButton*)sender; - [self muteEditedRoomNotifications:!button.tag]; + [self changeEditedRoomNotificationSettings]; } } } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsService.swift similarity index 100% rename from Riot/Modules/Room/NotificationSettings/RoomNotifcationsRepository.swift rename to Riot/Modules/Room/NotificationSettings/RoomNotifcationsService.swift diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsBridgePresenter.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsBridgePresenter.swift new file mode 100644 index 000000000..0be2f18a1 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsBridgePresenter.swift @@ -0,0 +1,100 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import Foundation + +@objc protocol RoomNotificationSettingsCoordinatorBridgePresenterDelegate { + func roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: RoomNotificationSettingsCoordinatorBridgePresenter) +} + +/// RoomNotificationSettingsCoordinatorBridgePresenter enables to start RoomNotificationSettingsCoordinator from a view controller. +/// This bridge is used while waiting for global usage of coordinator pattern. +/// It breaks the Coordinator abstraction and it has been introduced for Objective-C compatibility (mainly for integration in legacy view controllers). +/// Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator. +@objcMembers +final class RoomNotificationSettingsCoordinatorBridgePresenter: NSObject { + + // MARK: - Properties + + // MARK: Private + + private let room: MXRoom + private var coordinator: RoomNotificationSettingsCoordinator? + + // MARK: Public + + weak var delegate: RoomNotificationSettingsCoordinatorBridgePresenterDelegate? + + // MARK: - Setup + + init(room: MXRoom) { + self.room = room + super.init() + } + + // MARK: - Public + + // NOTE: Default value feature is not compatible with Objective-C. + // func present(from viewController: UIViewController, animated: Bool) { + // self.present(from: viewController, animated: animated) + // } + + func present(from viewController: UIViewController, animated: Bool) { + let roomNotificationSettingsCoordinator = RoomNotificationSettingsCoordinator(room: room) + roomNotificationSettingsCoordinator.delegate = self + let presentable = roomNotificationSettingsCoordinator.toPresentable() + let navigationController = RiotNavigationController(rootViewController: presentable) + navigationController.modalPresentationStyle = .formSheet + presentable.presentationController?.delegate = self + viewController.present(navigationController, animated: animated, completion: nil) + roomNotificationSettingsCoordinator.start() + + self.coordinator = roomNotificationSettingsCoordinator + } + + func dismiss(animated: Bool, completion: (() -> Void)?) { + guard let coordinator = self.coordinator else { + return + } + coordinator.toPresentable().dismiss(animated: animated) { + self.coordinator = nil + + if let completion = completion { + completion() + } + } + } +} + +// MARK: - RoomNotificationSettingsCoordinatorDelegate +extension RoomNotificationSettingsCoordinatorBridgePresenter: RoomNotificationSettingsCoordinatorDelegate { + func roomNotificationSettingsCoordinatorDidCancel(_ coordinator: RoomNotificationSettingsCoordinatorType) { + self.delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self) + } + + func roomNotificationSettingsCoordinatorDidComplete(_ coordinator: RoomNotificationSettingsCoordinatorType) { + self.delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self) + } +} + +// MARK: - UIAdaptivePresentationControllerDelegate + +extension RoomNotificationSettingsCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate { + + func roomNotificationSettingsCoordinatorDidComplete(_ presentationController: UIPresentationController) { + self.delegate?.roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self) + } + +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 31f441115..7135aaa95 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -22,7 +22,6 @@ final class RoomNotificationSettingsViewController: UIViewController { // MARK: - Properties private enum Constants { - static let plainStyleCellReuseIdentifier = "plain" static let linkToAccountSettings = "linkToAccountSettings" } // MARK: Outlets From 7a2ba9dfb4d2e12e796a34a64bc2f0527aa3bc1e Mon Sep 17 00:00:00 2001 From: langleyd Date: Sun, 4 Jul 2021 10:46:17 +0100 Subject: [PATCH 13/49] Add avatar view and title --- .../RoomNotificationSettingsAvatarView.swift | 50 ++++++++++++++++ .../RoomNotificationSettingsAvatarView.xib | 57 +++++++++++++++++++ .../RoomNotificationSettingsCoordinator.swift | 10 +++- ...omNotificationSettingsViewController.swift | 9 +++ .../RoomNotificationSettingsViewModel.swift | 4 +- ...oomNotificationSettingsViewStateType.swift | 2 + .../Room/RoomInfo/RoomInfoCoordinator.swift | 2 +- 7 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.xib diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift new file mode 100644 index 000000000..7abc30c36 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift @@ -0,0 +1,50 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Reusable + +struct RoomNotificationSettingsAvatarViewData { + let avatarUrl: String? + let mediaManager: MXMediaManager? + let displayName: String? + let roomId: String +} + +class RoomNotificationSettingsAvatarView: UIView, NibLoadable { + + @IBOutlet weak var avatarView: MXKImageView! + @IBOutlet weak var nameLabel: UILabel! + + func configure(viewData: RoomNotificationSettingsAvatarViewData) { + let avatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.roomId, withDisplayName: viewData.displayName) + + if let avatarUrl = viewData.avatarUrl { + avatarView.enableInMemoryCache = true + + avatarView.setImageURI(avatarUrl, + withType: nil, + andImageOrientation: .up, + toFitViewSize: avatarView.frame.size, + with: MXThumbnailingMethodCrop, + previewImage: avatarImage, + mediaManager: viewData.mediaManager) + } else { + avatarView.image = avatarImage + } + nameLabel.text = viewData.displayName + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.xib b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.xib new file mode 100644 index 000000000..b9c21f892 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.xib @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift index a377dd2b0..e3b7dae9a 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -36,9 +36,15 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin // MARK: - Setup - init(room: MXRoom) { + init(room: MXRoom, showAvatar: Bool = true) { let repository = RoomNotificationSettingsService(room: room) - let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository, roomEncrypted: room.summary.isEncrypted) + + let avatarData = showAvatar ? RoomNotificationSettingsAvatarViewData( + avatarUrl: room.summary.avatar, + mediaManager: room.mxSession.mediaManager, + displayName: room.summary.displayname, + roomId: room.roomId) : nil + let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository, roomEncrypted: room.summary.isEncrypted, avatarViewData: avatarData) let roomNotificationSettingsViewController = RoomNotificationSettingsViewController.instantiate(with: roomNotificationSettingsViewModel) self.roomNotificationSettingsViewModel = roomNotificationSettingsViewModel self.roomNotificationSettingsViewController = roomNotificationSettingsViewController diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 7135aaa95..db5d3df66 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -34,6 +34,9 @@ final class RoomNotificationSettingsViewController: UIViewController { private var theme: Theme! private var errorPresenter: MXKErrorPresentation! private var activityPresenter: ActivityIndicatorPresenter! + private lazy var avatarView: RoomNotificationSettingsAvatarView = { + RoomNotificationSettingsAvatarView.loadFromNib() + }() private struct Row { var cellState: RoomNotificationSettingsCell.State @@ -107,6 +110,8 @@ final class RoomNotificationSettingsViewController: UIViewController { } private func setupViews() { + + self.title = VectorL10n.roomDetailsNotifs let doneBarButtonItem = MXKBarButtonItem(title: VectorL10n.roomNotifsSettingsDoneAction, style: .plain) { [weak self] in self?.viewModel.process(viewAction: .save) } @@ -133,6 +138,10 @@ final class RoomNotificationSettingsViewController: UIViewController { activityPresenter.removeCurrentActivityIndicator(animated: true) } self.viewState = viewState + if let avatarData = viewState.avatarData { + mainTableView.tableHeaderView = avatarView + avatarView.configure(viewData: avatarData) + } updateSections() } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index 961770b33..511269c52 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -39,11 +39,11 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Setup - init(roomNotificationRepository: RoomNotificationSettingsServiceType, roomEncrypted: Bool) { + init(roomNotificationRepository: RoomNotificationSettingsServiceType, roomEncrypted: Bool, avatarViewData: RoomNotificationSettingsAvatarViewData?) { self.roomNotificationRepository = roomNotificationRepository let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationRepository.notificationState) - self.state = RoomNotificationSettingsViewState(roomEncrypted: roomEncrypted, saving: false, notificationState: notificationState) + self.state = RoomNotificationSettingsViewState(roomEncrypted: roomEncrypted, saving: false, notificationState: notificationState, avatarData: avatarViewData) self.roomNotificationRepository.observeNotificationState { [weak self] state in guard let self = self else { return } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift index 01bc56261..5d35fe9cd 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift @@ -30,6 +30,7 @@ struct RoomNotificationSettingsViewState: RoomNotificationSettingsViewStateType return RoomNotificationState.allCases } } + let avatarData: RoomNotificationSettingsAvatarViewData? } protocol RoomNotificationSettingsViewStateType { @@ -37,4 +38,5 @@ protocol RoomNotificationSettingsViewStateType { var roomEncrypted: Bool { get } var notificationOptions: [RoomNotificationState] { get } var notificationState: RoomNotificationState { get } + var avatarData: RoomNotificationSettingsAvatarViewData? { get } } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index 5776bccbd..495d3468b 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -138,7 +138,7 @@ final class RoomInfoCoordinator: NSObject, RoomInfoCoordinatorType { } private func createRoomNotificationSettingsCoordinator() -> RoomNotificationSettingsCoordinator { - let coordinator = RoomNotificationSettingsCoordinator(room: room) + let coordinator = RoomNotificationSettingsCoordinator(room: room, showAvatar: false) coordinator.delegate = self return coordinator } From ff61a79ffb7d1058f733c45700fc1fbbc53f6cf7 Mon Sep 17 00:00:00 2001 From: langleyd Date: Sun, 4 Jul 2021 17:01:42 +0100 Subject: [PATCH 14/49] Add ViewModel tests and change avatar data to use existing AvatarViewDataProtocol --- .../RoomNotificationSettingsAvatarView.swift | 11 +- .../RoomNotificationSettingsCoordinator.swift | 9 +- ...omNotificationSettingsViewController.swift | 6 +- .../RoomNotificationSettingsViewModel.swift | 2 +- ...oomNotificationSettingsViewModelType.swift | 2 +- ...oomNotificationSettingsViewStateType.swift | 4 +- ...omNotificationSettingsViewModelTests.swift | 146 ++++++++++++++++++ 7 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 RiotTests/RoomNotificationSettingsViewModelTests.swift diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift index 7abc30c36..39fe4dbec 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift @@ -17,20 +17,13 @@ import Foundation import Reusable -struct RoomNotificationSettingsAvatarViewData { - let avatarUrl: String? - let mediaManager: MXMediaManager? - let displayName: String? - let roomId: String -} - class RoomNotificationSettingsAvatarView: UIView, NibLoadable { @IBOutlet weak var avatarView: MXKImageView! @IBOutlet weak var nameLabel: UILabel! - func configure(viewData: RoomNotificationSettingsAvatarViewData) { - let avatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.roomId, withDisplayName: viewData.displayName) + func configure(viewData: AvatarViewDataProtocol) { + let avatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.matrixItemId, withDisplayName: viewData.displayName) if let avatarUrl = viewData.avatarUrl { avatarView.enableInMemoryCache = true diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift index e3b7dae9a..134abafc1 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -39,11 +39,12 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin init(room: MXRoom, showAvatar: Bool = true) { let repository = RoomNotificationSettingsService(room: room) - let avatarData = showAvatar ? RoomNotificationSettingsAvatarViewData( - avatarUrl: room.summary.avatar, - mediaManager: room.mxSession.mediaManager, + let avatarData = showAvatar ? RoomAvatarViewData( + roomId: room.roomId, displayName: room.summary.displayname, - roomId: room.roomId) : nil + avatarUrl: room.summary.avatar, + mediaManager: room.mxSession.mediaManager + ) : nil let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository, roomEncrypted: room.summary.isEncrypted, avatarViewData: avatarData) let roomNotificationSettingsViewController = RoomNotificationSettingsViewController.instantiate(with: roomNotificationSettingsViewModel) self.roomNotificationSettingsViewModel = roomNotificationSettingsViewModel diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index db5d3df66..6d39381e8 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -21,9 +21,11 @@ import UIKit final class RoomNotificationSettingsViewController: UIViewController { // MARK: - Properties + private enum Constants { static let linkToAccountSettings = "linkToAccountSettings" } + // MARK: Outlets @IBOutlet private weak var mainTableView: UITableView! @@ -161,7 +163,7 @@ final class RoomNotificationSettingsViewController: UIViewController { } } -// MARK - UITableViewDataSource +// MARK: - UITableViewDataSource extension RoomNotificationSettingsViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { @@ -187,7 +189,7 @@ extension RoomNotificationSettingsViewController: UITableViewDataSource { } -// MARK - UITableViewDelegate +// MARK: - UITableViewDelegate extension RoomNotificationSettingsViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index 511269c52..343864d4b 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -39,7 +39,7 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Setup - init(roomNotificationRepository: RoomNotificationSettingsServiceType, roomEncrypted: Bool, avatarViewData: RoomNotificationSettingsAvatarViewData?) { + init(roomNotificationRepository: RoomNotificationSettingsServiceType, roomEncrypted: Bool, avatarViewData: AvatarViewDataProtocol?) { self.roomNotificationRepository = roomNotificationRepository let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationRepository.notificationState) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift index d6f470e16..b43a2a325 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift @@ -19,7 +19,7 @@ import Foundation protocol RoomNotificationSettingsViewModelViewDelegate: AnyObject { - func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewSate: RoomNotificationSettingsViewStateType) + func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewState: RoomNotificationSettingsViewStateType) } protocol RoomNotificationSettingsViewModelCoordinatorDelegate: AnyObject { diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift index 5d35fe9cd..48e9d6290 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift @@ -30,7 +30,7 @@ struct RoomNotificationSettingsViewState: RoomNotificationSettingsViewStateType return RoomNotificationState.allCases } } - let avatarData: RoomNotificationSettingsAvatarViewData? + let avatarData: AvatarViewDataProtocol? } protocol RoomNotificationSettingsViewStateType { @@ -38,5 +38,5 @@ protocol RoomNotificationSettingsViewStateType { var roomEncrypted: Bool { get } var notificationOptions: [RoomNotificationState] { get } var notificationState: RoomNotificationState { get } - var avatarData: RoomNotificationSettingsAvatarViewData? { get } + var avatarData: AvatarViewDataProtocol? { get } } diff --git a/RiotTests/RoomNotificationSettingsViewModelTests.swift b/RiotTests/RoomNotificationSettingsViewModelTests.swift new file mode 100644 index 000000000..5afe0a47c --- /dev/null +++ b/RiotTests/RoomNotificationSettingsViewModelTests.swift @@ -0,0 +1,146 @@ +// +// Copyright 2021 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 XCTest +@testable import Riot + + +class MockRoomNotificationSettingsService: RoomNotificationSettingsServiceType { + + var listener: NotificationSettingCallback? + var notificationState: RoomNotificationState + + init(initialState: RoomNotificationState) { + notificationState = initialState + } + + func observeNotificationState(listener: @escaping NotificationSettingCallback) { + self.listener = listener + } + + func update(state: RoomNotificationState, completion: @escaping Completion) { + self.notificationState = state + completion() + listener?(state) + } +} + +class MockRoomNotificationSettingsView: RoomNotificationSettingsViewModelViewDelegate { + + var viewState: RoomNotificationSettingsViewStateType? + + func roomNotificationSettingsViewModel(_ viewModel: RoomNotificationSettingsViewModelType, didUpdateViewState viewState: RoomNotificationSettingsViewStateType) { + self.viewState = viewState + } +} + +class MockRoomNotificationSettingsCoordinator: RoomNotificationSettingsViewModelCoordinatorDelegate { + + var didComplete = false + var didCancel = false + func roomNotificationSettingsViewModelDidComplete(_ viewModel: RoomNotificationSettingsViewModelType) { + didComplete = true + } + + func roomNotificationSettingsViewModelDidCancel(_ viewModel: RoomNotificationSettingsViewModelType) { + didCancel = true + } +} + +class RoomNotificationSettingsViewModelTests: XCTestCase { + + enum Constants{ + static let roomDisplayName: String = "Test Room Name" + static let roomId: String = "1" + static let avatarUrl: String = "http://test.url.com" + static let avatarData = RoomAvatarViewData(roomId: "1", displayName: roomDisplayName, avatarUrl: avatarUrl, mediaManager: MXMediaManager()) + } + + var coordinator: MockRoomNotificationSettingsCoordinator! + var service: MockRoomNotificationSettingsService! + var view: MockRoomNotificationSettingsView! + var viewModel: RoomNotificationSettingsViewModel! + + override func setUpWithError() throws { + service = MockRoomNotificationSettingsService(initialState: .all) + view = MockRoomNotificationSettingsView() + coordinator = MockRoomNotificationSettingsCoordinator() + } + + func setupViewModel(roomEncrypted: Bool, showAvatar: Bool) { + let avatarData = showAvatar ? Constants.avatarData : nil + let viewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: service, roomEncrypted: roomEncrypted, avatarViewData: avatarData) + viewModel.viewDelegate = view + viewModel.coordinatorDelegate = coordinator + self.viewModel = viewModel + } + + func testUnloaded() throws { + setupViewModel(roomEncrypted: true, showAvatar: false) + XCTAssertNil(view.viewState) + } + + func testUnencryptedOptions() throws { + setupViewModel(roomEncrypted: false, showAvatar: false) + viewModel.process(viewAction: .load) + XCTAssertNotNil(view.viewState) + XCTAssertTrue(view.viewState!.notificationOptions.count == 3) + } + + func testEncryptedOptions() throws { + setupViewModel(roomEncrypted: true, showAvatar: false) + viewModel.process(viewAction: .load) + XCTAssertNotNil(view.viewState) + XCTAssertTrue(view.viewState!.notificationOptions.count == 2) + } + + func testAvatar() throws { + setupViewModel(roomEncrypted: true, showAvatar: true) + viewModel.process(viewAction: .load) + XCTAssertNotNil(view.viewState?.avatarData) + XCTAssertEqual(view.viewState!.avatarData!.avatarUrl, Constants.avatarUrl) + } + + func testSelectionUpdateAndSave() throws { + setupViewModel(roomEncrypted: false, showAvatar: false) + viewModel.process(viewAction: .load) + XCTAssertNotNil(view.viewState) + XCTAssertTrue(view.viewState!.notificationState == .all) + viewModel.process(viewAction: .selectNotificationState(.mentionsOnly)) + XCTAssertTrue(view.viewState!.notificationState == .mentionsOnly) + viewModel.process(viewAction: .save) + XCTAssertTrue(service.notificationState == .mentionsOnly) + XCTAssertTrue(coordinator.didComplete) + } + + func testCancel() throws { + setupViewModel(roomEncrypted: false, showAvatar: false) + viewModel.process(viewAction: .load) + XCTAssertNotNil(view.viewState) + viewModel.process(viewAction: .cancel) + XCTAssertTrue(coordinator.didCancel) + } + + func testMentionsOnlyNotAvaileOnEncryptedRoom() throws { + service = MockRoomNotificationSettingsService(initialState: .mentionsOnly) + setupViewModel(roomEncrypted: true, showAvatar: false) + + viewModel.process(viewAction: .load) + XCTAssertNotNil(view.viewState) + XCTAssertTrue(view.viewState!.notificationState == .mute) + } + +} From 5cacdac19eda684ef8861f85b6c1abf863e54a80 Mon Sep 17 00:00:00 2001 From: langleyd Date: Sun, 4 Jul 2021 17:06:19 +0100 Subject: [PATCH 15/49] Change in behaviour: mute should actually mean mute on update now. --- .../RoomNotificationSettingsViewModel.swift | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index 343864d4b..65eb9f222 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -61,8 +61,7 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel self.state.notificationState = state case .save: self.state.saving = true - let updateState = Self.mapNotificationStateOnUpdate(encrypted: self.state.roomEncrypted, state: state.notificationState) - roomNotificationRepository.update(state: updateState) { [weak self] in + roomNotificationRepository.update(state: state.notificationState) { [weak self] in guard let self = self else { return } self.state.saving = false self.coordinatorDelegate?.roomNotificationSettingsViewModelDidComplete(self) @@ -83,15 +82,6 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel } } - private static func mapNotificationStateOnUpdate(encrypted: Bool, state: RoomNotificationState) -> RoomNotificationState { - if encrypted, case .mute = state { - // Notifications not supported on encrypted rooms, map mute to mentions only on update - return .mentionsOnly - } else { - return state - } - } - private func update(viewState: RoomNotificationSettingsViewStateType) { self.viewDelegate?.roomNotificationSettingsViewModel(self, didUpdateViewState: viewState) } From 64efc159ba80341c21bb3876c135071d682a1b03 Mon Sep 17 00:00:00 2001 From: langleyd Date: Sun, 4 Jul 2021 17:27:19 +0100 Subject: [PATCH 16/49] Fix service naming --- .../RoomNotificationSettingsViewModel.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index 65eb9f222..d8117f5a6 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -25,7 +25,7 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: Private - private let roomNotificationRepository: RoomNotificationSettingsServiceType + private let roomNotificationService: RoomNotificationSettingsServiceType private var state: RoomNotificationSettingsViewState { willSet { update(viewState: newValue) @@ -39,12 +39,12 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Setup - init(roomNotificationRepository: RoomNotificationSettingsServiceType, roomEncrypted: Bool, avatarViewData: AvatarViewDataProtocol?) { - self.roomNotificationRepository = roomNotificationRepository + init(roomNotificationService: RoomNotificationSettingsServiceType, roomEncrypted: Bool, avatarViewData: AvatarViewDataProtocol?) { + self.roomNotificationService = roomNotificationService - let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationRepository.notificationState) + let notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: roomNotificationService.notificationState) self.state = RoomNotificationSettingsViewState(roomEncrypted: roomEncrypted, saving: false, notificationState: notificationState, avatarData: avatarViewData) - self.roomNotificationRepository.observeNotificationState { [weak self] state in + self.roomNotificationService.observeNotificationState { [weak self] state in guard let self = self else { return } self.state.notificationState = Self.mapNotificationStateOnRead(encrypted: roomEncrypted, state: state) @@ -61,7 +61,7 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel self.state.notificationState = state case .save: self.state.saving = true - roomNotificationRepository.update(state: state.notificationState) { [weak self] in + roomNotificationService.update(state: state.notificationState) { [weak self] in guard let self = self else { return } self.state.saving = false self.coordinatorDelegate?.roomNotificationSettingsViewModelDidComplete(self) From 62540cd0ca2c90e682b0cb56249faf0ae1c2a592 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 4 Jul 2021 21:11:12 +0100 Subject: [PATCH 17/49] enable extendedLayoutIncludesOpaqueBars on the other tabs (not just Home) to fix iPhone 12 Pro Max layout issues fixes https://github.com/vector-im/element-ios/issues/4516 --- Riot/Assets/Base.lproj/Main.storyboard | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Riot/Assets/Base.lproj/Main.storyboard b/Riot/Assets/Base.lproj/Main.storyboard index aec7a4605..c562c4d0b 100644 --- a/Riot/Assets/Base.lproj/Main.storyboard +++ b/Riot/Assets/Base.lproj/Main.storyboard @@ -151,7 +151,7 @@ - + @@ -177,7 +177,7 @@ - + @@ -463,7 +463,7 @@ - + @@ -581,7 +581,7 @@ - + From 508fb9441cf72058344efe825eac7ecba7e496dd Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 4 Jul 2021 21:14:34 +0100 Subject: [PATCH 18/49] changelog --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2e72d9c8e..45ed2aabe 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,7 @@ Changes to be released in next version * 🐛 Bugfix - * + * More fixes to Main.storyboard layout on iPhone 12 Pro Max (#4527) ⚠️ API Changes * From d073d144d9ef9ce35793e86d43bacf93a7b33f8f Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 5 Jul 2021 15:27:36 +0300 Subject: [PATCH 19/49] Do not present ended calls --- Riot/Managers/Call/CallPresenter.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Riot/Managers/Call/CallPresenter.swift b/Riot/Managers/Call/CallPresenter.swift index 4f5ad7e13..940ac98f3 100644 --- a/Riot/Managers/Call/CallPresenter.swift +++ b/Riot/Managers/Call/CallPresenter.swift @@ -393,7 +393,9 @@ class CallPresenter: NSObject { if let oldCallVC = self.callVCs.values.first, self.presentedCallVC == nil, !self.uiOperationQueue.containsPresentCallVCOperation, - !self.uiOperationQueue.containsEnterPiPOperation { + !self.uiOperationQueue.containsEnterPiPOperation, + let oldCall = oldCallVC.mxCall, + oldCall.state != .ended { // present the call screen after dismissing this one self.presentCallVC(oldCallVC) } From fea0d1bb2e2cd40d382d420b09e80f07d7ce6bb6 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Mon, 5 Jul 2021 15:30:43 +0300 Subject: [PATCH 20/49] Update CHANGES.rst --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2e72d9c8e..982ac85cc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,7 @@ Changes to be released in next version * 🐛 Bugfix - * + * VoIP: Do not present ended calls. ⚠️ API Changes * From 23884eb4c0e46bd0e1ea88158848479b132b06f9 Mon Sep 17 00:00:00 2001 From: langleyd Date: Mon, 5 Jul 2021 16:28:14 +0100 Subject: [PATCH 21/49] Fix build and naming of State -> ViewData --- ...RoomNotificationSettingsCellViewData.swift | 22 +++++++++++++++++++ .../RoomNotificationSettingsCoordinator.swift | 2 +- ...omNotificationSettingsViewController.swift | 8 +++---- .../RoomNotificationsSettingsCell.swift | 7 +----- 4 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCellViewData.swift diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCellViewData.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCellViewData.swift new file mode 100644 index 000000000..2b50835d1 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCellViewData.swift @@ -0,0 +1,22 @@ +// +// Copyright 2021 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 + +struct RoomNotificationSettingsCellViewData { + let notificicationState: RoomNotificationState + let selected: Bool +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift index 134abafc1..25e663ae4 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -45,7 +45,7 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin avatarUrl: room.summary.avatar, mediaManager: room.mxSession.mediaManager ) : nil - let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: repository, roomEncrypted: room.summary.isEncrypted, avatarViewData: avatarData) + let roomNotificationSettingsViewModel = RoomNotificationSettingsViewModel(roomNotificationService: repository, roomEncrypted: room.summary.isEncrypted, avatarViewData: avatarData) let roomNotificationSettingsViewController = RoomNotificationSettingsViewController.instantiate(with: roomNotificationSettingsViewModel) self.roomNotificationSettingsViewModel = roomNotificationSettingsViewModel self.roomNotificationSettingsViewController = roomNotificationSettingsViewController diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 6d39381e8..3c6ce1f01 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -41,7 +41,7 @@ final class RoomNotificationSettingsViewController: UIViewController { }() private struct Row { - var cellState: RoomNotificationSettingsCell.State + var cellViewData: RoomNotificationSettingsCellViewData var action: (() -> Void)? } @@ -149,8 +149,8 @@ final class RoomNotificationSettingsViewController: UIViewController { private func updateSections() { let rows = viewState.notificationOptions.map({ (setting) -> Row in - let cellState = RoomNotificationSettingsCell.State(notificicationState: setting, selected: viewState.notificationState == setting) - return Row(cellState: cellState, + let cellViewData = RoomNotificationSettingsCellViewData(notificicationState: setting, selected: viewState.notificationState == setting) + return Row(cellViewData: cellViewData, action: { self.viewModel.process(viewAction: .selectNotificationState(setting)) }) @@ -177,7 +177,7 @@ extension RoomNotificationSettingsViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let row = sections[indexPath.section].rows[indexPath.row] let cell: RoomNotificationSettingsCell = tableView.dequeueReusableCell(for: indexPath) - cell.update(state: row.cellState) + cell.update(state: row.cellViewData) cell.update(theme: theme) return cell } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift index 831c1ba73..2591b6c4e 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift @@ -18,12 +18,7 @@ import Reusable class RoomNotificationSettingsCell: UITableViewCell { - struct State { - let notificicationState: RoomNotificationState - let selected: Bool - } - - func update(state: State) { + func update(state: RoomNotificationSettingsCellViewData) { textLabel?.font = .systemFont(ofSize: 17) detailTextLabel?.font = .systemFont(ofSize: 16) textLabel?.text = state.notificicationState.title From 0fb949b294d2805b83f23fcc475807d0d0f06928 Mon Sep 17 00:00:00 2001 From: langleyd Date: Mon, 5 Jul 2021 16:49:06 +0100 Subject: [PATCH 22/49] spacing and cleanup dead code --- Riot/Assets/en.lproj/Vector.strings | 1 - .../Common/Recents/RecentsViewController.m | 13 ++-------- ... => RoomNotifcationsSettingsService.swift} | 18 ++------------ .../RoomNotificationSettingsFooter.swift | 3 +-- .../RoomNotificationSettingsSerivceType.swift | 24 +++++++++++++++++++ .../RoomNotificationSettingsViewModel.swift | 1 - .../RoomNotificationState.swift | 23 ++++++++++++++++++ 7 files changed, 52 insertions(+), 31 deletions(-) rename Riot/Modules/Room/NotificationSettings/{RoomNotifcationsService.swift => RoomNotifcationsSettingsService.swift} (96%) create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift create mode 100644 Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index f9b75b276..ab0cccfab 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -783,7 +783,6 @@ Tap the + to start adding people."; "room_notifs_settings_account_settings" = "Account settings"; "room_notifs_settings_encrypted_room_notice" = "Please note that mentions & keyword notifications are not available in encrypted rooms on mobile."; - // Group Details "group_details_title" = "Community Details"; "group_details_home" = "Home"; diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index a185a4753..3cfe7b938 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1317,16 +1317,6 @@ } } -- (void)openNotificationsSettings -{ - if (self.mainSession) - { - self.createRoomCoordinatorBridgePresenter = [[CreateRoomCoordinatorBridgePresenter alloc] initWithSession:self.mainSession]; - self.createRoomCoordinatorBridgePresenter.delegate = self; - [self.createRoomCoordinatorBridgePresenter presentFrom:self animated:YES]; - } -} - #pragma mark - UITableView delegate - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath; @@ -2207,10 +2197,11 @@ } } +#pragma mark - RoomNotificationSettingsCoordinatorBridgePresenterDelegate -(void)roomNotificationSettingsCoordinatorBridgePresenterDelegateDidComplete:(RoomNotificationSettingsCoordinatorBridgePresenter *)coordinatorBridgePresenter { [coordinatorBridgePresenter dismissWithAnimated:YES completion:nil]; - self.roomsDirectoryCoordinatorBridgePresenter = nil; + self.roomNotificationSettingsCoordinatorBridgePresenter = nil; } @end diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsService.swift b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift similarity index 96% rename from Riot/Modules/Room/NotificationSettings/RoomNotifcationsService.swift rename to Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift index 615a151cd..e47ce9862 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsService.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift @@ -16,22 +16,10 @@ import Foundation -enum RoomNotificationState: CaseIterable { - case all - case mentionsOnly - case mute -} - -protocol RoomNotificationSettingsServiceType { +final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType { + typealias Completion = () -> Void typealias NotificationSettingCallback = (RoomNotificationState) -> Void - - func observeNotificationState(listener: @escaping NotificationSettingCallback) - func update(state: RoomNotificationState, completion: @escaping Completion) - var notificationState: RoomNotificationState { get } -} - -final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType { // MARK: - Properties @@ -74,7 +62,6 @@ final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType observers += [ObjectIdentifier(observer)] } - func update(state: RoomNotificationState, completion: @escaping Completion) { switch state { case .all: @@ -208,7 +195,6 @@ final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType ) } - private func removePushRule(rule: MXPushRule, completion: @escaping Completion) { handleUpdateCallback(completion) { [weak self] in guard let self = self else { return true } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift index 4ccf9a124..12f7a2901 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift @@ -28,6 +28,7 @@ class RoomNotificationSettingsFooter: UITableViewHeaderFooterView { func update(footerState: State) { + // Don't include link until global settings in place // let paragraphStyle = NSMutableParagraphStyle() // paragraphStyle.lineHeightMultiple = 1.16 // let paragraphAttributes: [NSAttributedString.Key: Any] = [ @@ -35,8 +36,6 @@ class RoomNotificationSettingsFooter: UITableViewHeaderFooterView { // NSAttributedString.Key.paragraphStyle: paragraphStyle, // NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) // ] - - // Don't include link until global settings in place // let linkStr = VectorL10n.roomNotifsSettingsAccountSettings // let formatStr = VectorL10n.roomNotifsSettingsManageNotifications(linkStr) // diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift new file mode 100644 index 000000000..2499ac0d0 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift @@ -0,0 +1,24 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +protocol RoomNotificationSettingsServiceType { + + func observeNotificationState(listener: @escaping (RoomNotificationState) -> Void) + func update(state: RoomNotificationState, completion: @escaping () -> Void) + var notificationState: RoomNotificationState { get } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index d8117f5a6..3d7d22b09 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -18,7 +18,6 @@ import Foundation - final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType { // MARK: - Properties diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift new file mode 100644 index 000000000..8d37a6702 --- /dev/null +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift @@ -0,0 +1,23 @@ +// +// Copyright 2021 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 + +enum RoomNotificationState: CaseIterable { + case all + case mentionsOnly + case mute +} From 019b2c1a70e2c2fa514cca5a794906c81498c607 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 5 Jul 2021 19:19:51 +0100 Subject: [PATCH 23/49] Fix crash when running on macOS with Apple Silicon. --- Riot/Modules/Application/LegacyAppDelegate.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index ff81e5f57..32010f9bb 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -351,6 +351,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni NSURL *messageSoundURL = [[NSBundle mainBundle] URLForResource:@"message" withExtension:@"caf"]; AudioServicesCreateSystemSoundID((__bridge CFURLRef)messageSoundURL, &_messageSound); + // Set app info now as Mac (Designed for iPad) accesses it before didFinishLaunching is called + self.appInfo = AppInfo.current; + MXLogDebug(@"[AppDelegate] willFinishLaunchingWithOptions: Done"); return YES; @@ -371,8 +374,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni _configuration = [AppConfiguration new]; - self.appInfo = AppInfo.current; - // Log app information NSString *appDisplayName = self.appInfo.displayName; NSString* appVersion = self.appVersion; From 2838223b759a7e369d26cad5a83a81a86ff08385 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 5 Jul 2021 19:21:16 +0100 Subject: [PATCH 24/49] Update CHANGES.rst. --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2e72d9c8e..e6b12a975 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,7 @@ Changes to be released in next version * 🐛 Bugfix - * + * Fix crash on Apple Silicon Macs. ⚠️ API Changes * From d59ea07deab6dd260eeecef3f7cba8476b54d22b Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 6 Jul 2021 10:41:47 +0100 Subject: [PATCH 25/49] Generate video thumbnails with the correct orientation. --- CHANGES.rst | 1 + Riot/Modules/MediaPicker/MediaPickerViewController.m | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 04c0012ef..5837d3a37 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,7 @@ Changes to be released in next version 🐛 Bugfix * VoIP: Do not present ended calls. * More fixes to Main.storyboard layout on iPhone 12 Pro Max (#4527) + * Media Picker: Generate video thumbnails with the correct orientation (#4515). ⚠️ API Changes * diff --git a/Riot/Modules/MediaPicker/MediaPickerViewController.m b/Riot/Modules/MediaPicker/MediaPickerViewController.m index 6b7725a11..d08e6ab17 100644 --- a/Riot/Modules/MediaPicker/MediaPickerViewController.m +++ b/Riot/Modules/MediaPicker/MediaPickerViewController.m @@ -736,6 +736,7 @@ // create a thumbnail for the first frame AVAsset *asset = [AVAsset assetWithURL:selectedVideoURL]; AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + generator.appliesPreferredTrackTransform = YES; CGImageRef thumbnailRef = [generator copyCGImageAtTime:kCMTimeZero actualTime:nil error:nil]; // set thumbnail on validationView From 97496f93ea5d05ef90d42211655b292dfd369f40 Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 6 Jul 2021 11:38:29 +0100 Subject: [PATCH 26/49] Fix build, mute bug and footer label on unencrypted builds --- .../RoomNotifcationsSettingsService.swift | 5 ++--- .../RoomNotificationSettingsFooter.swift | 6 +++--- .../RoomNotificationSettingsSerivceType.swift | 7 +++++-- RiotTests/RoomNotificationSettingsViewModelTests.swift | 8 ++++---- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift index e47ce9862..c9d89f1b4 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift @@ -19,7 +19,6 @@ import Foundation final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType { typealias Completion = () -> Void - typealias NotificationSettingCallback = (RoomNotificationState) -> Void // MARK: - Properties @@ -50,7 +49,7 @@ final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType // MARK: - Public - func observeNotificationState(listener: @escaping NotificationSettingCallback) { + func observeNotificationState(listener: @escaping RoomNotificationStateCallback) { let observer = NotificationCenter.default.addObserver( forName: NSNotification.Name(rawValue: kMXNotificationCenterDidUpdateRules), @@ -81,7 +80,7 @@ final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType return } - if let rule = room.roomPushRule, room.isMentionsOnly { + if let rule = room.roomPushRule { removePushRule(rule: rule) { self.mute(completion: completion) } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift index 12f7a2901..db5285192 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsFooter.swift @@ -43,9 +43,9 @@ class RoomNotificationSettingsFooter: UITableViewHeaderFooterView { // let footer0 = NSMutableAttributedString(string: formattedStr, attributes: paragraphAttributes) // let linkRange = (footer0.string as NSString).range(of: linkStr) // footer0.addAttribute(NSAttributedString.Key.link, value: Constants.linkToAccountSettings, range: linkRange) - if footerState.showEncryptedNotice { - label.text = VectorL10n.roomNotifsSettingsEncryptedRoomNotice - } + + label.text = footerState.showEncryptedNotice ? VectorL10n.roomNotifsSettingsEncryptedRoomNotice : nil + } } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift index 2499ac0d0..22961ad03 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsSerivceType.swift @@ -16,9 +16,12 @@ import Foundation +typealias UpdateRoomNotificationStateCompletion = () -> Void +typealias RoomNotificationStateCallback = (RoomNotificationState) -> Void + protocol RoomNotificationSettingsServiceType { - func observeNotificationState(listener: @escaping (RoomNotificationState) -> Void) - func update(state: RoomNotificationState, completion: @escaping () -> Void) + func observeNotificationState(listener: @escaping RoomNotificationStateCallback) + func update(state: RoomNotificationState, completion: @escaping UpdateRoomNotificationStateCompletion) var notificationState: RoomNotificationState { get } } diff --git a/RiotTests/RoomNotificationSettingsViewModelTests.swift b/RiotTests/RoomNotificationSettingsViewModelTests.swift index 5afe0a47c..6f2615e4e 100644 --- a/RiotTests/RoomNotificationSettingsViewModelTests.swift +++ b/RiotTests/RoomNotificationSettingsViewModelTests.swift @@ -20,18 +20,18 @@ import XCTest class MockRoomNotificationSettingsService: RoomNotificationSettingsServiceType { - var listener: NotificationSettingCallback? + var listener: RoomNotificationStateCallback? var notificationState: RoomNotificationState init(initialState: RoomNotificationState) { notificationState = initialState } - func observeNotificationState(listener: @escaping NotificationSettingCallback) { + func observeNotificationState(listener: @escaping RoomNotificationStateCallback) { self.listener = listener } - func update(state: RoomNotificationState, completion: @escaping Completion) { + func update(state: RoomNotificationState, completion: @escaping UpdateRoomNotificationStateCompletion) { self.notificationState = state completion() listener?(state) @@ -82,7 +82,7 @@ class RoomNotificationSettingsViewModelTests: XCTestCase { func setupViewModel(roomEncrypted: Bool, showAvatar: Bool) { let avatarData = showAvatar ? Constants.avatarData : nil - let viewModel = RoomNotificationSettingsViewModel(roomNotificationRepository: service, roomEncrypted: roomEncrypted, avatarViewData: avatarData) + let viewModel = RoomNotificationSettingsViewModel(roomNotificationService: service, roomEncrypted: roomEncrypted, avatarViewData: avatarData) viewModel.viewDelegate = view viewModel.coordinatorDelegate = coordinator self.viewModel = viewModel From fe6a1953bd7d471e2d1d818c2cae6e9748fa192c Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 6 Jul 2021 11:59:54 +0100 Subject: [PATCH 27/49] Keep old mute behaviour enabled on slide menu and long press when new build setting is not enabled. --- .../Common/Recents/RecentsViewController.h | 5 ++ .../Common/Recents/RecentsViewController.m | 64 ++++++++++++++++++- Riot/Modules/Home/HomeViewController.m | 20 +++++- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/Riot/Modules/Common/Recents/RecentsViewController.h b/Riot/Modules/Common/Recents/RecentsViewController.h index 70a504c8b..d3968cfd6 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.h +++ b/Riot/Modules/Common/Recents/RecentsViewController.h @@ -160,6 +160,11 @@ */ - (void)makeDirectEditedRoom:(BOOL)isDirect; +/** +Enable/disable the notifications for the selected room. +*/ +- (void)muteEditedRoomNotifications:(BOOL)mute; + /** Edit notification settings for the selected room. */ diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 3cfe7b938..e76a83cab 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -1033,12 +1033,31 @@ UIContextualAction *muteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:title handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { - [self changeEditedRoomNotificationSettings]; + + if ([BuildSettings roomSettingsScreenShowNotificationsV2]) + { + [self changeEditedRoomNotificationSettings]; + } + else + { + [self muteEditedRoomNotifications:!isMuted]; + } + + completionHandler(YES); }]; muteAction.backgroundColor = actionBackgroundColor; - UIImage *notificationImage = isMuted ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + UIImage *notificationImage; + if([BuildSettings roomSettingsScreenShowNotificationsV2]) + { + notificationImage = isMuted ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + } + else + { + notificationImage = [UIImage imageNamed:@"room_action_notification"]; + } + notificationImage = [notificationImage vc_tintedImageUsingColor:isMuted ? unselectedColor : selectedColor]; muteAction.image = [notificationImage vc_notRenderedImage]; @@ -1317,6 +1336,47 @@ } } +- (void)muteEditedRoomNotifications:(BOOL)mute +{ + if (editedRoomId) + { + // Check whether the user didn't leave the room + MXRoom *room = [self.mainSession roomWithRoomId:editedRoomId]; + if (room) + { + [self startActivityIndicator]; + + if (mute) + { + [room mentionsOnly:^{ + + [self stopActivityIndicator]; + + // Leave editing mode + [self cancelEditionMode:self->isRefreshPending]; + + }]; + } + else + { + [room allMessages:^{ + + [self stopActivityIndicator]; + + // Leave editing mode + [self cancelEditionMode:self->isRefreshPending]; + + }]; + } + } + else + { + // Leave editing mode + [self cancelEditionMode:isRefreshPending]; + } + } +} + #pragma mark - UITableView delegate - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath; diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index 3f872cf2d..74fef7d37 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -347,7 +347,15 @@ tableViewCell.notificationsButton.tag = room.isMute || room.isMentionsOnly; [tableViewCell.notificationsButton addTarget:self action:@selector(onNotificationsButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - tableViewCell.notificationsImageView.image = tableViewCell.notificationsButton.tag ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + + if ([BuildSettings roomSettingsScreenShowNotificationsV2]) + { + tableViewCell.notificationsImageView.image = tableViewCell.notificationsButton.tag ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + } + else + { + tableViewCell.notificationsImageView.image = [UIImage imageNamed:@"room_action_notification"]; + } tableViewCell.notificationsImageView.tintColor = tableViewCell.notificationsButton.tag ? unselectedColor : selectedColor; @@ -664,7 +672,15 @@ MXRoom *room = [self.mainSession roomWithRoomId:editedRoomId]; if (room) { - [self changeEditedRoomNotificationSettings]; + if ([BuildSettings roomSettingsScreenShowNotificationsV2]) + { + [self changeEditedRoomNotificationSettings]; + } + else + { + UIButton *button = (UIButton*)sender; + [self muteEditedRoomNotifications:!button.tag]; + } } } } From f240fbf0d21c7b51e416c6039bd3ea31cf7f087f Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 6 Jul 2021 13:14:15 +0100 Subject: [PATCH 28/49] Enabled new room settings UI while I do ad hoc build --- Config/BuildSettings.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 0d5ae6dae..58d074b82 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -295,7 +295,7 @@ final class BuildSettings: NSObject { static let roomSettingsScreenShowFlairSettings: Bool = true static let roomSettingsScreenShowAdvancedSettings: Bool = true static let roomSettingsScreenAdvancedShowEncryptToVerifiedOption: Bool = true - static let roomSettingsScreenShowNotificationsV2: Bool = false + static let roomSettingsScreenShowNotificationsV2: Bool = true // MARK: - Room Member Screen From 8a2425aaa7ebefc2c7f5f69e470bd2728811dd63 Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 6 Jul 2021 19:39:15 +0100 Subject: [PATCH 29/49] Fix typos, naming and copywright --- .../RoomNotificationSettingsCoordinator.swift | 2 +- .../RoomNotificationSettingsCoordinatorType.swift | 4 ++-- .../RoomNotificationSettingsViewAction.swift | 2 +- .../RoomNotificationSettingsViewController.swift | 2 +- .../RoomNotificationSettingsViewModel.swift | 4 ++-- .../RoomNotificationSettingsViewModelType.swift | 2 +- .../RoomNotificationSettingsViewStateType.swift | 2 +- .../Room/NotificationSettings/RoomNotificationState.swift | 2 +- .../RoomNotificationsSettingsCell.swift | 2 +- ...rvice.swift => RoomNotificationsSettingsService.swift} | 4 ++-- RiotTests/RoomNotificationSettingsViewModelTests.swift | 8 ++++---- 11 files changed, 17 insertions(+), 17 deletions(-) rename Riot/Modules/Room/NotificationSettings/{RoomNotifcationsSettingsService.swift => RoomNotificationsSettingsService.swift} (99%) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift index 25e663ae4..2d8e48cee 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinator.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift index 99e30f617..ac0c6288b 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsCoordinatorType.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. @@ -23,7 +23,7 @@ protocol RoomNotificationSettingsCoordinatorDelegate: AnyObject { func roomNotificationSettingsCoordinatorDidCancel(_ coordinator: RoomNotificationSettingsCoordinatorType) } -/// `RoomNotificationSettingsCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +/// `RoomNotificationSettingsCoordinatorType` is a protocol describing a Coordinator that handles changes to the room navigation settings navigation flow. protocol RoomNotificationSettingsCoordinatorType: Coordinator, Presentable { var delegate: RoomNotificationSettingsCoordinatorDelegate? { get } } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift index ee6539614..5d42f64fa 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewAction.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 3c6ce1f01..21eb3e6e3 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift index 3d7d22b09..e9f5729df 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModel.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. @@ -73,7 +73,7 @@ final class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModel // MARK: - Private private static func mapNotificationStateOnRead(encrypted: Bool, state: RoomNotificationState) -> RoomNotificationState { - if encrypted, case .mentionsOnly = state { + if encrypted, case .mentionsAndKeywordsOnly = state { // Notifications not supported on encrypted rooms, map mentionsOnly to mute on read return .mute } else { diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift index b43a2a325..e2fe135d4 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewModelType.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift index 48e9d6290..56de53b13 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewStateType.swift @@ -1,7 +1,7 @@ // File created from ScreenTemplate // $ createScreen.sh Room/NotificationSettings RoomNotificationSettings /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift index 8d37a6702..054993117 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationState.swift @@ -18,6 +18,6 @@ import Foundation enum RoomNotificationState: CaseIterable { case all - case mentionsOnly + case mentionsAndKeywordsOnly case mute } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift index 2591b6c4e..967859228 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift @@ -47,7 +47,7 @@ fileprivate extension RoomNotificationState { switch self { case .all: return VectorL10n.roomNotifsSettingsAllMessages - case .mentionsOnly: + case .mentionsAndKeywordsOnly: return VectorL10n.roomNotifsSettingsMentionsAndKeywords case .mute: return VectorL10n.roomNotifsSettingsNone diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift similarity index 99% rename from Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift rename to Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift index c9d89f1b4..bb7e2fe81 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotifcationsSettingsService.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift @@ -65,7 +65,7 @@ final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType switch state { case .all: allMessages(completion: completion) - case .mentionsOnly: + case .mentionsAndKeywordsOnly: mentionsOnly(completion: completion) case .mute: mute(completion: completion) @@ -277,7 +277,7 @@ fileprivate extension MXRoom { return .mute } if isMentionsOnly { - return .mentionsOnly + return .mentionsAndKeywordsOnly } return .all } diff --git a/RiotTests/RoomNotificationSettingsViewModelTests.swift b/RiotTests/RoomNotificationSettingsViewModelTests.swift index 6f2615e4e..b10dbd63b 100644 --- a/RiotTests/RoomNotificationSettingsViewModelTests.swift +++ b/RiotTests/RoomNotificationSettingsViewModelTests.swift @@ -119,10 +119,10 @@ class RoomNotificationSettingsViewModelTests: XCTestCase { viewModel.process(viewAction: .load) XCTAssertNotNil(view.viewState) XCTAssertTrue(view.viewState!.notificationState == .all) - viewModel.process(viewAction: .selectNotificationState(.mentionsOnly)) - XCTAssertTrue(view.viewState!.notificationState == .mentionsOnly) + viewModel.process(viewAction: .selectNotificationState(.mentionsAndKeywordsOnly)) + XCTAssertTrue(view.viewState!.notificationState == .mentionsAndKeywordsOnly) viewModel.process(viewAction: .save) - XCTAssertTrue(service.notificationState == .mentionsOnly) + XCTAssertTrue(service.notificationState == .mentionsAndKeywordsOnly) XCTAssertTrue(coordinator.didComplete) } @@ -135,7 +135,7 @@ class RoomNotificationSettingsViewModelTests: XCTestCase { } func testMentionsOnlyNotAvaileOnEncryptedRoom() throws { - service = MockRoomNotificationSettingsService(initialState: .mentionsOnly) + service = MockRoomNotificationSettingsService(initialState: .mentionsAndKeywordsOnly) setupViewModel(roomEncrypted: true, showAvatar: false) viewModel.process(viewAction: .load) From 4c824cfced9b04794fd8162f2f8a7dd180c0d0bf Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 6 Jul 2021 21:10:42 +0100 Subject: [PATCH 30/49] Use theme font types --- .../NotificationSettings/RoomNotificationsSettingsCell.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift index 967859228..3d4bec1f7 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift @@ -19,8 +19,6 @@ import Reusable class RoomNotificationSettingsCell: UITableViewCell { func update(state: RoomNotificationSettingsCellViewData) { - textLabel?.font = .systemFont(ofSize: 17) - detailTextLabel?.font = .systemFont(ofSize: 16) textLabel?.text = state.notificicationState.title if state.selected { accessoryView = UIImageView(image: Asset.Images.checkmark.image) @@ -34,8 +32,8 @@ extension RoomNotificationSettingsCell: Reusable {} extension RoomNotificationSettingsCell: Themable { func update(theme: Theme) { + textLabel?.font = theme.fonts.body textLabel?.textColor = theme.textPrimaryColor - detailTextLabel?.textColor = theme.textSecondaryColor backgroundColor = theme.backgroundColor contentView.backgroundColor = .clear tintColor = theme.tintColor From 88d816ddf26a89bf78f66cc14df5d4e2fd31990f Mon Sep 17 00:00:00 2001 From: langleyd Date: Tue, 6 Jul 2021 22:46:31 +0100 Subject: [PATCH 31/49] disable new settings ui again --- Config/BuildSettings.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 58d074b82..0d5ae6dae 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -295,7 +295,7 @@ final class BuildSettings: NSObject { static let roomSettingsScreenShowFlairSettings: Bool = true static let roomSettingsScreenShowAdvancedSettings: Bool = true static let roomSettingsScreenAdvancedShowEncryptToVerifiedOption: Bool = true - static let roomSettingsScreenShowNotificationsV2: Bool = true + static let roomSettingsScreenShowNotificationsV2: Bool = false // MARK: - Room Member Screen From 0fee0e5c86a1b2c4628c4625debd7593b4b785a9 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 12:16:05 +0100 Subject: [PATCH 32/49] Rename roomsCount and moreThanRoomsCount to indicate they are for search results. Redefine roomsCount as the number of fetched rooms in the data source. --- .../Views/DirectoryRecentTableViewCell.m | 8 ++++---- .../PublicRoomsDirectoryDataSource.h | 11 ++++++++--- .../PublicRoomsDirectoryDataSource.m | 17 +++++++++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m b/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m index 63cdbfbce..26c103fb2 100644 --- a/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m +++ b/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m @@ -54,20 +54,20 @@ self.titleLabel.text = NSLocalizedStringFromTable(@"directory_search_results_title", @"Vector", nil); // Do we need to display like ">20 results found" or "18 results found"? - NSString *descriptionLabel = (publicRoomsDirectoryDataSource.moreThanRoomsCount && publicRoomsDirectoryDataSource.roomsCount > 0) ? NSLocalizedStringFromTable(@"directory_search_results_more_than", @"Vector", nil) : NSLocalizedStringFromTable(@"directory_search_results", @"Vector", nil); + NSString *descriptionLabel = (publicRoomsDirectoryDataSource.searchResultsCountIsLimited && publicRoomsDirectoryDataSource.searchResultsCount > 0) ? NSLocalizedStringFromTable(@"directory_search_results_more_than", @"Vector", nil) : NSLocalizedStringFromTable(@"directory_search_results", @"Vector", nil); self.descriptionLabel.text = [NSString stringWithFormat:descriptionLabel, - publicRoomsDirectoryDataSource.roomsCount, + publicRoomsDirectoryDataSource.searchResultsCount, publicRoomsDirectoryDataSource.searchPattern]; } else { self.titleLabel.text = NSLocalizedStringFromTable(@"directory_cell_title", @"Vector", nil); self.descriptionLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"directory_cell_description", @"Vector", nil), - publicRoomsDirectoryDataSource.roomsCount]; + publicRoomsDirectoryDataSource.searchResultsCount]; } - if (publicRoomsDirectoryDataSource.roomsCount) + if (publicRoomsDirectoryDataSource.searchResultsCount) { self.userInteractionEnabled = YES; self.chevronImageView.hidden = NO; diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h index 752cce049..73a4f9ed2 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h @@ -62,11 +62,16 @@ @property (nonatomic, readonly) NSString *directoryServerDisplayname; /** - The number of public rooms matching `searchPattern`. - It is accurate only if 'moreThanRoomsCount' is NO. + The number of public rooms that have been fetched so far. */ @property (nonatomic, readonly) NSUInteger roomsCount; +/** + The total number of public rooms matching `searchPattern`. + It is accurate only if 'moreThanRoomsCount' is NO. + */ +@property (nonatomic, readonly) NSUInteger searchResultsCount; + /** In case of search with a lot of matching public rooms, we cannot return an accurate value except by paginating the full list of rooms, which is not expected. @@ -74,7 +79,7 @@ This flag indicates that we know that there is more matching rooms than we got so far. */ -@property (nonatomic, readonly) BOOL moreThanRoomsCount; +@property (nonatomic, readonly) BOOL searchResultsCountIsLimited; /** The maximum number of public rooms to retrieve during a pagination. diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m index e69035aa0..fa8ac0ab0 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m @@ -165,6 +165,11 @@ static NSString *const kNSFWKeyword = @"nsfw"; } } +- (NSUInteger)roomsCount +{ + return rooms.count; +} + - (NSIndexPath*)cellIndexPathWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)matrixSession { NSIndexPath *indexPath = nil; @@ -217,8 +222,8 @@ static NSString *const kNSFWKeyword = @"nsfw"; // Reset all pagination vars [rooms removeAllObjects]; nextBatch = nil; - _roomsCount = 0; - _moreThanRoomsCount = NO; + _searchResultsCount = 0; + _searchResultsCountIsLimited = NO; _hasReachedPaginationEnd = NO; } @@ -264,14 +269,14 @@ static NSString *const kNSFWKeyword = @"nsfw"; if (!self->_searchPattern) { // When there is no search, we can use totalRoomCountEstimate returned by the server - self->_roomsCount = publicRoomsResponse.totalRoomCountEstimate; - self->_moreThanRoomsCount = NO; + self->_searchResultsCount = publicRoomsResponse.totalRoomCountEstimate; + self->_searchResultsCountIsLimited = NO; } else { // Else we can only display something like ">20 matching rooms" - self->_roomsCount = self->rooms.count; - self->_moreThanRoomsCount = publicRoomsResponse.nextBatch ? YES : NO; + self->_searchResultsCount = self->rooms.count; + self->_searchResultsCountIsLimited = publicRoomsResponse.nextBatch ? YES : NO; } // Detect pagination end From 40d4527f0d405d5a526d5292578a4b060daaea5a Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 12:17:42 +0100 Subject: [PATCH 33/49] Update CHANGES.rst. --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 486c751b3..595e1a070 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,6 +12,7 @@ Changes to be released in next version * More fixes to Main.storyboard layout on iPhone 12 Pro Max (#4527) * Fix crash on Apple Silicon Macs. * Media Picker: Generate video thumbnails with the correct orientation (#4515). + * Directory List (pop-up one): Fix duplicate rooms being shown (#4537). ⚠️ API Changes * From 2566650431b639db5e97f18db5b549759f577588 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 12:28:52 +0100 Subject: [PATCH 34/49] Fix documentation. --- .../PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h index 73a4f9ed2..750daac05 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h @@ -68,7 +68,7 @@ /** The total number of public rooms matching `searchPattern`. - It is accurate only if 'moreThanRoomsCount' is NO. + It is accurate only if 'searchResultsCountIsLimited' is NO. */ @property (nonatomic, readonly) NSUInteger searchResultsCount; From 6f1d7080f012d3ce5b8fbb7b24451d03475c56f5 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 16:26:19 +0100 Subject: [PATCH 35/49] Use AVAsset instead of NSURL to enable sending slow motion videos. Slow motion videos are returned as AVComposition objects when picked. which lacks a URL property. --- .../MediaPicker/MediaPickerCoordinator.swift | 4 +- ...ediaPickerCoordinatorBridgePresenter.swift | 6 +-- .../MediaPickerCoordinatorType.swift | 2 +- .../MediaPicker/MediaPickerViewController.h | 4 +- .../MediaPicker/MediaPickerViewController.m | 39 +++++++------------ .../SingleImagePickerPresenter.swift | 2 +- Riot/Modules/Room/RoomViewController.m | 4 +- 7 files changed, 26 insertions(+), 35 deletions(-) diff --git a/Riot/Modules/MediaPicker/MediaPickerCoordinator.swift b/Riot/Modules/MediaPicker/MediaPickerCoordinator.swift index d3b9c2c0d..61586be8d 100644 --- a/Riot/Modules/MediaPicker/MediaPickerCoordinator.swift +++ b/Riot/Modules/MediaPicker/MediaPickerCoordinator.swift @@ -83,8 +83,8 @@ extension MediaPickerCoordinator: MediaPickerViewControllerDelegate { self.delegate?.mediaPickerCoordinator(self, didSelectImageData: imageData, withUTI: uti) } - func mediaPickerController(_ mediaPickerController: MediaPickerViewController!, didSelectVideo videoURL: URL!) { - self.delegate?.mediaPickerCoordinator(self, didSelectVideoAt: videoURL) + func mediaPickerController(_ mediaPickerController: MediaPickerViewController!, didSelectVideo videoAsset: AVAsset!) { + self.delegate?.mediaPickerCoordinator(self, didSelectVideo: videoAsset) } func mediaPickerController(_ mediaPickerController: MediaPickerViewController!, didSelect assets: [PHAsset]!) { diff --git a/Riot/Modules/MediaPicker/MediaPickerCoordinatorBridgePresenter.swift b/Riot/Modules/MediaPicker/MediaPickerCoordinatorBridgePresenter.swift index 0ba21d893..782662ea9 100644 --- a/Riot/Modules/MediaPicker/MediaPickerCoordinatorBridgePresenter.swift +++ b/Riot/Modules/MediaPicker/MediaPickerCoordinatorBridgePresenter.swift @@ -20,7 +20,7 @@ import Foundation @objc protocol MediaPickerCoordinatorBridgePresenterDelegate { func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectImageData imageData: Data, withUTI uti: MXKUTI?) - func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectVideoAt url: URL) + func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectVideo videoAsset: AVAsset) func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectAssets assets: [PHAsset]) func mediaPickerCoordinatorBridgePresenterDidCancel(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter) } @@ -110,8 +110,8 @@ extension MediaPickerCoordinatorBridgePresenter: MediaPickerCoordinatorDelegate self.delegate?.mediaPickerCoordinatorBridgePresenter(self, didSelectImageData: imageData, withUTI: uti) } - func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectVideoAt url: URL) { - self.delegate?.mediaPickerCoordinatorBridgePresenter(self, didSelectVideoAt: url) + func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectVideo videoAsset: AVAsset) { + self.delegate?.mediaPickerCoordinatorBridgePresenter(self, didSelectVideo: videoAsset) } func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectAssets assets: [PHAsset]) { diff --git a/Riot/Modules/MediaPicker/MediaPickerCoordinatorType.swift b/Riot/Modules/MediaPicker/MediaPickerCoordinatorType.swift index 53f154536..9d91bdadc 100644 --- a/Riot/Modules/MediaPicker/MediaPickerCoordinatorType.swift +++ b/Riot/Modules/MediaPicker/MediaPickerCoordinatorType.swift @@ -20,7 +20,7 @@ import Foundation protocol MediaPickerCoordinatorDelegate: class { func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectImageData imageData: Data, withUTI uti: MXKUTI?) - func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectVideoAt url: URL) + func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectVideo videoAsset: AVAsset) func mediaPickerCoordinator(_ coordinator: MediaPickerCoordinatorType, didSelectAssets assets: [PHAsset]) func mediaPickerCoordinatorDidCancel(_ coordinator: MediaPickerCoordinatorType) } diff --git a/Riot/Modules/MediaPicker/MediaPickerViewController.h b/Riot/Modules/MediaPicker/MediaPickerViewController.h index 99e9365fe..71487e1ea 100644 --- a/Riot/Modules/MediaPicker/MediaPickerViewController.h +++ b/Riot/Modules/MediaPicker/MediaPickerViewController.h @@ -39,9 +39,9 @@ Tells the delegate that the user select a video. @param mediaPickerController the `MediaPickerViewController` instance. - @param videoURL the local url of the video to send. + @param videoAsset an `AVAsset` that represents the video to send. */ -- (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController didSelectVideo:(NSURL*)videoURL; +- (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController didSelectVideo:(AVAsset*)videoAsset; /** Tells the delegate that the user wants to cancel media picking. diff --git a/Riot/Modules/MediaPicker/MediaPickerViewController.m b/Riot/Modules/MediaPicker/MediaPickerViewController.m index d08e6ab17..e34617241 100644 --- a/Riot/Modules/MediaPicker/MediaPickerViewController.m +++ b/Riot/Modules/MediaPicker/MediaPickerViewController.m @@ -608,28 +608,19 @@ if (asset) { - if ([asset isKindOfClass:[AVURLAsset class]]) - { - MXLogDebug(@"[MediaPickerVC] didSelectAsset: Got AVAsset for video"); - AVURLAsset *avURLAsset = (AVURLAsset*)asset; + MXLogDebug(@"[MediaPickerVC] didSelectAsset: Got AVAsset for video"); + + // Validate first the selected video + [self validateSelectedVideo:asset responseHandler:^(BOOL isValidated) { + + if (isValidated) + { + [self.delegate mediaPickerController:self didSelectVideo:asset]; + } - // Validate first the selected video - [self validateSelectedVideo:[avURLAsset URL] responseHandler:^(BOOL isValidated) { - - if (isValidated) - { - [self.delegate mediaPickerController:self didSelectVideo:[avURLAsset URL]]; - } - - self->isValidationInProgress = NO; - - }]; - } - else - { - MXLogDebug(@"[MediaPickerVC] Selected video asset is not initialized from an URL!"); self->isValidationInProgress = NO; - } + + }]; } else { @@ -693,7 +684,7 @@ [self setNeedsStatusBarAppearanceUpdate]; } -- (void)validateSelectedVideo:(NSURL*)selectedVideoURL responseHandler:(void (^)(BOOL isValidated))handler +- (void)validateSelectedVideo:(AVAsset*)selectedVideo responseHandler:(void (^)(BOOL isValidated))handler { [self dismissImageValidationView]; @@ -727,15 +718,15 @@ videoPlayer = [[AVPlayerViewController alloc] init]; if (videoPlayer) { + AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:selectedVideo]; videoPlayer.allowsPictureInPicturePlayback = NO; videoPlayer.updatesNowPlayingInfoCenter = NO; - videoPlayer.player = [AVPlayer playerWithURL:selectedVideoURL]; + videoPlayer.player = [AVPlayer playerWithPlayerItem:item]; videoPlayer.videoGravity = AVLayerVideoGravityResizeAspect; videoPlayer.showsPlaybackControls = NO; // create a thumbnail for the first frame - AVAsset *asset = [AVAsset assetWithURL:selectedVideoURL]; - AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:selectedVideo]; generator.appliesPreferredTrackTransform = YES; CGImageRef thumbnailRef = [generator copyCGImageAtTime:kCMTimeZero actualTime:nil error:nil]; diff --git a/Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift b/Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift index f8bc066ee..56f501fdd 100644 --- a/Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift +++ b/Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift @@ -135,7 +135,7 @@ extension SingleImagePickerPresenter: MediaPickerCoordinatorBridgePresenterDeleg self.delegate?.singleImagePickerPresenter(self, didSelectImageData: imageData, withUTI: uti) } - func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectVideoAt url: URL) { + func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectVideo videoAsset: AVAsset) { self.delegate?.singleImagePickerPresenterDidCancel(self) } diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index fb4b7db8f..327704b47 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -6080,7 +6080,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } } -- (void)mediaPickerCoordinatorBridgePresenter:(MediaPickerCoordinatorBridgePresenter *)coordinatorBridgePresenter didSelectVideoAt:(NSURL *)url +- (void)mediaPickerCoordinatorBridgePresenter:(MediaPickerCoordinatorBridgePresenter *)coordinatorBridgePresenter didSelectVideo:(AVAsset *)videoAsset { [coordinatorBridgePresenter dismissWithAnimated:YES completion:nil]; self.mediaPickerPresenter = nil; @@ -6088,7 +6088,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; RoomInputToolbarView *roomInputToolbarView = [self inputToolbarViewAsRoomInputToolbarView]; if (roomInputToolbarView) { - [roomInputToolbarView sendSelectedVideo:url isPhotoLibraryAsset:YES]; + [roomInputToolbarView sendSelectedVideo:videoAsset isPhotoLibraryAsset:YES]; } } From d95b182fdadbb356a99664bfd3ef20b77571d777 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 16:55:32 +0100 Subject: [PATCH 36/49] Send videos from the camera as AVURLAsset objects. --- Riot/Modules/Room/RoomViewController.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 327704b47..03f224687 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -6056,7 +6056,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; RoomInputToolbarView *roomInputToolbarView = [self inputToolbarViewAsRoomInputToolbarView]; if (roomInputToolbarView) { - [roomInputToolbarView sendSelectedVideo:url isPhotoLibraryAsset:NO]; + AVURLAsset *selectedVideo = [AVURLAsset assetWithURL:url]; + [roomInputToolbarView sendSelectedVideo:selectedVideo isPhotoLibraryAsset:NO]; } } From 5257e82b1b3779d421bac562d794ace0c21d3cb0 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 17:16:54 +0100 Subject: [PATCH 37/49] Fix sending videos from the share extension. --- RiotShareExtension/Managers/ShareExtensionManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RiotShareExtension/Managers/ShareExtensionManager.m b/RiotShareExtension/Managers/ShareExtensionManager.m index 47dfb03c4..189a224d4 100644 --- a/RiotShareExtension/Managers/ShareExtensionManager.m +++ b/RiotShareExtension/Managers/ShareExtensionManager.m @@ -1174,7 +1174,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) UIImage *videoThumbnail = [[UIImage alloc] initWithCGImage:imageRef]; CFRelease(imageRef); - [room sendVideo:videoLocalUrl withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) { + [room sendVideo:urlAsset withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) { if (successBlock) { successBlock(); From ba8123c73ad894c978426ef91c7e58878eebc3d1 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 8 Jul 2021 17:41:55 +0100 Subject: [PATCH 38/49] Fix sending a video selected from a document picker. --- Riot/Modules/Room/DataSources/RoomDataSource.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 831f96634..8cd789153 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -887,8 +887,10 @@ const CGFloat kTypingCellHeight = 24; success:(void (^)(NSString *eventId))success failure:(void (^)(NSError *error))failure { + AVURLAsset *videoAsset = [AVURLAsset assetWithURL:videoLocalURL]; UIImage *videoThumbnail = [MXKVideoThumbnailGenerator.shared generateThumbnailFrom:videoLocalURL]; - [self sendVideo:videoLocalURL withThumbnail:videoThumbnail success:success failure:failure]; + + [self sendVideo:videoAsset withThumbnail:videoThumbnail success:success failure:failure]; } - (void)acceptVerificationRequestForEventId:(NSString*)eventId success:(void(^)(void))success failure:(void(^)(NSError*))failure From 816513cee6a79b6be9c9342e294d8197e6f0309f Mon Sep 17 00:00:00 2001 From: langleyd Date: Thu, 8 Jul 2021 20:54:32 +0100 Subject: [PATCH 39/49] Fix logging, add "Notify me for" label, fix theme on avatar and add changes --- CHANGES.rst | 2 +- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++ .../SectionHeaders/TitleHeaderView.swift | 39 +++++++++++++++++++ .../Common/SectionHeaders/TitleHeaderView.xib | 39 +++++++++++++++++++ .../RoomNotificationSettingsAvatarView.swift | 10 ++++- ...omNotificationSettingsViewController.swift | 27 ++++++++----- .../RoomNotificationsSettingsCell.swift | 2 + .../RoomNotificationsSettingsService.swift | 2 +- 9 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 Riot/Modules/Common/SectionHeaders/TitleHeaderView.swift create mode 100644 Riot/Modules/Common/SectionHeaders/TitleHeaderView.xib diff --git a/CHANGES.rst b/CHANGES.rst index 486c751b3..1f76bc4dc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,7 @@ Changes to be released in next version * 🙌 Improvements - * + * Room Norification Settings: Ability to change between "All Messages", "Mentions and Keywords" and "None". Not yet exposed in Element UI. (#4458). 🐛 Bugfix * VoIP: Do not present ended calls. diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index ab0cccfab..807d7069d 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -774,6 +774,7 @@ Tap the + to start adding people."; "room_details_copy_room_url" = "Copy Room URL"; // Room Notification Settings +"room_notifs_settings_notify_me_for" = "Notify me for"; "room_notifs_settings_all_messages" = "All Messages"; "room_notifs_settings_mentions_and_keywords" = "Mentions and Keywords only"; "room_notifs_settings_none" = "None"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index e192f4340..f42dc4450 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -3054,6 +3054,10 @@ internal enum VectorL10n { internal static var roomNotifsSettingsNone: String { return VectorL10n.tr("Vector", "room_notifs_settings_none") } + /// Notify me for + internal static var roomNotifsSettingsNotifyMeFor: String { + return VectorL10n.tr("Vector", "room_notifs_settings_notify_me_for") + } /// Connectivity to the server has been lost. internal static var roomOfflineNotification: String { return VectorL10n.tr("Vector", "room_offline_notification") diff --git a/Riot/Modules/Common/SectionHeaders/TitleHeaderView.swift b/Riot/Modules/Common/SectionHeaders/TitleHeaderView.swift new file mode 100644 index 000000000..a26d99820 --- /dev/null +++ b/Riot/Modules/Common/SectionHeaders/TitleHeaderView.swift @@ -0,0 +1,39 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Reusable + +class TitleHeaderView: UITableViewHeaderFooterView { + + @IBOutlet weak var label: UILabel! + + func update(title: String) { + label.text = title.uppercased() + } + +} + + +extension TitleHeaderView: NibReusable {} +extension TitleHeaderView: Themable { + + func update(theme: Theme) { + contentView.backgroundColor = theme.headerBackgroundColor + label.textColor = theme.headerTextSecondaryColor + label.font = theme.fonts.body + } +} diff --git a/Riot/Modules/Common/SectionHeaders/TitleHeaderView.xib b/Riot/Modules/Common/SectionHeaders/TitleHeaderView.xib new file mode 100644 index 000000000..c49ab7fff --- /dev/null +++ b/Riot/Modules/Common/SectionHeaders/TitleHeaderView.xib @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift index 39fe4dbec..c9bf9af89 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsAvatarView.swift @@ -17,7 +17,7 @@ import Foundation import Reusable -class RoomNotificationSettingsAvatarView: UIView, NibLoadable { +class RoomNotificationSettingsAvatarView: UIView { @IBOutlet weak var avatarView: MXKImageView! @IBOutlet weak var nameLabel: UILabel! @@ -41,3 +41,11 @@ class RoomNotificationSettingsAvatarView: UIView, NibLoadable { nameLabel.text = viewData.displayName } } + +extension RoomNotificationSettingsAvatarView: NibLoadable { } +extension RoomNotificationSettingsAvatarView: Themable { + func update(theme: Theme) { + nameLabel?.font = theme.fonts.title3SB + nameLabel?.textColor = theme.textPrimaryColor + } +} diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift index 21eb3e6e3..3e2adf89e 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationSettingsViewController.swift @@ -46,6 +46,7 @@ final class RoomNotificationSettingsViewController: UIViewController { } private struct Section { + var title: String var rows: [Row] var footerState: RoomNotificationSettingsFooter.State } @@ -128,8 +129,11 @@ final class RoomNotificationSettingsViewController: UIViewController { navigationItem.rightBarButtonItem = doneBarButtonItem mainTableView.register(cellType: RoomNotificationSettingsCell.self) mainTableView.register(headerFooterViewType: RoomNotificationSettingsFooter.self) + mainTableView.register(headerFooterViewType: TitleHeaderView.self) mainTableView.sectionFooterHeight = UITableView.automaticDimension + mainTableView.sectionHeaderHeight = UITableView.automaticDimension mainTableView.estimatedSectionFooterHeight = 50 + mainTableView.estimatedSectionHeaderHeight = 30 } private func render(viewState: RoomNotificationSettingsViewStateType) { @@ -143,6 +147,7 @@ final class RoomNotificationSettingsViewController: UIViewController { if let avatarData = viewState.avatarData { mainTableView.tableHeaderView = avatarView avatarView.configure(viewData: avatarData) + avatarView.update(theme: theme) } updateSections() } @@ -156,7 +161,7 @@ final class RoomNotificationSettingsViewController: UIViewController { }) }) let footerState = RoomNotificationSettingsFooter.State(showEncryptedNotice: viewState.roomEncrypted, showAccountLink: false) - let section0 = Section(rows: rows, footerState: footerState) + let section0 = Section(title: VectorL10n.roomNotifsSettingsNotifyMeFor, rows: rows, footerState: footerState) sections = [ section0 ] @@ -181,9 +186,12 @@ extension RoomNotificationSettingsViewController: UITableViewDataSource { cell.update(theme: theme) return cell } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return UITableView.automaticDimension + } func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - return UITableView.automaticDimension } @@ -192,14 +200,15 @@ extension RoomNotificationSettingsViewController: UITableViewDataSource { // MARK: - UITableViewDelegate extension RoomNotificationSettingsViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - cell.backgroundColor = theme.backgroundColor - cell.selectedBackgroundView = UIView() - cell.selectedBackgroundView?.backgroundColor = theme.selectedBackgroundColor + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + guard let headerView: TitleHeaderView = tableView.dequeueReusableHeaderFooterView() else { return nil } + headerView.update(title: sections[section].title) + headerView.update(theme: theme) + return headerView } - + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { - guard let footerView: RoomNotificationSettingsFooter = tableView.dequeueReusableHeaderFooterView() else { return nil } + guard let footerView: RoomNotificationSettingsFooter = tableView.dequeueReusableHeaderFooterView() else { return nil } let footerState = sections[section].footerState footerView.update(footerState: footerState) footerView.update(theme: theme) @@ -212,7 +221,7 @@ extension RoomNotificationSettingsViewController: UITableViewDelegate { let row = sections[indexPath.section].rows[indexPath.row] row.action?() } - + } // MARK: - RoomNotificationSettingsViewModelViewDelegate diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift index 3d4bec1f7..343c7bba4 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsCell.swift @@ -37,6 +37,8 @@ extension RoomNotificationSettingsCell: Themable { backgroundColor = theme.backgroundColor contentView.backgroundColor = .clear tintColor = theme.tintColor + selectedBackgroundView = UIView() + selectedBackgroundView?.backgroundColor = theme.selectedBackgroundColor } } diff --git a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift index bb7e2fe81..1bd0e4b6b 100644 --- a/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift +++ b/Riot/Modules/Room/NotificationSettings/RoomNotificationsSettingsService.swift @@ -93,7 +93,7 @@ final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType } guard notificationCenterDidUpdateObserver == nil else { - MXLog.debug("[MXRoom+Riot] Request in progress: ignore push rule update") + MXLog.debug("[RoomNotificationSettingsService] Request in progress: ignore push rule update") completion() return } From 239176067e5cf7a55b745bf39e255f4f386a1e63 Mon Sep 17 00:00:00 2001 From: langleyd Date: Fri, 9 Jul 2021 09:08:42 +0100 Subject: [PATCH 40/49] Update template copyright date --- .../FlowCoordinatorTemplate/FlowTemplateCoordinator.swift | 2 +- .../FlowTemplateCoordinatorBridgePresenter.swift | 2 +- .../FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift | 2 +- .../buildable/ScreenTemplate/TemplateScreenCoordinator.swift | 2 +- .../ScreenTemplate/TemplateScreenCoordinatorType.swift | 2 +- .../buildable/ScreenTemplate/TemplateScreenViewAction.swift | 2 +- .../buildable/ScreenTemplate/TemplateScreenViewController.swift | 2 +- .../buildable/ScreenTemplate/TemplateScreenViewModel.swift | 2 +- .../buildable/ScreenTemplate/TemplateScreenViewModelType.swift | 2 +- .../buildable/ScreenTemplate/TemplateScreenViewState.swift | 2 +- .../SimpleScreenTemplateViewController.swift | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift index a211ab040..2f51aa2c2 100644 --- a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift +++ b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift index bb7f824e4..25024f94d 100644 --- a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift +++ b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift index 4fa5cc5dc..057328e71 100644 --- a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift +++ b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift index 78ebc30f8..276fff2a8 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift index 745997b9c..8b390ac60 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift index 0bfc0f7f2..fc25efd98 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift index f3a30d180..78175a877 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift index 05c07ba58..4c386a8f7 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift index fd03254da..19e3af58c 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift index cc347baaa..4cebae662 100644 --- a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. diff --git a/Tools/Templates/buildable/SimpleScreenTemplate/SimpleScreenTemplateViewController.swift b/Tools/Templates/buildable/SimpleScreenTemplate/SimpleScreenTemplateViewController.swift index 2955714c9..b4c86a60b 100644 --- a/Tools/Templates/buildable/SimpleScreenTemplate/SimpleScreenTemplateViewController.swift +++ b/Tools/Templates/buildable/SimpleScreenTemplate/SimpleScreenTemplateViewController.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 New Vector Ltd + Copyright 2021 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. From b9ea5d4be9cf4a23c74b6fea8de3f1aaaae8f440 Mon Sep 17 00:00:00 2001 From: Doug Date: Fri, 9 Jul 2021 10:26:02 +0100 Subject: [PATCH 41/49] Update to use sendVideoAsset: on MXRoom. --- RiotShareExtension/Managers/ShareExtensionManager.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RiotShareExtension/Managers/ShareExtensionManager.m b/RiotShareExtension/Managers/ShareExtensionManager.m index 189a224d4..5b69743be 100644 --- a/RiotShareExtension/Managers/ShareExtensionManager.m +++ b/RiotShareExtension/Managers/ShareExtensionManager.m @@ -1165,8 +1165,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } // Retrieve the video frame at 1 sec to define the video thumbnail - AVURLAsset *urlAsset = [[AVURLAsset alloc] initWithURL:videoLocalUrl options:nil]; - AVAssetImageGenerator *assetImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset]; + AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoLocalUrl options:nil]; + AVAssetImageGenerator *assetImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:videoAsset]; assetImageGenerator.appliesPreferredTrackTransform = YES; CMTime time = CMTimeMake(1, 1); CGImageRef imageRef = [assetImageGenerator copyCGImageAtTime:time actualTime:NULL error:nil]; @@ -1174,7 +1174,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) UIImage *videoThumbnail = [[UIImage alloc] initWithCGImage:imageRef]; CFRelease(imageRef); - [room sendVideo:urlAsset withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) { + [room sendVideoAsset:videoAsset withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) { if (successBlock) { successBlock(); From 99b5286ed71f0fa4d9cc4a3c22099b92c57837bd Mon Sep 17 00:00:00 2001 From: Doug Date: Fri, 9 Jul 2021 11:04:00 +0100 Subject: [PATCH 42/49] Update CHANGES.rst. --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 486c751b3..803bdea12 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,7 @@ Changes to be released in next version * 🙌 Improvements - * + * Add support for sending slow motion videos (#4483). 🐛 Bugfix * VoIP: Do not present ended calls. From a8938f4794e70b93693154fd90a831c8bfa18d0a Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 9 Jul 2021 16:38:25 +0100 Subject: [PATCH 43/49] Don't show dialog on cancel if self-verifying The user should know they cancelled in if they're self verifying since they're the one who cancelled, from their other device (the copy referred to 'the other party', so was inaccurate, so we may as well just remove it). --- ...ficationVerifyByScanningViewController.swift | 17 +++++++++++++---- ...yVerificationVerifyByScanningViewModel.swift | 4 ++-- ...yVerificationVerifyByScanningViewState.swift | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift index cb8bc27f6..f9798806d 100644 --- a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift +++ b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift @@ -159,8 +159,8 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController { self.render(error: error) case .scannedCodeValidated(let isValid): self.renderScannedCode(valid: isValid) - case .cancelled(let reason): - self.renderCancelled(reason: reason) + case .cancelled(let reason, let verificationKind): + self.renderCancelled(reason: reason, verificationKind: verificationKind) case .cancelledByMe(let reason): self.renderCancelledByMe(reason: reason) } @@ -236,12 +236,21 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController { } } - private func renderCancelled(reason: MXTransactionCancelCode) { + private func renderCancelled(reason: MXTransactionCancelCode, + verificationKind: KeyVerificationKind) { self.activityPresenter.removeCurrentActivityIndicator(animated: true) self.stopQRCodeScanningIfPresented() - self.errorPresenter.presentError(from: self.alertPresentingViewController, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) { + // if we're verifying with someone else, let the user know threy cancelled. + // if we're verifying our own device, assume the user probably knows since it them who + // cancelled on their other device + if verificationKind == .user { + self.errorPresenter.presentError(from: self.alertPresentingViewController, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) { + self.dismissQRCodeScanningIfPresented(animated: false) + self.viewModel.process(viewAction: .cancel) + } + } else { self.dismissQRCodeScanningIfPresented(animated: false) self.viewModel.process(viewAction: .cancel) } diff --git a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewModel.swift b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewModel.swift index 706a121d9..de4b9e189 100644 --- a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewModel.swift +++ b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewModel.swift @@ -225,7 +225,7 @@ final class KeyVerificationVerifyByScanningViewModel: KeyVerificationVerifyBySca return } self.unregisterTransactionDidStateChangeNotification() - self.update(viewState: .cancelled(reason)) + self.update(viewState: .cancelled(cancelCode: reason, verificationKind: verificationKind)) case MXSASTransactionStateCancelledByMe: guard let reason = transaction.reasonCancelCode else { return @@ -251,7 +251,7 @@ final class KeyVerificationVerifyByScanningViewModel: KeyVerificationVerifyBySca return } self.unregisterTransactionDidStateChangeNotification() - self.update(viewState: .cancelled(reason)) + self.update(viewState: .cancelled(cancelCode: reason, verificationKind: verificationKind)) case .cancelledByMe: guard let reason = transaction.reasonCancelCode else { return diff --git a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewState.swift b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewState.swift index b6323eb70..e3ecc8238 100644 --- a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewState.swift +++ b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewState.swift @@ -29,7 +29,7 @@ enum KeyVerificationVerifyByScanningViewState { case loading case loaded(viewData: KeyVerificationVerifyByScanningViewData) case scannedCodeValidated(isValid: Bool) - case cancelled(MXTransactionCancelCode) + case cancelled(cancelCode: MXTransactionCancelCode, verificationKind: KeyVerificationKind) case cancelledByMe(MXTransactionCancelCode) case error(Error) } From 87f3cad5cfe4af072acd8eaded9574a3c1520d6d Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Fri, 9 Jul 2021 17:58:27 +0100 Subject: [PATCH 44/49] Fix typo in comments. --- .../KeyVerificationVerifyByScanningViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift index f9798806d..49f1a80ca 100644 --- a/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift +++ b/Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift @@ -242,8 +242,8 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController { self.stopQRCodeScanningIfPresented() - // if we're verifying with someone else, let the user know threy cancelled. - // if we're verifying our own device, assume the user probably knows since it them who + // if we're verifying with someone else, let the user know they cancelled. + // if we're verifying our own device, assume the user probably knows since it was them who // cancelled on their other device if verificationKind == .user { self.errorPresenter.presentError(from: self.alertPresentingViewController, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) { From b1d4f2dd372deb3dee3672dee42649be06bdc182 Mon Sep 17 00:00:00 2001 From: Gil Eluard Date: Fri, 9 Jul 2021 23:54:25 +0200 Subject: [PATCH 45/49] it's easy for the back button to trigger a leftpanel reveal (#4438) - Fixed --- Riot/Modules/TabBar/TabBarCoordinator.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/TabBar/TabBarCoordinator.swift b/Riot/Modules/TabBar/TabBarCoordinator.swift index 0efc1c03c..cb28c4427 100644 --- a/Riot/Modules/TabBar/TabBarCoordinator.swift +++ b/Riot/Modules/TabBar/TabBarCoordinator.swift @@ -245,9 +245,9 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { } private func setupSideMenuGestures() { - self.parameters.appNavigator.sideMenu.addScreenEdgePanGesturesToPresent(to: self.masterNavigationController.view) - - self.parameters.appNavigator.sideMenu.addPanGestureToPresent(to: self.masterNavigationController.navigationBar) + if let rootViewController = self.masterNavigationController.viewControllers.first { + self.parameters.appNavigator.sideMenu.addScreenEdgePanGesturesToPresent(to: rootViewController.view) + } } // MARK: Navigation From 31f02a543d930aaa0f39e62d44adef86c51cb1a6 Mon Sep 17 00:00:00 2001 From: Gil Eluard Date: Fri, 9 Jul 2021 23:57:34 +0200 Subject: [PATCH 46/49] it's easy for the back button to trigger a leftpanel reveal (#4438) - Updated CHANGES.rst --- Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme index 84ecb908a..a9bea1d96 100644 --- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme +++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme @@ -4,7 +4,8 @@ version = "1.3"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> Date: Fri, 9 Jul 2021 23:58:32 +0200 Subject: [PATCH 47/49] it's easy for the back button to trigger a leftpanel reveal (#4438) - Updated CHANGES.rst --- CHANGES.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index e62d281e9..65744cf74 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,7 +13,8 @@ Changes to be released in next version * Fix crash on Apple Silicon Macs. * Media Picker: Generate video thumbnails with the correct orientation (#4515). * Directory List (pop-up one): Fix duplicate rooms being shown (#4537). - * Use different title for scan button for self verification (#4525) + * Use different title for scan button for self verification (#4525). + * it's easy for the back button to trigger a leftpanel reveal (#4438). ⚠️ API Changes * From f8e89b99eafbb6910820de54fa8f4390a8ef211c Mon Sep 17 00:00:00 2001 From: Gil Eluard Date: Sat, 10 Jul 2021 00:01:47 +0200 Subject: [PATCH 48/49] it's easy for the back button to trigger a leftpanel reveal (#4438) - Reverted Riot.xcscheme --- Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme index a9bea1d96..84ecb908a 100644 --- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme +++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme @@ -4,8 +4,7 @@ version = "1.3"> + buildImplicitDependencies = "YES"> Date: Mon, 12 Jul 2021 14:02:29 +0100 Subject: [PATCH 49/49] Use updated methods in MatrixKit. --- Riot/Modules/Room/DataSources/RoomDataSource.m | 2 +- Riot/Modules/Room/RoomViewController.m | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 8cd789153..230d313ce 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -890,7 +890,7 @@ const CGFloat kTypingCellHeight = 24; AVURLAsset *videoAsset = [AVURLAsset assetWithURL:videoLocalURL]; UIImage *videoThumbnail = [MXKVideoThumbnailGenerator.shared generateThumbnailFrom:videoLocalURL]; - [self sendVideo:videoAsset withThumbnail:videoThumbnail success:success failure:failure]; + [self sendVideoAsset:videoAsset withThumbnail:videoThumbnail success:success failure:failure]; } - (void)acceptVerificationRequestForEventId:(NSString*)eventId success:(void(^)(void))success failure:(void(^)(NSError*))failure diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 03f224687..fbd8a25f0 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -6057,7 +6057,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if (roomInputToolbarView) { AVURLAsset *selectedVideo = [AVURLAsset assetWithURL:url]; - [roomInputToolbarView sendSelectedVideo:selectedVideo isPhotoLibraryAsset:NO]; + [roomInputToolbarView sendSelectedVideoAsset:selectedVideo isPhotoLibraryAsset:NO]; } } @@ -6089,7 +6089,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; RoomInputToolbarView *roomInputToolbarView = [self inputToolbarViewAsRoomInputToolbarView]; if (roomInputToolbarView) { - [roomInputToolbarView sendSelectedVideo:videoAsset isPhotoLibraryAsset:YES]; + [roomInputToolbarView sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:YES]; } }