diff --git a/Podfile b/Podfile index dac09e1641..6361c6779b 100644 --- a/Podfile +++ b/Podfile @@ -4,13 +4,15 @@ platform :ios, '10.0' # Use frameforks to allow usage of pod written in Swift (like PiwikTracker) use_frameworks! +# Suppress all warnings for now +inhibit_all_warnings! # Different flavours of pods to MatrixKit # The current MatrixKit pod version $matrixKitVersion = '0.12.6' # The develop branch version -#$matrixKitVersion = 'develop' +$matrixKitVersion = 'develop' # The one used for developing both MatrixSDK and MatrixKit # Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index d1a122ce64..e2b6ca4cb0 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -734,6 +734,16 @@ B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E5368C21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift */; }; B1E5368F21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1E5368E21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard */; }; B1FDF56021F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FDF55F21F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift */; }; + EC4968B224A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4968AA24A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.swift */; }; + EC4968B324A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC4968AB24A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.storyboard */; }; + EC4968B424A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4968AD24A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.swift */; }; + EC4968B524A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC4968AE24A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.storyboard */; }; + EC4968B624A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC4968B024A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.storyboard */; }; + EC4968B724A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4968B124A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.swift */; }; + EC8B26BC24A4D8B300025FEA /* MXKTableViewCellWithLabelAndSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8B26BB24A4D8B300025FEA /* MXKTableViewCellWithLabelAndSwitch.swift */; }; + EC8B26BE24A5131E00025FEA /* RoomNotificationSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8B26BD24A5131E00025FEA /* RoomNotificationSetting.swift */; }; + EC8B26C024A515A000025FEA /* MXRoom.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8B26BF24A515A000025FEA /* MXRoom.swift */; }; + EC8B26C224A54DD900025FEA /* RiotTableViewHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8B26C124A54DD900025FEA /* RiotTableViewHeaderFooterView.swift */; }; F05927C91FDED836009F2A68 /* MXGroup+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F05927C71FDED835009F2A68 /* MXGroup+Riot.m */; }; F083BD1E1E7009ED00A9B29C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BB0D1E7009EC00A9B29C /* AppDelegate.m */; }; F083BDE61E7009ED00A9B29C /* busy.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = F083BBDB1E7009EC00A9B29C /* busy.mp3 */; }; @@ -1749,6 +1759,16 @@ B43DC75D1590BB8A4243BD4D /* Pods-RiotPods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-Riot.release.xcconfig"; path = "Target Support Files/Pods-RiotPods-Riot/Pods-RiotPods-Riot.release.xcconfig"; sourceTree = ""; }; BABB6681FBD79219B1213D6C /* Pods-RiotTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotTests.debug.xcconfig"; path = "Target Support Files/Pods-RiotTests/Pods-RiotTests.debug.xcconfig"; sourceTree = ""; }; E2599D0ECB8DD206624E450B /* Pods-RiotPods-SiriIntents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-SiriIntents.release.xcconfig"; path = "Target Support Files/Pods-RiotPods-SiriIntents/Pods-RiotPods-SiriIntents.release.xcconfig"; sourceTree = ""; }; + EC4968AA24A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsHomeViewController.swift; sourceTree = ""; }; + EC4968AB24A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RoomNotificationSettingsHomeViewController.storyboard; sourceTree = ""; }; + EC4968AD24A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsNotifyViewController.swift; sourceTree = ""; }; + EC4968AE24A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RoomNotificationSettingsNotifyViewController.storyboard; sourceTree = ""; }; + EC4968B024A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RoomNotificationSettingsSoundViewController.storyboard; sourceTree = ""; }; + EC4968B124A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsSoundViewController.swift; sourceTree = ""; }; + EC8B26BB24A4D8B300025FEA /* MXKTableViewCellWithLabelAndSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXKTableViewCellWithLabelAndSwitch.swift; sourceTree = ""; }; + EC8B26BD24A5131E00025FEA /* RoomNotificationSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomNotificationSetting.swift; sourceTree = ""; }; + EC8B26BF24A515A000025FEA /* MXRoom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXRoom.swift; sourceTree = ""; }; + EC8B26C124A54DD900025FEA /* RiotTableViewHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiotTableViewHeaderFooterView.swift; sourceTree = ""; }; F05927C71FDED835009F2A68 /* MXGroup+Riot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MXGroup+Riot.m"; sourceTree = ""; }; F05927C81FDED835009F2A68 /* MXGroup+Riot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MXGroup+Riot.h"; sourceTree = ""; }; F083BB031E7005FD00A9B29C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -2179,13 +2199,14 @@ name = Frameworks; sourceTree = ""; }; - 6E6F1CAE244DFB840068B78B /* SectionHeaders */ = { + 6E6F1CAE244DFB840068B78B /* SectionHeaderFooters */ = { isa = PBXGroup; children = ( 6E6F1CA8244DC1E90068B78B /* SectionHeaderView.h */, 6E6F1CA9244DC1E90068B78B /* SectionHeaderView.m */, + EC8B26C124A54DD900025FEA /* RiotTableViewHeaderFooterView.swift */, ); - path = SectionHeaders; + path = SectionHeaderFooters; sourceTree = ""; }; 6E75C3E4245AF60500AF497D /* PushNotification */ = { @@ -3071,6 +3092,7 @@ B1B5569020EE6C4C00210D55 /* Settings */ = { isa = PBXGroup; children = ( + EC4968A824A38EF0004AE47B /* Notifications */, B1B5569120EE6C4C00210D55 /* RoomSettingsViewController.h */, B1B5569220EE6C4C00210D55 /* RoomSettingsViewController.m */, B1B5592D20EF7BAC00210D55 /* Views */, @@ -3246,7 +3268,7 @@ B1B556CD20EE6C4C00210D55 /* Common */ = { isa = PBXGroup; children = ( - 6E6F1CAE244DFB840068B78B /* SectionHeaders */, + 6E6F1CAE244DFB840068B78B /* SectionHeaderFooters */, B183226923F59F3E0035B2E8 /* Buttons */, B1963B3622933B9500CBA17F /* CollectionView */, B1B556CE20EE6C4C00210D55 /* WebViewController */, @@ -4327,6 +4349,43 @@ path = Recover; sourceTree = ""; }; + EC4968A824A38EF0004AE47B /* Notifications */ = { + isa = PBXGroup; + children = ( + EC4968A924A38EF0004AE47B /* Home */, + EC4968AC24A38EF0004AE47B /* Notify */, + EC4968AF24A38EF0004AE47B /* Sound */, + ); + path = Notifications; + sourceTree = ""; + }; + EC4968A924A38EF0004AE47B /* Home */ = { + isa = PBXGroup; + children = ( + EC4968AA24A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.swift */, + EC4968AB24A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.storyboard */, + ); + path = Home; + sourceTree = ""; + }; + EC4968AC24A38EF0004AE47B /* Notify */ = { + isa = PBXGroup; + children = ( + EC4968AD24A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.swift */, + EC4968AE24A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.storyboard */, + ); + path = Notify; + sourceTree = ""; + }; + EC4968AF24A38EF0004AE47B /* Sound */ = { + isa = PBXGroup; + children = ( + EC4968B024A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.storyboard */, + EC4968B124A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.swift */, + ); + path = Sound; + sourceTree = ""; + }; F083BB021E7005FD00A9B29C /* RiotTests */ = { isa = PBXGroup; children = ( @@ -4433,6 +4492,8 @@ 6E6F1CB424506FA40068B78B /* UITableView.swift */, B117E1F12453244B0089679F /* UILabel.swift */, B1CA93752493CBF200575122 /* MXRecoveryService.swift */, + EC8B26BB24A4D8B300025FEA /* MXKTableViewCellWithLabelAndSwitch.swift */, + EC8B26BF24A515A000025FEA /* MXRoom.swift */, ); path = Categories; sourceTree = ""; @@ -4454,6 +4515,7 @@ F083BBFD1E7009EC00A9B29C /* RoomPreviewData.h */, F083BBFE1E7009EC00A9B29C /* RoomPreviewData.m */, B1D44998243CD73700959523 /* RoomPowerLevel.swift */, + EC8B26BD24A5131E00025FEA /* RoomNotificationSetting.swift */, ); path = Room; sourceTree = ""; @@ -4730,6 +4792,7 @@ B105778B221304FA00334B1E /* KeyBackupSetupSuccessFromPassphraseViewController.storyboard in Resources */, B1664DA220F4F95800808783 /* Localizable.strings in Resources */, B169328720F3954A00746532 /* SharedImages.xcassets in Resources */, + EC4968B524A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.storyboard in Resources */, B1664DA120F4F94F00808783 /* InfoPlist.strings in Resources */, B1B5579B20EF575B00210D55 /* AuthInputsView.xib in Resources */, B1B5594620EF7BD000210D55 /* RoomCollectionViewCell.xib in Resources */, @@ -4781,6 +4844,7 @@ B1550FCA2420E8F500CE097B /* QRCodeReaderViewController.storyboard in Resources */, B1B5579C20EF575B00210D55 /* ForgotPasswordInputsView.xib in Resources */, F083BE011E7009ED00A9B29C /* third_party_licenses.html in Resources */, + EC4968B324A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.storyboard in Resources */, B1098BFC21ECFE65000DDA48 /* PasswordStrengthView.xib in Resources */, B1B5573720EE6C4D00210D55 /* GroupParticipantsViewController.xib in Resources */, B110872421F098F0003554A5 /* ActivityIndicatorView.xib in Resources */, @@ -4860,6 +4924,7 @@ B1B557B320EF5AEF00210D55 /* EventDetailsView.xib in Resources */, B1963B30228F1C4900CBA17F /* BubbleReactionsView.xib in Resources */, B1B557DD20EF5FBB00210D55 /* FilesSearchTableViewCell.xib in Resources */, + EC4968B624A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.storyboard in Resources */, B1B5590320EF768F00210D55 /* RoomSelectedStickerBubbleCell.xib in Resources */, B1B5573F20EE6C4D00210D55 /* SegmentedViewController.xib in Resources */, B1B5581E20EF625800210D55 /* RoomTitleView.xib in Resources */, @@ -5094,6 +5159,7 @@ B1B5573A20EE6C4D00210D55 /* GroupRoomsViewController.m in Sources */, B1B558F920EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.m in Sources */, B1FDF56021F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift in Sources */, + EC4968B224A38EF0004AE47B /* RoomNotificationSettingsHomeViewController.swift in Sources */, B1B5573120EE6C4D00210D55 /* BugReportViewController.m in Sources */, 324A2051225FC571004FE8B0 /* DeviceVerificationIncomingViewState.swift in Sources */, B16932A520F3A21C00746532 /* empty.mm in Sources */, @@ -5211,7 +5277,9 @@ B1B558E120EF768F00210D55 /* RoomMembershipCollapsedBubbleCell.m in Sources */, B1B5571A20EE6C4D00210D55 /* SettingsViewController.m in Sources */, B1CE9EFD22148703000FAE6A /* SignOutAlertPresenter.swift in Sources */, + EC8B26C024A515A000025FEA /* MXRoom.swift in Sources */, 32F6B9692270623100BBA352 /* KeyVerificationDataLoadingCoordinator.swift in Sources */, + EC8B26C224A54DD900025FEA /* RiotTableViewHeaderFooterView.swift in Sources */, B157A7BA2445BD86008A5504 /* KeyVerificationScanConfirmationCoordinator.swift in Sources */, B125FE1D231D5DE400B72806 /* SettingsDiscoveryViewModel.swift in Sources */, 32863A5A2384070300D07C4A /* RiotSharedSettings.swift in Sources */, @@ -5252,6 +5320,7 @@ 32DB557922FDADE50016329E /* ServiceTermsModalScreenViewModel.swift in Sources */, B19C4E8B248F7A0E009A423F /* SecretsRecoveryWithPassphraseCoordinator.swift in Sources */, 32891D75226728EE00C82226 /* KeyVerificationDataLoadingViewController.swift in Sources */, + EC4968B724A38EF0004AE47B /* RoomNotificationSettingsSoundViewController.swift in Sources */, B117E1F22453244B0089679F /* UILabel.swift in Sources */, F083BDEF1E7009ED00A9B29C /* UINavigationController+Riot.m in Sources */, B1B5581F20EF625800210D55 /* SimpleRoomTitleView.m in Sources */, @@ -5337,6 +5406,7 @@ B1BEE71423DF2ACF0003A4CB /* UserVerificationCoordinatorType.swift in Sources */, B1B5596F20EFA85D00210D55 /* EncryptionInfoView.m in Sources */, B1B5573820EE6C4D00210D55 /* GroupParticipantsViewController.m in Sources */, + EC8B26BC24A4D8B300025FEA /* MXKTableViewCellWithLabelAndSwitch.swift in Sources */, 3232ABAB225730E100AD6A5C /* KeyVerificationCoordinator.swift in Sources */, B1BEE73B23DF44A60003A4CB /* UserVerificationSessionsStatusCoordinator.swift in Sources */, B1B5583E20EF6E7F00210D55 /* GroupRoomTableViewCell.m in Sources */, @@ -5495,6 +5565,7 @@ B1DCC61822E5E17100625807 /* EmojiPickerViewState.swift in Sources */, B1B336BF242B933700F95EC4 /* KeyVerificationSelfVerifyStartViewController.swift in Sources */, B1CE83E32422817200D07506 /* VerifyEmojiCollectionViewCell.swift in Sources */, + EC4968B424A38EF0004AE47B /* RoomNotificationSettingsNotifyViewController.swift in Sources */, B1C562DB228C0BB00037F12A /* RoomContextualMenuAction.swift in Sources */, B1B5574720EE6C4D00210D55 /* UsersDevicesViewController.m in Sources */, B1098BFF21ECFE65000DDA48 /* PasswordStrengthView.swift in Sources */, @@ -5530,6 +5601,7 @@ B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */, B1963B3822933BC800CBA17F /* AutosizedCollectionView.swift in Sources */, B12D79FB23E2462200FACEDC /* UserVerificationStartCoordinator.swift in Sources */, + EC8B26BE24A5131E00025FEA /* RoomNotificationSetting.swift in Sources */, B169330320F3C98900746532 /* RoomBubbleCellData.m in Sources */, B1B336C3242B933700F95EC4 /* KeyVerificationSelfVerifyStartCoordinator.swift in Sources */, B1B557CC20EF5D8000210D55 /* DirectoryServerTableViewCell.m in Sources */, diff --git a/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Contents.json new file mode 100644 index 0000000000..afdccdf211 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Vector 26.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Vector 26@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Vector 26@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26.png b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26.png new file mode 100644 index 0000000000..3b612b8b15 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26.png differ diff --git a/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26@2x.png b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26@2x.png new file mode 100644 index 0000000000..e2f29d9823 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26@3x.png b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26@3x.png new file mode 100644 index 0000000000..0fc9c5d967 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/checkmark.imageset/Vector 26@3x.png differ diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index eb2d3e5894..54d109abd7 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -636,7 +636,7 @@ "identity_server_settings_alert_error_invalid_identity_server" = "%@ is not a valid identity server."; -// Room Details +// MARK: Room Details "room_details_title" = "Room Details"; "room_details_people" = "Members"; "room_details_files" = "Files"; @@ -646,7 +646,7 @@ "room_details_topic" = "Topic"; "room_details_favourite_tag" = "Favourite"; "room_details_low_priority_tag" = "Low priority"; -"room_details_mute_notifs" = "Mute notifications"; +"room_details_notifications_row_title" = "Notifications"; "room_details_direct_chat" = "Direct Chat"; "room_details_access_section"="Who can access this room?"; "room_details_access_section_invited_only"="Only people who have been invited"; @@ -700,6 +700,9 @@ "room_details_copy_room_address" = "Copy Room Address"; "room_details_copy_room_url" = "Copy Room URL"; +// Notifications +"room_notification_settings_home_title" = "Room Notifications"; + // Group Details "group_details_title" = "Community Details"; "group_details_home" = "Home"; diff --git a/Riot/Categories/MXKTableViewCellWithLabelAndSwitch.swift b/Riot/Categories/MXKTableViewCellWithLabelAndSwitch.swift new file mode 100644 index 0000000000..161424386b --- /dev/null +++ b/Riot/Categories/MXKTableViewCellWithLabelAndSwitch.swift @@ -0,0 +1,28 @@ +/* + 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 Reusable + +extension MXKTableViewCellWithLabelAndSwitch: Reusable, Themable { + + func update(theme: Theme) { + mxkLabel.textColor = theme.textPrimaryColor + backgroundColor = theme.backgroundColor + contentView.backgroundColor = .clear + } + +} diff --git a/Riot/Categories/MXRoom.swift b/Riot/Categories/MXRoom.swift new file mode 100644 index 0000000000..63435ef30b --- /dev/null +++ b/Riot/Categories/MXRoom.swift @@ -0,0 +1,98 @@ +/* + 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 + +private var _notifySettingForNotifications: RoomNotificationSetting? +private var _soundSettingForNotifications: RoomNotificationSetting? +private var _notifyOnRoomMentions: Bool? +private var _showNumberOfMessages: Bool? + +extension MXRoom { + + var notifySettingForNotifications: RoomNotificationSetting { + return _notifySettingForNotifications ?? .mentionsKeywords + } + + var soundSettingForNotifications: RoomNotificationSetting { + return _soundSettingForNotifications ?? .dmsMentionsKeywords + } + + var notifyOnRoomMentions: Bool { + return _notifyOnRoomMentions ?? true + } + + var showNumberOfMessages: Bool { + return _showNumberOfMessages ?? false + } + + func updateNotifySetting(to newSetting: RoomNotificationSetting, completion: @escaping (_ response: MXResponse) -> Void) { + let isSuccess = Bool.random() + if isSuccess { + _notifySettingForNotifications = newSetting + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + if isSuccess { + completion(MXResponse.success(Void())) + } else { + completion(MXResponse.failure(NSError(domain: "Some domain", code: 1002, userInfo: nil))) + } + } + } + + func updateSoundSetting(to newSetting: RoomNotificationSetting, completion: @escaping (_ response: MXResponse) -> Void) { + let isSuccess = Bool.random() + if isSuccess { + _soundSettingForNotifications = newSetting + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + if isSuccess { + completion(MXResponse.success(Void())) + } else { + completion(MXResponse.failure(NSError(domain: "Some domain", code: 1002, userInfo: nil))) + } + } + } + + func updateNotifyOnRoomMentionsSetting(to newSetting: Bool, completion: @escaping (_ response: MXResponse) -> Void) { + let isSuccess = Bool.random() + if isSuccess { + _notifyOnRoomMentions = newSetting + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + if isSuccess { + completion(MXResponse.success(Void())) + } else { + completion(MXResponse.failure(NSError(domain: "Some domain", code: 1002, userInfo: nil))) + } + } + } + + func updateShowNumberOfMessagesSetting(to newSetting: Bool, completion: @escaping (_ response: MXResponse) -> Void) { + let isSuccess = Bool.random() + if isSuccess { + _showNumberOfMessages = newSetting + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + if isSuccess { + completion(MXResponse.success(Void())) + } else { + completion(MXResponse.failure(NSError(domain: "Some domain", code: 1002, userInfo: nil))) + } + } + } + +} diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index a49bd2bbb8..38f72158c0 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -32,6 +32,7 @@ internal enum Asset { internal static let adminIcon = ImageAsset(name: "admin_icon") internal static let backIcon = ImageAsset(name: "back_icon") internal static let camera = ImageAsset(name: "camera") + internal static let checkmark = ImageAsset(name: "checkmark") internal static let chevron = ImageAsset(name: "chevron") internal static let closeButton = ImageAsset(name: "close_button") internal static let disclosureIcon = ImageAsset(name: "disclosure_icon") diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index 9a1e6c9942..c376bbd2f7 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -127,6 +127,21 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: RoomContextualMenuViewController.self) } + internal enum RoomNotificationSettingsHomeViewController: StoryboardType { + internal static let storyboardName = "RoomNotificationSettingsHomeViewController" + + internal static let initialScene = InitialSceneType(storyboard: RoomNotificationSettingsHomeViewController.self) + } + internal enum RoomNotificationSettingsNotifyViewController: StoryboardType { + internal static let storyboardName = "RoomNotificationSettingsNotifyViewController" + + internal static let initialScene = InitialSceneType(storyboard: RoomNotificationSettingsNotifyViewController.self) + } + internal enum RoomNotificationSettingsSoundViewController: StoryboardType { + internal static let storyboardName = "RoomNotificationSettingsSoundViewController" + + internal static let initialScene = InitialSceneType(storyboard: RoomNotificationSettingsSoundViewController.self) + } internal enum SecretsRecoveryWithKeyViewController: StoryboardType { internal static let storyboardName = "SecretsRecoveryWithKeyViewController" diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index c5b8032ec7..1513f38091 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2226,10 +2226,6 @@ internal enum VectorL10n { internal static var roomDetailsLowPriorityTag: String { return VectorL10n.tr("Vector", "room_details_low_priority_tag") } - /// Mute notifications - internal static var roomDetailsMuteNotifs: String { - return VectorL10n.tr("Vector", "room_details_mute_notifs") - } /// Add new address internal static var roomDetailsNewAddress: String { return VectorL10n.tr("Vector", "room_details_new_address") @@ -2246,6 +2242,10 @@ internal enum VectorL10n { internal static var roomDetailsNoLocalAddresses: String { return VectorL10n.tr("Vector", "room_details_no_local_addresses") } + /// Notifications + internal static var roomDetailsNotificationsRowTitle: String { + return VectorL10n.tr("Vector", "room_details_notifications_row_title") + } /// Members internal static var roomDetailsPeople: String { return VectorL10n.tr("Vector", "room_details_people") @@ -2458,6 +2458,10 @@ internal enum VectorL10n { internal static func roomNewMessagesNotification(_ p1: Int) -> String { return VectorL10n.tr("Vector", "room_new_messages_notification", p1) } + /// Room Notifications + internal static var roomNotificationSettingsHomeTitle: String { + return VectorL10n.tr("Vector", "room_notification_settings_home_title") + } /// Connectivity to the server has been lost. internal static var roomOfflineNotification: String { return VectorL10n.tr("Vector", "room_offline_notification") diff --git a/Riot/Model/Room/RoomNotificationSetting.swift b/Riot/Model/Room/RoomNotificationSetting.swift new file mode 100644 index 0000000000..dfb897c14d --- /dev/null +++ b/Riot/Model/Room/RoomNotificationSetting.swift @@ -0,0 +1,51 @@ +/* + 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 + +/// Riot Standard Room Member Power Level +enum RoomNotificationSetting: CaseIterable { + case allMessages + case dmsMentionsKeywords + case mentionsKeywords + case never + + var longTitle: String { + switch self { + case .allMessages: + return "All Messages" + case .dmsMentionsKeywords: + return "DMs, mentions and keywords only" + case .mentionsKeywords: + return "Mentions and keywords only" + case .never: + return "Never" + } + } + + var shortTitle: String { + switch self { + case .allMessages: + return "All Messages" + case .dmsMentionsKeywords: + return "DMs, Mentions & Keywords" + case .mentionsKeywords: + return "Mentions & Keywords" + case .never: + return "Never" + } + } +} diff --git a/Riot/Modules/Common/SectionHeaderFooters/RiotTableViewHeaderFooterView.swift b/Riot/Modules/Common/SectionHeaderFooters/RiotTableViewHeaderFooterView.swift new file mode 100644 index 0000000000..b8e51f6ae3 --- /dev/null +++ b/Riot/Modules/Common/SectionHeaderFooters/RiotTableViewHeaderFooterView.swift @@ -0,0 +1,109 @@ +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import Reusable + +protocol RiotTableViewHeaderFooterViewDelegate: UITextViewDelegate { + +} + +class RiotTableViewHeaderFooterView: UITableViewHeaderFooterView { + + // MARK - Private + private var _textView: UITextView? + + private var textViewLeftConstraint: NSLayoutConstraint? + private var textViewTopConstraint: NSLayoutConstraint? + private var textViewRightConstraint: NSLayoutConstraint? + private var textViewBottomConstraint: NSLayoutConstraint? + + // MARK - Public + + weak var delegate: RiotTableViewHeaderFooterViewDelegate? + + var textViewInsets: UIEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) { + didSet { + setNeedsUpdateConstraints() + } + } + + /// Will be created if accessed + var textView: UITextView { + // hide text label if textView accessed + textLabel?.isHidden = true + + if let _textView = _textView { + return _textView + } + + let view = UITextView() + view.backgroundColor = .clear + view.translatesAutoresizingMaskIntoConstraints = false + view.delegate = self + view.isEditable = false + view.isScrollEnabled = false + view.scrollsToTop = false + contentView.addSubview(view) + textViewLeftConstraint = view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: textViewInsets.left) + textViewTopConstraint = view.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textViewInsets.top) + textViewRightConstraint = contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: textViewInsets.right) + textViewBottomConstraint = contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: textViewInsets.bottom) + textViewLeftConstraint?.isActive = true + textViewTopConstraint?.isActive = true + textViewRightConstraint?.isActive = true + textViewBottomConstraint?.isActive = true + _textView = view + return view + } + + override func updateConstraints() { + super.updateConstraints() + + textViewLeftConstraint?.constant = textViewInsets.left + textViewTopConstraint?.constant = textViewInsets.top + textViewRightConstraint?.constant = textViewInsets.right + textViewBottomConstraint?.constant = textViewInsets.bottom + } + +} + +extension RiotTableViewHeaderFooterView: Reusable { } + +extension RiotTableViewHeaderFooterView: Themable { + + func update(theme: Theme) { + contentView.backgroundColor = theme.headerBackgroundColor + textLabel?.textColor = theme.textPrimaryColor + _textView?.textColor = theme.textPrimaryColor + _textView?.linkTextAttributes = [NSAttributedString.Key.foregroundColor: theme.tintColor] + } + +} + +extension RiotTableViewHeaderFooterView: UITextViewDelegate { + + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + return delegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction: interaction) ?? (interaction == .invokeDefaultAction) + } + + func textViewDidChangeSelection(_ textView: UITextView) { + return delegate?.textViewDidChangeSelection?(textView) ?? { + textView.selectedRange = NSRange(location: 0, length: 0) + }() + } + +} diff --git a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.h b/Riot/Modules/Common/SectionHeaderFooters/SectionHeaderView.h similarity index 100% rename from Riot/Modules/Common/SectionHeaders/SectionHeaderView.h rename to Riot/Modules/Common/SectionHeaderFooters/SectionHeaderView.h diff --git a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m b/Riot/Modules/Common/SectionHeaderFooters/SectionHeaderView.m similarity index 100% rename from Riot/Modules/Common/SectionHeaders/SectionHeaderView.m rename to Riot/Modules/Common/SectionHeaderFooters/SectionHeaderView.m diff --git a/Riot/Modules/Room/Settings/Notifications/Home/RoomNotificationSettingsHomeViewController.storyboard b/Riot/Modules/Room/Settings/Notifications/Home/RoomNotificationSettingsHomeViewController.storyboard new file mode 100644 index 0000000000..1b031d9692 --- /dev/null +++ b/Riot/Modules/Room/Settings/Notifications/Home/RoomNotificationSettingsHomeViewController.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/Settings/Notifications/Home/RoomNotificationSettingsHomeViewController.swift b/Riot/Modules/Room/Settings/Notifications/Home/RoomNotificationSettingsHomeViewController.swift new file mode 100644 index 0000000000..f11a416557 --- /dev/null +++ b/Riot/Modules/Room/Settings/Notifications/Home/RoomNotificationSettingsHomeViewController.swift @@ -0,0 +1,355 @@ +// File created from simpleScreenTemplate +// $ createSimpleScreen.sh Room/Settings/Notifications/Home RoomNotificationSettingsHome +/* + 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 +import Reusable + +protocol RoomNotificationSettingsHomeViewControllerDelegate: class { + +} + +final class RoomNotificationSettingsHomeViewController: UIViewController { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var mainTableView: UITableView! + + // MARK: Private + + private var theme: Theme! + private var mxRoom: MXRoom! + private let value1StyleCellReuseIdentifier = "value1" + private let linkToAccountSettings = "linkToAccountSettings" + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + private enum RowType { + case withRightValue(_ value: String?) + case withSwitch(_ isOn: Bool, onValueChanged: ((UISwitch) -> Void)?) + } + + private struct Row { + var type: RowType + 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 func showActivityIndicator() { + if self.activityPresenter.isPresenting == false { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + } + + private func hideActivityIndicator() { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + } + + private func updateSections() { + let row_0_0 = Row(type: .withRightValue(mxRoom.notifySettingForNotifications.shortTitle), text: "Notify me with", accessoryType: .disclosureIndicator) { [weak self] in + guard let self = self else { return } + let controller = RoomNotificationSettingsNotifyViewController.instantiate(withRoom: self.mxRoom) + self.navigationController?.pushViewController(controller, animated: true) + } + + let section0 = Section(header: "General", rows: [row_0_0], footer: nil) + + let row_1_0 = Row(type: .withSwitch(mxRoom.notifyOnRoomMentions, onValueChanged: { [weak self] (_switch) in + guard let self = self else { return } + self.showActivityIndicator() + self.mxRoom.updateNotifyOnRoomMentionsSetting(to: _switch.isOn, completion: { (response) in + self.hideActivityIndicator() + self.updateSections() + + switch response { + case .success: + break + case .failure(let error): + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: { + + }) + } + }) + }), text: "Notify me when @room is used", accessoryType: .none) { + + } + + let row_1_1 = Row(type: .withSwitch(mxRoom.showNumberOfMessages, onValueChanged: { [weak self] (_switch) in + guard let self = self else { return } + self.showActivityIndicator() + self.mxRoom.updateShowNumberOfMessagesSetting(to: _switch.isOn, completion: { (response) in + self.hideActivityIndicator() + self.updateSections() + + switch response { + case .success: + break + case .failure(let error): + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: { + + }) + } + }) + }), text: "Show number of messages", accessoryType: .none) { + + } + + let section1 = Section(header: "Appearance & Sound", rows: [row_1_0, row_1_1], footer: nil) + + let row_2_0 = Row(type: .withRightValue(mxRoom.soundSettingForNotifications.shortTitle), text: "Play a sound", accessoryType: .disclosureIndicator) { [weak self] in + guard let self = self else { return } + let controller = RoomNotificationSettingsSoundViewController.instantiate(withRoom: self.mxRoom) + self.navigationController?.pushViewController(controller, animated: true) + } + + let section2 = Section(header: nil, rows: [row_2_0], footer: nil) + + let row_3_0 = Row(type: .withRightValue("Off"), text: "Custom Sounds", accessoryType: .disclosureIndicator) { + + } + + let formatStr = "Set a custom sound for this room. Manage global settings in the %@" + let linkStr = "Account Settings" + let formattedStr = String(format: formatStr, arguments: [linkStr]) + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineHeightMultiple = 1.16 + let footer_3 = NSMutableAttributedString(string: formattedStr, attributes: [ + NSAttributedString.Key.kern: -0.08, + NSAttributedString.Key.paragraphStyle: paragraphStyle, + NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13.0) + ]) + let linkRange = (footer_3.string as NSString).range(of: linkStr) + footer_3.addAttribute(NSAttributedString.Key.link, value: linkToAccountSettings, range: linkRange) + let section3 = Section(header: "Custom Sounds", rows: [row_3_0], footer: footer_3) + + sections = [ + section0, + section1, + section2, + section3 + ] + } + + // MARK: Public + + weak var delegate: RoomNotificationSettingsHomeViewControllerDelegate? + + // MARK: - Setup + + @objc class func instantiate(withRoom room: MXRoom) -> RoomNotificationSettingsHomeViewController { + let viewController = StoryboardScene.RoomNotificationSettingsHomeViewController.initialScene.instantiate() + viewController.theme = ThemeService.shared().theme + viewController.mxRoom = room + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = VectorL10n.roomNotificationSettingsHomeTitle + self.vc_removeBackTitle() + + self.setupViews() + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateSections() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func setupViews() { + mainTableView.register(cellType: MXKTableViewCellWithLabelAndSwitch.self) + mainTableView.register(headerFooterViewType: RiotTableViewHeaderFooterView.self) + mainTableView.sectionFooterHeight = UITableView.automaticDimension + mainTableView.estimatedSectionFooterHeight = 50 + } + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + self.mainTableView.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + // MARK: - Actions + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + +} + +// MARK: - UITableViewDataSource + +extension RoomNotificationSettingsHomeViewController: 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 .withRightValue(let rightValue): + var cell: UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: value1StyleCellReuseIdentifier) + if cell == nil { + cell = UITableViewCell(style: .value1, reuseIdentifier: value1StyleCellReuseIdentifier) + } + cell.textLabel?.font = .systemFont(ofSize: 17) + cell.detailTextLabel?.font = .systemFont(ofSize: 16) + cell.textLabel?.text = row.text + cell.detailTextLabel?.text = rightValue + cell.accessoryType = row.accessoryType + cell.textLabel?.textColor = theme.textPrimaryColor + cell.detailTextLabel?.textColor = theme.textSecondaryColor + cell.backgroundColor = theme.backgroundColor + cell.contentView.backgroundColor = .clear + return cell + case .withSwitch(let isOn, let onValueChanged): + let cell: MXKTableViewCellWithLabelAndSwitch = tableView.dequeueReusableCell(for: indexPath) + cell.mxkLabel.font = .systemFont(ofSize: 17) + cell.mxkLabel.text = row.text + cell.mxkSwitch.isOn = isOn + cell.mxkSwitch.removeTarget(nil, action: nil, for: .valueChanged) + cell.mxkSwitch.vc_addAction(for: .valueChanged) { + onValueChanged?(cell.mxkSwitch) + } + cell.mxkLabelLeadingConstraint.constant = cell.vc_separatorInset.left + cell.mxkSwitchTrailingConstraint.constant = 15 + cell.update(theme: theme) + + return cell + } + } + +} + +// MARK: - UITableViewDelegate + +extension RoomNotificationSettingsHomeViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + cell.backgroundColor = theme.backgroundColor + + if let selectedBackgroundColor = theme.selectedBackgroundColor { + cell.selectedBackgroundView = UIView() + cell.selectedBackgroundView?.backgroundColor = selectedBackgroundColor + } else { + if tableView.style == .plain { + cell.selectedBackgroundView = nil + } else { + cell.selectedBackgroundView?.backgroundColor = nil + } + } + } + + 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 - RiotTableViewHeaderFooterViewDelegate + +extension RoomNotificationSettingsHomeViewController: RiotTableViewHeaderFooterViewDelegate { + + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + if interaction == .invokeDefaultAction { + if URL.absoluteString == linkToAccountSettings { + let alert = UIAlertController(title: "Info", message: "Will go to Account Settings", preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) + + self.present(alert, animated: true) + return true + } + return false + } + return false + } + +} diff --git a/Riot/Modules/Room/Settings/Notifications/Notify/RoomNotificationSettingsNotifyViewController.storyboard b/Riot/Modules/Room/Settings/Notifications/Notify/RoomNotificationSettingsNotifyViewController.storyboard new file mode 100644 index 0000000000..99da2e1904 --- /dev/null +++ b/Riot/Modules/Room/Settings/Notifications/Notify/RoomNotificationSettingsNotifyViewController.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/Settings/Notifications/Notify/RoomNotificationSettingsNotifyViewController.swift b/Riot/Modules/Room/Settings/Notifications/Notify/RoomNotificationSettingsNotifyViewController.swift new file mode 100644 index 0000000000..8b418ac0ff --- /dev/null +++ b/Riot/Modules/Room/Settings/Notifications/Notify/RoomNotificationSettingsNotifyViewController.swift @@ -0,0 +1,297 @@ +// File created from simpleScreenTemplate +// $ createSimpleScreen.sh Room/Settings/Notifications/Notify RoomNotificationSettingsNotify +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +protocol RoomNotificationSettingsNotifyViewControllerDelegate: class { + +} + +final class RoomNotificationSettingsNotifyViewController: UIViewController { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var mainTableView: UITableView! + + // MARK: Private + + private var theme: Theme! + private var mxRoom: MXRoom! + private let plainStyleCellReuseIdentifier = "plain" + private let linkToAccountSettings = "linkToAccountSettings" + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + private enum RowType { + case plain + } + + private struct Row { + var type: RowType + var setting: RoomNotificationSetting + 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 func showActivityIndicator() { + if self.activityPresenter.isPresenting == false { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + } + + private func hideActivityIndicator() { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + } + + private func updateSections() { + let rows = RoomNotificationSetting.allCases.map({ (setting) -> Row in + return Row(type: .plain, + setting: setting, + text: setting.longTitle, + accessoryType: mxRoom.notifySettingForNotifications == setting ? .checkmark : .none, + action: { + self.showActivityIndicator() + self.mxRoom.updateNotifySetting(to: setting, completion: { (response) in + self.hideActivityIndicator() + + switch response { + case .success: + self.updateSections() + case .failure(let error): + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: { + + }) + } + }) + }) + }) + + 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: linkToAccountSettings, range: linkRange) + let section0 = Section(header: nil, rows: rows, footer: footer_0) + + sections = [ + section0 + ] + } + + // MARK: Public + + weak var delegate: RoomNotificationSettingsNotifyViewControllerDelegate? + + // MARK: - Setup + + class func instantiate(withRoom room: MXRoom) -> RoomNotificationSettingsNotifyViewController { + let viewController = StoryboardScene.RoomNotificationSettingsNotifyViewController.initialScene.instantiate() + viewController.theme = ThemeService.shared().theme + viewController.mxRoom = room + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = "Notify me with" + self.vc_removeBackTitle() + + self.setupViews() + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + updateSections() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func setupViews() { + mainTableView.register(headerFooterViewType: RiotTableViewHeaderFooterView.self) + mainTableView.sectionFooterHeight = UITableView.automaticDimension + mainTableView.estimatedSectionFooterHeight = 50 + } + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + self.mainTableView.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + // MARK: - Actions + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + +} + +// MARK - UITableViewDataSource + +extension RoomNotificationSettingsNotifyViewController: 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: plainStyleCellReuseIdentifier) + if cell == nil { + cell = UITableViewCell(style: .value1, reuseIdentifier: 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 RoomNotificationSettingsNotifyViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + cell.backgroundColor = theme.backgroundColor + + if let selectedBackgroundColor = theme.selectedBackgroundColor { + cell.selectedBackgroundView = UIView() + cell.selectedBackgroundView?.backgroundColor = selectedBackgroundColor + } else { + if tableView.style == .plain { + cell.selectedBackgroundView = nil + } else { + cell.selectedBackgroundView?.backgroundColor = nil + } + } + } + + 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 - RiotTableViewHeaderFooterViewDelegate + +extension RoomNotificationSettingsNotifyViewController: RiotTableViewHeaderFooterViewDelegate { + + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + if interaction == .invokeDefaultAction { + if URL.absoluteString == linkToAccountSettings { + let alert = UIAlertController(title: "Info", message: "Will go to Account Settings", preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) + + self.present(alert, animated: true) + return true + } + return false + } + return false + } + +} diff --git a/Riot/Modules/Room/Settings/Notifications/Sound/RoomNotificationSettingsSoundViewController.storyboard b/Riot/Modules/Room/Settings/Notifications/Sound/RoomNotificationSettingsSoundViewController.storyboard new file mode 100644 index 0000000000..97ac5d464e --- /dev/null +++ b/Riot/Modules/Room/Settings/Notifications/Sound/RoomNotificationSettingsSoundViewController.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/Settings/Notifications/Sound/RoomNotificationSettingsSoundViewController.swift b/Riot/Modules/Room/Settings/Notifications/Sound/RoomNotificationSettingsSoundViewController.swift new file mode 100644 index 0000000000..6652cdd5af --- /dev/null +++ b/Riot/Modules/Room/Settings/Notifications/Sound/RoomNotificationSettingsSoundViewController.swift @@ -0,0 +1,239 @@ +// File created from simpleScreenTemplate +// $ createSimpleScreen.sh Room/Settings/Notifications/Sound RoomNotificationSettingsSound +/* + Copyright 2020 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +protocol RoomNotificationSettingsSoundViewControllerDelegate: class { + +} + +final class RoomNotificationSettingsSoundViewController: UIViewController { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var mainTableView: UITableView! + + // MARK: Private + + private var theme: Theme! + private var mxRoom: MXRoom! + private let plainStyleCellReuseIdentifier = "plain" + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + private enum RowType { + case plain + } + + private struct Row { + var type: RowType + var setting: RoomNotificationSetting + 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 func showActivityIndicator() { + if self.activityPresenter.isPresenting == false { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + } + + private func hideActivityIndicator() { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + } + + private func updateSections() { + let rows = RoomNotificationSetting.allCases.map({ (setting) -> Row in + return Row(type: .plain, + setting: setting, + text: setting.longTitle, + accessoryType: mxRoom.soundSettingForNotifications == setting ? .checkmark : .none, + action: { + self.showActivityIndicator() + self.mxRoom.updateSoundSetting(to: setting, completion: { (response) in + self.hideActivityIndicator() + + switch response { + case .success: + self.updateSections() + case .failure(let error): + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: { + + }) + } + }) + }) + }) + + let section0 = Section(header: nil, rows: rows, footer: nil) + + sections = [ + section0 + ] + } + + // MARK: Public + + weak var delegate: RoomNotificationSettingsSoundViewControllerDelegate? + + // MARK: - Setup + + class func instantiate(withRoom room: MXRoom) -> RoomNotificationSettingsSoundViewController { + let viewController = StoryboardScene.RoomNotificationSettingsSoundViewController.initialScene.instantiate() + viewController.theme = ThemeService.shared().theme + viewController.mxRoom = room + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = "Play a sound" + self.vc_removeBackTitle() + + self.setupViews() + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + updateSections() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func setupViews() { + + } + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + self.mainTableView.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + // MARK: - Actions + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + +} + + +// MARK - UITableViewDataSource + +extension RoomNotificationSettingsSoundViewController: 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: plainStyleCellReuseIdentifier) + if cell == nil { + cell = UITableViewCell(style: .value1, reuseIdentifier: 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 RoomNotificationSettingsSoundViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + cell.backgroundColor = theme.backgroundColor + + if let selectedBackgroundColor = theme.selectedBackgroundColor { + cell.selectedBackgroundView = UIView() + cell.selectedBackgroundView?.backgroundColor = selectedBackgroundColor + } else { + if tableView.style == .plain { + cell.selectedBackgroundView = nil + } else { + cell.selectedBackgroundView?.backgroundColor = nil + } + } + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let row = sections[indexPath.section].rows[indexPath.row] + row.action?() + } + +} diff --git a/Riot/Modules/Room/Settings/RoomSettingsViewController.m b/Riot/Modules/Room/Settings/RoomSettingsViewController.m index 2a94158b5c..41d3492392 100644 --- a/Riot/Modules/Room/Settings/RoomSettingsViewController.m +++ b/Riot/Modules/Room/Settings/RoomSettingsViewController.m @@ -54,7 +54,7 @@ ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC, ROOM_SETTINGS_MAIN_SECTION_ROW_TAG , ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT, - ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS, + ROOM_SETTINGS_MAIN_SECTION_ROW_NOTIFICATIONS, ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE, ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT }; @@ -85,7 +85,7 @@ NSString *const kRoomSettingsNameKey = @"kRoomSettingsNameKey"; NSString *const kRoomSettingsTopicKey = @"kRoomSettingsTopicKey"; NSString *const kRoomSettingsTagKey = @"kRoomSettingsTagKey"; -NSString *const kRoomSettingsMuteNotifKey = @"kRoomSettingsMuteNotifKey"; +NSString *const kRoomSettingsNotificationsKey = @"kRoomSettingsNotificationsKey"; NSString *const kRoomSettingsDirectChatKey = @"kRoomSettingsDirectChatKey"; NSString *const kRoomSettingsJoinRuleKey = @"kRoomSettingsJoinRuleKey"; NSString *const kRoomSettingsGuestAccessKey = @"kRoomSettingsGuestAccessKey"; @@ -220,6 +220,7 @@ - (void)setNavBarButtons [self getNavigationItem].rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onSave:)]; [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); [self getNavigationItem].leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onCancel:)]; + [self getNavigationItem].backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; } - (void)viewDidLoad @@ -1736,39 +1737,6 @@ - (IBAction)onSave:(id)sender return; } - if (updatedItemsDict[kRoomSettingsMuteNotifKey]) - { - if (((NSNumber*) updatedItemsDict[kRoomSettingsMuteNotifKey]).boolValue) - { - [mxRoom mentionsOnly:^{ - - if (weakSelf) - { - typeof(self) self = weakSelf; - - [self->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; - [self onSave:nil]; - } - - }]; - } - else - { - [mxRoom allMessages:^{ - - if (weakSelf) - { - typeof(self) self = weakSelf; - - [self->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; - [self onSave:nil]; - } - - }]; - } - return; - } - if (updatedItemsDict[kRoomSettingsDirectChatKey]) { pendingOperation = [mxRoom setIsDirect:((NSNumber*) updatedItemsDict[kRoomSettingsDirectChatKey]).boolValue withUserId:nil success:^{ @@ -2148,26 +2116,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N // general settings if (indexPath.section == ROOM_SETTINGS_MAIN_SECTION_INDEX) { - if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS) - { - MXKTableViewCellWithLabelAndSwitch *roomNotifCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; - - [roomNotifCell.mxkSwitch addTarget:self action:@selector(toggleRoomNotification:) forControlEvents:UIControlEventValueChanged]; - - roomNotifCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_mute_notifs", @"Vector", nil); - - if (updatedItemsDict[kRoomSettingsMuteNotifKey]) - { - roomNotifCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsMuteNotifKey]).boolValue; - } - else - { - roomNotifCell.mxkSwitch.on = mxRoom.isMute || mxRoom.isMentionsOnly; - } - - cell = roomNotifCell; - } - else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT) + if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT) { MXKTableViewCellWithLabelAndSwitch *roomDirectChat = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; @@ -2341,6 +2290,21 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = roomTagCell; } + else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_NOTIFICATIONS) + { + MXKTableViewCell *notificationsCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCell defaultReuseIdentifier] forIndexPath:indexPath]; + + notificationsCell.selectionStyle = UITableViewCellSelectionStyleDefault; + notificationsCell.textLabel.accessibilityIdentifier = nil; + notificationsCell.textLabel.font = [UIFont systemFontOfSize:17]; + notificationsCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor; + notificationsCell.contentView.backgroundColor = UIColor.clearColor; + + notificationsCell.textLabel.text = NSLocalizedStringFromTable(@"room_details_notifications_row_title", @"Vector", nil); + notificationsCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + + cell = notificationsCell; + } else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE) { MXKTableViewCellWithButton *leaveCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath]; @@ -2885,6 +2849,11 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self editRoomTopic]; } } + else if (indexPath.row == ROOM_SETTINGS_MAIN_SECTION_ROW_NOTIFICATIONS) + { + RoomNotificationSettingsHomeViewController *controller = [RoomNotificationSettingsHomeViewController instantiateWithRoom:self->mxRoom]; + [self.navigationController pushViewController:controller animated:YES]; + } } else if (indexPath.section == ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX) { @@ -3386,20 +3355,6 @@ - (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer self.imagePickerPresenter = singleImagePickerPresenter; } -- (void)toggleRoomNotification:(UISwitch*)theSwitch -{ - if (theSwitch.on == (mxRoom.isMute || mxRoom.isMentionsOnly)) - { - [updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; - } - else - { - updatedItemsDict[kRoomSettingsMuteNotifKey] = @(theSwitch.on); - } - - [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); -} - - (void)toggleDirectChat:(UISwitch*)theSwitch { if (theSwitch.on == mxRoom.isDirect)