diff --git a/CHANGES.rst b/CHANGES.rst index 0e8f410e35..105b577eaa 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,25 @@ +Changes in Vector iOS in 0.1.12 (2016-07-15) +=============================================== + +Improvements: + * Upgrade MatrixKit version (v0.3.11). + * Chat Screen: Set the right tint color of the "send" button. + * Messages: Add pink red badge on each invitation #426. + * Add 'leave' button to room settings #417. + * Settings: Set the right label text color. + * Room Settings: Add "Addresses" section #412. + * Messages: switch decline and preview buttons on invites #447. + +Bug fixes: + * App crashes when the user leaves Settings whereas an email binding is in progress. + * App crashes during [AppDelegate applicationDidEnterBackground:] #452. + * Room Participants: Admin badge is missing sometimes. + * Room Participants: The swipe to Leave/Kick is broken. + * Markdown swallows leading #'s even if there are less than 3 #423. + * HTML blockquote is badly rendered: some characters can miss #437. + * Room Settings: check room permissions and grey out those boxes (disable) if you can't change them #430. + * Room Settings: if there isn't a topic (new rooms) you can't actually change/set it. #441. + Changes in Vector iOS in 0.1.11 (2016-07-01) =============================================== diff --git a/Podfile b/Podfile index 86689d1cfb..8944c49618 100644 --- a/Podfile +++ b/Podfile @@ -8,7 +8,7 @@ target "Vector" do # Different flavours of pods to MatrixKit # The tagged version on which this version of Console has been built -pod 'MatrixKit', '~> 0.3.10' +pod 'MatrixKit', '~> 0.3.11' # The lastest release available on the CocoaPods repository #pod 'MatrixKit' diff --git a/Podfile.lock b/Podfile.lock index adea497887..e5b1d2bac8 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,24 +1,18 @@ PODS: - - AFNetworking (2.6.3): - - AFNetworking/NSURLConnection (= 2.6.3) - - AFNetworking/NSURLSession (= 2.6.3) - - AFNetworking/Reachability (= 2.6.3) - - AFNetworking/Security (= 2.6.3) - - AFNetworking/Serialization (= 2.6.3) - - AFNetworking/UIKit (= 2.6.3) - - AFNetworking/NSURLConnection (2.6.3): + - AFNetworking (3.1.0): + - AFNetworking/NSURLSession (= 3.1.0) + - AFNetworking/Reachability (= 3.1.0) + - AFNetworking/Security (= 3.1.0) + - AFNetworking/Serialization (= 3.1.0) + - AFNetworking/UIKit (= 3.1.0) + - AFNetworking/NSURLSession (3.1.0): - AFNetworking/Reachability - AFNetworking/Security - AFNetworking/Serialization - - AFNetworking/NSURLSession (2.6.3): - - AFNetworking/Reachability - - AFNetworking/Security - - AFNetworking/Serialization - - AFNetworking/Reachability (2.6.3) - - AFNetworking/Security (2.6.3) - - AFNetworking/Serialization (2.6.3) - - AFNetworking/UIKit (2.6.3): - - AFNetworking/NSURLConnection + - AFNetworking/Reachability (3.1.0) + - AFNetworking/Security (3.1.0) + - AFNetworking/Serialization (3.1.0) + - AFNetworking/UIKit (3.1.0): - AFNetworking/NSURLSession - DTCoreText (1.6.17): - DTFoundation/Core (~> 1.7.5) @@ -38,22 +32,22 @@ PODS: - GoogleAnalytics (3.14.0) - HPGrowingTextView (1.1) - libPhoneNumber-iOS (0.8.14) - - MatrixKit (0.3.10): + - MatrixKit (0.3.11): - DTCoreText (~> 1.6.17) - GHMarkdownParser (~> 0.1.2) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.8.14) - - MatrixSDK (~> 0.6.9) - - MatrixSDK (0.6.9): - - AFNetworking (~> 2.6.0) + - MatrixSDK (~> 0.6.10) + - MatrixSDK (0.6.10): + - AFNetworking (~> 3.1.0) DEPENDENCIES: - GBDeviceInfo (~> 4.1.0) - GoogleAnalytics - - MatrixKit (~> 0.3.10) + - MatrixKit (~> 0.3.11) SPEC CHECKSUMS: - AFNetworking: cb8d14a848e831097108418f5d49217339d4eb60 + AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67 DTCoreText: 3ea8bba23dd2141ba18adb227a7dd33a822df1c4 DTFoundation: 3b6b1b817d2a7fb02e7eaf2596c922a68145bd43 GBDeviceInfo: e50df975a95e21faec93e2bf98376846fe17d307 @@ -61,9 +55,9 @@ SPEC CHECKSUMS: GoogleAnalytics: 9be1afdb8deeac4bb5f13ca7f7d3b9db2a1f43dc HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19 libPhoneNumber-iOS: fb165271ebe7fb32e55da97b83219382f2f9d409 - MatrixKit: f777a251efb4c62d6b6414dab032998add4a415e - MatrixSDK: 46b12fd15ef0d50c6ac189989897855b47ce6ba2 + MatrixKit: 711c7b8c1a0751432de3b718f948d25b736925be + MatrixSDK: 39f5fd09a729e88ce7f159a66f2d2515c7252664 -PODFILE CHECKSUM: 812ddb9e9f6d58c224447005986ba00c3a441ae8 +PODFILE CHECKSUM: fd4aa6cba642bed3736613be8b2d9b3c64b62327 COCOAPODS: 1.0.1 diff --git a/Vector.xcodeproj/project.pbxproj b/Vector.xcodeproj/project.pbxproj index b41fa716bd..0438b1161f 100644 --- a/Vector.xcodeproj/project.pbxproj +++ b/Vector.xcodeproj/project.pbxproj @@ -164,8 +164,11 @@ F05641941C7DF9DE002276ED /* error@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F05641911C7DF9DE002276ED /* error@3x.png */; }; F05895001B8B7E6600B73E85 /* RoomBubbleCellData.m in Sources */ = {isa = PBXBuildFile; fileRef = F05894FF1B8B7E6600B73E85 /* RoomBubbleCellData.m */; }; F067F2BC1CF6F0EA00F35EE8 /* third_party_licenses.html in Resources */ = {isa = PBXBuildFile; fileRef = F067F2BB1CF6F0EA00F35EE8 /* third_party_licenses.html */; }; - F072E9A01D217C2C002921AF /* TableViewCellWithSwitches.m in Sources */ = {isa = PBXBuildFile; fileRef = F072E99F1D217C2C002921AF /* TableViewCellWithSwitches.m */; }; - F072E9A21D217EA0002921AF /* TableViewCellWithSwitches.xib in Resources */ = {isa = PBXBuildFile; fileRef = F072E9A11D217EA0002921AF /* TableViewCellWithSwitches.xib */; }; + F07ECA4D1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.m in Sources */ = {isa = PBXBuildFile; fileRef = F07ECA4B1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.m */; }; + F07ECA4E1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.xib in Resources */ = {isa = PBXBuildFile; fileRef = F07ECA4C1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.xib */; }; + F07ECA521D2D730D0060C09F /* main_alias_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = F07ECA4F1D2D730D0060C09F /* main_alias_icon.png */; }; + F07ECA531D2D730D0060C09F /* main_alias_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F07ECA501D2D730D0060C09F /* main_alias_icon@2x.png */; }; + F07ECA541D2D730D0060C09F /* main_alias_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F07ECA511D2D730D0060C09F /* main_alias_icon@3x.png */; }; F08BE09E1B87025B00C480FB /* EventFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = F08BE09D1B87025B00C480FB /* EventFormatter.m */; }; F08BE0A21B87064000C480FB /* RoomDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = F08BE0A11B87064000C480FB /* RoomDataSource.m */; }; F094A9A81B78D8F000B1FBBF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F094A9A71B78D8F000B1FBBF /* main.m */; }; @@ -200,8 +203,8 @@ F0A2413A1CB7E28F00E150C3 /* RoomParticipantsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0A241391CB7E28F00E150C3 /* RoomParticipantsViewController.xib */; }; F0AF11F51D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0AF11F31D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.m */; }; F0AF11F61D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0AF11F41D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.xib */; }; - F0B7037E1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = F0B7037C1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.m */; }; - F0B7037F1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0B7037D1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.xib */; }; + F0B7037E1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = F0B7037C1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.m */; }; + F0B7037F1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0B7037D1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.xib */; }; F0BE3DF01C6CE17200AC3111 /* RoomMemberDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0BE3DEF1C6CE17200AC3111 /* RoomMemberDetailsViewController.m */; }; F0BE3DF21C6CE28300AC3111 /* RoomMemberDetailsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0BE3DF11C6CE28300AC3111 /* RoomMemberDetailsViewController.xib */; }; F0C34B611C15C28300C36F09 /* RoomOutgoingAttachmentBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0C34B561C15C28300C36F09 /* RoomOutgoingAttachmentBubbleCell.m */; }; @@ -466,9 +469,12 @@ F05894FE1B8B7E6600B73E85 /* RoomBubbleCellData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomBubbleCellData.h; sourceTree = ""; }; F05894FF1B8B7E6600B73E85 /* RoomBubbleCellData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomBubbleCellData.m; sourceTree = ""; }; F067F2BB1CF6F0EA00F35EE8 /* third_party_licenses.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = third_party_licenses.html; sourceTree = ""; }; - F072E99E1D217C2C002921AF /* TableViewCellWithSwitches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithSwitches.h; path = TableViewCell/TableViewCellWithSwitches.h; sourceTree = ""; }; - F072E99F1D217C2C002921AF /* TableViewCellWithSwitches.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithSwitches.m; path = TableViewCell/TableViewCellWithSwitches.m; sourceTree = ""; }; - F072E9A11D217EA0002921AF /* TableViewCellWithSwitches.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithSwitches.xib; path = TableViewCell/TableViewCellWithSwitches.xib; sourceTree = ""; }; + F07ECA4A1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithCheckBoxes.h; path = TableViewCell/TableViewCellWithCheckBoxes.h; sourceTree = ""; }; + F07ECA4B1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithCheckBoxes.m; path = TableViewCell/TableViewCellWithCheckBoxes.m; sourceTree = ""; }; + F07ECA4C1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithCheckBoxes.xib; path = TableViewCell/TableViewCellWithCheckBoxes.xib; sourceTree = ""; }; + F07ECA4F1D2D730D0060C09F /* main_alias_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = main_alias_icon.png; sourceTree = ""; }; + F07ECA501D2D730D0060C09F /* main_alias_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "main_alias_icon@2x.png"; sourceTree = ""; }; + F07ECA511D2D730D0060C09F /* main_alias_icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "main_alias_icon@3x.png"; sourceTree = ""; }; F08BE09C1B87025B00C480FB /* EventFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventFormatter.h; sourceTree = ""; }; F08BE09D1B87025B00C480FB /* EventFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EventFormatter.m; sourceTree = ""; }; F08BE0A01B87064000C480FB /* RoomDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomDataSource.h; sourceTree = ""; }; @@ -523,9 +529,9 @@ F0AF11F21D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomIdOrAliasTableViewCell.h; sourceTree = ""; }; F0AF11F31D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomIdOrAliasTableViewCell.m; sourceTree = ""; }; F0AF11F41D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomIdOrAliasTableViewCell.xib; sourceTree = ""; }; - F0B7037B1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithTickAndLabel.h; path = TableViewCell/TableViewCellWithTickAndLabel.h; sourceTree = ""; }; - F0B7037C1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithTickAndLabel.m; path = TableViewCell/TableViewCellWithTickAndLabel.m; sourceTree = ""; }; - F0B7037D1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithTickAndLabel.xib; path = TableViewCell/TableViewCellWithTickAndLabel.xib; sourceTree = ""; }; + F0B7037B1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithCheckBoxAndLabel.h; path = TableViewCell/TableViewCellWithCheckBoxAndLabel.h; sourceTree = ""; }; + F0B7037C1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithCheckBoxAndLabel.m; path = TableViewCell/TableViewCellWithCheckBoxAndLabel.m; sourceTree = ""; }; + F0B7037D1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithCheckBoxAndLabel.xib; path = TableViewCell/TableViewCellWithCheckBoxAndLabel.xib; sourceTree = ""; }; F0BE3DEE1C6CE17200AC3111 /* RoomMemberDetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMemberDetailsViewController.h; sourceTree = ""; }; F0BE3DEF1C6CE17200AC3111 /* RoomMemberDetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMemberDetailsViewController.m; sourceTree = ""; }; F0BE3DF11C6CE28300AC3111 /* RoomMemberDetailsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomMemberDetailsViewController.xib; sourceTree = ""; }; @@ -660,12 +666,12 @@ 7179283B1C0384DE00407D96 /* TableViewCell */ = { isa = PBXGroup; children = ( - F0B7037B1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.h */, - F0B7037C1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.m */, - F0B7037D1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.xib */, - F072E99E1D217C2C002921AF /* TableViewCellWithSwitches.h */, - F072E99F1D217C2C002921AF /* TableViewCellWithSwitches.m */, - F072E9A11D217EA0002921AF /* TableViewCellWithSwitches.xib */, + F07ECA4A1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.h */, + F07ECA4B1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.m */, + F07ECA4C1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.xib */, + F0B7037B1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.h */, + F0B7037C1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.m */, + F0B7037D1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.xib */, F05641781C7C9FD7002276ED /* TableViewCellWithButton.h */, F05641791C7C9FD7002276ED /* TableViewCellWithButton.m */, F056417A1C7C9FD7002276ED /* TableViewCellWithButton.xib */, @@ -1067,6 +1073,9 @@ F0DD7D1B1B7AA8C900C4BE02 /* Images */ = { isa = PBXGroup; children = ( + F07ECA4F1D2D730D0060C09F /* main_alias_icon.png */, + F07ECA501D2D730D0060C09F /* main_alias_icon@2x.png */, + F07ECA511D2D730D0060C09F /* main_alias_icon@3x.png */, F0CC255E1D099F30000819CA /* newmessages.png */, F0CC255F1D099F30000819CA /* newmessages@2x.png */, F0CC25601D099F30000819CA /* newmessages@3x.png */, @@ -1282,9 +1291,10 @@ F008D6FC1D0180FB0049444D /* GoogleService-Info.plist in Resources */, F02528E01C11B6FC00E1FE1B /* create_room.png in Resources */, F02528DF1C11B6FC00E1FE1B /* camera_video.png in Resources */, - F0B7037F1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.xib in Resources */, + F0B7037F1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.xib in Resources */, F02BB04C1CBE2EE70022A025 /* PreviewRoomTitleView.xib in Resources */, F056418C1C7CBEBD002276ED /* group.png in Resources */, + F07ECA541D2D730D0060C09F /* main_alias_icon@3x.png in Resources */, F0C34B681C15C28300C36F09 /* RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib in Resources */, F0CC256F1D099F30000819CA /* scrollup@3x.png in Resources */, F0026B631C916E68001D2C04 /* priorityLow@3x.png in Resources */, @@ -1309,6 +1319,7 @@ F02528FC1C11B6FC00E1FE1B /* selection_tick@3x.png in Resources */, F03FBCCD1CBBF521000A5770 /* mod_icon@3x.png in Resources */, F025290B1C11B6FC00E1FE1B /* upload_icon@3x.png in Resources */, + F07ECA531D2D730D0060C09F /* main_alias_icon@2x.png in Resources */, F0CC25691D099F30000819CA /* newmessages@3x.png in Resources */, F02529011C11B6FC00E1FE1B /* settings_icon@2x.png in Resources */, F0026B511C916E68001D2C04 /* favourite@3x.png in Resources */, @@ -1382,6 +1393,7 @@ 325F6A491C21D4C100C12F51 /* chevron@3x.png in Resources */, F001D76E1B83156000A162C3 /* MediaPickerViewController.xib in Resources */, F02529031C11B6FC00E1FE1B /* typing.png in Resources */, + F07ECA521D2D730D0060C09F /* main_alias_icon.png in Resources */, 32D200851C15C56A00A4E396 /* search_bg@3x.png in Resources */, F056418D1C7CBEBD002276ED /* group@2x.png in Resources */, F0026B501C916E68001D2C04 /* favourite@2x.png in Resources */, @@ -1434,10 +1446,10 @@ F0026B521C916E68001D2C04 /* favouriteOff.png in Resources */, 32A887221C89B9580037DC17 /* SimpleRoomTitleView.xib in Resources */, F02528FD1C11B6FC00E1FE1B /* selection_untick.png in Resources */, + F07ECA4E1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.xib in Resources */, F0026B5C1C916E68001D2C04 /* notificationsOff@2x.png in Resources */, F0CC4DC11C4E26FA003BBE45 /* MediaAlbumTableCell.xib in Resources */, F02528DD1C11B6FC00E1FE1B /* camera_switch@2x.png in Resources */, - F072E9A21D217EA0002921AF /* TableViewCellWithSwitches.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1508,7 +1520,6 @@ F094A9AB1B78D8F000B1FBBF /* AppDelegate.m in Sources */, 32C52BF61CBE4B0A00863B33 /* RoomEmailInvitation.m in Sources */, F047DBB91C576F6600952DA2 /* AuthInputsView.m in Sources */, - F072E9A01D217C2C002921AF /* TableViewCellWithSwitches.m in Sources */, 323A520B1C3183CC00010773 /* UIViewController+VectorSearch.m in Sources */, 32A887211C89B9580037DC17 /* SimpleRoomTitleView.m in Sources */, F056417B1C7C9FD7002276ED /* TableViewCellWithButton.m in Sources */, @@ -1542,7 +1553,7 @@ F094A9A81B78D8F000B1FBBF /* main.m in Sources */, F00C47861BFF77C800DBABC9 /* RecentTableViewCell.m in Sources */, F0CC4DCA1C4E594C003BBE45 /* MediaAlbumContentViewController.m in Sources */, - F0B7037E1D22D4AD00B63766 /* TableViewCellWithTickAndLabel.m in Sources */, + F0B7037E1D22D4AD00B63766 /* TableViewCellWithCheckBoxAndLabel.m in Sources */, 32AAC3E61C3525DE007A3B5B /* RoomSearchViewController.m in Sources */, 32F2E61B1C230D4D003BDEA5 /* PublicRoomsDirectoryDataSource.m in Sources */, 3235CD851C341FAA0084EA40 /* HomeSearchViewController.m in Sources */, @@ -1569,6 +1580,7 @@ F0C34CB31C16269D00C36F09 /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.m in Sources */, F0D2D9851C197DCB007B8C96 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, 71046D5E1C0C639300DCA984 /* RoomTitleView.m in Sources */, + F07ECA4D1D2BB0A60060C09F /* TableViewCellWithCheckBoxes.m in Sources */, F02BB04B1CBE2EE70022A025 /* PreviewRoomTitleView.m in Sources */, F0C34B631C15C28300C36F09 /* RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, F09EE0061C5134BE0078712F /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.m in Sources */, diff --git a/Vector/AppDelegate.m b/Vector/AppDelegate.m index c48d64bd79..5f916ddf18 100644 --- a/Vector/AppDelegate.m +++ b/Vector/AppDelegate.m @@ -360,7 +360,7 @@ - (void)applicationDidEnterBackground:(UIApplication *)application } [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:nil]; [[AFNetworkReachabilityManager sharedManager] stopMonitoring]; - self.isOffline = NO; + _isOffline = NO; // check if some media must be released to reduce the cache size [MXKMediaManager reduceCacheSizeToInsert:0]; diff --git a/Vector/Assets/Images/main_alias_icon.png b/Vector/Assets/Images/main_alias_icon.png new file mode 100644 index 0000000000..f2bbb9c082 Binary files /dev/null and b/Vector/Assets/Images/main_alias_icon.png differ diff --git a/Vector/Assets/Images/main_alias_icon@2x.png b/Vector/Assets/Images/main_alias_icon@2x.png new file mode 100644 index 0000000000..4d4a1db603 Binary files /dev/null and b/Vector/Assets/Images/main_alias_icon@2x.png differ diff --git a/Vector/Assets/Images/main_alias_icon@3x.png b/Vector/Assets/Images/main_alias_icon@3x.png new file mode 100644 index 0000000000..5619537b03 Binary files /dev/null and b/Vector/Assets/Images/main_alias_icon@3x.png differ diff --git a/Vector/Assets/en.lproj/Vector.strings b/Vector/Assets/en.lproj/Vector.strings index a631eb1482..3a2c846ef1 100644 --- a/Vector/Assets/en.lproj/Vector.strings +++ b/Vector/Assets/en.lproj/Vector.strings @@ -116,8 +116,8 @@ "room_participants_add_participant" = "Add participant"; "room_participants_one_participant" = "1 participant"; "room_participants_multi_participants" = "%d participants"; -"room_participants_leave_prompt_title" = "Leave?"; -"room_participants_leave_prompt_msg" = "Are you sure you want to leave this chat?"; +"room_participants_leave_prompt_title" = "Leave room"; +"room_participants_leave_prompt_msg" = "Are you sure you want to leave the room?"; "room_participants_remove_prompt_title" = "Remove?"; "room_participants_remove_prompt_msg" = "Are you sure you want to remove %@ from this chat?"; "room_participants_invite_prompt_title" = "Invite?"; @@ -249,18 +249,29 @@ "room_details_favourite_tag" = "Favourite"; "room_details_low_priority_tag" = "Low priority"; "room_details_mute_notifs" = "Mute notifications"; -"room_details_access_section"="WHO CAN ACCESS THIS ROOM?"; +"room_details_access_section"="Who can access this room?"; "room_details_access_section_invited_only"="Only people who have been invited"; "room_details_access_section_anyone_apart_from_guest"="Anyone who knows the room's link, apart from guests"; "room_details_access_section_anyone"="Anyone who knows the room's link, including guests"; +"room_details_access_section_no_address_warning" = "To link to a room it must have an address"; "room_details_access_section_directory_toggle"="List this room in room directory"; -"room_details_history_section"="WHO CAN READ HISTORY?"; +"room_details_history_section"="Who can read history?"; "room_details_history_section_anyone"="Anyone"; "room_details_history_section_members_only"="Members only (since the point in time of selecting this option)"; "room_details_history_section_members_only_since_invited"="Members only (since they were invited)"; "room_details_history_section_members_only_since_joined"="Members only (since they joined)"; "room_details_history_section_prompt_title" = "Privacy warning"; "room_details_history_section_prompt_msg" = "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged."; +"room_details_addresses_section"="Addresses"; +"room_details_no_local_addresses" = "This room has no local addresses"; +"room_details_new_address" = "Add new address"; +"room_details_new_address_placeholder" = "Add new address (e.g. #foo%@)"; +"room_details_addresses_invalid_address_prompt_title" = "Invalid alias format"; +"room_details_addresses_invalid_address_prompt_msg" = "%@ is not a valid format for an alias"; +"room_details_addresses_disable_main_address_prompt_title" = "Main address warning"; +"room_details_addresses_disable_main_address_prompt_msg"="You will have no main address specified. The default main address for this room will be picked randomly"; +"room_details_advanced_section"="Advanced"; +"room_details_advanced_room_id"="Room ID:"; "room_details_fail_to_update_avatar" = "Fail to update the room photo"; "room_details_fail_to_update_room_name" = "Fail to update the room name"; "room_details_fail_to_update_topic" = "Fail to update the topic"; @@ -268,7 +279,13 @@ "room_details_fail_to_update_room_join_rule" = "Fail to update the join rule"; "room_details_fail_to_update_room_directory_visibility" = "Fail to update the room directory visibility"; "room_details_fail_to_update_history_visibility" = "Fail to update the history visibility"; -"room_details_with_updates" = "Do you want to save changes?"; +"room_details_fail_to_add_room_aliases" = "Fail to add the new room addresses"; +"room_details_fail_to_remove_room_aliases" = "Fail to remove the room addresses"; +"room_details_fail_to_update_room_canonical_alias" = "Fail to update the main address"; +"room_details_save_changes_prompt" = "Do you want to save changes?"; +"room_details_copy_room_id" = "Copy Room ID"; +"room_details_copy_room_address" = "Copy Room Address"; +"room_details_copy_room_url" = "Copy Room URL"; // Media picker "media_picker_library" = "Library"; diff --git a/Vector/Info.plist b/Vector/Info.plist index 1c0d039d7b..360d55c2bf 100644 --- a/Vector/Info.plist +++ b/Vector/Info.plist @@ -36,7 +36,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1.11 + 0.1.12 CFBundleSignature ???? CFBundleVersion diff --git a/Vector/ViewController/RoomParticipantsViewController.m b/Vector/ViewController/RoomParticipantsViewController.m index a8604da221..1de1a81a6b 100644 --- a/Vector/ViewController/RoomParticipantsViewController.m +++ b/Vector/ViewController/RoomParticipantsViewController.m @@ -384,6 +384,9 @@ - (void)startActivityIndicator if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class]) { [((SegmentedViewController*)self.parentViewController) startActivityIndicator]; + + // Force stop the activity view of the view controller + [self.activityIndicator stopAnimating]; } else { @@ -397,6 +400,9 @@ - (void)stopActivityIndicator if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class]) { [((SegmentedViewController*)self.parentViewController) stopActivityIndicator]; + + // Force stop the activity view of the view controller + [self.activityIndicator stopAnimating]; } else { @@ -914,7 +920,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (disambiguatedDisplayName) { - contact = [[Contact alloc] initMatrixContactWithDisplayName:disambiguatedDisplayName andMatrixID:contact.mxMember.userId]; + MXRoomMember* mxMember = contact.mxMember; + contact = [[Contact alloc] initMatrixContactWithDisplayName:disambiguatedDisplayName andMatrixID:mxMember.userId]; + contact.mxMember = mxMember; } } @@ -974,6 +982,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N return participantCell; } +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.section == participantsSection || indexPath.section == invitedSection) + { + return YES; + } + return NO; +} + - (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath { // iOS8 requires this method to enable editing (see editActionsForRowAtIndexPath). @@ -1114,20 +1131,21 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath { - NSMutableArray* actions = [[NSMutableArray alloc] init]; + NSMutableArray* actions; // add the swipe to delete only on participants sections if (indexPath.section == participantsSection || indexPath.section == invitedSection) { - NSString* title = @" "; + actions = [[NSMutableArray alloc] init]; - UITableViewRowAction *leaveAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:title handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){ + // Patch: Force the width of the button by adding whitespace characters into the title string. + UITableViewRowAction *leaveAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@" " handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){ [self onDeleteAt:indexPath]; }]; - leaveAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon" backgroundColor:kVectorColorLightGrey patternSize:CGSizeMake(74, 74) resourceSize:CGSizeMake(30, 30)]; + leaveAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon" backgroundColor:kVectorColorLightGrey patternSize:CGSizeMake(74, 74) resourceSize:CGSizeMake(25, 24)]; [actions insertObject:leaveAction atIndex:0]; } diff --git a/Vector/ViewController/RoomSettingsViewController.h b/Vector/ViewController/RoomSettingsViewController.h index a2f407baf6..3e20bcad29 100644 --- a/Vector/ViewController/RoomSettingsViewController.h +++ b/Vector/ViewController/RoomSettingsViewController.h @@ -17,8 +17,9 @@ #import #import "MediaPickerViewController.h" +#import "TableViewCellWithCheckBoxes.h" -@interface RoomSettingsViewController : MXKRoomSettingsViewController +@interface RoomSettingsViewController : MXKRoomSettingsViewController @end diff --git a/Vector/ViewController/RoomSettingsViewController.m b/Vector/ViewController/RoomSettingsViewController.m index 4e18a7d42c..b31b9910ce 100644 --- a/Vector/ViewController/RoomSettingsViewController.m +++ b/Vector/ViewController/RoomSettingsViewController.m @@ -17,8 +17,7 @@ #import "RoomSettingsViewController.h" #import "TableViewCellWithLabelAndLargeTextView.h" -#import "TableViewCellWithSwitches.h" -#import "TableViewCellWithTickAndLabel.h" +#import "TableViewCellWithCheckBoxAndLabel.h" #import "SegmentedViewController.h" @@ -27,6 +26,7 @@ #import "VectorDesignValues.h" #import "AvatarGenerator.h" +#import "Tools.h" #import "MXRoom+Vector.h" @@ -35,20 +35,22 @@ #define ROOM_SETTINGS_MAIN_SECTION_INDEX 0 #define ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX 1 #define ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_INDEX 2 -#define ROOM_SETTINGS_SECTION_COUNT 3 +#define ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX 3 +#define ROOM_SETTINGS_ADVANCED_SECTION_INDEX 4 +#define ROOM_SETTINGS_SECTION_COUNT 5 #define ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO 0 #define ROOM_SETTINGS_MAIN_SECTION_ROW_NAME 1 #define ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC 2 #define ROOM_SETTINGS_MAIN_SECTION_ROW_TAG 3 #define ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS 4 -#define ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT 5 +#define ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE 5 +#define ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT 6 #define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY 0 #define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST 1 #define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE 2 -#define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_DIRECTORY_TOGGLE 3 -#define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_COUNT 4 +#define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_SUB_COUNT 3 #define ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE 0 #define ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY 1 @@ -68,6 +70,16 @@ NSString *const kRoomSettingsGuestAccessKey = @"kRoomSettingsGuestAccessKey"; NSString *const kRoomSettingsDirectoryKey = @"kRoomSettingsDirectoryKey"; NSString *const kRoomSettingsHistoryVisibilityKey = @"kRoomSettingsHistoryVisibilityKey"; +NSString *const kRoomSettingsNewAliasesKey = @"kRoomSettingsNewAliasesKey"; +NSString *const kRoomSettingsRemovedAliasesKey = @"kRoomSettingsRemovedAliasesKey"; +NSString *const kRoomSettingsCanonicalAliasKey = @"kRoomSettingsCanonicalAliasKey"; + +NSString *const kRoomSettingsNameCellViewIdentifier = @"kRoomSettingsNameCellViewIdentifier"; +NSString *const kRoomSettingsTopicCellViewIdentifier = @"kRoomSettingsTopicCellViewIdentifier"; +NSString *const kRoomSettingsWarningCellViewIdentifier = @"kRoomSettingsWarningCellViewIdentifier"; +NSString *const kRoomSettingsNewAddressCellViewIdentifier = @"kRoomSettingsNewAddressCellViewIdentifier"; +NSString *const kRoomSettingsAddressCellViewIdentifier = @"kRoomSettingsAddressCellViewIdentifier"; +NSString *const kRoomSettingsAdvancedCellViewIdentifier = @"kRoomSettingsAdvancedCellViewIdentifier"; @interface RoomSettingsViewController () { @@ -77,18 +89,28 @@ @interface RoomSettingsViewController () // The current table items UITextField* nameTextField; UITextView* topicTextView; - UISwitch *favouriteTagSwitch; - UISwitch *lowPriorityTagSwitch; + + // The room tag items + TableViewCellWithCheckBoxes *roomTagCell; // Room Access items - TableViewCellWithTickAndLabel *accessInvitedOnlyTickCell; - TableViewCellWithTickAndLabel *accessAnyoneApartGuestTickCell; - TableViewCellWithTickAndLabel *accessAnyoneTickCell; + NSInteger directoryVisibilityIndex; + NSInteger missingAddressWarningIndex; + TableViewCellWithCheckBoxAndLabel *accessInvitedOnlyTickCell; + TableViewCellWithCheckBoxAndLabel *accessAnyoneApartGuestTickCell; + TableViewCellWithCheckBoxAndLabel *accessAnyoneTickCell; UISwitch *directoryVisibilitySwitch; MXRoomDirectoryVisibility actualDirectoryVisibility; + MXHTTPOperation* actualDirectoryVisibilityRequest; // History Visibility items - NSMutableDictionary *historyVisibilityTickCells; + NSMutableDictionary *historyVisibilityTickCells; + + // Room aliases + NSMutableArray *roomAddresses; + NSUInteger localAddressesCount; + NSInteger roomAddressNewAliasIndex; + UITextField* addAddressTextField; // The potential image loader MXKMediaLoader *uploader; @@ -144,12 +166,23 @@ - (void)viewDidLoad updatedItemsDict = [[NSMutableDictionary alloc] init]; historyVisibilityTickCells = [[NSMutableDictionary alloc] initWithCapacity:4]; + roomAddresses = [NSMutableArray array]; + [self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]]; [self.tableView registerClass:MXKTableViewCellWithLabelAndMXKImageView.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]]; - [self.tableView registerClass:TableViewCellWithLabelAndLargeTextView.class forCellReuseIdentifier:[TableViewCellWithLabelAndLargeTextView defaultReuseIdentifier]]; - [self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndTextField defaultReuseIdentifier]]; - [self.tableView registerClass:TableViewCellWithSwitches.class forCellReuseIdentifier:[TableViewCellWithSwitches defaultReuseIdentifier]]; - [self.tableView registerClass:TableViewCellWithTickAndLabel.class forCellReuseIdentifier:[TableViewCellWithTickAndLabel defaultReuseIdentifier]]; + + // Use a specific cell identifier for the room name, the topic and the address in order to be able to keep reference + // on the text input field without being disturbed by the cell dequeuing process. + [self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNameCellViewIdentifier]; + [self.tableView registerClass:TableViewCellWithLabelAndLargeTextView.class forCellReuseIdentifier:kRoomSettingsTopicCellViewIdentifier]; + [self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNewAddressCellViewIdentifier]; + [self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:kRoomSettingsAddressCellViewIdentifier]; + [self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:kRoomSettingsWarningCellViewIdentifier]; + + [self.tableView registerClass:MXKTableViewCellWithButton.class forCellReuseIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]]; + [self.tableView registerClass:TableViewCellWithCheckBoxes.class forCellReuseIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier]]; + [self.tableView registerClass:TableViewCellWithCheckBoxAndLabel.class forCellReuseIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier]]; + [self.tableView registerClass:MXKTableViewCell.class forCellReuseIdentifier:[MXKTableViewCell defaultReuseIdentifier]]; [self setNavBarButtons]; } @@ -219,6 +252,12 @@ - (void)destroy { self.navigationItem.rightBarButtonItem.enabled = NO; + if (currentAlert) + { + [currentAlert dismiss:NO]; + currentAlert = nil; + } + if (uploader) { [uploader cancel]; @@ -231,6 +270,12 @@ - (void)destroy pendingOperation = nil; } + if (actualDirectoryVisibilityRequest) + { + [actualDirectoryVisibilityRequest cancel]; + actualDirectoryVisibilityRequest = nil; + } + if (appDelegateDidTapStatusBarNotificationObserver) { [[NSNotificationCenter defaultCenter] removeObserver:appDelegateDidTapStatusBarNotificationObserver]; @@ -240,6 +285,8 @@ - (void)destroy updatedItemsDict = nil; historyVisibilityTickCells = nil; + roomAddresses = nil; + [super destroy]; } @@ -258,9 +305,12 @@ - (void)withdrawViewControllerAnimated:(BOOL)animated completion:(void (^)(void) - (void)refreshRoomSettings { + [self retrieveActualDirectoryVisibility]; + // Check whether a text input is currently edited BOOL isNameEdited = nameTextField ? nameTextField.isFirstResponder : NO; BOOL isTopicEdited = topicTextView ? topicTextView.isFirstResponder : NO; + BOOL isAddressEdited = addAddressTextField ? addAddressTextField.isFirstResponder : NO; // Trigger a full table reloadData [super refreshRoomSettings]; @@ -274,6 +324,10 @@ - (void)refreshRoomSettings { [self editRoomTopic]; } + else if (isAddressEdited) + { + [self editAddRoomAddress]; + } } #pragma mark - private @@ -304,6 +358,19 @@ - (void)editRoomTopic } } +- (void)editAddRoomAddress +{ + if (![addAddressTextField becomeFirstResponder]) + { + // Retry asynchronously + dispatch_async(dispatch_get_main_queue(), ^{ + + [self editAddRoomAddress]; + + }); + } +} + - (void)dismissFirstResponder { if ([topicTextView isFirstResponder]) @@ -315,6 +382,11 @@ - (void)dismissFirstResponder { [nameTextField resignFirstResponder]; } + + if ([addAddressTextField isFirstResponder]) + { + [addAddressTextField resignFirstResponder]; + } } - (void)startActivityIndicator @@ -326,6 +398,9 @@ - (void)startActivityIndicator if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class]) { [((SegmentedViewController*)self.parentViewController) startActivityIndicator]; + + // Force stop the activity view of the view controller + [self.activityIndicator stopAnimating]; } else { @@ -345,6 +420,9 @@ - (void)stopActivityIndicator if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class]) { [((SegmentedViewController*)self.parentViewController) stopActivityIndicator]; + + // Force stop the activity view of the view controller + [self.activityIndicator stopAnimating]; } else { @@ -360,7 +438,7 @@ - (void)promptUserToSaveChanges __weak typeof(self) weakSelf = self; - currentAlert = [[MXKAlert alloc] initWithTitle:nil message:NSLocalizedStringFromTable(@"room_details_with_updates", @"Vector", nil) style:MXKAlertStyleAlert]; + currentAlert = [[MXKAlert alloc] initWithTitle:nil message:NSLocalizedStringFromTable(@"room_details_save_changes_prompt", @"Vector", nil) style:MXKAlertStyleAlert]; currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"no"] style:MXKAlertActionStyleCancel handler:^(MXKAlert *alert) { @@ -391,6 +469,160 @@ - (void)promptUserToSaveChanges [currentAlert showInViewController:self]; } +- (void)promptUserToCopyRoomId:(UILabel*)roomIdLabel +{ + if (roomIdLabel) + { + [currentAlert dismiss:NO]; + + __weak typeof(self) weakSelf = self; + + currentAlert = [[MXKAlert alloc] initWithTitle:nil message:nil style:MXKAlertStyleActionSheet]; + + [currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_details_copy_room_id", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + + [[UIPasteboard generalPasteboard] setString:roomIdLabel.text]; + } + + }]; + + currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + } + + }]; + + currentAlert.sourceView = roomIdLabel; + [currentAlert showInViewController:self]; + } +} + +- (void)promptUserOnSelectedRoomAlias:(UILabel*)roomAliasLabel +{ + if (roomAliasLabel) + { + [currentAlert dismiss:NO]; + + __weak typeof(self) weakSelf = self; + + currentAlert = [[MXKAlert alloc] initWithTitle:nil message:nil style:MXKAlertStyleActionSheet]; + + [currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_details_copy_room_address", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + + [[UIPasteboard generalPasteboard] setString:roomAliasLabel.text]; + } + + }]; + + [currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_details_copy_room_url", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + + // Create a room url that is common to all Vector.im clients + NSString *roomURL = [NSString stringWithFormat:@"%@/#/room/%@", + [Tools webAppUrl], + roomAliasLabel.text]; + + [[UIPasteboard generalPasteboard] setString:roomURL]; + } + + }]; + + [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"delete"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + + [strongSelf removeRoomAlias:roomAliasLabel.text]; + } + + }]; + + currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + } + + }]; + + currentAlert.sourceView = roomAliasLabel; + [currentAlert showInViewController:self]; + } +} + +- (void)retrieveActualDirectoryVisibility +{ + if (!mxRoom || actualDirectoryVisibilityRequest) + { + return; + } + + // Trigger a new request to check the actual directory visibility + __weak typeof(self) weakSelf = self; + + actualDirectoryVisibilityRequest = [mxRoom directoryVisibility:^(MXRoomDirectoryVisibility directoryVisibility) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->actualDirectoryVisibilityRequest = nil; + + strongSelf->actualDirectoryVisibility = directoryVisibility; + + // Update the value of the displayed toggle button (if any) + if (directoryVisibilitySwitch) + { + // Check a potential user's change before the end of the request + MXRoomDirectoryVisibility modifiedDirectoryVisibility = [updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]; + if (modifiedDirectoryVisibility) + { + if ([modifiedDirectoryVisibility isEqualToString:directoryVisibility]) + { + // The requested change corresponds to the actual settings + [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey]; + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); + } + } + + directoryVisibilitySwitch.on = ([directoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic]); + } + } + + } failure:^(NSError *error) { + + NSLog(@"[RoomSettingsViewController] request to get directory visibility failed"); + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->actualDirectoryVisibilityRequest = nil; + } + }]; +} + #pragma mark - UITextViewDelegate - (void)textViewDidBeginEditing:(UITextView *)textView; @@ -439,11 +671,112 @@ - (void)textViewDidChange:(UITextView *)textView } } +#pragma mark - UITextFieldDelegate + +- (void)textFieldDidBeginEditing:(UITextField *)textField +{ + if (textField == addAddressTextField) + { + if (textField.text.length == 0) + { + textField.text = @"#"; + } + } +} +- (void)textFieldDidEndEditing:(UITextField *)textField +{ + if (textField == addAddressTextField) + { + if (textField.text.length < 2) + { + // reset text field + textField.text = nil; + } + else + { + // Check whether homeserver suffix should be added + NSRange range = [textField.text rangeOfString:@":"]; + if (range.location == NSNotFound) + { + textField.text = [textField.text stringByAppendingString:self.mainSession.matrixRestClient.homeserverSuffix]; + } + } + } +} + +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string +{ + // Auto complete room alias + if (textField == addAddressTextField) + { + // Add # if none + if (!textField.text.length || textField.text.length == range.length) + { + if ([string hasPrefix:@"#"] == NO) + { + if ([string isEqualToString:@":"]) + { + textField.text = [NSString stringWithFormat:@"#%@",self.mainSession.matrixRestClient.homeserverSuffix]; + } + else + { + textField.text = [NSString stringWithFormat:@"#%@",string]; + } + return NO; + } + } + else + { + // Remove default '#' if the string start with '#' + if ([string hasPrefix:@"#"] && [textField.text isEqualToString:@"#"]) + { + textField.text = string; + return NO; + } + // Add homeserver automatically when user adds ':' at the end + else if (range.location == textField.text.length && [string isEqualToString:@":"]) + { + textField.text = [textField.text stringByAppendingString:self.mainSession.matrixRestClient.homeserverSuffix]; + return NO; + } + } + } + return YES; +} + +- (BOOL)textFieldShouldClear:(UITextField *)textField +{ + if (textField == addAddressTextField) + { + textField.text = @"#"; + return NO; + } + return YES; +} + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + if (textField == addAddressTextField) + { + // Dismiss the keyboard + [addAddressTextField resignFirstResponder]; + + NSString *roomAlias = addAddressTextField.text; + if (!roomAlias.length || [self addRoomAlias:roomAlias]) + { + // Reset the input field + addAddressTextField.text = nil; + } + } + + return YES; +} + #pragma mark - actions - (IBAction)onTextFieldUpdate:(UITextField*)textField { - if (nameTextField == textField) + if (textField == nameTextField) { NSString* currentName = mxRoomState.name; @@ -565,7 +898,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_avatar", @"Vector", nil) withKey:kRoomSettingsAvatarKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_avatar", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsAvatarKey]; }); } @@ -601,7 +939,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_avatar", @"Vector", nil) withKey:kRoomSettingsAvatarURLKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_avatar", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsAvatarURLKey]; }); } @@ -638,7 +981,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_room_name", @"Vector", nil) withKey:kRoomSettingsNameKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_name", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsNameKey]; }); } @@ -675,7 +1023,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_topic", @"Vector", nil) withKey:kRoomSettingsTopicKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_topic", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsTopicKey]; }); } @@ -712,7 +1065,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_room_guest_access", @"Vector", nil) withKey:kRoomSettingsGuestAccessKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_guest_access", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsGuestAccessKey]; }); } @@ -749,7 +1107,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_room_join_rule", @"Vector", nil) withKey:kRoomSettingsJoinRuleKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_join_rule", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsJoinRuleKey]; }); } @@ -786,7 +1149,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_history_visibility", @"Vector", nil) withKey:kRoomSettingsHistoryVisibilityKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_history_visibility", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsHistoryVisibilityKey]; }); } @@ -795,49 +1163,197 @@ - (IBAction)onSave:(id)sender return; } - } - - // Update here other room settings - NSString *roomTag = [updatedItemsDict objectForKey:kRoomSettingsTagKey]; - if (roomTag) - { - if (!roomTag.length) - { - roomTag = nil; - } - [mxRoom setRoomTag:roomTag completion:^{ + // Room addresses + NSMutableArray *aliases = [updatedItemsDict objectForKey:kRoomSettingsNewAliasesKey]; + if (aliases.count) + { + NSString *roomAlias = aliases.firstObject; - if (weakSelf) - { - __strong __typeof(weakSelf)strongSelf = weakSelf; + pendingOperation = [mxRoom addAlias:roomAlias success:^{ - [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; - [strongSelf onSave:nil]; - } + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf->pendingOperation = nil; + + if (aliases.count > 1) + { + [aliases removeObjectAtIndex:0]; + [strongSelf->updatedItemsDict setObject:aliases forKey:kRoomSettingsNewAliasesKey]; + } + else + { + [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsNewAliasesKey]; + } + + [strongSelf onSave:nil]; + } + + } failure:^(NSError *error) { + + NSLog(@"[RoomSettingsViewController] Add room aliases failed"); + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf->pendingOperation = nil; + + dispatch_async(dispatch_get_main_queue(), ^{ + + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_add_room_aliases", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsNewAliasesKey]; + + }); + } + + }]; - }]; + return; + } - return; - } - - if ([updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]) - { - [mxRoom setMute:roomNotifSwitch.on completion:^{ + aliases = [updatedItemsDict objectForKey:kRoomSettingsRemovedAliasesKey]; + if (aliases.count) + { + NSString *roomAlias = aliases.firstObject; - if (weakSelf) - { - __strong __typeof(weakSelf)strongSelf = weakSelf; + pendingOperation = [mxRoom removeAlias:roomAlias success:^{ - [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; - [strongSelf onSave:nil]; - } - - }]; - - return; - } - + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf->pendingOperation = nil; + + if (aliases.count > 1) + { + [aliases removeObjectAtIndex:0]; + [strongSelf->updatedItemsDict setObject:aliases forKey:kRoomSettingsRemovedAliasesKey]; + } + else + { + [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsRemovedAliasesKey]; + } + + [strongSelf onSave:nil]; + } + + } failure:^(NSError *error) { + + NSLog(@"[RoomSettingsViewController] Remove room aliases failed"); + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf->pendingOperation = nil; + + dispatch_async(dispatch_get_main_queue(), ^{ + + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_remove_room_aliases", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsRemovedAliasesKey]; + + }); + } + + }]; + + return; + } + + NSString* canonicalAlias = [updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]; + if (canonicalAlias) + { + pendingOperation = [mxRoom setCanonicalAlias:canonicalAlias success:^{ + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf->pendingOperation = nil; + [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey]; + [strongSelf onSave:nil]; + } + + } failure:^(NSError *error) { + + NSLog(@"[RoomSettingsViewController] Update canonical alias failed"); + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + strongSelf->pendingOperation = nil; + + dispatch_async(dispatch_get_main_queue(), ^{ + + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_canonical_alias", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsCanonicalAliasKey]; + + }); + } + + }]; + + return; + } + } + + // Update here other room settings + NSString *roomTag = [updatedItemsDict objectForKey:kRoomSettingsTagKey]; + if (roomTag) + { + if (!roomTag.length) + { + roomTag = nil; + } + + [mxRoom setRoomTag:roomTag completion:^{ + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; + [strongSelf onSave:nil]; + } + + }]; + + return; + } + + if ([updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]) + { + [mxRoom setMute:roomNotifSwitch.on completion:^{ + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + [strongSelf->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; + [strongSelf onSave:nil]; + } + + }]; + + return; + } + // Room directory visibility MXRoomDirectoryVisibility directoryVisibility = [updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]; if (directoryVisibility) @@ -864,7 +1380,12 @@ - (IBAction)onSave:(id)sender dispatch_async(dispatch_get_main_queue(), ^{ - [strongSelf onSaveFailed:NSLocalizedStringFromTable(@"room_details_fail_to_update_room_directory_visibility", @"Vector", nil) withKey:kRoomSettingsDirectoryKey]; + NSString* message = error.localizedDescription; + if (!message.length) + { + message = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_directory_visibility", @"Vector", nil); + } + [strongSelf onSaveFailed:message withKey:kRoomSettingsDirectoryKey]; }); } @@ -886,25 +1407,105 @@ - (IBAction)onSave:(id)sender - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + // Refresh here the room addresses list + [roomAddresses removeAllObjects]; + localAddressesCount = 0; + + NSArray *removedAliases = [updatedItemsDict objectForKey:kRoomSettingsRemovedAliasesKey]; + + NSArray *aliases = mxRoomState.aliases; + if (aliases) + { + for (NSString *alias in aliases) + { + // Check whether the user did not remove it + if (!removedAliases || [removedAliases indexOfObject:alias] == NSNotFound) + { + // Add it + if ([alias hasSuffix:self.mainSession.matrixRestClient.homeserverSuffix]) + { + [roomAddresses insertObject:alias atIndex:localAddressesCount]; + localAddressesCount++; + } + else + { + [roomAddresses addObject:alias]; + } + } + } + } + + aliases = [updatedItemsDict objectForKey:kRoomSettingsNewAliasesKey]; + for (NSString *alias in aliases) + { + // Add this new alias to local addresses + [roomAddresses insertObject:alias atIndex:localAddressesCount]; + localAddressesCount++; + } + + // Return the fixed number of sections return ROOM_SETTINGS_SECTION_COUNT; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + NSInteger count = 0; + if (section == ROOM_SETTINGS_MAIN_SECTION_INDEX) { - return ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT; + count = ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT; } else if (section == ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX) { - return ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_COUNT; + missingAddressWarningIndex = -1; + directoryVisibilityIndex = -1; + + count = ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_SUB_COUNT; + + // Check whether a room address is required for the current join rule + NSString *joinRule = [updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey]; + if (!joinRule) + { + // Use the actual values if no change is pending. + joinRule = mxRoomState.joinRule; + } + + if ([joinRule isEqualToString:kMXRoomJoinRulePublic] && !roomAddresses.count) + { + // Notify the user that a room address is required. + missingAddressWarningIndex = count++; + } + + directoryVisibilityIndex = count++; } else if (section == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_INDEX) { - return ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_COUNT; + count = ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_COUNT; + } + else if (section == ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX) + { + roomAddressNewAliasIndex = -1; + + count = (localAddressesCount ? roomAddresses.count : roomAddresses.count + 1); + + if (self.mainSession) + { + // Check user's power level to know whether the user is allowed to add room alias + MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels]; + NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + + if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases]) + { + roomAddressNewAliasIndex = count++; + } + } + } + else if (section == ROOM_SETTINGS_ADVANCED_SECTION_INDEX) + { + count = 1; } - return 0; + return count; } - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section @@ -917,6 +1518,14 @@ - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSectio { return NSLocalizedStringFromTable(@"room_details_history_section", @"Vector", nil); } + else if (section == ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX) + { + return NSLocalizedStringFromTable(@"room_details_addresses_section", @"Vector", nil); + } + else if (section == ROOM_SETTINGS_ADVANCED_SECTION_INDEX) + { + return NSLocalizedStringFromTable(@"room_details_advanced_section", @"Vector", nil); + } return nil; } @@ -950,15 +1559,14 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N { MXKTableViewCellWithLabelAndSwitch *roomNotifCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; - UIEdgeInsets separatorInset = roomNotifCell.separatorInset; - - roomNotifCell.mxkLabelLeadingConstraint.constant = separatorInset.left; + roomNotifCell.mxkLabelLeadingConstraint.constant = roomNotifCell.separatorInset.left; roomNotifCell.mxkSwitchTrailingConstraint.constant = 15; [roomNotifCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; roomNotifCell.mxkSwitch.onTintColor = kVectorColorGreen; roomNotifCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_mute_notifs", @"Vector", nil); + roomNotifCell.mxkLabel.textColor = kVectorTextColorBlack; roomNotifSwitch = roomNotifCell.mxkSwitch; if ([updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]) @@ -970,14 +1578,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N roomNotifSwitch.on = mxRoom.isMute; } - [roomNotifCell layoutIfNeeded]; cell = roomNotifCell; } else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO) { MXKTableViewCellWithLabelAndMXKImageView *roomPhotoCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier] forIndexPath:indexPath]; - roomPhotoCell.mxkLabelLeadingConstraint.constant = 15; + roomPhotoCell.mxkLabelLeadingConstraint.constant = roomPhotoCell.separatorInset.left; roomPhotoCell.mxkImageViewTrailingConstraint.constant = 10; roomPhotoCell.mxkImageViewWidthConstraint.constant = roomPhotoCell.mxkImageViewHeightConstraint.constant = 30; @@ -994,6 +1601,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N roomPhotoCell.mxkImageView.backgroundColor = [UIColor clearColor]; roomPhotoCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_photo", @"Vector", nil); + roomPhotoCell.mxkLabel.textColor = kVectorTextColorBlack; if ([updatedItemsDict objectForKey:kRoomSettingsAvatarKey]) { @@ -1011,7 +1619,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC) { - TableViewCellWithLabelAndLargeTextView *roomTopicCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithLabelAndLargeTextView defaultReuseIdentifier] forIndexPath:indexPath]; + TableViewCellWithLabelAndLargeTextView *roomTopicCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsTopicCellViewIdentifier forIndexPath:indexPath]; + + roomTopicCell.labelLeadingConstraint.constant = roomTopicCell.separatorInset.left; roomTopicCell.label.text = NSLocalizedStringFromTable(@"room_details_topic", @"Vector", nil); @@ -1039,15 +1649,16 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_NAME) { - MXKTableViewCellWithLabelAndTextField *roomNameCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndTextField defaultReuseIdentifier] forIndexPath:indexPath]; + MXKTableViewCellWithLabelAndTextField *roomNameCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNameCellViewIdentifier forIndexPath:indexPath]; - UIEdgeInsets separatorInset = roomNameCell.separatorInset; - - roomNameCell.mxkLabelLeadingConstraint.constant = separatorInset.left; + roomNameCell.mxkLabelLeadingConstraint.constant = roomNameCell.separatorInset.left; roomNameCell.mxkTextFieldTrailingConstraint.constant = 15; roomNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_room_name", @"Vector", nil); + roomNameCell.mxkLabel.textColor = kVectorTextColorBlack; + roomNameCell.accessoryType = UITableViewCellAccessoryNone; + roomNameCell.accessoryView = nil; nameTextField = roomNameCell.mxkTextField; @@ -1076,22 +1687,20 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TAG) { - TableViewCellWithSwitches *tagCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithSwitches defaultReuseIdentifier] forIndexPath:indexPath]; + roomTagCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier] forIndexPath:indexPath]; - tagCell.switchesNumber = 2; + roomTagCell.mainContainerLeadingConstraint.constant = roomTagCell.separatorInset.left; - favouriteTagSwitch = tagCell.switches[0]; - [favouriteTagSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; - favouriteTagSwitch.onTintColor = kVectorColorGreen; + roomTagCell.checkBoxesNumber = 2; - lowPriorityTagSwitch = tagCell.switches[1]; - [lowPriorityTagSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; - lowPriorityTagSwitch.onTintColor = kVectorColorGreen; + roomTagCell.allowsMultipleSelection = NO; + roomTagCell.delegate = self; + NSArray *labels = roomTagCell.labels; UILabel *label; - label = tagCell.labels[0]; + label = labels[0]; label.text = NSLocalizedStringFromTable(@"room_details_favourite_tag", @"Vector", nil); - label = tagCell.labels[1]; + label = labels[1]; label.text = NSLocalizedStringFromTable(@"room_details_low_priority_tag", @"Vector", nil); if ([updatedItemsDict objectForKey:kRoomSettingsTagKey]) @@ -1099,41 +1708,55 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N NSString *roomTag = [updatedItemsDict objectForKey:kRoomSettingsTagKey]; if ([roomTag isEqualToString:kMXRoomTagFavourite]) { - favouriteTagSwitch.on = YES; - lowPriorityTagSwitch.on = NO; + [roomTagCell setCheckBoxValue:YES atIndex:0]; } else if ([roomTag isEqualToString:kMXRoomTagLowPriority]) { - favouriteTagSwitch.on = NO; - lowPriorityTagSwitch.on = YES; - } - else - { - favouriteTagSwitch.on = NO; - lowPriorityTagSwitch.on = NO; + [roomTagCell setCheckBoxValue:YES atIndex:1]; } } else { - favouriteTagSwitch.on = (mxRoom.accountData.tags[kMXRoomTagFavourite] != 0); - lowPriorityTagSwitch.on = (mxRoom.accountData.tags[kMXRoomTagLowPriority] != 0); + if (mxRoom.accountData.tags[kMXRoomTagFavourite] != nil) + { + [roomTagCell setCheckBoxValue:YES atIndex:0]; + } + else if (mxRoom.accountData.tags[kMXRoomTagLowPriority] != nil) + { + [roomTagCell setCheckBoxValue:YES atIndex:1]; + } } - cell = tagCell; + cell = roomTagCell; + } + else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE) + { + MXKTableViewCellWithButton *leaveCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath]; + + NSString* title = NSLocalizedStringFromTable(@"leave", @"Vector", nil); + + [leaveCell.mxkButton setTitle:title forState:UIControlStateNormal]; + [leaveCell.mxkButton setTitle:title forState:UIControlStateHighlighted]; + [leaveCell.mxkButton setTintColor:kVectorColorGreen]; + leaveCell.mxkButton.titleLabel.font = [UIFont boldSystemFontOfSize:16]; + + [leaveCell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; + [leaveCell.mxkButton addTarget:self action:@selector(onLeave:) forControlEvents:UIControlEventTouchUpInside]; + + cell = leaveCell; } } else if (indexPath.section == ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX) { - if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_DIRECTORY_TOGGLE) + if (indexPath.row == directoryVisibilityIndex) { MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; - UIEdgeInsets separatorInset = directoryToggleCell.separatorInset; - - directoryToggleCell.mxkLabelLeadingConstraint.constant = separatorInset.left; + directoryToggleCell.mxkLabelLeadingConstraint.constant = directoryToggleCell.separatorInset.left; directoryToggleCell.mxkSwitchTrailingConstraint.constant = 15; directoryToggleCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle", @"Vector", nil); + directoryToggleCell.mxkLabel.textColor = kVectorTextColorBlack; directoryVisibilitySwitch = directoryToggleCell.mxkSwitch; @@ -1148,236 +1771,252 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N { // Use the last retrieved value if any directoryVisibilitySwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO; - - // Trigger a request to check the actual directory visibility - [self startActivityIndicator]; - - __weak typeof(self) weakSelf = self; - - pendingOperation = [mxRoom directoryVisibility:^(MXRoomDirectoryVisibility directoryVisibility) { - - if (weakSelf) - { - __strong __typeof(weakSelf)strongSelf = weakSelf; - strongSelf->pendingOperation = nil; - - strongSelf->actualDirectoryVisibility = directoryVisibility; - - // Check a potential change before update - if ([updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]) - { - if (directoryVisibilitySwitch.on == ([directoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic])) - { - // The requested change corresponds to the actual settings - [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey]; - - [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); - } - } - else - { - directoryVisibilitySwitch.on = ([directoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic]); - } - - [strongSelf stopActivityIndicator]; - } - - } failure:^(NSError *error) { - - NSLog(@"[RoomSettingsViewController] request to get directory visibility failed"); - - if (weakSelf) - { - __strong __typeof(weakSelf)strongSelf = weakSelf; - strongSelf->pendingOperation = nil; - - [strongSelf stopActivityIndicator]; - } - }]; } + // Check whether the user can change this option + directoryVisibilitySwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault); + cell = directoryToggleCell; } + else if (indexPath.row == missingAddressWarningIndex) + { + cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsWarningCellViewIdentifier forIndexPath:indexPath]; + + cell.textLabel.font = [UIFont systemFontOfSize:17]; + cell.textLabel.textColor = kVectorColorPinkRed; + cell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + cell.accessoryView = nil; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_no_address_warning", @"Vector", nil); + } else { - TableViewCellWithTickAndLabel *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithTickAndLabel defaultReuseIdentifier] forIndexPath:indexPath]; + TableViewCellWithCheckBoxAndLabel *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath]; + + roomAccessCell.checkBoxLeadingConstraint.constant = roomAccessCell.separatorInset.left; + + // Retrieve the potential updated values for joinRule and guestAccess + NSString *joinRule = [updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey]; + NSString *guestAccess = [updatedItemsDict objectForKey:kRoomSettingsGuestAccessKey]; + + // Use the actual values if no change is pending + if (!joinRule) + { + joinRule = mxRoomState.joinRule; + } + if (!guestAccess) + { + guestAccess = mxRoomState.guestAccess; + } if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY) { + roomAccessCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_invited_only", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey]) - { - NSString *joinRule = [updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey]; - if ([joinRule isEqualToString:kMXRoomJoinRuleInvite]) - { - roomAccessCell.enabled = YES; - } - else - { - roomAccessCell.enabled = NO; - } - } - else - { - roomAccessCell.enabled = ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRuleInvite]); - } + roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRuleInvite]); accessInvitedOnlyTickCell = roomAccessCell; } else if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST) { + roomAccessCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_apart_from_guest", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey] || [updatedItemsDict objectForKey:kRoomSettingsGuestAccessKey]) - { - NSString *joinRule = [updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey]; - NSString *guestAccess = [updatedItemsDict objectForKey:kRoomSettingsGuestAccessKey]; - - if ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessForbidden]) - { - roomAccessCell.enabled = YES; - } - else - { - roomAccessCell.enabled = NO; - } - } - else - { - roomAccessCell.enabled = ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRulePublic] && [mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessForbidden]); - } + roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessForbidden]); accessAnyoneApartGuestTickCell = roomAccessCell; } else if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE) { + roomAccessCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey] || [updatedItemsDict objectForKey:kRoomSettingsGuestAccessKey]) - { - NSString *joinRule = [updatedItemsDict objectForKey:kRoomSettingsJoinRuleKey]; - NSString *guestAccess = [updatedItemsDict objectForKey:kRoomSettingsGuestAccessKey]; - - if ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessCanJoin]) - { - roomAccessCell.enabled = YES; - } - else - { - roomAccessCell.enabled = NO; - } - } - else - { - roomAccessCell.enabled = ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRulePublic] && [mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessCanJoin]); - } + roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessCanJoin]); accessAnyoneTickCell = roomAccessCell; } + // Check whether the user can change this option + roomAccessCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]); + roomAccessCell.checkBox.alpha = roomAccessCell.userInteractionEnabled ? 1.0f : 0.5f; + cell = roomAccessCell; } - } else if (indexPath.section == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_INDEX) { - TableViewCellWithTickAndLabel *historyVisibilityCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithTickAndLabel defaultReuseIdentifier] forIndexPath:indexPath]; + TableViewCellWithCheckBoxAndLabel *historyVisibilityCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath]; + + historyVisibilityCell.checkBoxLeadingConstraint.constant = historyVisibilityCell.separatorInset.left; + + // Retrieve first the potential updated value for history visibility + NSString *visibility = [updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]; + + // Use the actual value if no change is pending + if (!visibility) + { + visibility = mxRoomState.historyVisibility; + } if (indexPath.row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE) { + historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; historyVisibilityCell.label.text = NSLocalizedStringFromTable(@"room_details_history_section_anyone", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]) - { - NSString *visibility = [updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]; - if ([visibility isEqualToString:kMXRoomHistoryVisibilityWorldReadable]) - { - historyVisibilityCell.enabled = YES; - } - else - { - historyVisibilityCell.enabled = NO; - } - } - else - { - historyVisibilityCell.enabled = ([mxRoomState.historyVisibility isEqualToString:kMXRoomHistoryVisibilityWorldReadable]); - } + historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityWorldReadable]); [historyVisibilityTickCells setObject:historyVisibilityCell forKey:kMXRoomHistoryVisibilityWorldReadable]; } else if (indexPath.row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY) { + historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; historyVisibilityCell.label.text = NSLocalizedStringFromTable(@"room_details_history_section_members_only", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]) - { - NSString *visibility = [updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]; - if ([visibility isEqualToString:kMXRoomHistoryVisibilityShared]) - { - historyVisibilityCell.enabled = YES; - } - else - { - historyVisibilityCell.enabled = NO; - } - } - else - { - historyVisibilityCell.enabled = ([mxRoomState.historyVisibility isEqualToString:kMXRoomHistoryVisibilityShared]); - } + historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityShared]); [historyVisibilityTickCells setObject:historyVisibilityCell forKey:kMXRoomHistoryVisibilityShared]; } else if (indexPath.row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED) { + historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; historyVisibilityCell.label.text = NSLocalizedStringFromTable(@"room_details_history_section_members_only_since_invited", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]) - { - NSString *visibility = [updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]; - if ([visibility isEqualToString:kMXRoomHistoryVisibilityInvited]) - { - historyVisibilityCell.enabled = YES; - } - else - { - historyVisibilityCell.enabled = NO; - } - } - else - { - historyVisibilityCell.enabled = ([mxRoomState.historyVisibility isEqualToString:kMXRoomHistoryVisibilityInvited]); - } + historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityInvited]); [historyVisibilityTickCells setObject:historyVisibilityCell forKey:kMXRoomHistoryVisibilityInvited]; } else if (indexPath.row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED) { + historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle; historyVisibilityCell.label.text = NSLocalizedStringFromTable(@"room_details_history_section_members_only_since_joined", @"Vector", nil); - if ([updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]) + historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityJoined]); + + [historyVisibilityTickCells setObject:historyVisibilityCell forKey:kMXRoomHistoryVisibilityJoined]; + } + + // Check whether the user can change this option + historyVisibilityCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomHistoryVisibility]); + historyVisibilityCell.checkBox.alpha = historyVisibilityCell.userInteractionEnabled ? 1.0f : 0.5f; + + cell = historyVisibilityCell; + } + else if (indexPath.section == ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX) + { + if (indexPath.row == roomAddressNewAliasIndex) + { + MXKTableViewCellWithLabelAndTextField *addAddressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNewAddressCellViewIdentifier forIndexPath:indexPath]; + + // Retrieve the current edited value if any + NSString *currentValue = (addAddressTextField ? addAddressTextField.text : nil); + + addAddressCell.mxkLabelLeadingConstraint.constant = 0; + addAddressCell.mxkTextFieldLeadingConstraint.constant = addAddressCell.separatorInset.left; + addAddressCell.mxkTextFieldTrailingConstraint.constant = 15; + + addAddressCell.mxkLabel.text = nil; + + addAddressCell.accessoryType = UITableViewCellAccessoryNone; + addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"plus_icon"]]; + + addAddressTextField = addAddressCell.mxkTextField; + addAddressTextField.placeholder = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_details_new_address_placeholder", @"Vector", nil), self.mainSession.matrixRestClient.homeserverSuffix]; + addAddressTextField.userInteractionEnabled = YES; + addAddressTextField.text = currentValue; + addAddressTextField.textColor = kVectorTextColorGray; + + addAddressTextField.tintColor = kVectorColorGreen; + addAddressTextField.font = [UIFont systemFontOfSize:17]; + addAddressTextField.borderStyle = UITextBorderStyleNone; + addAddressTextField.textAlignment = NSTextAlignmentLeft; + + addAddressTextField.autocorrectionType = UITextAutocorrectionTypeNo; + addAddressTextField.spellCheckingType = UITextSpellCheckingTypeNo; + addAddressTextField.delegate = self; + + cell = addAddressCell; + } + else + { + UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath]; + + addressCell.textLabel.font = [UIFont systemFontOfSize:16]; + addressCell.textLabel.textColor = kVectorTextColorBlack; + addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + addressCell.accessoryView = nil; + addressCell.accessoryType = UITableViewCellAccessoryNone; + addressCell.selectionStyle = UITableViewCellSelectionStyleNone; + + while (addressCell.textLabel.gestureRecognizers.count) { - NSString *visibility = [updatedItemsDict objectForKey:kRoomSettingsHistoryVisibilityKey]; - if ([visibility isEqualToString:kMXRoomHistoryVisibilityJoined]) - { - historyVisibilityCell.enabled = YES; - } - else - { - historyVisibilityCell.enabled = NO; - } + [addressCell.textLabel removeGestureRecognizer:addressCell.textLabel.gestureRecognizers[0]]; + } + addressCell.textLabel.userInteractionEnabled = NO; + + // Check whether there is no local addresses + if (localAddressesCount == 0 && indexPath.row == 0) + { + addressCell.textLabel.text = NSLocalizedStringFromTable(@"room_details_no_local_addresses", @"Vector", nil); } else { - historyVisibilityCell.enabled = ([mxRoomState.historyVisibility isEqualToString:kMXRoomHistoryVisibilityJoined]); + NSInteger row = (localAddressesCount ? indexPath.row : indexPath.row - 1); + + if (row < roomAddresses.count) + { + NSString *alias = roomAddresses[indexPath.row]; + NSString *canonicalAlias; + + if ([updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]) + { + canonicalAlias = [updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]; + } + else + { + canonicalAlias = mxRoomState.canonicalAlias; + } + + addressCell.textLabel.text = alias; + + // Check whether this alias is the main address + if (canonicalAlias) + { + if ([alias isEqualToString:canonicalAlias]) + { + addressCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"main_alias_icon"]]; + } + } + + // Add a long gesture recognizer on alias label + UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)]; + [addressCell.textLabel addGestureRecognizer:longPress]; + addressCell.textLabel.userInteractionEnabled = YES; + } } - [historyVisibilityTickCells setObject:historyVisibilityCell forKey:kMXRoomHistoryVisibilityJoined]; + cell = addressCell; + } + } + else if (indexPath.section == ROOM_SETTINGS_ADVANCED_SECTION_INDEX) + { + cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedCellViewIdentifier]; + if (!cell) + { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedCellViewIdentifier]; } - cell = historyVisibilityCell; + cell.textLabel.font = [UIFont systemFontOfSize:17]; + cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_room_id", @"Vector", nil); + cell.textLabel.textColor = kVectorTextColorBlack; + + cell.detailTextLabel.font = [UIFont systemFontOfSize:15]; + cell.detailTextLabel.text = mxRoomState.roomId; + cell.detailTextLabel.textColor = kVectorTextColorGray; + cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + + cell.selectionStyle = UITableViewCellSelectionStyleNone; } // Sanity check @@ -1390,6 +2029,32 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N return cell; } +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.section == ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX && indexPath.row != roomAddressNewAliasIndex) + { + if (localAddressesCount != 0 || indexPath.row != 0) + { + // Check user's power level to know whether the user is allowed to remove room alias + MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels]; + NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + + if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases]) + { + return YES; + } + } + } + return NO; +} + +- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath +{ + // iOS8 requires this method to enable editing (see editActionsForRowAtIndexPath). +} + +#pragma mark - UITableViewDelegate + - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (self.tableView == tableView) @@ -1402,9 +2067,18 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath { [self onRoomAvatarTap:nil]; } + else if (indexPath.row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC) + { + if (topicTextView.editable) + { + [self editRoomTopic]; + } + } } else if (indexPath.section == ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX) { + BOOL isUpdated = NO; + if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY) { // Ignore the selection if the option is already enabled @@ -1438,6 +2112,8 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [updatedItemsDict setObject:kMXRoomGuestAccessCanJoin forKey:kRoomSettingsGuestAccessKey]; } } + + isUpdated = YES; } } else if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST) @@ -1478,6 +2154,8 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [updatedItemsDict setObject:kMXRoomGuestAccessForbidden forKey:kRoomSettingsGuestAccessKey]; } } + + isUpdated = YES; } } else if (indexPath.row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE) @@ -1518,15 +2196,29 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [updatedItemsDict setObject:kMXRoomGuestAccessCanJoin forKey:kRoomSettingsGuestAccessKey]; } } + + isUpdated = YES; } } + else if (indexPath.row == missingAddressWarningIndex) + { + // Scroll to room addresses section + NSIndexPath *addressIndexPath = [NSIndexPath indexPathForRow:0 inSection:ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX]; + [tableView scrollToRowAtIndexPath:addressIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; + } - [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); + if (isUpdated) + { + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX]; + [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); + } } else if (indexPath.section == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_INDEX) { // Ignore the selection if the option is already enabled - TableViewCellWithTickAndLabel *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath]; + TableViewCellWithCheckBoxAndLabel *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath]; if (! selectedCell.isEnabled) { MXRoomHistoryVisibility historyVisibility; @@ -1555,9 +2247,112 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath } } } + else if (indexPath.section == ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX) + { + if (indexPath.row == roomAddressNewAliasIndex) + { + NSString *roomAlias = addAddressTextField.text; + if (!roomAlias.length || [self addRoomAlias:roomAlias]) + { + // Reset the input field + addAddressTextField.text = nil; + } + } + else if (localAddressesCount != 0 || indexPath.row != 0) + { + NSInteger row = (localAddressesCount ? indexPath.row : indexPath.row - 1); + + if (row < roomAddresses.count) + { + NSString *alias = roomAddresses[row]; + NSString *currentCanonicalAlias = mxRoomState.canonicalAlias; + NSString *canonicalAlias; + + if ([updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]) + { + canonicalAlias = [updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]; + } + else + { + canonicalAlias = currentCanonicalAlias; + } + + if (canonicalAlias) + { + if ([alias isEqualToString:canonicalAlias]) + { + // Prompt user before removing the current main address (use dispatch_async here to not be stuck by the table refresh). + dispatch_async(dispatch_get_main_queue(), ^{ + + [self shouldRemoveCanonicalAlias:nil]; + + }); + } + else + { + // Update the current canonical address + if ([alias isEqualToString:currentCanonicalAlias]) + { + [updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey]; + } + else + { + [updatedItemsDict setObject:alias forKey:kRoomSettingsCanonicalAliasKey]; + } + + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX]; + [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); + } + } + } + } + } + else if (indexPath.section == ROOM_SETTINGS_ADVANCED_SECTION_INDEX) + { + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + if (cell) + { + // Prompt user to copy the room id (use dispatch_async here to not be stuck by the table refresh). + dispatch_async(dispatch_get_main_queue(), ^{ + + [self promptUserToCopyRoomId:cell.detailTextLabel]; + + }); + } + } + + [tableView deselectRowAtIndexPath:indexPath animated:YES]; } } +- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSMutableArray* actions; + + // Add the swipe to delete only on addresses section + if (indexPath.section == ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX && indexPath.row != roomAddressNewAliasIndex) + { + if (localAddressesCount != 0 || indexPath.row != 0) + { + actions = [[NSMutableArray alloc] init]; + + // Patch: Force the width of the button by adding whitespace characters into the title string. + UITableViewRowAction *removeAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@" " handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){ + + [self removeAddressAtIndexPath:indexPath]; + + }]; + + removeAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon" backgroundColor:kVectorColorLightGrey patternSize:CGSizeMake(44, 44) resourceSize:CGSizeMake(25, 24)]; + [actions insertObject:removeAction atIndex:0]; + } + } + + return actions; +} + #pragma mark - - (void)shouldChangeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility @@ -1600,7 +2395,7 @@ - (void)changeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility { // Disable all history visibility options NSArray *tickCells = historyVisibilityTickCells.allValues; - for (TableViewCellWithTickAndLabel *historyVisibilityTickCell in tickCells) + for (TableViewCellWithCheckBoxAndLabel *historyVisibilityTickCell in tickCells) { historyVisibilityTickCell.enabled = NO; } @@ -1623,6 +2418,51 @@ - (void)changeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility } } +- (void)shouldRemoveCanonicalAlias:(void (^)())didRemoveCanonicalAlias +{ + // Prompt the user before removing the current main address + [currentAlert dismiss:NO]; + + __weak typeof(self) weakSelf = self; + + currentAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"room_details_addresses_disable_main_address_prompt_title", @"Vector", nil) message:NSLocalizedStringFromTable(@"room_details_addresses_disable_main_address_prompt_msg", @"Vector", nil) style:MXKAlertStyleAlert]; + + currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleCancel handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + } + + }]; + + [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"continue"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + + // Remove the canonical address + [strongSelf->updatedItemsDict setObject:@"" forKey:kRoomSettingsCanonicalAliasKey]; + + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX]; + [strongSelf.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; + + [strongSelf getNavigationItem].rightBarButtonItem.enabled = (strongSelf->updatedItemsDict.count != 0); + + if (didRemoveCanonicalAlias) + { + didRemoveCanonicalAlias(); + } + } + + }]; + + [currentAlert showInViewController:self]; +} + #pragma mark - MediaPickerViewController Delegate - (void)dismissMediaPicker @@ -1656,6 +2496,59 @@ - (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController #pragma mark - actions +- (void)onLeave:(id)sender +{ + // Prompt user before leaving the room + __weak typeof(self) weakSelf = self; + + [currentAlert dismiss:NO]; + + + currentAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil) + message:NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil) + style:MXKAlertStyleAlert]; + + currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] + style:MXKAlertActionStyleCancel + handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + } + }]; + + [currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"leave", @"Vector", nil) + style:MXKAlertActionStyleDefault + handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + + [strongSelf startActivityIndicator]; + [strongSelf->mxRoom leave:^{ + + [strongSelf withdrawViewControllerAnimated:YES completion:nil]; + + } failure:^(NSError *error) { + + [strongSelf stopActivityIndicator]; + + NSLog(@"[RoomSettingsViewController] Leave room failed"); + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + }]; + } + + }]; + + [currentAlert showInViewController:self]; +} + - (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer { mediaPicker = [MediaPickerViewController mediaPickerViewController]; @@ -1669,75 +2562,238 @@ - (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer - (void)onSwitchUpdate:(UISwitch*)theSwitch { - if (theSwitch == favouriteTagSwitch) + if (theSwitch == roomNotifSwitch) { - if (favouriteTagSwitch.on) + if (roomNotifSwitch.on == mxRoom.isMute) { - // Check the actual tag on mxRoom - if (mxRoom.accountData.tags[kMXRoomTagFavourite]) + [updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; + } + else + { + [updatedItemsDict setObject:[NSNumber numberWithBool:roomNotifSwitch.on] forKey:kRoomSettingsMuteNotifKey]; + } + } + else if (theSwitch == directoryVisibilitySwitch) + { + MXRoomDirectoryVisibility visibility = directoryVisibilitySwitch.on ? kMXRoomDirectoryVisibilityPublic : kMXRoomDirectoryVisibilityPrivate; + + // Check whether the actual settings has been retrieved + if (actualDirectoryVisibility) + { + if ([visibility isEqualToString:actualDirectoryVisibility]) { - [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; + [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey]; } else { - [updatedItemsDict setObject:kMXRoomTagFavourite forKey:kRoomSettingsTagKey]; + [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; } - - // Force off the low priority toggle - lowPriorityTagSwitch.on = NO; } else { - // Retrieve the current change on room tag (if any) - NSString *updatedRoomTag = [updatedItemsDict objectForKey:kRoomSettingsTagKey]; + [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; + } + } + + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); +} + +- (IBAction)onLongPressGesture:(UILongPressGestureRecognizer*)longPressGestureRecognizer +{ + if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) + { + UIView* view = longPressGestureRecognizer.view; + + if ([view isKindOfClass:UILabel.class]) + { + UILabel *aliasLabel = (UILabel*)view; - // Check the actual tag on mxRoom - if (mxRoom.accountData.tags[kMXRoomTagFavourite]) + [self promptUserOnSelectedRoomAlias:aliasLabel]; + } + } +} + +- (void)removeAddressAtIndexPath:(NSIndexPath *)indexPath +{ + NSInteger row = (localAddressesCount ? indexPath.row : indexPath.row - 1); + + if (row < roomAddresses.count) + { + NSString *alias = roomAddresses[indexPath.row]; + [self removeRoomAlias:alias]; + } +} + +- (void)removeRoomAlias:(NSString*)roomAlias +{ + NSString *canonicalAlias; + + if ([updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]) + { + canonicalAlias = [updatedItemsDict objectForKey:kRoomSettingsCanonicalAliasKey]; + } + else + { + canonicalAlias = mxRoomState.canonicalAlias; + } + + // Check whether this alias is the main address + if (canonicalAlias && [roomAlias isEqualToString:canonicalAlias]) + { + // Prompt user before remove this alias which is the main address + [self shouldRemoveCanonicalAlias:^{ + + // The room alias can be removed now + [self removeRoomAlias:roomAlias]; + + }]; + } + else + { + // Check whether the alias has just been added + NSMutableArray *addedAlias = [updatedItemsDict objectForKey:kRoomSettingsNewAliasesKey]; + if (addedAlias && [addedAlias indexOfObject:roomAlias] != NSNotFound) + { + [addedAlias removeObject:roomAlias]; + + if (!addedAlias.count) { - // The actual tag must be updated, check whether another tag is already set - if (!updatedRoomTag) - { - [updatedItemsDict setObject:@"" forKey:kRoomSettingsTagKey]; - } + [updatedItemsDict removeObjectForKey:kRoomSettingsNewAliasesKey]; } - else if (updatedRoomTag && [updatedRoomTag isEqualToString:kMXRoomTagFavourite]) + } + else + { + NSMutableArray *removedAlias = [updatedItemsDict objectForKey:kRoomSettingsRemovedAliasesKey]; + if (!removedAlias) { - // Cancel the updated tag, but take into account the cancellation of the another tag (low priority) when favourite was selected - if (mxRoom.accountData.tags[kMXRoomTagLowPriority]) - { - [updatedItemsDict setObject:@"" forKey:kRoomSettingsTagKey]; - } - else - { - [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; - } + removedAlias = [NSMutableArray array]; + [updatedItemsDict setObject:removedAlias forKey:kRoomSettingsRemovedAliasesKey]; } + + [removedAlias addObject:roomAlias]; } + + NSMutableIndexSet *mutableIndexSet = [NSMutableIndexSet indexSet]; + + if (roomAddresses.count <= 1) + { + // The user remove here all the room addresses, reload the room access section to display potential warning message + [mutableIndexSet addIndex:ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX]; + } + + [mutableIndexSet addIndex:ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX]; + [self.tableView reloadSections:mutableIndexSet withRowAnimation:UITableViewRowAnimationAutomatic]; + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); } - else if (theSwitch == lowPriorityTagSwitch) +} + +- (BOOL)addRoomAlias:(NSString*)roomAlias +{ + // Check whether the provided alias is valid + if ([MXTools isMatrixRoomAlias:roomAlias]) { - if (lowPriorityTagSwitch.on) + // Check whether this alias has just been deleted + NSMutableArray *removedAlias = [updatedItemsDict objectForKey:kRoomSettingsRemovedAliasesKey]; + if (removedAlias && [removedAlias indexOfObject:roomAlias] != NSNotFound) { - // Check the actual tag on mxRoom - if (mxRoom.accountData.tags[kMXRoomTagLowPriority]) + [removedAlias removeObject:roomAlias]; + + if (!removedAlias.count) { - [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; + [updatedItemsDict removeObjectForKey:kRoomSettingsRemovedAliasesKey]; + } + } + // Check whether this alias is not already defined for this room + else if ([roomAddresses indexOfObject:roomAlias] == NSNotFound) + { + NSMutableArray *addedAlias = [updatedItemsDict objectForKey:kRoomSettingsNewAliasesKey]; + if (!addedAlias) + { + addedAlias = [NSMutableArray array]; + [updatedItemsDict setObject:addedAlias forKey:kRoomSettingsNewAliasesKey]; + } + + [addedAlias addObject:roomAlias]; + } + + NSMutableIndexSet *mutableIndexSet = [NSMutableIndexSet indexSet]; + + if (!roomAddresses.count) + { + // The first added alias is defined as the main address by default. + // Update the current canonical address. + NSString *currentCanonicalAlias = mxRoomState.canonicalAlias; + if (currentCanonicalAlias && [roomAlias isEqualToString:currentCanonicalAlias]) + { + // The right canonical alias is already defined + [updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey]; } else { - [updatedItemsDict setObject:kMXRoomTagLowPriority forKey:kRoomSettingsTagKey]; + [updatedItemsDict setObject:roomAlias forKey:kRoomSettingsCanonicalAliasKey]; } - // Force off the favourite toggle - favouriteTagSwitch.on = NO; + if (missingAddressWarningIndex != -1) + { + // Reload room access section to remove warning message + [mutableIndexSet addIndex:ROOM_SETTINGS_ROOM_ACCESS_SECTION_INDEX]; + } } - else + + [mutableIndexSet addIndex:ROOM_SETTINGS_ROOM_ADDRESSES_SECTION_INDEX]; + [self.tableView reloadSections:mutableIndexSet withRowAnimation:UITableViewRowAnimationAutomatic]; + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); + + return YES; + } + + // Prompt here user for invalid alias + __weak typeof(self) weakSelf = self; + + [currentAlert dismiss:NO]; + + NSString *alertMsg = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_details_addresses_invalid_address_prompt_msg", @"Vector", nil), roomAlias]; + + currentAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"room_details_addresses_invalid_address_prompt_title", @"Vector", nil) + message:alertMsg + style:MXKAlertStyleAlert]; + + currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] + style:MXKAlertActionStyleDefault + handler:^(MXKAlert *alert) { + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->currentAlert = nil; + } + }]; + + [currentAlert showInViewController:self]; + + return NO; +} + +#pragma mark - TableViewCellWithCheckBoxesDelegate + +- (void)tableViewCellWithCheckBoxes:(TableViewCellWithCheckBoxes *)tableViewCellWithCheckBoxes didTapOnCheckBoxAtIndex:(NSUInteger)index +{ + if (tableViewCellWithCheckBoxes == roomTagCell) + { + NSString *tappedRoomTag = (index == 0) ? kMXRoomTagFavourite : kMXRoomTagLowPriority; + BOOL isCurrentlySelected = [roomTagCell checkBoxValueAtIndex:index]; + + if (isCurrentlySelected) { + // The user wants to unselect this tag // Retrieve the current change on room tag (if any) NSString *updatedRoomTag = [updatedItemsDict objectForKey:kRoomSettingsTagKey]; // Check the actual tag on mxRoom - if (mxRoom.accountData.tags[kMXRoomTagLowPriority]) + if (mxRoom.accountData.tags[tappedRoomTag]) { // The actual tag must be updated, check whether another tag is already set if (!updatedRoomTag) @@ -1745,10 +2801,10 @@ - (void)onSwitchUpdate:(UISwitch*)theSwitch [updatedItemsDict setObject:@"" forKey:kRoomSettingsTagKey]; } } - else if (updatedRoomTag && [updatedRoomTag isEqualToString:kMXRoomTagLowPriority]) + else if (updatedRoomTag && [updatedRoomTag isEqualToString:tappedRoomTag]) { - // Cancel the updated tag, but take into account the cancellation of the another tag (favourite) when low priority was selected - if (mxRoom.accountData.tags[kMXRoomTagFavourite]) + // Cancel the updated tag, but take into account the cancellation of another tag when 'tappedRoomTag' was selected. + if (mxRoom.accountData.tags.count) { [updatedItemsDict setObject:@"" forKey:kRoomSettingsTagKey]; } @@ -1757,43 +2813,29 @@ - (void)onSwitchUpdate:(UISwitch*)theSwitch [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; } } - } - } - else if (theSwitch == roomNotifSwitch) - { - if (roomNotifSwitch.on == mxRoom.isMute) - { - [updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; + + // Unselect the tag + [roomTagCell setCheckBoxValue:NO atIndex:index]; } else { - [updatedItemsDict setObject:[NSNumber numberWithBool:roomNotifSwitch.on] forKey:kRoomSettingsMuteNotifKey]; - } - } - else if (theSwitch == directoryVisibilitySwitch) - { - MXRoomDirectoryVisibility visibility = directoryVisibilitySwitch.on ? kMXRoomDirectoryVisibilityPublic : kMXRoomDirectoryVisibilityPrivate; - - // Check whether the actual settings has been retrieved - if (actualDirectoryVisibility) - { - if ([visibility isEqualToString:actualDirectoryVisibility]) + // The user wants to select this room tag + // Check the actual tag on mxRoom + if (mxRoom.accountData.tags[tappedRoomTag]) { - [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey]; + [updatedItemsDict removeObjectForKey:kRoomSettingsTagKey]; } else { - [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; + [updatedItemsDict setObject:tappedRoomTag forKey:kRoomSettingsTagKey]; } + + // Select the tapped tag + [roomTagCell setCheckBoxValue:YES atIndex:index]; } - else - { - [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; - } + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); } - - - [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); } @end diff --git a/Vector/ViewController/RoomViewController.m b/Vector/ViewController/RoomViewController.m index 85e4e40628..6079225883 100644 --- a/Vector/ViewController/RoomViewController.m +++ b/Vector/ViewController/RoomViewController.m @@ -1982,8 +1982,9 @@ - (void)roomTitleView:(RoomTitleView*)titleView recognizeTapGesture:(UITapGestur selectedRoomDetailsIndex = 0; [self performSegueWithIdentifier:@"showRoomDetails" sender:self]; } - else if (view == previewHeader.leftButton) + else if (view == previewHeader.rightButton) { + // 'Join' button has been pressed if (roomPreviewData) { // Attempt to join the room (keep reference on the potential eventId, the preview data will be removed automatically in case of success). @@ -2045,8 +2046,9 @@ - (void)roomTitleView:(RoomTitleView*)titleView recognizeTapGesture:(UITapGestur }]; } } - else if (view == previewHeader.rightButton) + else if (view == previewHeader.leftButton) { + // 'Decline' button has been pressed if (roomPreviewData) { // Decline this invitation = leave this page diff --git a/Vector/ViewController/SettingsViewController.m b/Vector/ViewController/SettingsViewController.m index 62d8a8e6c5..edc2c8ba52 100644 --- a/Vector/ViewController/SettingsViewController.m +++ b/Vector/ViewController/SettingsViewController.m @@ -105,9 +105,10 @@ @interface SettingsViewController () // Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar. id kAppDelegateDidTapStatusBarNotificationObserver; - // Postpone destroy operation when saving or pwd reset is in progress + // Postpone destroy operation when saving, pwd reset or email binding is in progress BOOL isSavingInProgress; BOOL isResetPwdInProgress; + BOOL isEmailBindingInProgress; blockSettingsViewController_onReadyToDestroy onReadyToDestroyHandler; // @@ -135,6 +136,10 @@ - (void)viewDidLoad self.tableView.backgroundColor = kVectorColorLightGrey; + [self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndTextField defaultReuseIdentifier]]; + [self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]]; + [self.tableView registerClass:MXKTableViewCellWithLabelAndMXKImageView.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]]; + // Add observer to handle removed accounts removedAccountObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidRemoveAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { @@ -181,7 +186,7 @@ - (void)didReceiveMemoryWarning - (void)destroy { - if (isSavingInProgress || isResetPwdInProgress) + if (isSavingInProgress || isResetPwdInProgress || isEmailBindingInProgress) { __weak typeof(self) weakSelf = self; onReadyToDestroyHandler = ^() { @@ -384,54 +389,96 @@ - (void)showValidationEmailDialogWithMessage:(NSString*)message for3PID:(MXK3PID currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"abort"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert){ - __strong __typeof(weakSelf)strongSelf = weakSelf; - strongSelf->currentAlert = nil; - - [strongSelf stopActivityIndicator]; - - // Reset new email adding - strongSelf.newEmailEditingEnabled = NO; - }]; - - __strong __typeof(threePID)strongThreePID = threePID; - - [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"continue"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { - - // We always bind emails when registering, so let's do the same here - [threePID add3PIDToUser:YES success:^{ - + if (weakSelf) + { __strong __typeof(weakSelf)strongSelf = weakSelf; strongSelf->currentAlert = nil; - + [strongSelf stopActivityIndicator]; - + // Reset new email adding strongSelf.newEmailEditingEnabled = NO; + } + + }]; - // Update linked emails - [strongSelf loadLinkedEmails]; + __strong __typeof(threePID)strongThreePID = threePID; - } failure:^(NSError *error) { + [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"continue"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + if (weakSelf) + { __strong __typeof(weakSelf)strongSelf = weakSelf; - strongSelf->currentAlert = nil; - - NSLog(@"[SettingsViewController] Failed to bind email: %@", error); - - // Display the same popup again if the error is M_THREEPID_AUTH_FAILED - MXError *mxError = [[MXError alloc] initWithNSError:error]; - if (mxError && [mxError.errcode isEqualToString:kMXErrCodeStringThreePIDAuthFailed]) - { - [strongSelf showValidationEmailDialogWithMessage:[NSBundle mxk_localizedStringForKey:@"account_email_validation_error"] for3PID:strongThreePID]; - } - else - { - [strongSelf stopActivityIndicator]; - - // Notify MatrixKit user - [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error]; - } - }]; + strongSelf->isEmailBindingInProgress = YES; + + // We always bind emails when registering, so let's do the same here + [threePID add3PIDToUser:YES success:^{ + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->isEmailBindingInProgress = NO; + + // Check whether destroy has been called during email binding + if (strongSelf->onReadyToDestroyHandler) + { + // Ready to destroy + strongSelf->onReadyToDestroyHandler(); + strongSelf->onReadyToDestroyHandler = nil; + } + else + { + strongSelf->currentAlert = nil; + + [strongSelf stopActivityIndicator]; + + // Reset new email adding + strongSelf.newEmailEditingEnabled = NO; + + // Update linked emails + [strongSelf loadLinkedEmails]; + } + } + + } failure:^(NSError *error) { + + NSLog(@"[SettingsViewController] Failed to bind email: %@", error); + + if (weakSelf) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->isEmailBindingInProgress = NO; + + // Check whether destroy has been called during email binding + if (strongSelf->onReadyToDestroyHandler) + { + // Ready to destroy + strongSelf->onReadyToDestroyHandler(); + strongSelf->onReadyToDestroyHandler = nil; + } + else + { + strongSelf->currentAlert = nil; + + // Display the same popup again if the error is M_THREEPID_AUTH_FAILED + MXError *mxError = [[MXError alloc] initWithNSError:error]; + if (mxError && [mxError.errcode isEqualToString:kMXErrCodeStringThreePIDAuthFailed]) + { + [strongSelf showValidationEmailDialogWithMessage:[NSBundle mxk_localizedStringForKey:@"account_email_validation_error"] for3PID:strongThreePID]; + } + else + { + [strongSelf stopActivityIndicator]; + + // Notify MatrixKit user + [[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error]; + } + } + } + + }]; + } + }]; [currentAlert showInViewController:self]; @@ -516,19 +563,14 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger return count; } -- (MXKTableViewCellWithLabelAndTextField*)getLabelAndTextFieldCell:(UITableView*)tableview +- (MXKTableViewCellWithLabelAndTextField*)getLabelAndTextFieldCell:(UITableView*)tableview forIndexPath:(NSIndexPath *)indexPath { - MXKTableViewCellWithLabelAndTextField *cell = [tableview dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndTextField defaultReuseIdentifier]]; + MXKTableViewCellWithLabelAndTextField *cell = [tableview dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndTextField defaultReuseIdentifier] forIndexPath:indexPath]; - if (!cell) - { - cell = [[MXKTableViewCellWithLabelAndTextField alloc] init]; - - UIEdgeInsets separatorInset = cell.separatorInset; - - cell.mxkLabelLeadingConstraint.constant = separatorInset.left; - cell.mxkTextFieldTrailingConstraint.constant = 15; - } + cell.mxkLabelLeadingConstraint.constant = cell.separatorInset.left; + cell.mxkTextFieldTrailingConstraint.constant = 15; + + cell.mxkLabel.textColor = kVectorTextColorBlack; cell.mxkTextField.userInteractionEnabled = YES; cell.mxkTextField.borderStyle = UITextBorderStyleNone; @@ -544,19 +586,14 @@ - (MXKTableViewCellWithLabelAndTextField*)getLabelAndTextFieldCell:(UITableView* return cell; } -- (MXKTableViewCellWithLabelAndSwitch*)getLabelAndSwitchCell:(UITableView*)tableview +- (MXKTableViewCellWithLabelAndSwitch*)getLabelAndSwitchCell:(UITableView*)tableview forIndexPath:(NSIndexPath *)indexPath { - MXKTableViewCellWithLabelAndSwitch *cell = [tableview dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]]; + MXKTableViewCellWithLabelAndSwitch *cell = [tableview dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; - if (!cell) - { - cell = [[MXKTableViewCellWithLabelAndSwitch alloc] init]; - - UIEdgeInsets separatorInset = cell.separatorInset; - - cell.mxkLabelLeadingConstraint.constant = separatorInset.left; - cell.mxkSwitchTrailingConstraint.constant = 15; - } + cell.mxkLabelLeadingConstraint.constant = cell.separatorInset.left; + cell.mxkSwitchTrailingConstraint.constant = 15; + + cell.mxkLabel.textColor = kVectorTextColorBlack; return cell; } @@ -606,25 +643,23 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (row == userSettingsProfilePictureIndex) { - MXKTableViewCellWithLabelAndMXKImageView *profileCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]]; + MXKTableViewCellWithLabelAndMXKImageView *profileCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier] forIndexPath:indexPath]; + + profileCell.mxkLabelLeadingConstraint.constant = profileCell.separatorInset.left; + profileCell.mxkImageViewTrailingConstraint.constant = 10; - if (!profileCell) + profileCell.mxkImageViewWidthConstraint.constant = profileCell.mxkImageViewHeightConstraint.constant = 30; + profileCell.mxkImageViewDisplayBoxType = MXKTableViewCellDisplayBoxTypeCircle; + + if (!profileCell.mxkImageView.gestureRecognizers.count) { - profileCell = [[MXKTableViewCellWithLabelAndMXKImageView alloc] init]; - - profileCell.mxkLabelLeadingConstraint.constant = 15; - profileCell.mxkImageViewTrailingConstraint.constant = 10; - - profileCell.mxkImageViewWidthConstraint.constant = profileCell.mxkImageViewHeightConstraint.constant = 30; - - profileCell.mxkImageViewDisplayBoxType = MXKTableViewCellDisplayBoxTypeCircle; - // tap on avatar to update it UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onProfileAvatarTap:)]; [profileCell.mxkImageView addGestureRecognizer:tap]; } profileCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_profile_picture", @"Vector", nil); + profileCell.mxkLabel.textColor = kVectorTextColorBlack; // if the user defines a new avatar if (newAvatarImage) @@ -651,7 +686,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsDisplayNameIndex) { - MXKTableViewCellWithLabelAndTextField *displaynameCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *displaynameCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; displaynameCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_display_name", @"Vector", nil); displaynameCell.mxkTextField.text = myUser.displayname; @@ -664,7 +699,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsFirstNameIndex) { - MXKTableViewCellWithLabelAndTextField *firstCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *firstCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; firstCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_first_name", @"Vector", nil); firstCell.mxkTextField.userInteractionEnabled = NO; @@ -673,7 +708,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsSurnameIndex) { - MXKTableViewCellWithLabelAndTextField *surnameCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *surnameCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; surnameCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_surname", @"Vector", nil); surnameCell.mxkTextField.userInteractionEnabled = NO; @@ -682,7 +717,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (userSettingsEmailStartIndex <= row && row < userSettingsNewEmailIndex) { - MXKTableViewCellWithLabelAndTextField *emailCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *emailCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; emailCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_email_address", @"Vector", nil); emailCell.mxkTextField.text = account.linkedEmails[row - userSettingsEmailStartIndex]; @@ -692,7 +727,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsNewEmailIndex) { - MXKTableViewCellWithLabelAndTextField *newEmailCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *newEmailCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; // Render the cell according to the `newEmailEditingEnabled` property if (!_newEmailEditingEnabled) @@ -734,7 +769,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsChangePasswordIndex) { - MXKTableViewCellWithLabelAndTextField *passwordCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *passwordCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; passwordCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_change_password", @"Vector", nil); passwordCell.mxkTextField.text = @"*********"; @@ -744,7 +779,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsPhoneNumberIndex) { - MXKTableViewCellWithLabelAndTextField *phonenumberCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *phonenumberCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; phonenumberCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_phone_number", @"Vector", nil); phonenumberCell.mxkTextField.userInteractionEnabled = NO; @@ -760,7 +795,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (row == userSettingsNightModeIndex) { - MXKTableViewCellWithLabelAndTextField *nightModeCell = [self getLabelAndTextFieldCell:tableView]; + MXKTableViewCellWithLabelAndTextField *nightModeCell = [self getLabelAndTextFieldCell:tableView forIndexPath:indexPath]; nightModeCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_night_mode", @"Vector", nil); nightModeCell.mxkTextField.userInteractionEnabled = NO; @@ -776,7 +811,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (row == NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX) { - MXKTableViewCellWithLabelAndSwitch* enableAllCell = [self getLabelAndSwitchCell:tableView]; + MXKTableViewCellWithLabelAndSwitch* enableAllCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; enableAllCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_push_notif", @"Vector", nil); enableAllCell.mxkSwitch.on = account.pushNotificationServiceIsActive; @@ -797,63 +832,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N globalInfoCell.textLabel.numberOfLines = 0; cell = globalInfoCell; } -// else if (row == NOTIFICATION_SETTINGS_CONTAINING_MY_USER_NAME_INDEX) -// { -// MXKTableViewCellWithLabelAndSwitch* myNameCell = [self getLabelAndSwitchCell:tableView]; -// -// myNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_messages_my_user_name", @"Vector", nil); -// rule = [session.notificationCenter ruleById:kMXNotificationCenterContainUserNameRuleID]; -// cell = myNameCell; -// } -// else if (row == NOTIFICATION_SETTINGS_CONTAINING_MY_DISPLAY_NAME_INDEX) -// { -// MXKTableViewCellWithLabelAndSwitch* myNameCell = [self getLabelAndSwitchCell:tableView]; -// -// myNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_messages_my_display_name", @"Vector", nil); -// rule = [session.notificationCenter ruleById:kMXNotificationCenterContainDisplayNameRuleID]; -// cell = myNameCell; -// } -// else if (row == NOTIFICATION_SETTINGS_SENT_TO_ME_INDEX) -// { -// MXKTableViewCellWithLabelAndSwitch* sentToMeCell = [self getLabelAndSwitchCell:tableView]; -// sentToMeCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_messages_sent_to_me", @"Vector", nil); -// rule = [session.notificationCenter ruleById:kMXNotificationCenterOneToOneRoomRuleID]; -// cell = sentToMeCell; -// } -// else if (row == NOTIFICATION_SETTINGS_INVITED_TO_ROOM_INDEX) -// { -// MXKTableViewCellWithLabelAndSwitch* invitedToARoom = [self getLabelAndSwitchCell:tableView]; -// invitedToARoom.mxkLabel.text = NSLocalizedStringFromTable(@"settings_invited_to_room", @"Vector", nil); -// rule = [session.notificationCenter ruleById:kMXNotificationCenterInviteMeRuleID]; -// cell = invitedToARoom; -// } -// else if (row == NOTIFICATION_SETTINGS_PEOPLE_LEAVE_JOIN_INDEX) -// { -// MXKTableViewCellWithLabelAndSwitch* peopleJoinLeaveCell = [self getLabelAndSwitchCell:tableView]; -// peopleJoinLeaveCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_join_leave_rooms", @"Vector", nil); -// rule = [session.notificationCenter ruleById:kMXNotificationCenterMemberEventRuleID]; -// cell = peopleJoinLeaveCell; -// } -// else if (row == NOTIFICATION_SETTINGS_CALL_INVITATION_INDEX) -// { -// MXKTableViewCellWithLabelAndSwitch* callInvitationCell = [self getLabelAndSwitchCell:tableView]; -// callInvitationCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_call_invitations", @"Vector", nil); -// rule = [session.notificationCenter ruleById:kMXNotificationCenterCallRuleID]; -// cell = callInvitationCell; -// } - -// // common management -// MXKTableViewCellWithLabelAndSwitch* switchCell = (MXKTableViewCellWithLabelAndSwitch*)cell; -// switchCell.mxkSwitch.tag = row; -// -// if (rule) -// { -// switchCell.mxkSwitch.on = rule.enabled; -// } -// -// [switchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; -// [switchCell.mxkSwitch addTarget:self action:@selector(onRuleUpdate:) forControlEvents:UIControlEventTouchUpInside]; - } else if (section == SETTINGS_SECTION_ADVANCED_INDEX) { @@ -868,6 +846,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N configCell.textLabel.text =[NSString stringWithFormat:configFormat, account.mxCredentials.userId, account.mxCredentials.homeServer, account.identityServerURL]; configCell.textLabel.numberOfLines = 0; + configCell.textLabel.textColor = kVectorTextColorBlack; + cell = configCell; } else if (section == SETTINGS_SECTION_OTHER_INDEX) @@ -885,6 +865,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N NSString* build = [AppDelegate theDelegate].build; versionCell.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"settings_version", @"Vector", nil), [NSString stringWithFormat:@"%@ %@", appVersion, build]]; + versionCell.textLabel.textColor = kVectorTextColorBlack; cell = versionCell; } @@ -898,6 +879,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } termAndConditionCell.textLabel.text = NSLocalizedStringFromTable(@"settings_term_conditions", @"Vector", nil); + termAndConditionCell.textLabel.textColor = kVectorTextColorBlack; cell = termAndConditionCell; } @@ -911,6 +893,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } privacyPolicyCell.textLabel.text = NSLocalizedStringFromTable(@"settings_privacy_policy", @"Vector", nil); + privacyPolicyCell.textLabel.textColor = kVectorTextColorBlack; cell = privacyPolicyCell; } @@ -924,12 +907,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } thirdPartyCell.textLabel.text = NSLocalizedStringFromTable(@"settings_third_party_notices", @"Vector", nil); + thirdPartyCell.textLabel.textColor = kVectorTextColorBlack; cell = thirdPartyCell; } else if (row == OTHER_CRASH_REPORT_INDEX) { - MXKTableViewCellWithLabelAndSwitch* sendCrashReportCell = [self getLabelAndSwitchCell:tableView]; + MXKTableViewCellWithLabelAndSwitch* sendCrashReportCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; sendCrashReportCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_send_crash_report", @"Vector", nil); sendCrashReportCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]; @@ -949,6 +933,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N NSString *btnTitle = [NSString stringWithFormat:@"%@", NSLocalizedStringFromTable(@"settings_clear_cache", @"Vector", nil)]; [clearCacheBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal]; [clearCacheBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateHighlighted]; + [clearCacheBtnCell.mxkButton setTintColor:kVectorColorGreen]; [clearCacheBtnCell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; [clearCacheBtnCell.mxkButton addTarget:self action:@selector(onClearCache:) forControlEvents:UIControlEventTouchUpInside]; diff --git a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m index a1f1da0b3d..2b45a22889 100644 --- a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m +++ b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m @@ -63,6 +63,9 @@ - (void)awakeFromNib self.rightInputToolbarButton.hidden = YES; + [self.rightInputToolbarButton setTitleColor:kVectorColorGreen forState:UIControlStateNormal]; + [self.rightInputToolbarButton setTitleColor:kVectorColorGreen forState:UIControlStateHighlighted]; + self.separatorView.backgroundColor = kVectorColorSilver; // Custom the growingTextView display @@ -72,6 +75,7 @@ - (void)awakeFromNib growingTextView.font = [UIFont systemFontOfSize:15]; growingTextView.textColor = kVectorTextColorBlack; + growingTextView.tintColor = kVectorColorGreen; self.placeholder = NSLocalizedStringFromTable(@"room_message_placeholder", @"Vector", nil); } diff --git a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib index 4add0b805d..a2c1e9d028 100644 --- a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib +++ b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib @@ -1,8 +1,8 @@ - + - + @@ -52,6 +52,7 @@ + diff --git a/Vector/Views/RoomList/InviteRecentTableViewCell.h b/Vector/Views/RoomList/InviteRecentTableViewCell.h index 87977dae4a..1b4ca9d937 100644 --- a/Vector/Views/RoomList/InviteRecentTableViewCell.h +++ b/Vector/Views/RoomList/InviteRecentTableViewCell.h @@ -45,4 +45,7 @@ extern NSString *const kInviteRecentTableViewCellRoomKey; @property (weak, nonatomic) IBOutlet UIButton *leftButton; @property (weak, nonatomic) IBOutlet UIButton *rightButton; +@property (weak, nonatomic) IBOutlet UIView *noticeBadgeView; + + @end diff --git a/Vector/Views/RoomList/InviteRecentTableViewCell.m b/Vector/Views/RoomList/InviteRecentTableViewCell.m index 198d517566..5e7941b6dc 100644 --- a/Vector/Views/RoomList/InviteRecentTableViewCell.m +++ b/Vector/Views/RoomList/InviteRecentTableViewCell.m @@ -40,17 +40,20 @@ - (void)awakeFromNib [self.leftButton.layer setCornerRadius:5]; self.leftButton.clipsToBounds = YES; self.leftButton.backgroundColor = kVectorColorGreen; - [self.leftButton setTitle:NSLocalizedStringFromTable(@"preview", @"Vector", nil) forState:UIControlStateNormal]; - [self.leftButton setTitle:NSLocalizedStringFromTable(@"preview", @"Vector", nil) forState:UIControlStateHighlighted]; - [self.leftButton addTarget:self action:@selector(onPreviewPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.leftButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateNormal]; + [self.leftButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateHighlighted]; + [self.leftButton addTarget:self action:@selector(onDeclinePressed:) forControlEvents:UIControlEventTouchUpInside]; [self.rightButton.layer setCornerRadius:5]; self.rightButton.clipsToBounds = YES; self.rightButton.backgroundColor = kVectorColorGreen; - [self.rightButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateNormal]; - [self.rightButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateHighlighted]; - [self.rightButton addTarget:self action:@selector(onDeclinePressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.rightButton setTitle:NSLocalizedStringFromTable(@"preview", @"Vector", nil) forState:UIControlStateNormal]; + [self.rightButton setTitle:NSLocalizedStringFromTable(@"preview", @"Vector", nil) forState:UIControlStateHighlighted]; + [self.rightButton addTarget:self action:@selector(onPreviewPressed:) forControlEvents:UIControlEventTouchUpInside]; + + self.noticeBadgeView.backgroundColor = kVectorColorPinkRed; + [self.noticeBadgeView.layer setCornerRadius:10]; self.selectionStyle = UITableViewCellSelectionStyleNone; } diff --git a/Vector/Views/RoomList/InviteRecentTableViewCell.xib b/Vector/Views/RoomList/InviteRecentTableViewCell.xib index fbd8b60208..95ca5ab1a8 100644 --- a/Vector/Views/RoomList/InviteRecentTableViewCell.xib +++ b/Vector/Views/RoomList/InviteRecentTableViewCell.xib @@ -1,8 +1,8 @@ - + - + @@ -71,12 +71,33 @@ + + + + + + + + + + + + + + + + @@ -91,6 +112,7 @@ + diff --git a/Vector/Views/RoomTitle/PreviewRoomTitleView.m b/Vector/Views/RoomTitle/PreviewRoomTitleView.m index aeb34b0a3a..c3190c8b3f 100644 --- a/Vector/Views/RoomTitle/PreviewRoomTitleView.m +++ b/Vector/Views/RoomTitle/PreviewRoomTitleView.m @@ -54,8 +54,8 @@ - (void)awakeFromNib [self.leftButton.layer setCornerRadius:5]; self.leftButton.clipsToBounds = YES; self.leftButton.backgroundColor = kVectorColorGreen; - [self.leftButton setTitle:NSLocalizedStringFromTable(@"join", @"Vector", nil) forState:UIControlStateNormal]; - [self.leftButton setTitle:NSLocalizedStringFromTable(@"join", @"Vector", nil) forState:UIControlStateHighlighted]; + [self.leftButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateNormal]; + [self.leftButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateHighlighted]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; [tap setNumberOfTouchesRequired:1]; [tap setNumberOfTapsRequired:1]; @@ -66,8 +66,8 @@ - (void)awakeFromNib [self.rightButton.layer setCornerRadius:5]; self.rightButton.clipsToBounds = YES; self.rightButton.backgroundColor = kVectorColorGreen; - [self.rightButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateNormal]; - [self.rightButton setTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) forState:UIControlStateHighlighted]; + [self.rightButton setTitle:NSLocalizedStringFromTable(@"join", @"Vector", nil) forState:UIControlStateNormal]; + [self.rightButton setTitle:NSLocalizedStringFromTable(@"join", @"Vector", nil) forState:UIControlStateHighlighted]; tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; [tap setNumberOfTouchesRequired:1]; [tap setNumberOfTapsRequired:1]; diff --git a/Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.h b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.h similarity index 77% rename from Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.h rename to Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.h index 03e294c6b5..bf6a6f14b9 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.h +++ b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.h @@ -16,11 +16,13 @@ #import "MXKTableViewCell.h" -@interface TableViewCellWithTickAndLabel : MXKTableViewCell +@interface TableViewCellWithCheckBoxAndLabel : MXKTableViewCell -@property (strong, nonatomic) IBOutlet UIImageView *tick; +@property (strong, nonatomic) IBOutlet UIImageView *checkBox; @property (strong, nonatomic) IBOutlet UILabel *label; @property (nonatomic, getter=isEnabled) BOOL enabled; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *checkBoxLeadingConstraint; + @end diff --git a/Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.m b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.m similarity index 65% rename from Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.m rename to Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.m index 2386b4cbfb..25bb01eeda 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.m +++ b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.m @@ -14,19 +14,28 @@ limitations under the License. */ -#import "TableViewCellWithTickAndLabel.h" +#import "TableViewCellWithCheckBoxAndLabel.h" -@implementation TableViewCellWithTickAndLabel +#import "VectorDesignValues.h" + +@implementation TableViewCellWithCheckBoxAndLabel + +- (void)awakeFromNib +{ + [super awakeFromNib]; + + _label.textColor = kVectorTextColorBlack; +} - (void)setEnabled:(BOOL)enabled { if (enabled) { - _tick.image = [UIImage imageNamed:@"selection_tick"]; + _checkBox.image = [UIImage imageNamed:@"selection_tick"]; } else { - _tick.image = [UIImage imageNamed:@"selection_untick"]; + _checkBox.image = [UIImage imageNamed:@"selection_untick"]; } _enabled = enabled; diff --git a/Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.xib b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.xib similarity index 94% rename from Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.xib rename to Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.xib index 2bf709e1fc..e93af9266c 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithTickAndLabel.xib +++ b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxAndLabel.xib @@ -7,7 +7,7 @@ - + @@ -37,8 +37,9 @@ + + - diff --git a/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.h b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.h new file mode 100644 index 0000000000..598f622edb --- /dev/null +++ b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.h @@ -0,0 +1,91 @@ +/* + Copyright 2016 OpenMarket 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 "MXKTableViewCell.h" + +@class TableViewCellWithCheckBoxes; + +/** + `TableViewCellWithCheckBoxes` delegate. + */ +@protocol TableViewCellWithCheckBoxesDelegate + +/** + Tells the delegate that the user taps on a check box. + + @param tableViewCellWithCheckBoxes the `TableViewCellWithCheckBoxes` instance. + @param index the index of the concerned check box. + */ +- (void)tableViewCellWithCheckBoxes:(TableViewCellWithCheckBoxes *)tableViewCellWithCheckBoxes didTapOnCheckBoxAtIndex:(NSUInteger)index; + +@end + +/** + 'TableViewCellWithCheckBoxes' inherits 'MXKTableViewCell' class. + It displays several options in a UITableViewCell. Each option has its own check box and its label. + All option have the same width and they are horizontally aligned inside the main container. + They are vertically centered. + */ +@interface TableViewCellWithCheckBoxes : MXKTableViewCell + +@property (weak, nonatomic) IBOutlet UIView *mainContainer; + +/** + The number of boxes + */ +@property (nonatomic) NSUInteger checkBoxesNumber; + +/** + The current array of checkBoxes + */ +@property (nonatomic, readonly) NSArray *checkBoxes; + +/** + The current array of labels + */ +@property (nonatomic, readonly) NSArray *labels; + +/** + Leading/Trailing constraints define here spacing to nearest neighbor (no relative to margin) + */ +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainContainerLeadingConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainContainerTrailingConstraint; + +/** + The delegate for the cell. + */ +@property (nonatomic, weak) id delegate; + +/** + Default is NO. Controls whether multiple check boxes can be selected simultaneously + */ +@property (nonatomic) BOOL allowsMultipleSelection; + +/** + Select or unselect a check box. + If multiple selection is not allowed, this method unselect the current selected box in case of a new selection. + + @param isSelected the new value of the check box. + @param index the index of the check box. + */ +- (void)setCheckBoxValue:(BOOL)isSelected atIndex:(NSUInteger)index; + +/** + Get the current state of a check box + */ +- (BOOL)checkBoxValueAtIndex:(NSUInteger)index; + +@end \ No newline at end of file diff --git a/Vector/Views/TableViewCell/TableViewCellWithSwitches.m b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.m similarity index 53% rename from Vector/Views/TableViewCell/TableViewCellWithSwitches.m rename to Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.m index 63ad150dce..cf15248be6 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithSwitches.m +++ b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.m @@ -14,23 +14,25 @@ limitations under the License. */ -#import "TableViewCellWithSwitches.h" +#import "TableViewCellWithCheckBoxes.h" -// The space between 2 switches -#define TABLEVIEWCELLWITHSWITCHES_MARGIN 8 +#import "VectorDesignValues.h" -@interface TableViewCellWithSwitches () +// The space between 2 check boxes +#define TABLEVIEWCELLWITHCHECKBOXES_MARGIN 8 + +@interface TableViewCellWithCheckBoxes () { - NSMutableArray *switchArray; + NSMutableArray *checkBoxesArray; NSMutableArray *labelArray; } @end -@implementation TableViewCellWithSwitches +@implementation TableViewCellWithCheckBoxes -- (void)setSwitchesNumber:(NSUInteger)switchesNumber +- (void)setCheckBoxesNumber:(NSUInteger)checkBoxesNumber { - if (_switchesNumber == switchesNumber) + if (_checkBoxesNumber == checkBoxesNumber) { return; } @@ -42,58 +44,58 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber [view removeFromSuperview]; } - _switchesNumber = switchesNumber; + _checkBoxesNumber = checkBoxesNumber; - if (!switchesNumber) + if (!_checkBoxesNumber) { // Nothing to do return; } - switchArray = [NSMutableArray arrayWithCapacity:switchesNumber]; - labelArray = [NSMutableArray arrayWithCapacity:switchesNumber]; + checkBoxesArray = [NSMutableArray arrayWithCapacity:checkBoxesNumber]; + labelArray = [NSMutableArray arrayWithCapacity:checkBoxesNumber]; - CGFloat containerWidth = (self.mainContainer.frame.size.width - ((switchesNumber - 1.0) * TABLEVIEWCELLWITHSWITCHES_MARGIN)) / switchesNumber; + CGFloat containerWidth = (self.mainContainer.frame.size.width - ((checkBoxesNumber - 1.0) * TABLEVIEWCELLWITHCHECKBOXES_MARGIN)) / checkBoxesNumber; UIView *previousContainer = nil; NSLayoutConstraint *topConstraint, *leftConstraint, *bottomConstraint; - NSLayoutConstraint *widthConstraint, *centerYConstraint; + NSLayoutConstraint *widthConstraint, *heightConstraint, *centerYConstraint, *centerXConstraint; - for (NSInteger index = 0; index < switchesNumber; index++) + for (NSInteger index = 0; index < checkBoxesNumber; index++) { - UIView *switchContainer = [[UIView alloc] initWithFrame:CGRectMake(index * (containerWidth + TABLEVIEWCELLWITHSWITCHES_MARGIN), 0, containerWidth, self.mainContainer.frame.size.height)]; - switchContainer.backgroundColor = [UIColor clearColor]; - [self.mainContainer addSubview:switchContainer]; + UIView *checkboxContainer = [[UIView alloc] initWithFrame:CGRectMake(index * (containerWidth + TABLEVIEWCELLWITHCHECKBOXES_MARGIN), 0, containerWidth, self.mainContainer.frame.size.height)]; + checkboxContainer.backgroundColor = [UIColor clearColor]; + [self.mainContainer addSubview:checkboxContainer]; // Add container constraints - switchContainer.translatesAutoresizingMaskIntoConstraints = NO; + checkboxContainer.translatesAutoresizingMaskIntoConstraints = NO; if (!previousContainer) { - leftConstraint = [NSLayoutConstraint constraintWithItem:switchContainer + leftConstraint = [NSLayoutConstraint constraintWithItem:checkboxContainer attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.mainContainer attribute:NSLayoutAttributeLeading multiplier:1 constant:0]; - widthConstraint = [NSLayoutConstraint constraintWithItem:switchContainer + widthConstraint = [NSLayoutConstraint constraintWithItem:checkboxContainer attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.mainContainer attribute:NSLayoutAttributeWidth - multiplier:(1.0 / switchesNumber) - constant:(- ((switchesNumber - 1.0) * TABLEVIEWCELLWITHSWITCHES_MARGIN) / switchesNumber)]; + multiplier:(1.0 / checkBoxesNumber) + constant:(- ((checkBoxesNumber - 1.0) * TABLEVIEWCELLWITHCHECKBOXES_MARGIN) / checkBoxesNumber)]; } else { - leftConstraint = [NSLayoutConstraint constraintWithItem:switchContainer + leftConstraint = [NSLayoutConstraint constraintWithItem:checkboxContainer attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:previousContainer attribute:NSLayoutAttributeTrailing multiplier:1 - constant:TABLEVIEWCELLWITHSWITCHES_MARGIN]; - widthConstraint = [NSLayoutConstraint constraintWithItem:switchContainer + constant:TABLEVIEWCELLWITHCHECKBOXES_MARGIN]; + widthConstraint = [NSLayoutConstraint constraintWithItem:checkboxContainer attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:previousContainer @@ -102,7 +104,7 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber constant:0]; } - topConstraint = [NSLayoutConstraint constraintWithItem:switchContainer + topConstraint = [NSLayoutConstraint constraintWithItem:checkboxContainer attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.mainContainer @@ -110,7 +112,7 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber multiplier:1 constant:0]; - bottomConstraint = [NSLayoutConstraint constraintWithItem:switchContainer + bottomConstraint = [NSLayoutConstraint constraintWithItem:checkboxContainer attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.mainContainer @@ -120,40 +122,57 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber [NSLayoutConstraint activateConstraints:@[leftConstraint, widthConstraint, topConstraint, bottomConstraint]]; - previousContainer = switchContainer; + previousContainer = checkboxContainer; + + // Add Checkbox and Label + UIImageView *checkbox = [[UIImageView alloc] initWithFrame:CGRectMake(14, 11, 22, 22)]; + checkbox.translatesAutoresizingMaskIntoConstraints = NO; + [checkboxContainer addSubview:checkbox]; - // Add Switch and Label - UISwitch *theSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 51, 31)]; - theSwitch.translatesAutoresizingMaskIntoConstraints = NO; - [switchContainer addSubview:theSwitch]; - [switchArray addObject:theSwitch]; + // Store the new check box unselected by default + checkbox.image = [UIImage imageNamed:@"selection_untick"]; + checkbox.tag = 0; + [checkBoxesArray addObject:checkbox]; UILabel *theLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, containerWidth - 60, 31)]; theLabel.translatesAutoresizingMaskIntoConstraints = NO; - [switchContainer addSubview:theLabel]; + theLabel.textColor = kVectorTextColorBlack; + [checkboxContainer addSubview:theLabel]; [labelArray addObject:theLabel]; + UIView *checkboxMask = [[UIView alloc] initWithFrame:CGRectMake(7, 4, 36, 36)]; + checkboxMask.translatesAutoresizingMaskIntoConstraints = NO; + [checkboxContainer addSubview:checkboxMask]; + // Listen to check box tap + checkboxMask.tag = index; + checkboxMask.userInteractionEnabled = YES; + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onCheckBoxTap:)]; + [tapGesture setNumberOfTouchesRequired:1]; + [tapGesture setNumberOfTapsRequired:1]; + [tapGesture setDelegate:self]; + [checkboxMask addGestureRecognizer:tapGesture]; + // Add switch constraints - leftConstraint = [NSLayoutConstraint constraintWithItem:theSwitch + leftConstraint = [NSLayoutConstraint constraintWithItem:checkbox attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual - toItem:switchContainer + toItem:checkboxContainer attribute:NSLayoutAttributeLeading multiplier:1 - constant:0]; + constant:14]; - widthConstraint = [NSLayoutConstraint constraintWithItem:theSwitch + widthConstraint = [NSLayoutConstraint constraintWithItem:checkbox attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 - constant:51]; + constant:22]; - centerYConstraint = [NSLayoutConstraint constraintWithItem:theSwitch + centerYConstraint = [NSLayoutConstraint constraintWithItem:checkbox attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual - toItem:switchContainer + toItem:checkboxContainer attribute:NSLayoutAttributeCenterY multiplier:1 constant:0.0f]; @@ -165,7 +184,7 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber topConstraint = [NSLayoutConstraint constraintWithItem:theLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual - toItem:switchContainer + toItem:checkboxContainer attribute:NSLayoutAttributeTop multiplier:1 constant:0]; @@ -173,7 +192,7 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber leftConstraint = [NSLayoutConstraint constraintWithItem:theLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual - toItem:theSwitch + toItem:checkbox attribute:NSLayoutAttributeTrailing multiplier:1 constant:9]; @@ -181,18 +200,53 @@ - (void)setSwitchesNumber:(NSUInteger)switchesNumber centerYConstraint = [NSLayoutConstraint constraintWithItem:theLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual - toItem:switchContainer + toItem:checkboxContainer attribute:NSLayoutAttributeCenterY multiplier:1 constant:0.0f]; [NSLayoutConstraint activateConstraints:@[topConstraint, leftConstraint, centerYConstraint]]; + + // Add check box mask constraints + widthConstraint = [NSLayoutConstraint constraintWithItem:checkboxMask + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:36]; + + heightConstraint = [NSLayoutConstraint constraintWithItem:checkboxMask + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:36]; + + centerXConstraint = [NSLayoutConstraint constraintWithItem:checkboxMask + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:checkbox + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0.0f]; + + centerYConstraint = [NSLayoutConstraint constraintWithItem:checkboxMask + attribute:NSLayoutAttributeCenterY + relatedBy:NSLayoutRelationEqual + toItem:checkbox + attribute:NSLayoutAttributeCenterY + multiplier:1 + constant:0.0f]; + + [NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, centerXConstraint, centerYConstraint]]; } } -- (NSArray*)switches +- (NSArray*)checkBoxes { - return [NSArray arrayWithArray:switchArray]; + return [NSArray arrayWithArray:checkBoxesArray]; } - (NSArray*)labels @@ -200,5 +254,62 @@ - (NSArray*)labels return [NSArray arrayWithArray:labelArray]; } +- (void)setCheckBoxValue:(BOOL)isSelected atIndex:(NSUInteger)index +{ + if (index < checkBoxesArray.count) + { + UIImageView *checkBox = checkBoxesArray[index]; + + if (isSelected && !checkBox.tag) + { + checkBox.image = [UIImage imageNamed:@"selection_tick"]; + checkBox.tag = 1; + + if (!self.allowsMultipleSelection) + { + // Unselect others check boxes + for (NSUInteger k = 0; k < checkBoxesArray.count; k++) + { + if (k != index) + { + checkBox = checkBoxesArray[k]; + if (checkBox.tag) + { + checkBox.image = [UIImage imageNamed:@"selection_untick"]; + checkBox.tag = 0; + } + } + } + } + } + else if (checkBox.tag) + { + checkBox.image = [UIImage imageNamed:@"selection_untick"]; + checkBox.tag = 0; + } + } +} + +- (BOOL)checkBoxValueAtIndex:(NSUInteger)index +{ + if (index < checkBoxesArray.count) + { + UIImageView *checkBox = checkBoxesArray[index]; + + return ((BOOL)checkBox.tag); + } + + return NO; +} + +#pragma mark - Action + +- (IBAction)onCheckBoxTap:(UITapGestureRecognizer*)sender +{ + if (_delegate) + { + [_delegate tableViewCellWithCheckBoxes:self didTapOnCheckBoxAtIndex:sender.view.tag]; + } +} @end diff --git a/Vector/Views/TableViewCell/TableViewCellWithSwitches.xib b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.xib similarity index 99% rename from Vector/Views/TableViewCell/TableViewCellWithSwitches.xib rename to Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.xib index 29b6440762..c5bb3c9693 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithSwitches.xib +++ b/Vector/Views/TableViewCell/TableViewCellWithCheckBoxes.xib @@ -7,7 +7,7 @@ - + diff --git a/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.h b/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.h index bf879c2735..c810ffbb19 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.h +++ b/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.h @@ -22,6 +22,7 @@ @property (strong, nonatomic) IBOutlet UITextView *textView; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelTrailingMinConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelLeadingConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewWidthConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewTrailingConstraint; diff --git a/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.m b/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.m index 68fe4bb0a7..40183a14d2 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.m +++ b/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.m @@ -16,12 +16,16 @@ #import "TableViewCellWithLabelAndLargeTextView.h" +#import "VectorDesignValues.h" + @implementation TableViewCellWithLabelAndLargeTextView - (void)awakeFromNib { [super awakeFromNib]; + _label.textColor = kVectorTextColorBlack; + // Adjust text view // Remove the container inset: this operation impacts only the vertical margin. // Reset textContainer.lineFragmentPadding to remove horizontal margin. @@ -40,7 +44,7 @@ - (void)layoutSubviews CGFloat maxTextViewWidth = cellWidth - minTextViewPosX - _textViewTrailingConstraint.constant; - if (_textView.isFirstResponder) + if (_textView.isEditable && _textView.isFirstResponder) { // Use the full available width when the field is edited _textViewWidthConstraint.constant = maxTextViewWidth; diff --git a/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.xib b/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.xib index 8b4c4224a3..35cf1afa61 100644 --- a/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.xib +++ b/Vector/Views/TableViewCell/TableViewCellWithLabelAndLargeTextView.xib @@ -46,6 +46,7 @@ + diff --git a/Vector/Views/TableViewCell/TableViewCellWithSwitches.h b/Vector/Views/TableViewCell/TableViewCellWithSwitches.h deleted file mode 100644 index 672a5a41b2..0000000000 --- a/Vector/Views/TableViewCell/TableViewCellWithSwitches.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright 2016 OpenMarket 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 "MXKTableViewCell.h" - -/** - 'TableViewCellWithSwitches' inherits 'MXKTableViewCell' class. - It displays several switches in a UITableViewCell. Each switch has its own label. - All switches have the same width and they are horizontally aligned inside the main container. - They are vertically centered. - */ -@interface TableViewCellWithSwitches : MXKTableViewCell - -@property (weak, nonatomic) IBOutlet UIView *mainContainer; - -/** - The number of switches - */ -@property (nonatomic) NSUInteger switchesNumber; - -/** - The current array of switches - */ -@property (nonatomic, readonly) NSArray *switches; - -/** - The current array of labels - */ -@property (nonatomic, readonly) NSArray *labels; - -/** - Leading/Trailing constraints define here spacing to nearest neighbor (no relative to margin) - */ -@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainContainerLeadingConstraint; -@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainContainerTrailingConstraint; - -@end \ No newline at end of file