diff --git a/Vector.xcodeproj/project.pbxproj b/Vector.xcodeproj/project.pbxproj index 6307b4f4c..04077d2a4 100644 --- a/Vector.xcodeproj/project.pbxproj +++ b/Vector.xcodeproj/project.pbxproj @@ -32,9 +32,15 @@ 717928481C03852C00407D96 /* TableViewCellWithLabelAndLargeTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 717928411C03852C00407D96 /* TableViewCellWithLabelAndLargeTextView.xib */; }; 717928491C03852C00407D96 /* TableViewCellWithLabelAndTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 717928431C03852C00407D96 /* TableViewCellWithLabelAndTextField.m */; }; 7179284A1C03852C00407D96 /* TableViewCellWithLabelAndTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = 717928441C03852C00407D96 /* TableViewCellWithLabelAndTextField.xib */; }; + 71B2A3BB1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B2A3B91C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.m */; }; + 71B2A3BC1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 71B2A3BA1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.xib */; }; + 71B2A3C01C203C7100472061 /* TableViewCellWithLabelAndSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B2A3BE1C203C7100472061 /* TableViewCellWithLabelAndSwitch.m */; }; + 71B2A3C11C203C7100472061 /* TableViewCellWithLabelAndSwitch.xib in Resources */ = {isa = PBXBuildFile; fileRef = 71B2A3BF1C203C7100472061 /* TableViewCellWithLabelAndSwitch.xib */; }; 71C5F2951C074ACC004C094B /* RoomSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71C5F2941C074ACC004C094B /* RoomSettingsViewController.m */; }; 71EBE66D1C04C4D300E7D953 /* RoomActivitiesView.m in Sources */ = {isa = PBXBuildFile; fileRef = 71EBE66B1C04C4D300E7D953 /* RoomActivitiesView.m */; }; 71EBE66E1C04C4D300E7D953 /* RoomActivitiesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 71EBE66C1C04C4D300E7D953 /* RoomActivitiesView.xib */; }; + 71F7F5151C218D8900E7ED8F /* RecentCellData.m in Sources */ = {isa = PBXBuildFile; fileRef = 71F7F5141C218D8900E7ED8F /* RecentCellData.m */; }; + 71F7F5181C22CC7500E7ED8F /* MXRoom+Vector.m in Sources */ = {isa = PBXBuildFile; fileRef = 71F7F5171C22CC7500E7ED8F /* MXRoom+Vector.m */; }; F001D7621B8207C000A162C3 /* RoomInputToolbarView.m in Sources */ = {isa = PBXBuildFile; fileRef = F001D75C1B8207C000A162C3 /* RoomInputToolbarView.m */; }; F001D7631B8207C000A162C3 /* RoomInputToolbarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F001D75D1B8207C000A162C3 /* RoomInputToolbarView.xib */; }; F001D76C1B821E4F00A162C3 /* MediaPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F001D76B1B821E4F00A162C3 /* MediaPickerViewController.m */; }; @@ -205,12 +211,22 @@ 717928421C03852C00407D96 /* TableViewCellWithLabelAndTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithLabelAndTextField.h; path = TableViewCell/TableViewCellWithLabelAndTextField.h; sourceTree = ""; }; 717928431C03852C00407D96 /* TableViewCellWithLabelAndTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithLabelAndTextField.m; path = TableViewCell/TableViewCellWithLabelAndTextField.m; sourceTree = ""; }; 717928441C03852C00407D96 /* TableViewCellWithLabelAndTextField.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithLabelAndTextField.xib; path = TableViewCell/TableViewCellWithLabelAndTextField.xib; sourceTree = ""; }; + 71B2A3B81C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithLabelAndMXKImageView.h; path = TableViewCell/TableViewCellWithLabelAndMXKImageView.h; sourceTree = ""; }; + 71B2A3B91C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithLabelAndMXKImageView.m; path = TableViewCell/TableViewCellWithLabelAndMXKImageView.m; sourceTree = ""; }; + 71B2A3BA1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithLabelAndMXKImageView.xib; path = TableViewCell/TableViewCellWithLabelAndMXKImageView.xib; sourceTree = ""; }; + 71B2A3BD1C203C7100472061 /* TableViewCellWithLabelAndSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithLabelAndSwitch.h; path = TableViewCell/TableViewCellWithLabelAndSwitch.h; sourceTree = ""; }; + 71B2A3BE1C203C7100472061 /* TableViewCellWithLabelAndSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithLabelAndSwitch.m; path = TableViewCell/TableViewCellWithLabelAndSwitch.m; sourceTree = ""; }; + 71B2A3BF1C203C7100472061 /* TableViewCellWithLabelAndSwitch.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithLabelAndSwitch.xib; path = TableViewCell/TableViewCellWithLabelAndSwitch.xib; sourceTree = ""; }; 71C5F2931C074ACC004C094B /* RoomSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomSettingsViewController.h; sourceTree = ""; }; 71C5F2941C074ACC004C094B /* RoomSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomSettingsViewController.m; sourceTree = ""; }; 71C5F2991C077007004C094B /* VectorDesignValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VectorDesignValues.h; sourceTree = ""; }; 71EBE66A1C04C4D300E7D953 /* RoomActivitiesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RoomActivitiesView.h; path = RoomActivitiesView/RoomActivitiesView.h; sourceTree = ""; }; 71EBE66B1C04C4D300E7D953 /* RoomActivitiesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RoomActivitiesView.m; path = RoomActivitiesView/RoomActivitiesView.m; sourceTree = ""; }; 71EBE66C1C04C4D300E7D953 /* RoomActivitiesView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = RoomActivitiesView.xib; path = RoomActivitiesView/RoomActivitiesView.xib; sourceTree = ""; }; + 71F7F5131C218D8900E7ED8F /* RecentCellData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentCellData.h; sourceTree = ""; }; + 71F7F5141C218D8900E7ED8F /* RecentCellData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentCellData.m; sourceTree = ""; }; + 71F7F5161C22CC7500E7ED8F /* MXRoom+Vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MXRoom+Vector.h"; sourceTree = ""; }; + 71F7F5171C22CC7500E7ED8F /* MXRoom+Vector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MXRoom+Vector.m"; sourceTree = ""; }; 9B179239B79688A61A3F465F /* libPods-Vector.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Vector.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F001D75B1B8207C000A162C3 /* RoomInputToolbarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomInputToolbarView.h; sourceTree = ""; }; F001D75C1B8207C000A162C3 /* RoomInputToolbarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomInputToolbarView.m; sourceTree = ""; }; @@ -419,9 +435,15 @@ 7179283C1C03852C00407D96 /* TableViewCellSeparator.h */, 7179283D1C03852C00407D96 /* TableViewCellSeparator.m */, 7179283E1C03852C00407D96 /* TableViewCellSeparator.xib */, + 71B2A3BD1C203C7100472061 /* TableViewCellWithLabelAndSwitch.h */, + 71B2A3BE1C203C7100472061 /* TableViewCellWithLabelAndSwitch.m */, + 71B2A3BF1C203C7100472061 /* TableViewCellWithLabelAndSwitch.xib */, 7179283F1C03852C00407D96 /* TableViewCellWithLabelAndLargeTextView.h */, 717928401C03852C00407D96 /* TableViewCellWithLabelAndLargeTextView.m */, 717928411C03852C00407D96 /* TableViewCellWithLabelAndLargeTextView.xib */, + 71B2A3B81C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.h */, + 71B2A3B91C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.m */, + 71B2A3BA1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.xib */, 717928421C03852C00407D96 /* TableViewCellWithLabelAndTextField.h */, 717928431C03852C00407D96 /* TableViewCellWithLabelAndTextField.m */, 717928441C03852C00407D96 /* TableViewCellWithLabelAndTextField.xib */, @@ -534,6 +556,8 @@ F00C47881BFF854400DBABC9 /* RoomList */ = { isa = PBXGroup; children = ( + 71F7F5131C218D8900E7ED8F /* RecentCellData.h */, + 71F7F5141C218D8900E7ED8F /* RecentCellData.m */, F00C47891BFF854400DBABC9 /* RecentsDataSource.h */, F00C478A1BFF854400DBABC9 /* RecentsDataSource.m */, 32F2E6191C230D4D003BDEA5 /* PublicRoomsDirectoryDataSource.h */, @@ -721,6 +745,8 @@ F0C34CB51C17145F00C36F09 /* Categories */ = { isa = PBXGroup; children = ( + 71F7F5161C22CC7500E7ED8F /* MXRoom+Vector.h */, + 71F7F5171C22CC7500E7ED8F /* MXRoom+Vector.m */, F0C34CB61C17145F00C36F09 /* MXKRoomBubbleTableViewCell+Vector.h */, F0C34CB71C17145F00C36F09 /* MXKRoomBubbleTableViewCell+Vector.m */, ); @@ -885,6 +911,7 @@ F02528D91C11B6FC00E1FE1B /* camera_play.png in Resources */, F0D2D9881C197DCB007B8C96 /* RoomIncomingTextMsgBubbleCell.xib in Resources */, F02529001C11B6FC00E1FE1B /* settings_icon.png in Resources */, + 71B2A3BC1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.xib in Resources */, F02528D81C11B6FC00E1FE1B /* camera_picture.png in Resources */, F02528E01C11B6FC00E1FE1B /* create_room.png in Resources */, F02528DF1C11B6FC00E1FE1B /* camera_video.png in Resources */, @@ -917,6 +944,7 @@ F0C34B641C15C28300C36F09 /* RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib in Resources */, F02528D61C11B6FC00E1FE1B /* camera_capture@2x.png in Resources */, 71046D601C0C86C600DCA984 /* RoomTitleViewWithTopic.xib in Resources */, + 71B2A3C11C203C7100472061 /* TableViewCellWithLabelAndSwitch.xib in Resources */, F02528D51C11B6FC00E1FE1B /* camera_capture.png in Resources */, F02528EA1C11B6FC00E1FE1B /* low_priority_icon@2x.png in Resources */, F02528EE1C11B6FC00E1FE1B /* mute_icon@3x.png in Resources */, @@ -1053,6 +1081,7 @@ F094AA051B78E3D400B1FBBF /* empty.mm in Sources */, F0A1CD221B9F4BBA00F9C15C /* RoomParticipantsViewController.m in Sources */, F001D76C1B821E4F00A162C3 /* MediaPickerViewController.m in Sources */, + 71F7F5151C218D8900E7ED8F /* RecentCellData.m in Sources */, F084DAAE1BB57BD100B4C530 /* AuthInputsEmailIdentityBasedView.m in Sources */, 71352D591C10569F001D50B0 /* AvatarGenerator.m in Sources */, 717928471C03852C00407D96 /* TableViewCellWithLabelAndLargeTextView.m in Sources */, @@ -1062,6 +1091,7 @@ 325F6A391C21810E00C12F51 /* DirectoryViewController.m in Sources */, F094AA321B78E42600B1FBBF /* GlobalNotificationSettingsViewController.m in Sources */, F094A9A81B78D8F000B1FBBF /* main.m in Sources */, + 71B2A3C01C203C7100472061 /* TableViewCellWithLabelAndSwitch.m in Sources */, F00C47861BFF77C800DBABC9 /* RecentTableViewCell.m in Sources */, 32F2E61B1C230D4D003BDEA5 /* PublicRoomsDirectoryDataSource.m in Sources */, F0DD7D881B7B507100C4BE02 /* RoomCreationStep2ViewController.m in Sources */, @@ -1073,6 +1103,7 @@ F08BE09E1B87025B00C480FB /* EventFormatter.m in Sources */, 325F6A421C21D20F00C12F51 /* DirectoryRecentTableViewCell.m in Sources */, F05895001B8B7E6600B73E85 /* RoomBubbleCellData.m in Sources */, + 71F7F5181C22CC7500E7ED8F /* MXRoom+Vector.m in Sources */, F0D2D9831C197DCB007B8C96 /* RoomIncomingAttachmentBubbleCell.m in Sources */, F0C34B611C15C28300C36F09 /* RoomOutgoingAttachmentBubbleCell.m in Sources */, 71C5F2951C074ACC004C094B /* RoomSettingsViewController.m in Sources */, @@ -1082,6 +1113,7 @@ F08BE0A21B87064000C480FB /* RoomDataSource.m in Sources */, 716FDC8A1C186A3A001034CB /* InviteRecentTableViewCell.m in Sources */, F0C34CB31C16269D00C36F09 /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.m in Sources */, + 71B2A3BB1C2013DC00472061 /* TableViewCellWithLabelAndMXKImageView.m in Sources */, F0D2D9851C197DCB007B8C96 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, 71046D5E1C0C639300DCA984 /* RoomTitleViewWithTopic.m in Sources */, F0C34B631C15C28300C36F09 /* RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, @@ -1182,7 +1214,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1218,7 +1250,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1233,7 +1265,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ENABLE_BITCODE = NO; INFOPLIST_FILE = Vector/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1247,7 +1279,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ENABLE_BITCODE = NO; INFOPLIST_FILE = Vector/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Vector/AppDelegate.m b/Vector/AppDelegate.m index e6a4e31eb..9dc84e981 100644 --- a/Vector/AppDelegate.m +++ b/Vector/AppDelegate.m @@ -189,10 +189,14 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + // define the navigation bar text color [[UINavigationBar appearance] setTintColor:VECTOR_GREEN_COLOR]; - // Override point for customization after application launch. + // Customize the localized string table + [NSBundle mxk_customizeLocalizedStringTableName:@"Vector"]; + mxSessionArray = [NSMutableArray array]; // To simplify navigation into the app, we retrieve here the navigation controller and the view controller related @@ -417,7 +421,7 @@ - (void)popRoomViewControllerAnimated:(BOOL)animated { - // Force back to recents list if room details is displayed in Recents Tab + // Force back to the main screen if (homeViewController) { [_homeNavigationController popToViewController:homeViewController animated:animated]; @@ -475,16 +479,9 @@ { if (!isAPNSRegistered) { - if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) - { - // Registration on iOS 8 and later - UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound |UIUserNotificationTypeAlert) categories:nil]; - [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; - } - else - { - [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)]; - } + // Registration on iOS 8 and later + UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound |UIUserNotificationTypeAlert) categories:nil]; + [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; } } @@ -1243,14 +1240,24 @@ { // Do it asynchronously to avoid hasardous dispatch_async after calling restoreInitialDisplay [self.window.rootViewController dismissViewControllerAnimated:NO completion:^{ + [self popRoomViewControllerAnimated:NO]; - completion(); + + // Dispatch the completion in order to let navigation stack refresh itself. + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); + }]; } else { [self popRoomViewControllerAnimated:NO]; - completion(); + + // Dispatch the completion in order to let navigation stack refresh itself. + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); } } diff --git a/Vector/Assets/en.lproj/Vector.strings b/Vector/Assets/en.lproj/Vector.strings index 0964e785d..727eea9c8 100644 --- a/Vector/Assets/en.lproj/Vector.strings +++ b/Vector/Assets/en.lproj/Vector.strings @@ -89,6 +89,16 @@ "room_one_user_is_typing" = "%@ is typing..."; "room_two_users_are_typing" = "%@ & %@ are typing..."; "room_many_users_are_typing" = "%@, %@ & others are typing..."; +"room_message_placeholder" = "Type a message..."; +"room_event_action_edit" = "Edit"; +"room_event_action_copy" = "Copy"; +"room_event_action_share" = "Share"; +"room_event_action_redact" = "Redact"; +"room_event_action_save" = "Save"; +"room_event_action_resend" = "Resend"; +"room_event_action_delete" = "Delete"; +"room_event_action_cancel_upload" = "Cancel Upload"; +"room_event_action_cancel_download" = "Cancel Download"; // Settings "account_logout_all" = "Logout all accounts"; @@ -138,12 +148,17 @@ // Room Details "room_details_title" = "Room Details"; +"room_details_mute_notifs" = "Mute notifications"; +"room_details_photo" = "Room Photo"; "room_details_room_name" = "Room Name"; "room_details_topic" = "Topic"; "room_details_people" = "People"; "room_details_settings" = "Settings"; "room_details_fail_to_update_topic" = "Fail to update the topic"; "room_details_fail_to_update_room_name" = "Fail to update the room name"; +"room_details_with_updates" = "The updates will be lost : are you sure to leave ?"; +"room_details_room_is_public" = "This room is public"; +"room_details_room_is_private" = "This room is private"; "notification_settings_global_notification_settings" = "Global Notification Settings"; @@ -166,4 +181,11 @@ "public_room_section_title" = "Public Rooms (at %@):"; "bug_report_prompt" = "The application has crashed last time. Would you like to submit a crash report?"; "rage_shake_prompt" = "You seem to be shaking the phone in frustration. Would you like to submit a bug report?"; -"camera_access_not_granted" = "Vector doesn't have permission to use Camera, please change privacy settings"; \ No newline at end of file +"camera_access_not_granted" = "Vector doesn't have permission to use Camera, please change privacy settings"; + +// room display name +"room_displayname_invite_from" = "Invite from %@"; +"room_displayname_room_invite" = "Room Invite"; +"room_displayname_two_members" = "%@ and %@"; +"room_displayname_more_than_two_members" = "%@ and %u others"; + diff --git a/Vector/Base.lproj/Main.storyboard b/Vector/Base.lproj/Main.storyboard index 9c5e81c57..5fe68b5d2 100644 --- a/Vector/Base.lproj/Main.storyboard +++ b/Vector/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -31,7 +31,7 @@ - + diff --git a/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.h b/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.h index 1a388b25d..a624e3faa 100644 --- a/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.h +++ b/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.h @@ -14,7 +14,14 @@ limitations under the License. */ -#import +#import + +/** + Action identifier used when the user pressed edit button displayed in front of a selected event. + + The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the selected event. + */ +extern NSString *const kMXKRoomBubbleCellVectorEditButtonPressed; /** Define a `MXKRoomBubbleTableViewCell` category at Vector level to handle bubble customisation. @@ -52,4 +59,19 @@ */ @property(nonatomic) BOOL blurred; +/** + The 'edit' button displayed in front of the selected component (if any). Default is nil. + */ +@property(nonatomic) UIButton *editButton; + +/** + The read receipts container associated to the selected component (if any). Default is nil. + */ +@property(nonatomic) MXKReceiptSendersContainer* selectedReadReceiptsContainer; + +/** + The trailing constraint of the read receipts container associated to the selected component (if any). Default is nil. + */ +@property(nonatomic) NSLayoutConstraint* selectedReadReceiptsContainerTrailingConstraint; + @end diff --git a/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.m b/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.m index 389c44ae5..3d113cf18 100644 --- a/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.m +++ b/Vector/Categories/MXKRoomBubbleTableViewCell+Vector.m @@ -18,8 +18,12 @@ #import "RoomBubbleCellData.h" +#import "VectorDesignValues.h" + #import +NSString *const kMXKRoomBubbleCellVectorEditButtonPressed = @"kMXKRoomBubbleCellVectorEditButtonPressed"; + @implementation MXKRoomBubbleTableViewCell (Vector) - (void)addTimestampLabelForComponent:(NSUInteger)componentIndex @@ -34,13 +38,21 @@ if (component && component.date) { - UILabel *dateTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, component.position.y, self.bubbleInfoContainer.frame.size.width , 15)]; + UILabel *dateTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, component.position.y, self.bubbleInfoContainer.frame.size.width , 18)]; dateTimeLabel.text = [self.bubbleData.eventFormatter timeStringFromDate:component.date]; dateTimeLabel.textAlignment = NSTextAlignmentRight; - dateTimeLabel.textColor = [UIColor lightGrayColor]; - dateTimeLabel.font = [UIFont systemFontOfSize:11]; - dateTimeLabel.adjustsFontSizeToFitWidth = NO; + dateTimeLabel.textColor = VECTOR_TEXT_GRAY_COLOR; + if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) + { + dateTimeLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium]; + } + else + { + dateTimeLabel.font = [UIFont systemFontOfSize:15]; + } + dateTimeLabel.adjustsFontSizeToFitWidth = YES; + dateTimeLabel.tag = componentIndex; [dateTimeLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; @@ -61,7 +73,6 @@ attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0]; - // Vertical constraints are required for iOS > 8 NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:dateTimeLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual @@ -75,19 +86,10 @@ toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 - constant:15]; + constant:18]; - if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)]) - { - [NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint, heightConstraint]]; - } - else - { - [self.bubbleInfoContainer addConstraint:leftConstraint]; - [self.bubbleInfoContainer addConstraint:rightConstraint]; - [self.bubbleInfoContainer addConstraint:topConstraint]; - [dateTimeLabel addConstraint:heightConstraint]; - } + // Available on iOS 8 and later + [NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint, heightConstraint]]; } } @@ -109,8 +111,10 @@ MXKRoomBubbleComponent *component; if (componentIndex < self.bubbleData.bubbleComponents.count) { + // Add time label [self addTimestampLabelForComponent:componentIndex]; + // Hightlight selection by blurring other components component = self.bubbleData.bubbleComponents[componentIndex]; [self highlightTextMessageForEvent:component.event.eventId]; @@ -124,7 +128,8 @@ } } - // Blur read receipts which are not related to the selected component (if any) + // Retrieve the read receipts container related to the selected component (if any) + // Blur the others for (UIView* view in self.bubbleOverlayContainer.subviews) { // Note read receipt container tag is equal to the index of the related component. @@ -132,12 +137,22 @@ { view.alpha = 0.2; } + else if ([view isKindOfClass:MXKReceiptSendersContainer.class]) + { + self.selectedReadReceiptsContainer = (MXKReceiptSendersContainer*)view; + } } + + // Add the edit button (shift left the receipts container if any). + [self addEditButtonForComponent:componentIndex completion:nil]; } } - (void)unselectComponent { + // Remove edit button (Restore receipts container position if any) + [self removeEditButton:nil]; + // Remove all timestamps by default [self removeTimestampLabels]; @@ -210,4 +225,223 @@ return NO; } +- (void)setEditButton:(UIButton *)editButton +{ + objc_setAssociatedObject(self, @selector(editButton), editButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIButton*)editButton +{ + return objc_getAssociatedObject(self, @selector(editButton)); +} + +- (void)setSelectedReadReceiptsContainer:(MXKReceiptSendersContainer *)readReceiptsContainer +{ + objc_setAssociatedObject(self, @selector(selectedReadReceiptsContainer), readReceiptsContainer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIButton*)selectedReadReceiptsContainer +{ + return objc_getAssociatedObject(self, @selector(selectedReadReceiptsContainer)); +} + +- (void)setSelectedReadReceiptsContainerTrailingConstraint:(NSLayoutConstraint *)readReceiptsContainerTrailingConstraint +{ + objc_setAssociatedObject(self, @selector(selectedReadReceiptsContainerTrailingConstraint), readReceiptsContainerTrailingConstraint, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIButton*)selectedReadReceiptsContainerTrailingConstraint +{ + return objc_getAssociatedObject(self, @selector(selectedReadReceiptsContainerTrailingConstraint)); +} + +#pragma mark - User actions + +- (IBAction)onEditButtonPressed:(id)sender +{ + if (self.delegate) + { + MXEvent *selectedEvent = nil; + + // Note edit button tag is equal to the index of the related component. + NSInteger index = ((UIView*)sender).tag; + if (index < self.bubbleData.bubbleComponents.count) + { + MXKRoomBubbleComponent *component = self.bubbleData.bubbleComponents[index]; + selectedEvent = component.event; + } + + if (selectedEvent) + { + [self.delegate cell:self didRecognizeAction:kMXKRoomBubbleCellVectorEditButtonPressed userInfo:@{kMXKRoomBubbleCellEventKey:selectedEvent}]; + } + } +} + +#pragma mark - Internals + +- (void)addEditButtonForComponent:(NSUInteger)componentIndex completion:(void (^ __nullable)(BOOL finished))completion +{ + MXKRoomBubbleComponent *component = self.bubbleData.bubbleComponents[componentIndex]; + + // Define 'Edit' button frame by overlapping slightly the time label + // (vertical pos = (component.position.y + 9) instead of (component.position.y + 18)) + UIButton *editButton = [[UIButton alloc] initWithFrame:CGRectMake(0, component.position.y + 9, self.bubbleInfoContainer.frame.size.width , 33)]; + + [editButton setTitle:NSLocalizedStringFromTable(@"room_event_action_edit", @"Vector", nil) forState:UIControlStateNormal]; + [editButton setTitle:NSLocalizedStringFromTable(@"room_event_action_edit", @"Vector", nil) forState:UIControlStateSelected]; + [editButton setTitleColor:VECTOR_GREEN_COLOR forState:UIControlStateNormal]; + [editButton setTitleColor:VECTOR_GREEN_COLOR forState:UIControlStateSelected]; + editButton.titleLabel.textAlignment = NSTextAlignmentRight; + + editButton.backgroundColor = [UIColor clearColor]; + if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) + { + editButton.titleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium]; + } + else + { + editButton.titleLabel.font = [UIFont systemFontOfSize:15]; + } + + editButton.hidden = YES; + editButton.tag = componentIndex; + [editButton addTarget:self action:@selector(onEditButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + + [editButton setTranslatesAutoresizingMaskIntoConstraints:NO]; + [self.bubbleInfoContainer addSubview:editButton]; + self.bubbleInfoContainer.userInteractionEnabled = YES; + + // Force edit button in full width (to handle auto-layout in case of screen rotation) + NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:editButton + attribute:NSLayoutAttributeLeading + relatedBy:NSLayoutRelationEqual + toItem:self.bubbleInfoContainer + attribute:NSLayoutAttributeLeading + multiplier:1.0 + constant:0]; + NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:editButton + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.bubbleInfoContainer + attribute:NSLayoutAttributeTrailing + multiplier:1.0 + constant:0]; + NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:editButton + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.bubbleInfoContainer + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:component.position.y + 9]; + NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:editButton + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:33]; + // Available on iOS 8 and later + [NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint, heightConstraint]]; + + // Store the created button + self.editButton = editButton; + + // Check whether this edit button overlaps a potential receipts container displayed for this component + if (self.selectedReadReceiptsContainer) + { + // Adjust edit button frame to be able to compare it to bubble overlay container (superview of receipts container). + CGRect frame = CGRectOffset (editButton.frame, self.bubbleInfoContainer.frame.origin.x, self.bubbleInfoContainer.frame.origin.y); + if (CGRectIntersectsRect(frame, self.selectedReadReceiptsContainer.frame)) + { + // Retrieve the trailing constraint of the receipts container + NSArray *constraints = self.bubbleOverlayContainer.constraints; + for (NSLayoutConstraint *constraint in constraints) + { + if (constraint.firstAttribute == NSLayoutAttributeTrailing && constraint.firstItem == self.selectedReadReceiptsContainer) + { + self.selectedReadReceiptsContainerTrailingConstraint = constraint; + break; + } + } + } + } + + if (self.selectedReadReceiptsContainerTrailingConstraint) + { + // Update layout with animation + [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn + animations:^{ + + // Shift the container to left + self.selectedReadReceiptsContainerTrailingConstraint.constant -= (self.bubbleInfoContainer.frame.size.width + 6); + + // Force to render the view + [self layoutIfNeeded]; + + editButton.hidden = NO; + + } + completion:^(BOOL finished){ + + if (completion) + { + completion(finished); + } + + }]; + } + else + { + editButton.hidden = NO; + + if (completion) + { + completion(YES); + } + } +} + +- (void)removeEditButton:(void (^ __nullable)(BOOL finished))completion +{ + if (self.selectedReadReceiptsContainerTrailingConstraint) + { + // Update layout with animation + [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn + animations:^{ + + [self.editButton removeFromSuperview]; + + self.selectedReadReceiptsContainerTrailingConstraint.constant = -6; + + // Force to render the view + [self layoutIfNeeded]; + } + completion:^(BOOL finished){ + + self.editButton = nil; + self.selectedReadReceiptsContainer = nil; + self.selectedReadReceiptsContainerTrailingConstraint = nil; + + if (completion) + { + completion(finished); + } + + }]; + } + else + { + [self.editButton removeFromSuperview]; + self.editButton = nil; + self.selectedReadReceiptsContainer = nil; + self.selectedReadReceiptsContainerTrailingConstraint = nil; + + if (completion) + { + completion(YES); + } + } +} + @end diff --git a/Vector/Categories/MXRoom+Vector.h b/Vector/Categories/MXRoom+Vector.h new file mode 100644 index 000000000..e1b8ef200 --- /dev/null +++ b/Vector/Categories/MXRoom+Vector.h @@ -0,0 +1,58 @@ +/* + Copyright 2015 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 + +/** + Define a `MXRoom` category at Vector level. + */ +@interface MXRoom (Vector) + +/** + Returns YES if there is an push rule to disable the notifications for this room. + */ +@property(nonatomic, readonly) BOOL areRoomNotificationsMuted; + +/** + Returns YES if the oneself user is a moderator i.e. he is allowed to update the room name or the avatar.. + */ +@property(nonatomic, readonly) BOOL isModerator; + +/** + Returns the vector displayname. + */ +@property(nonatomic, readonly) NSString* vectorDisplayname; + +/** + Toggle a room rule notifications. + + @param mute YES to disable room notification + @return the dedicated push rule + */ +- (void)toggleRoomNotifications:(BOOL)mute; + +/** + Set the room avatar in the dedicated MXKImageView. + The vector style implies to use in order : + 1 - the default avatar if there is one + 2 - the member avatar for < 3 members rooms + 3 - the first later of the room name. + + @param mxkImageView the destinated MXKImageView. + */ +- (void)setRoomAvatarImageIn:(MXKImageView*)mxkImageView; + +@end diff --git a/Vector/Categories/MXRoom+Vector.m b/Vector/Categories/MXRoom+Vector.m new file mode 100644 index 000000000..9c99d8fa7 --- /dev/null +++ b/Vector/Categories/MXRoom+Vector.m @@ -0,0 +1,373 @@ +/* + Copyright 2015 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 "MXRoom+Vector.h" + +#import "AvatarGenerator.h" + +@interface MXRoom () + +// create property for the extensions + +// rule events observer +@property id notificationCenterDidFailObserver; +@property id notificationCenterDidUpdateObserver; + +@end + +@implementation MXRoom (Vector) + +/** + Returns the room rule notifition. + + @return the dedicated push rule + */ +- (MXPushRule*)getRoomPushRule +{ + NSArray* rules = self.mxSession.notificationCenter.rules.global.room; + + // sanity checks + if (rules) + { + for(MXPushRule* rule in rules) + { + // the rule id is the room Id + // it is the server trick to avoid duplicated rule on the same room. + if ([rule.ruleId isEqualToString:self.state.roomId]) + { + return rule; + } + } + } + + return nil; +} + +- (BOOL)areRoomNotificationsMuted +{ + MXPushRule* rule = [self getRoomPushRule]; + + if (rule) + { + for (MXPushRuleAction *ruleAction in rule.actions) + { + if (ruleAction.actionType == MXPushRuleActionTypeDontNotify) + { + return rule.enabled; + } + } + } + + return NO; +} + +- (BOOL)isModerator +{ + // Check whether the user has enough power to rename the room or update the avatar + MXRoomPowerLevels *powerLevels = [self.state powerLevels]; + + NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxSession.myUser.userId]; + + return (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName]); +} + +- (void)toggleRoomNotifications:(BOOL)mute +{ + BOOL isNotified = ![self areRoomNotificationsMuted]; + + // check if the state is already in the right state + if (isNotified == !mute) + { + return; + } + + MXNotificationCenter* notificationCenter = self.mxSession.notificationCenter; + MXPushRule* rule = [self getRoomPushRule]; + + if (!mute) + { + // let the other notification rules manage the pushes. + [notificationCenter removeRule:rule]; + } + else + { + // user does not want to have push + + // if there is no rule + if (!rule) + { + // add one + [notificationCenter addRoomRule:self.state.roomId + notify:NO + sound:NO + highlight:NO]; + } + else + { + + // check if the user did not define one + BOOL hasDontNotifyRule = NO; + + for (MXPushRuleAction *ruleAction in rule.actions) + { + if (ruleAction.actionType == MXPushRuleActionTypeDontNotify) + { + hasDontNotifyRule = YES; + break; + } + } + + // if the user defined one, use it + if (hasDontNotifyRule) + { + [notificationCenter enableRule:rule isEnabled:YES]; + } + else + { + __weak typeof(self) weakSelf = self; + + // if the user defined a room rule + // the rule is deleted before adding new one + + id localNotificationCenterDidUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidUpdateRules object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + + MXPushRule* rule = [self getRoomPushRule]; + + // check if the rule has been deleted + // there is no way to know if the notif is really for this rule.. + if (!rule) + { + __strong __typeof(weakSelf)strongSelf = weakSelf; + + if (strongSelf.notificationCenterDidUpdateObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver]; + strongSelf.notificationCenterDidUpdateObserver = nil; + } + + if (strongSelf.notificationCenterDidFailObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver]; + strongSelf.notificationCenterDidUpdateObserver = nil; + } + + // add one dedicated rule + [notificationCenter addRoomRule:self.state.roomId + notify:NO + sound:NO + highlight:NO]; + } + }]; + + id localNotificationCenterDidFailObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXNotificationCenterDidFailRulesUpdate object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + + if (strongSelf.notificationCenterDidUpdateObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver]; + strongSelf.notificationCenterDidUpdateObserver = nil; + } + + if (strongSelf.notificationCenterDidFailObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:strongSelf.notificationCenterDidUpdateObserver]; + strongSelf.notificationCenterDidUpdateObserver = nil; + } + }]; + + self.notificationCenterDidUpdateObserver = localNotificationCenterDidUpdateObserver; + self.notificationCenterDidFailObserver = localNotificationCenterDidFailObserver; + + // remove the rule notification + // the notifications are used to tell + [notificationCenter removeRule:rule]; + } + } + } +} + +- (void)setRoomAvatarImageIn:(MXKImageView*)mxkImageView +{ + NSString* roomAvatarUrl = self.state.avatar; + + // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) + if (!roomAvatarUrl) + { + NSString* myUserId = self.mxSession.myUser.userId; + + NSArray* members = self.state.members; + + if (members.count < 3) + { + // use the member avatar only it is an active member + for (MXRoomMember *roomMember in members) + { + if ((MXMembershipJoin == roomMember.membership) && ((members.count == 1) || ![roomMember.userId isEqualToString:myUserId])) + { + roomAvatarUrl = roomMember.avatarUrl; + break; + } + } + } + } + + UIImage* avatarImage = [AvatarGenerator generateRoomAvatar:self]; + + if (roomAvatarUrl) + { + mxkImageView.enableInMemoryCache = YES; + + [mxkImageView setImageURL:[self.mxSession.matrixRestClient urlOfContentThumbnail:roomAvatarUrl toFitViewSize:mxkImageView.frame.size withMethod:MXThumbnailingMethodCrop] withType:nil andImageOrientation:UIImageOrientationUp previewImage:avatarImage]; + } + else + { + mxkImageView.image = avatarImage; + } + + mxkImageView.contentMode = UIViewContentModeScaleAspectFill; +} + +- (NSString *)vectorDisplayname +{ + // this algo is the one defined in + // https://github.com/matrix-org/matrix-js-sdk/blob/develop/lib/models/room.js#L617 + // calculateRoomName(room, userId) + + MXRoomState* roomState = self.state; + + if (roomState.name.length > 0) + { + return roomState.name; + } + + NSString *alias = roomState.canonicalAlias; + + if (!alias) + { + // For rooms where canonical alias is not defined, we use the 1st alias as a workaround + NSArray *aliases = roomState.aliases; + + if (aliases.count) + { + alias = [aliases[0] copy]; + } + } + + if (alias) + { + return alias; + } + + NSString* myUserId = self.mxSession.myUser.userId; + + NSArray* members = roomState.members; + NSMutableArray* othersActiveMembers = [[NSMutableArray alloc] init]; + NSMutableArray* activeMembers = [[NSMutableArray alloc] init]; + + for(MXRoomMember* member in members) + { + if (member.membership != MXMembershipLeave) + { + if (![member.userId isEqualToString:myUserId]) + { + [othersActiveMembers addObject:member]; + } + + [activeMembers addObject:member]; + } + } + + // sort the members by their creation (oldest first) + othersActiveMembers = [[othersActiveMembers sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { + + uint64_t originServerTs1 = 0; + uint64_t originServerTs2 = 0; + + MXRoomMember* member1 = (MXRoomMember*)obj1; + MXRoomMember* member2 = (MXRoomMember*)obj2; + + if (member1.originalEvent) + { + originServerTs1 = member1.originalEvent.originServerTs; + } + + if (member2.originalEvent) + { + originServerTs2 = member2.originalEvent.originServerTs; + } + + if (originServerTs1 == originServerTs2) + { + return NSOrderedSame; + } + else + { + return originServerTs1 > originServerTs2 ? NSOrderedDescending : NSOrderedAscending; + } + }] mutableCopy]; + + + NSString* displayName = @""; + + // TODO: Localisation + if (othersActiveMembers.count == 0) + { + if (activeMembers.count == 1) + { + MXRoomMember* member = [activeMembers objectAtIndex:0]; + + if (member.membership == MXMembershipInvite) + { + if (member.originalEvent.sender) + { + // extract who invited us to the room + displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_displayname_invite_from", @"Vector", nil), [roomState memberName:member.originalEvent.sender]]; + } + else + { + displayName = NSLocalizedStringFromTable(@"room_displayname_room_invite", @"Vector", nil); + } + } + else + { + displayName = myUserId; + } + } + } + else if (othersActiveMembers.count == 1) + { + MXRoomMember* member = [othersActiveMembers objectAtIndex:0]; + + displayName = [roomState memberName:member.userId]; + } + else if (othersActiveMembers.count == 2) + { + MXRoomMember* member1 = [othersActiveMembers objectAtIndex:0]; + MXRoomMember* member2 = [othersActiveMembers objectAtIndex:1]; + + displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_displayname_two_members", @"Vector", nil), [roomState memberName:member1.userId], [roomState memberName:member2.userId]]; + } + else + { + MXRoomMember* member = [othersActiveMembers objectAtIndex:0]; + displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_displayname_more_than_two_members", @"Vector", nil), [roomState memberName:member.userId], othersActiveMembers.count - 1]; + } + + return displayName; +} + +@end diff --git a/Vector/Model/Room/RoomDataSource.m b/Vector/Model/Room/RoomDataSource.m index 2a9d4173b..ff9779575 100644 --- a/Vector/Model/Room/RoomDataSource.m +++ b/Vector/Model/Room/RoomDataSource.m @@ -158,12 +158,12 @@ // Force receipts container size NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer - attribute:NSLayoutAttributeWidth - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:150]; + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:150]; NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual @@ -173,13 +173,13 @@ constant:12]; // Force receipts container position - NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer - attribute:NSLayoutAttributeTrailing - relatedBy:NSLayoutRelationEqual - toItem:bubbleCell.bubbleOverlayContainer - attribute:NSLayoutAttributeTrailing - multiplier:1.0 - constant:-6]; + NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:bubbleCell.bubbleOverlayContainer + attribute:NSLayoutAttributeTrailing + multiplier:1.0 + constant:-6]; NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual @@ -188,17 +188,8 @@ multiplier:1.0 constant:bottomPositionY - 12]; - if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)]) - { - [NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, rightConstraint]]; - } - else - { - [avatarsContainer addConstraint:heightConstraint]; - [avatarsContainer addConstraint:widthConstraint]; - [bubbleCell.bubbleOverlayContainer addConstraint:topConstraint]; - [bubbleCell.bubbleOverlayContainer addConstraint:rightConstraint]; - } + // Available on iOS 8 and later + [NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]]; } } diff --git a/Vector/Model/RoomList/RecentCellData.h b/Vector/Model/RoomList/RecentCellData.h new file mode 100644 index 000000000..db6d007e4 --- /dev/null +++ b/Vector/Model/RoomList/RecentCellData.h @@ -0,0 +1,26 @@ +/* + Copyright 2015 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 +#import + +#import "MXKRecentCellData.h" +/** + `RecentCellData` is Vector cuustomized MXKRecentCellData` cell. + */ +@interface RecentCellData : MXKRecentCellData + +@end diff --git a/Vector/Model/RoomList/RecentCellData.m b/Vector/Model/RoomList/RecentCellData.m new file mode 100644 index 000000000..55c41312c --- /dev/null +++ b/Vector/Model/RoomList/RecentCellData.m @@ -0,0 +1,32 @@ +/* + Copyright 2015 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 "RecentCellData.h" + +#import "MXRoom+Vector.h" + +@implementation RecentCellData +// trick to hide the mother class property as it is readonly one. +// self.roomDisplayname returns this value instead of the mother class. +@synthesize roomDisplayname; + +- (void)update +{ + [super update]; + roomDisplayname = self.roomDataSource.room.vectorDisplayname; +} + +@end diff --git a/Vector/Model/RoomList/RecentsDataSource.m b/Vector/Model/RoomList/RecentsDataSource.m index 71dc63f24..a8eb4df3a 100644 --- a/Vector/Model/RoomList/RecentsDataSource.m +++ b/Vector/Model/RoomList/RecentsDataSource.m @@ -25,6 +25,10 @@ #import "PublicRoomsDirectoryDataSource.h" +#import "MXRoom+Vector.h" + +#import "RecentCellData.h" + @interface RecentsDataSource() { NSMutableArray* invitesCellDataArray; @@ -67,6 +71,9 @@ sectionsCount = 0; roomTagsListenerByUserId = [[NSMutableDictionary alloc] init]; + + // Set default data and view classes + [self registerCellDataClass:RecentCellData.class forCellIdentifier:kMXKRecentCellIdentifier]; } return self; } @@ -141,6 +148,28 @@ } } +- (BOOL)isRoomNotifiedAtIndexPath:(NSIndexPath *)indexPath +{ + MXRoom* room = [self getRoomAtIndexPath:indexPath]; + + if (room) + { + return !room.areRoomNotificationsMuted; + } + + return YES; +} + +- (void)muteRoomNotifications:(BOOL)mute atIndexPath:(NSIndexPath *)indexPath +{ + MXRoom* room = [self getRoomAtIndexPath:indexPath]; + + // sanity check + if (room) + { + [room toggleRoomNotifications:mute]; + } +} - (void)refreshRoomsSectionsAndReload { @@ -698,7 +727,7 @@ - (void)moveRoomCell:(MXRoom*)room from:(NSIndexPath*)oldPath to:(NSIndexPath*)newPath success:(void (^)())moveSuccess failure:(void (^)(NSError *error))moveFailure; { - NSLog(@"[RecentsDataSource] moveCellFrom (%d, %d) to (%d, %d)", oldPath.section, oldPath.row, newPath.section, newPath.row); + NSLog(@"[RecentsDataSource] moveCellFrom (%tu, %tu) to (%tu, %tu)", oldPath.section, oldPath.row, newPath.section, newPath.row); if ([self canCellMoveFrom:oldPath to:newPath] && ![newPath isEqual:oldPath]) { diff --git a/Vector/Utils/AvatarGenerator.m b/Vector/Utils/AvatarGenerator.m index 61ff78e47..fdde410c3 100644 --- a/Vector/Utils/AvatarGenerator.m +++ b/Vector/Utils/AvatarGenerator.m @@ -16,6 +16,8 @@ #import "AvatarGenerator.h" +#import "MXRoom+Vector.h" + @implementation AvatarGenerator static NSMutableDictionary *imageByKeyDict = nil; @@ -156,7 +158,7 @@ static UILabel* backgroundLabel = nil; // if the displayname is the userID // skip the @ - if (!displayname && [text hasPrefix:@"@"]) + if (!displayname && ([text hasPrefix:@"@"] || [text hasPrefix:@"#"])) { text = [text substringFromIndex:1]; } @@ -176,7 +178,7 @@ static UILabel* backgroundLabel = nil; */ + (UIImage*)generateRoomAvatar:(MXRoom*)room { - NSString* displayName = room.state.displayname; + NSString* displayName = room.vectorDisplayname; NSString* roomId = room.state.roomId; // the selected color is based on the roomId @@ -184,7 +186,7 @@ static UILabel* backgroundLabel = nil; NSString* text = displayName; // ignore the first # - if ([text hasPrefix:@"#"]) + if ([text hasPrefix:@"#"] || [text hasPrefix:@"@"]) { text = [text substringFromIndex:1]; } diff --git a/Vector/Utils/EventFormatter.m b/Vector/Utils/EventFormatter.m index 1d30ff793..f6328a8c0 100644 --- a/Vector/Utils/EventFormatter.m +++ b/Vector/Utils/EventFormatter.m @@ -124,7 +124,7 @@ if (time) { [dateFormatter setDateFormat:nil]; - return [NSString stringWithFormat:@"today %@", [super dateStringFromDate:date withTime:YES]]; + return [NSString stringWithFormat:@"%@", [super dateStringFromDate:date withTime:YES]]; } return @"today"; } diff --git a/Vector/Utils/VectorDesignValues.h b/Vector/Utils/VectorDesignValues.h index c61b22c59..c19cd8d7c 100644 --- a/Vector/Utils/VectorDesignValues.h +++ b/Vector/Utils/VectorDesignValues.h @@ -14,14 +14,20 @@ limitations under the License. */ -// the green text color +#pragma mark - Vector Colors + #define VECTOR_GREEN_COLOR [UIColor colorWithRed:(98.0/256.0) green:(206.0/256.0) blue:(156.0/256.0) alpha:1.0] +#define VECTOR_LIGHT_GRAY_COLOR [UIColor colorWithRed:(242.0 / 256.0) green:(242.0 / 256.0) blue:(242.0 / 256.0) alpha:1.0] + +#define VECTOR_SILVER_COLOR [UIColor colorWithRed:(199.0 / 256.0) green:(199.0 / 256.0) blue:(204.0 / 256.0) alpha:1.0] + + +#pragma mark - Vector Text Colors + #define VECTOR_TEXT_BLACK_COLOR [UIColor colorWithRed:(60.0 / 256.0) green:(60.0 / 256.0) blue:(60.0 / 256.0) alpha:1.0] #define VECTOR_TEXT_GRAY_COLOR [UIColor colorWithRed:(157.0 / 256.0) green:(157.0 / 256.0) blue:(157.0 / 256.0) alpha:1.0] -#define VECTOR_LIGHT_GRAY_COLOR [UIColor colorWithRed:(242.0 / 256.0) green:(242.0 / 256.0) blue:(242.0 / 256.0) alpha:1.0] - // to update the navigation bar buttons color // [[AppDelegate theDelegate] recentsNavigationController].navigationBar.tintColor = [UIColor greenColor]; diff --git a/Vector/ViewController/MediaPickerViewController.m b/Vector/ViewController/MediaPickerViewController.m index 7345e487b..1cda89a9d 100644 --- a/Vector/ViewController/MediaPickerViewController.m +++ b/Vector/ViewController/MediaPickerViewController.m @@ -731,14 +731,8 @@ NSString* const recentItemCollectionViewCellId = @"recentItemCollectionViewCellI AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo]; if ([connection isVideoStabilizationSupported]) { - if ([connection respondsToSelector:@selector(setPreferredVideoStabilizationMode:)]) - { - [connection setPreferredVideoStabilizationMode:YES]; - } - else - { - [connection setEnablesVideoStabilizationWhenAvailable:YES]; - } + // Available on iOS 8 and later + [connection setPreferredVideoStabilizationMode:YES]; } } [movieFileOutput addObserver:self forKeyPath:@"recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext]; diff --git a/Vector/ViewController/RecentsViewController.m b/Vector/ViewController/RecentsViewController.m index 943258ac2..f3c27cd77 100644 --- a/Vector/ViewController/RecentsViewController.m +++ b/Vector/ViewController/RecentsViewController.m @@ -326,11 +326,18 @@ static NSMutableDictionary* backgroundByImageNameDict; - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath { NSMutableArray* actions = [[NSMutableArray alloc] init]; - MXRoom* room = [self.dataSource getRoomAtIndexPath:indexPath]; if (room) { + NSArray* invitedRooms = room.mxSession.invitedRooms; + + // display no action for the invited room + if (invitedRooms && ([invitedRooms indexOfObject:room] != NSNotFound)) + { + return actions; + } + NSString* title = @" "; // pushes settings diff --git a/Vector/ViewController/RoomSettingsViewController.h b/Vector/ViewController/RoomSettingsViewController.h index 86c6fc929..391480dc1 100644 --- a/Vector/ViewController/RoomSettingsViewController.h +++ b/Vector/ViewController/RoomSettingsViewController.h @@ -16,7 +16,9 @@ #import -@interface RoomSettingsViewController : MXKRoomSettingsViewController +#import "MediaPickerViewController.h" + +@interface RoomSettingsViewController : MXKRoomSettingsViewController @end diff --git a/Vector/ViewController/RoomSettingsViewController.m b/Vector/ViewController/RoomSettingsViewController.m index 09df3a691..adfa284aa 100644 --- a/Vector/ViewController/RoomSettingsViewController.m +++ b/Vector/ViewController/RoomSettingsViewController.m @@ -16,19 +16,32 @@ #import "RoomSettingsViewController.h" +#import +#import + #import "TableViewCellWithLabelAndTextField.h" #import "TableViewCellWithLabelAndLargeTextView.h" +#import "TableViewCellWithLabelAndMXKImageView.h" +#import "TableViewCellWithLabelAndSwitch.h" + #import "TableViewCellSeparator.h" #import "RageShakeManager.h" #import "VectorDesignValues.h" +#import "AvatarGenerator.h" + +#import "MXRoom+Vector.h" + #define ROOM_SECTION 0 -#define ROOM_SECTION_NAME 0 -#define ROOM_SECTION_TOPIC 1 -#define ROOM_SECTION_COUNT 2 +#define ROOM_SECTION_PHOTO 0 +#define ROOM_SECTION_NAME 1 +#define ROOM_SECTION_TOPIC 2 +#define ROOM_SECTION_PRIV_PUB 3 +#define ROOM_SECTION_MUTE_NOTIFICATIONS 4 +#define ROOM_SECTION_COUNT 5 #define ROOM_TOPIC_CELL_HEIGHT 99 @@ -48,6 +61,15 @@ UIActivityIndicatorView* updatingSpinner; MXKAlert *currentAlert; + + // listen to more events than the mother class + id extraEventsListener; + + // picker + MediaPickerViewController* mediaPicker; + + // switches + UISwitch *roomNotifSwitch; } @end @@ -93,6 +115,8 @@ [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXSessionStateChange:) name:kMXSessionStateDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRules:) name:kMXNotificationCenterDidUpdateRules object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didAccountUserInfoDidChange:) name:kMXKAccountUserInfoDidChangeNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated @@ -101,6 +125,8 @@ [self dismissFirstResponder]; [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionStateDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXNotificationCenterDidUpdateRules object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXKAccountUserInfoDidChangeNotification object:nil]; } // this method is called when the viewcontroller is displayed inside another one. @@ -150,16 +176,19 @@ - (void)showUpdatingSpinner { - self.tableView.userInteractionEnabled = NO; - - // Add a spinner - updatingSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; - updatingSpinner.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); - updatingSpinner.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0]; - updatingSpinner.hidesWhenStopped = NO; - [updatingSpinner startAnimating]; - updatingSpinner.center = self.view.center; - [self.view addSubview:updatingSpinner]; + if (!updatingSpinner) + { + self.tableView.userInteractionEnabled = NO; + + // Add a spinner + updatingSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + updatingSpinner.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); + updatingSpinner.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0]; + updatingSpinner.hidesWhenStopped = NO; + [updatingSpinner startAnimating]; + updatingSpinner.center = self.view.center; + [self.view addSubview:updatingSpinner]; + } } - (void)hideUpdatingSpinner @@ -232,10 +261,38 @@ } } +- (void)didUpdateRules:(NSNotification *)notif +{ + [self.tableView reloadData]; +} + +- (void)didAccountUserInfoDidChange:(NSNotification *)notif +{ + [self.tableView reloadData]; +} + - (IBAction)onCancel:(id)sender { - // warn if there is a pending update ? - [self.navigationController popViewControllerAnimated:YES]; + // if there are some updated fields + if (updatedItemsDict && (updatedItemsDict.count > 0)) + { + // ensure that the user understands that the updates will be lost if + MXKAlert* alert = [[MXKAlert alloc] initWithTitle:nil message:NSLocalizedStringFromTable(@"room_details_with_updates", @"Vector", nil) style:MXKAlertStyleAlert]; + + [alert addActionWithTitle:NSLocalizedStringFromTable(@"cancel", @"Vector", nil) style:MXKAlertActionStyleCancel handler:^(MXKAlert *alert) { + [self.navigationController popViewControllerAnimated:YES]; + }]; + + [alert addActionWithTitle:NSLocalizedStringFromTable(@"save", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + [self onSave:nil]; + }]; + + [alert showInViewController:self]; + } + else + { + [self.navigationController popViewControllerAnimated:YES]; + } } - (void)onSaveFailed:(NSString*)message withKey:(NSString*)key @@ -274,9 +331,60 @@ - (IBAction)onSave:(id)sender { + [self showUpdatingSpinner]; + // check if there is some update if (mxRoomState && updatedItemsDict && (updatedItemsDict.count > 0)) { + if ([updatedItemsDict objectForKey:@"ROOM_SECTION_PHOTO"]) + { + // Retrieve the current picture and make sure its orientation is up + UIImage *updatedPicture = [MXKTools forceImageOrientationUp:[updatedItemsDict objectForKey:@"ROOM_SECTION_PHOTO"]]; + + // Upload picture + MXKMediaLoader *uploader = [MXKMediaManager prepareUploaderWithMatrixSession:mxRoom.mxSession initialRange:0 andRange:1.0]; + + [uploader uploadData:UIImageJPEGRepresentation(updatedPicture, 0.5) filename:nil mimeType:@"image/jpeg" success:^(NSString *url) + { + [updatedItemsDict removeObjectForKey:@"ROOM_SECTION_PHOTO"]; + [updatedItemsDict setObject:url forKey:@"ROOM_SECTION_PHOTO_URL"]; + + [self onSave:nil]; + } failure:^(NSError *error) + { + NSLog(@"[Vector RoomSettingsViewController] Failed to upload image: %@", error); + [updatedItemsDict removeObjectForKey:@"ROOM_SECTION_PHOTO"]; + [self onSave:nil]; + }]; + + return; + } + + if ([updatedItemsDict objectForKey:@"ROOM_SECTION_PHOTO_URL"]) + { + __weak typeof(self) weakSelf = self; + + NSString* photoUrl = [updatedItemsDict objectForKey:@"ROOM_SECTION_PHOTO_URL"]; + + [mxRoom setAvatar:photoUrl success:^{ + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf->updatedItemsDict removeObjectForKey:@"ROOM_SECTION_PHOTO_URL"]; + [strongSelf onSave:nil]; + + } failure:^(NSError *error) { + + NSLog(@"[Vector RoomSettingsViewController] Failed to update the room avatar %@", error); + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf->updatedItemsDict removeObjectForKey:@"ROOM_SECTION_PHOTO_URL"]; + [strongSelf onSave:nil]; + + }]; + + return; + } + // has a new room name if ([updatedItemsDict objectForKey:@"ROOM_SECTION_NAME"]) { @@ -284,7 +392,6 @@ if (![newName isEqualToString:mxRoomState.name]) { - [self showUpdatingSpinner]; __weak typeof(self) weakSelf = self; pendingOperation = [mxRoom setName:newName success:^{ @@ -319,7 +426,6 @@ if (![newTopic isEqualToString:mxRoomState.topic]) { - [self showUpdatingSpinner]; __weak typeof(self) weakSelf = self; pendingOperation = [mxRoom setTopic:newTopic success:^{ @@ -348,6 +454,15 @@ } } + if ([updatedItemsDict objectForKey:@"ROOM_SECTION_MUTE_NOTIFICATIONS"]) + { + [mxRoom toggleRoomNotifications:roomNotifSwitch.on]; + [updatedItemsDict removeObjectForKey:@"ROOM_SECTION_MUTE_NOTIFICATIONS"]; + [self onSave:nil]; + } + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); + [self hideUpdatingSpinner]; [self.navigationController popViewControllerAnimated:YES]; @@ -430,7 +545,63 @@ // retrieve row as a ROOM_SECTION_XX index row = (row - 1) / 2; - if (row == ROOM_SECTION_TOPIC) + if (row == ROOM_SECTION_MUTE_NOTIFICATIONS) + { + TableViewCellWithLabelAndSwitch *roomNotifCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithLabelAndSwitch defaultReuseIdentifier]]; + + if (!roomNotifCell) + { + roomNotifCell = [[TableViewCellWithLabelAndSwitch alloc] init]; + [roomNotifCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; + roomNotifCell.mxkSwitch.onTintColor = VECTOR_GREEN_COLOR; + } + + roomNotifCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_mute_notifs", @"Vector", nil); + roomNotifSwitch = roomNotifCell.mxkSwitch; + + if (updatedItemsDict && [updatedItemsDict objectForKey:@"ROOM_SECTION_MUTE_NOTIFICATIONS"]) + { + roomNotifSwitch.on = ((NSNumber*)[updatedItemsDict objectForKey:@"ROOM_SECTION_MUTE_NOTIFICATIONS"]).boolValue; + } + else + { + roomNotifSwitch.on = mxRoom.areRoomNotificationsMuted; + } + + cell = roomNotifCell; + } + else if (row == ROOM_SECTION_PHOTO) + { + TableViewCellWithLabelAndMXKImageView *roomPhotoCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]]; + + if (!roomPhotoCell) + { + roomPhotoCell = [[TableViewCellWithLabelAndMXKImageView alloc] init]; + + // tap on avatar to update it + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onRoomAvatarTap:)]; + [roomPhotoCell.mxkImageView addGestureRecognizer:tap]; + } + + roomPhotoCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_photo", @"Vector", nil); + + if (updatedItemsDict && [updatedItemsDict objectForKey:@"ROOM_SECTION_PHOTO"]) + { + roomPhotoCell.mxkImageView.image = (UIImage*)[updatedItemsDict objectForKey:@"ROOM_SECTION_PHOTO"]; + } + else + { + [mxRoom setRoomAvatarImageIn:roomPhotoCell.mxkImageView]; + roomPhotoCell.mxkImageView.alpha = mxRoom.isModerator ? 1.0f : 0.5f; + } + + [roomPhotoCell.mxkImageView.layer setCornerRadius:roomPhotoCell.mxkImageView.frame.size.width / 2]; + roomPhotoCell.mxkImageView.clipsToBounds = YES; + roomPhotoCell.userInteractionEnabled = mxRoom.isModerator; + + cell = roomPhotoCell; + } + else if (row == ROOM_SECTION_TOPIC) { TableViewCellWithLabelAndLargeTextView *roomTopicCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithLabelAndLargeTextView defaultReuseIdentifier]]; @@ -460,8 +631,8 @@ roomTopicCell.mxkTextView.delegate = self; // disable the edition if the user cannoy update it - roomTopicCell.mxkTextView.editable = isSuperUser; - roomTopicCell.mxkTextView.textColor = isSuperUser ? [UIColor blackColor] : [UIColor lightGrayColor]; + roomTopicCell.mxkTextView.editable = mxRoom.isModerator; + roomTopicCell.mxkTextView.textColor = VECTOR_TEXT_GRAY_COLOR; cell = roomTopicCell; } @@ -492,13 +663,28 @@ nameTextField = roomNameCell.mxkTextField; // disable the edition if the user cannoy update it - roomNameCell.editable = isSuperUser; - roomNameCell.mxkTextField.textColor = isSuperUser ? [UIColor blackColor] : [UIColor lightGrayColor]; + roomNameCell.editable = mxRoom.isModerator; + roomNameCell.mxkTextField.textColor = VECTOR_TEXT_GRAY_COLOR; // Add a "textFieldDidChange" notification method to the text field control. [roomNameCell.mxkTextField addTarget:self action:@selector(onTextFieldUpdate:) forControlEvents:UIControlEventEditingChanged]; } + else if (row == ROOM_SECTION_PRIV_PUB) + { + TableViewCellWithLabelAndTextField *privPublicCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithLabelAndTextField defaultReuseIdentifier]]; + + if (!privPublicCell) + { + privPublicCell = [[TableViewCellWithLabelAndTextField alloc] init]; + } + + privPublicCell.mxkTextField.userInteractionEnabled = NO; + privPublicCell.mxkTextField.text = @""; + privPublicCell.mxkLabel.text = mxRoom.state.isPublic ? NSLocalizedStringFromTable(@"room_details_room_is_public", @"Vector", nil) : NSLocalizedStringFromTable(@"room_details_room_is_private", @"Vector", nil); + + cell = privPublicCell; + } } return cell; @@ -509,14 +695,124 @@ if (self.tableView == aTableView) { [self dismissFirstResponder]; + + if (indexPath.section == ROOM_SECTION) + { + NSUInteger row = indexPath.row; + + // the even views are the line separator + if ((row % 2) == 0) + { + return; + } + + // retrieve row as a ROOM_SECTION_XX index + row = (row - 1) / 2; + + if (row == ROOM_SECTION_PHOTO) + { + [self onRoomAvatarTap:nil]; + } + } } } -- (void)scrollViewDidScroll:(UIScrollView *)scrollView +#pragma mark - MediaPickerViewController Delegate + +- (void)dismissMediaPicker { - if (scrollView == self.tableView) + if (mediaPicker) { - [self dismissFirstResponder]; + [mediaPicker withdrawViewControllerAnimated:YES completion:nil]; + mediaPicker = nil; + } +} + +- (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController didSelectImage:(UIImage*)image withURL:(NSURL *)imageURL +{ + [self dismissMediaPicker]; + + if (image) + { + [self getNavigationItem].rightBarButtonItem.enabled = YES; + + NSMutableDictionary* dict = [self getUpdatedItemsDict]; + [dict setObject:image forKey:@"ROOM_SECTION_PHOTO"]; + + [self.tableView reloadData]; + } +} + +- (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController didSelectVideo:(NSURL*)videoURL isCameraRecording:(BOOL)isCameraRecording +{ + // this method should not be called + [self dismissMediaPicker]; +} + +- (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController didSelectAssets:(NSArray *)assets +{ + if (assets.count > 0) + { + PHAsset* asset = [assets objectAtIndex:0]; + PHContentEditingInputRequestOptions *editOptions = [[PHContentEditingInputRequestOptions alloc] init]; + + [asset requestContentEditingInputWithOptions:editOptions + completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) { + + if (contentEditingInput.mediaType == PHAssetMediaTypeImage) + { + // Here the fullSizeImageURL is related to a local file path + NSData *data = [NSData dataWithContentsOfURL:contentEditingInput.fullSizeImageURL]; + UIImage *image = [UIImage imageWithData:data]; + + if (image) + { + [self getNavigationItem].rightBarButtonItem.enabled = YES; + + NSMutableDictionary* dict = [self getUpdatedItemsDict]; + [dict setObject:image forKey:@"ROOM_SECTION_PHOTO"]; + + [self.tableView reloadData]; + } + } + }]; + } + + [self dismissMediaPicker]; +} + +#pragma mark - actions + +- (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer +{ + mediaPicker = [MediaPickerViewController mediaPickerViewController]; + mediaPicker.mediaTypes = @[(NSString *)kUTTypeImage]; + mediaPicker.multipleSelections = NO; + mediaPicker.selectionButtonCustomLabel = NSLocalizedStringFromTable(@"media_picker_attach", @"Vector", nil); + mediaPicker.delegate = self; + UINavigationController *navigationController = [UINavigationController new]; + [navigationController pushViewController:mediaPicker animated:NO]; + + [self presentViewController:navigationController animated:YES completion:nil]; +} + +- (void)onSwitchUpdate:(UISwitch*)uiSwitch +{ + if (uiSwitch == roomNotifSwitch) + { + NSMutableDictionary* dict = [self getUpdatedItemsDict]; + + if (roomNotifSwitch.on == mxRoom.areRoomNotificationsMuted) + { + [dict removeObjectForKey:@"ROOM_SECTION_MUTE_NOTIFICATIONS"]; + } + else + { + [dict setObject:[NSNumber numberWithBool:roomNotifSwitch.on] forKey:@"ROOM_SECTION_MUTE_NOTIFICATIONS"]; + } + + [self getNavigationItem].rightBarButtonItem.enabled = (dict.count != 0); + [self.tableView reloadData]; } } diff --git a/Vector/ViewController/RoomViewController.m b/Vector/ViewController/RoomViewController.m index ebd62a986..d6ac37eff 100644 --- a/Vector/ViewController/RoomViewController.m +++ b/Vector/ViewController/RoomViewController.m @@ -96,7 +96,24 @@ // Replace the default input toolbar view. // Note: this operation will force the layout of subviews. That is why cell view classes must be registered before. [self setRoomInputToolbarViewClass:RoomInputToolbarView.class]; - [self roomInputToolbarView:self.inputToolbarView heightDidChanged:((RoomInputToolbarView*)self.inputToolbarView).mainToolbarHeightConstraint.constant completion:nil]; + [self roomInputToolbarView:self.inputToolbarView heightDidChanged:((RoomInputToolbarView*)self.inputToolbarView).mainToolbarMinHeightConstraint.constant completion:nil]; + + // Set user picture in input toolbar + MXKImageView *userPictureView = ((RoomInputToolbarView*)self.inputToolbarView).pictureView; + if (userPictureView) + { + UIImage *preview = [AvatarGenerator generateRoomMemberAvatar:self.mainSession.myUser.userId displayName:self.mainSession.myUser.displayname]; + NSString *avatarThumbURL = nil; + if (self.mainSession.myUser.avatarUrl) + { + // Suppose this url is a matrix content uri, we use SDK to get the well adapted thumbnail from server + avatarThumbURL = [self.mainSession.matrixRestClient urlOfContentThumbnail:self.mainSession.myUser.avatarUrl toFitViewSize:userPictureView.frame.size withMethod:MXThumbnailingMethodCrop]; + } + userPictureView.enableInMemoryCache = YES; + [userPictureView setImageURL:avatarThumbURL withType:nil andImageOrientation:UIImageOrientationUp previewImage:preview]; + [userPictureView.layer setCornerRadius:userPictureView.frame.size.width / 2]; + userPictureView.clipsToBounds = YES; + } // set extra area [self setRoomActivitiesViewClass:RoomActivitiesView.class]; @@ -233,7 +250,7 @@ [[AppDelegate theDelegate] showRoom:room.state.roomId withMatrixSession:self.mainSession]; } failure:^(NSError *error) { - NSLog(@"[Console RoomVC] Join roomAlias (%@) failed: %@", roomAlias, error); + NSLog(@"[Vector RoomVC] Join roomAlias (%@) failed: %@", roomAlias, error); //Alert user [[AppDelegate theDelegate] showErrorAsAlert:error]; }]; @@ -358,35 +375,22 @@ // Handle here user actions on bubbles for Vector app if (customizedRoomDataSource) { - if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnMessageTextView]) + if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnMessageTextView] || [actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnContentView]) { // Retrieve the tapped event MXEvent *tappedEvent = userInfo[kMXKRoomBubbleCellEventKey]; - // Update display of the visible table cell view - NSArray* cellArray = self.bubblesTableView.visibleCells; - // Check whether a selection already exist or not if (customizedRoomDataSource.selectedEventId) { - // Cancel the current selection - for (MXKRoomBubbleTableViewCell *tableViewCell in cellArray) - { - if (tableViewCell.blurred) - { - tableViewCell.blurred = NO; - } - else - { - [tableViewCell unselectComponent]; - } - } - - customizedRoomDataSource.selectedEventId = nil; + [self cancelEventSelection]; } else if (tappedEvent) { // Highlight this event in displayed message + + // Update display of the visible table cell view + NSArray* cellArray = self.bubblesTableView.visibleCells; // Blur all table cells, except the tapped one for (MXKRoomBubbleTableViewCell *tableViewCell in cellArray) @@ -418,21 +422,272 @@ else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnOverlayContainer]) { // Cancel the current event selection - NSArray* cellArray = self.bubblesTableView.visibleCells; + [self cancelEventSelection]; + } + else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellVectorEditButtonPressed]) + { + [self dismissKeyboard]; - for (MXKRoomBubbleTableViewCell *tableViewCell in cellArray) + MXEvent *selectedEvent = userInfo[kMXKRoomBubbleCellEventKey]; + MXKRoomBubbleTableViewCell *roomBubbleTableViewCell = (MXKRoomBubbleTableViewCell *)cell; + MXKAttachment *attachment = roomBubbleTableViewCell.bubbleData.attachment; + + if (selectedEvent) { - if (tableViewCell.blurred) + if (self.currentAlert) { - tableViewCell.blurred = NO; + [self.currentAlert dismiss:NO]; + self.currentAlert = nil; + } + + __weak __typeof(self) weakSelf = self; + self.currentAlert = [[MXKAlert alloc] initWithTitle:nil message:nil style:MXKAlertStyleActionSheet]; + + // Add actions for a failed event + if (selectedEvent.mxkState == MXKEventStateSendingFailed) + { + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_resend", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + // Let the datasource resend. It will manage local echo, etc. + [strongSelf.roomDataSource resendEventWithEventId:selectedEvent.eventId success:nil failure:nil]; + + }]; + + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_delete", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + [strongSelf.roomDataSource removeEventWithEventId:selectedEvent.eventId]; + }]; + } + + // Add actions for text message + if (!attachment) + { + // Retrieved data related to the selected event + NSArray *components = roomBubbleTableViewCell.bubbleData.bubbleComponents; + MXKRoomBubbleComponent *selectedComponent; + for (selectedComponent in components) + { + if ([selectedComponent.event.eventId isEqualToString:selectedEvent.eventId]) + { + break; + } + selectedComponent = nil; + } + + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_copy", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + [[UIPasteboard generalPasteboard] setString:selectedComponent.textMessage]; + + }]; + + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_share", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + NSArray *activityItems = [NSArray arrayWithObjects:selectedComponent.textMessage, nil]; + + UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil]; + activityViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; + + if (activityViewController) + { + [strongSelf presentViewController:activityViewController animated:YES completion:nil]; + } + + }]; + } + else // Add action for attachment + { + if (attachment.type == MXKAttachmentTypeImage || attachment.type == MXKAttachmentTypeVideo) + { + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_save", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + [strongSelf startActivityIndicator]; + + [attachment save:^{ + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopActivityIndicator]; + + } failure:^(NSError *error) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopActivityIndicator]; + + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + }]; + + // Start animation in case of download during attachment preparing + [roomBubbleTableViewCell startProgressUI]; + + }]; + } + + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_copy", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + [strongSelf startActivityIndicator]; + + [attachment copy:^{ + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopActivityIndicator]; + + } failure:^(NSError *error) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopActivityIndicator]; + + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + }]; + + // Start animation in case of download during attachment preparing + [roomBubbleTableViewCell startProgressUI]; + }]; + + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_share", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + [attachment prepareShare:^(NSURL *fileURL) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + strongSelf->documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:fileURL]; + [strongSelf->documentInteractionController setDelegate:strongSelf]; + strongSelf->currentSharedAttachment = attachment; + + if (![strongSelf->documentInteractionController presentOptionsMenuFromRect:strongSelf.view.frame inView:strongSelf.view animated:YES]) + { + strongSelf->documentInteractionController = nil; + [attachment onShareEnded]; + strongSelf->currentSharedAttachment = nil; + } + + } failure:^(NSError *error) { + + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + }]; + + // Start animation in case of download during attachment preparing + [roomBubbleTableViewCell startProgressUI]; + }]; + } + + // Check status of the selected event + if (selectedEvent.mxkState == MXKEventStateUploading) + { + // Upload id is stored in attachment url (nasty trick) + NSString *uploadId = roomBubbleTableViewCell.bubbleData.attachment.actualURL; + if ([MXKMediaManager existingUploaderWithId:uploadId]) + { + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_cancel_upload", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + // Get again the loader + MXKMediaLoader *loader = [MXKMediaManager existingUploaderWithId:uploadId]; + if (loader) + { + [loader cancel]; + } + // Hide the progress animation + roomBubbleTableViewCell.progressView.hidden = YES; + + }]; + } + } + else if (selectedEvent.mxkState != MXKEventStateSending && selectedEvent.mxkState != MXKEventStateSendingFailed) + { + // Check whether download is in progress + if (selectedEvent.isMediaAttachment) + { + NSString *cacheFilePath = roomBubbleTableViewCell.bubbleData.attachment.cacheFilePath; + if ([MXKMediaManager existingDownloaderWithOutputFilePath:cacheFilePath]) + { + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_cancel_download", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + // Get again the loader + MXKMediaLoader *loader = [MXKMediaManager existingDownloaderWithOutputFilePath:cacheFilePath]; + if (loader) + { + [loader cancel]; + } + // Hide the progress animation + roomBubbleTableViewCell.progressView.hidden = YES; + + }]; + } + } + + [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"room_event_action_redact", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + [strongSelf startActivityIndicator]; + + [strongSelf.roomDataSource.room redactEvent:selectedEvent.eventId reason:nil success:^{ + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopActivityIndicator]; + + } failure:^(NSError *error) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopActivityIndicator]; + + NSLog(@"[Vector RoomVC] Redact event (%@) failed: %@", selectedEvent.eventId, error); + //Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + + }]; + }]; + } + + self.currentAlert.cancelButtonIndex = [self.currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"cancel", @"Vector", nil) style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) { + + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf cancelEventSelection]; + + }]; + + // Do not display empty action sheet + if (self.currentAlert.cancelButtonIndex) + { + self.currentAlert.sourceView = roomBubbleTableViewCell; + [self.currentAlert showInViewController:self]; } else { - [tableViewCell unselectComponent]; + self.currentAlert = nil; } } - - customizedRoomDataSource.selectedEventId = nil; } else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellLongPressOnEvent]) { @@ -451,6 +706,31 @@ } } +- (void)cancelEventSelection +{ + if (self.currentAlert) + { + [self.currentAlert dismiss:NO]; + self.currentAlert = nil; + } + + // Cancel the current selection + NSArray* cellArray = self.bubblesTableView.visibleCells; + for (MXKRoomBubbleTableViewCell *tableViewCell in cellArray) + { + if (tableViewCell.blurred) + { + tableViewCell.blurred = NO; + } + else + { + [tableViewCell unselectComponent]; + } + } + + customizedRoomDataSource.selectedEventId = nil; +} + #pragma mark - Segues - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender diff --git a/Vector/ViewController/SettingsViewController.m b/Vector/ViewController/SettingsViewController.m index 000ff9210..ac35e1829 100644 --- a/Vector/ViewController/SettingsViewController.m +++ b/Vector/ViewController/SettingsViewController.m @@ -24,6 +24,9 @@ #import "AvatarGenerator.h" +#import +#import + #define SETTINGS_SECTION_SIGN_OUT_INDEX 0 #define SETTINGS_SECTION_USER_SETTINGS_INDEX 1 #define SETTINGS_SECTION_NOTIFICATIONS_SETTINGS_INDEX 2 @@ -1001,7 +1004,26 @@ - (void)mediaPickerController:(MediaPickerViewController *)mediaPickerController didSelectAssets:(NSArray *)assets { - // this method should not be called + if (assets.count > 0) + { + PHAsset* asset = [assets objectAtIndex:0]; + PHContentEditingInputRequestOptions *editOptions = [[PHContentEditingInputRequestOptions alloc] init]; + + [asset requestContentEditingInputWithOptions:editOptions + completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) { + + if (contentEditingInput.mediaType == PHAssetMediaTypeImage) + { + // Here the fullSizeImageURL is related to a local file path + NSData *data = [NSData dataWithContentsOfURL:contentEditingInput.fullSizeImageURL]; + UIImage *image = [UIImage imageWithData:data]; + + newAvatarImage = image; + [self.tableView reloadData]; + } + }]; + } + [self dismissMediaPicker]; } diff --git a/Vector/Views/RoomActivitiesView/RoomActivitiesView.h b/Vector/Views/RoomActivitiesView/RoomActivitiesView.h index 14843d4a5..b027e6406 100644 --- a/Vector/Views/RoomActivitiesView/RoomActivitiesView.h +++ b/Vector/Views/RoomActivitiesView/RoomActivitiesView.h @@ -22,6 +22,7 @@ */ @interface RoomActivitiesView : MXKRoomActivitiesView +@property (weak, nonatomic) IBOutlet UIView *separatorView; @property (weak, nonatomic) IBOutlet UIImageView *typingImageView; @property (weak, nonatomic) IBOutlet UILabel *messageLabel; diff --git a/Vector/Views/RoomActivitiesView/RoomActivitiesView.m b/Vector/Views/RoomActivitiesView/RoomActivitiesView.m index 4c02cc5a5..10e050ade 100644 --- a/Vector/Views/RoomActivitiesView/RoomActivitiesView.m +++ b/Vector/Views/RoomActivitiesView/RoomActivitiesView.m @@ -35,11 +35,11 @@ { [super awakeFromNib]; - // Remove default toolbar background color - self.backgroundColor = [UIColor whiteColor]; + self.separatorView.backgroundColor = VECTOR_GREEN_COLOR; + self.messageLabel.textColor = VECTOR_TEXT_GRAY_COLOR; - self.typingImageView.backgroundColor = VECTOR_GREEN_COLOR; - self.typingImageView.layer.cornerRadius = self.typingImageView.frame.size.height / 2; +// self.typingImageView.backgroundColor = VECTOR_GREEN_COLOR; +// self.typingImageView.layer.cornerRadius = self.typingImageView.frame.size.height / 2; } diff --git a/Vector/Views/RoomActivitiesView/RoomActivitiesView.xib b/Vector/Views/RoomActivitiesView/RoomActivitiesView.xib index b452031fc..b97079ad0 100644 --- a/Vector/Views/RoomActivitiesView/RoomActivitiesView.xib +++ b/Vector/Views/RoomActivitiesView/RoomActivitiesView.xib @@ -8,14 +8,14 @@ - + - + - + @@ -23,19 +23,19 @@ - + - + - - + + - - - - - - + + + + + + - - + + @@ -70,11 +70,12 @@ + - + diff --git a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.m b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.m index 89e68b84a..1acfff6c9 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.m @@ -16,6 +16,15 @@ #import "RoomIncomingAttachmentBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomIncomingAttachmentBubbleCell +- (void)awakeFromNib +{ + [super awakeFromNib]; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; +} + @end diff --git a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.xib index 517714adf..5e2f9416b 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentBubbleCell.xib @@ -1,114 +1,84 @@ - + - + - + - + - - + - - - + - + - - - - - - - + + + + - - - + + - - - - - + + + - - + - @@ -175,7 +137,6 @@ - diff --git a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.h b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.h index 4844d96cd..50bc9219e 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.h +++ b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.h @@ -23,5 +23,6 @@ @property (weak, nonatomic) IBOutlet UIView *paginationTitleView; @property (weak, nonatomic) IBOutlet UILabel *paginationLabel; +@property (weak, nonatomic) IBOutlet UIView *paginationSeparatorView; @end diff --git a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m index a53445cc8..d2fbbdd56 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.m @@ -16,15 +16,27 @@ #import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomIncomingAttachmentWithPaginationTitleBubbleCell +- (void)awakeFromNib +{ + [super awakeFromNib]; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; + + self.paginationLabel.textColor = VECTOR_GREEN_COLOR; + self.paginationSeparatorView.backgroundColor = VECTOR_GREEN_COLOR; +} + - (void)render:(MXKCellData *)cellData { [super render:cellData]; if (self.bubbleData) { - self.paginationLabel.text = [self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO]; + self.paginationLabel.text = [[self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO] uppercaseString]; } } diff --git a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib index da644e81f..243f363a0 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib @@ -1,137 +1,109 @@ - + - + - + - + - + - - - - + - - - + - - + - - - + - + - - - - - - - - + + + + - - - - - + + + - - + + - - - + + - - + + - @@ -197,13 +161,13 @@ + - diff --git a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib index 84a26bd3c..45c94973b 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib @@ -1,23 +1,22 @@ - + - + - + - + - - + @@ -25,62 +24,43 @@ - - - - + - - + - - - - + + + @@ -123,7 +98,6 @@ - diff --git a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.m b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.m index fe99a5e6a..746be4da4 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.m @@ -16,6 +16,15 @@ #import "RoomIncomingTextMsgBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomIncomingTextMsgBubbleCell +- (void)awakeFromNib +{ + [super awakeFromNib]; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; +} + @end diff --git a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.xib index eebcd75e7..e2ba94f11 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgBubbleCell.xib @@ -1,127 +1,93 @@ - + - + - + - + - - + - - - + - - + + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - + - + - diff --git a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.h b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.h index e30efa145..8c1555f56 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.h +++ b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.h @@ -23,5 +23,6 @@ @property (weak, nonatomic) IBOutlet UIView *paginationTitleView; @property (weak, nonatomic) IBOutlet UILabel *paginationLabel; +@property (weak, nonatomic) IBOutlet UIView *paginationSeparatorView; @end diff --git a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m index 7393a02ce..5ccc3efaf 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.m @@ -16,15 +16,27 @@ #import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomIncomingTextMsgWithPaginationTitleBubbleCell +- (void)awakeFromNib +{ + [super awakeFromNib]; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; + + self.paginationLabel.textColor = VECTOR_GREEN_COLOR; + self.paginationSeparatorView.backgroundColor = VECTOR_GREEN_COLOR; +} + - (void)render:(MXKCellData *)cellData { [super render:cellData]; if (self.bubbleData) { - self.paginationLabel.text = [self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO]; + self.paginationLabel.text = [[self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO] uppercaseString]; } } diff --git a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib index ac6bb8c29..c9f423b4c 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib @@ -1,141 +1,109 @@ - + - + - + - + - - + + - - - - - - - - - - + + + + - - + - - - + - - + + - + - - - - - - + + + + - - + - - + - - - + + + - - - + + - - - - + + - @@ -146,11 +114,11 @@ - - - + + + + - diff --git a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib index 8376fe238..5b75858aa 100644 --- a/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib @@ -1,79 +1,58 @@ - + - + - + - + - - + - + - + - - - - - + - - + - + - diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.m b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.m index e817473a4..49a47576f 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.m @@ -16,12 +16,16 @@ #import "RoomOutgoingAttachmentBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomOutgoingAttachmentBubbleCell - (void)awakeFromNib { [super awakeFromNib]; self.readReceiptsAlignment = ReadReceiptAlignmentRight; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; } - (void)render:(MXKCellData *)cellData diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.xib index eba62bada..f9b803244 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentBubbleCell.xib @@ -1,23 +1,22 @@ - + - + - + - + - - + @@ -25,86 +24,64 @@ - - + - + - - - - - - - + + + + + + + - - - - + + + - - - - - - - - + + + + - - + + - - + - + - + diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h index 0777a4140..528ddc3bb 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h +++ b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h @@ -23,5 +23,6 @@ @property (weak, nonatomic) IBOutlet UIView *paginationTitleView; @property (weak, nonatomic) IBOutlet UILabel *paginationLabel; +@property (weak, nonatomic) IBOutlet UIView *paginationSeparatorView; @end diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m index 33ed8fbb5..168e5f305 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m @@ -16,12 +16,19 @@ #import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomOutgoingAttachmentWithPaginationTitleBubbleCell - (void)awakeFromNib { [super awakeFromNib]; self.readReceiptsAlignment = ReadReceiptAlignmentRight; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; + + self.paginationLabel.textColor = VECTOR_GREEN_COLOR; + self.paginationSeparatorView.backgroundColor = VECTOR_GREEN_COLOR; } - (void)render:(MXKCellData *)cellData @@ -30,7 +37,7 @@ if (self.bubbleData) { - self.paginationLabel.text = [self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO]; + self.paginationLabel.text = [[self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO] uppercaseString]; } } diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib index ef4c30f47..e69ff3660 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib @@ -1,44 +1,47 @@ - + - + - + - + - - + + - - - - - - - + + + + - - + @@ -46,86 +49,64 @@ - - + - + - - - - - - + + + + + - - - - - - - + + + + - - - - - - - - - + + + + + + - + - + + + - - + - - + + - - + + - - + + + diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib index 00a6d7344..877b502d1 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib @@ -1,86 +1,69 @@ - + - + - + - + - - + - + - + - - - - - - - + + - - - - + + + - - - - - + + + + - + + - - + - + - + diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.m b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.m index 8841a746a..9e119257c 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.m @@ -16,12 +16,16 @@ #import "RoomOutgoingTextMsgBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomOutgoingTextMsgBubbleCell - (void)awakeFromNib { [super awakeFromNib]; self.readReceiptsAlignment = ReadReceiptAlignmentRight; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; } @end \ No newline at end of file diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.xib index 5c1075b02..1ba33fe74 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgBubbleCell.xib @@ -1,23 +1,22 @@ - + - + - + - + - - + @@ -25,91 +24,69 @@ - - + - - + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - + + + + - - - + + - + - + diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h index 75802d3de..4ad6deea0 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h +++ b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h @@ -23,5 +23,6 @@ @property (weak, nonatomic) IBOutlet UIView *paginationTitleView; @property (weak, nonatomic) IBOutlet UILabel *paginationLabel; +@property (weak, nonatomic) IBOutlet UIView *paginationSeparatorView; @end diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m index 9327ceafb..945562ea6 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m +++ b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m @@ -16,12 +16,19 @@ #import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h" +#import "VectorDesignValues.h" + @implementation RoomOutgoingTextMsgWithPaginationTitleBubbleCell - (void)awakeFromNib { [super awakeFromNib]; self.readReceiptsAlignment = ReadReceiptAlignmentRight; + + self.userNameLabel.textColor = VECTOR_TEXT_BLACK_COLOR; + + self.paginationLabel.textColor = VECTOR_GREEN_COLOR; + self.paginationSeparatorView.backgroundColor = VECTOR_GREEN_COLOR; } - (void)render:(MXKCellData *)cellData @@ -30,7 +37,7 @@ if (self.bubbleData) { - self.paginationLabel.text = [self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO]; + self.paginationLabel.text = [[self.bubbleData.eventFormatter dateStringFromDate:self.bubbleData.date withTime:NO] uppercaseString]; } } diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib index 6be961c9f..b1098b63e 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib @@ -1,45 +1,47 @@ - + - + - + - + - - + + - - - - - - - - + + + + - - + @@ -47,96 +49,75 @@ - - + - - + + - + - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + - - + + - - - + + - - + + - - - + + + + diff --git a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib index fd3555745..9b9992ef7 100644 --- a/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib +++ b/Vector/Views/RoomBubbleList/RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib @@ -1,87 +1,66 @@ - + - + - + - + - - + - - + + - + - - - - - - - + + + + - - - - + - - + + - - + - + diff --git a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.h b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.h index 4f76cf83e..96b3af4df 100644 --- a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.h +++ b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.h @@ -25,6 +25,11 @@ @interface RoomInputToolbarView : MXKRoomInputToolbarViewWithHPGrowingText @property (weak, nonatomic) IBOutlet UIView *mainToolbarView; + +@property (weak, nonatomic) IBOutlet UIView *separatorView; +@property (strong, nonatomic) IBOutlet MXKImageView *pictureView; + +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainToolbarMinHeightConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainToolbarHeightConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageComposerContainerTrailingConstraint; diff --git a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m index 228791aa6..7bebf8e99 100644 --- a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m +++ b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m @@ -16,6 +16,8 @@ #import "RoomInputToolbarView.h" +#import "VectorDesignValues.h" + #import #import @@ -52,22 +54,34 @@ [super awakeFromNib]; // Remove default toolbar background color - self.backgroundColor = [UIColor whiteColor]; + self.backgroundColor = [UIColor clearColor]; self.rightInputToolbarButton.hidden = YES; + + self.separatorView.backgroundColor = VECTOR_LIGHT_GRAY_COLOR; + + // Custom the growingTextView display + growingTextView.layer.cornerRadius = 0; + growingTextView.layer.borderWidth = 0; + growingTextView.backgroundColor = [UIColor clearColor]; + + growingTextView.font = [UIFont systemFontOfSize:15]; + growingTextView.textColor = VECTOR_TEXT_BLACK_COLOR; + + self.placeholder = NSLocalizedStringFromTable(@"room_message_placeholder", @"Vector", nil); } #pragma mark - HPGrowingTextView delegate -- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView -{ - // The return sends the message rather than giving a carriage return. - [self onTouchUpInside:self.rightInputToolbarButton]; - - return NO; -} +//- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)hpGrowingTextView +//{ +// // The return sends the message rather than giving a carriage return. +// [self onTouchUpInside:self.rightInputToolbarButton]; +// +// return NO; +//} -- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView +- (void)growingTextViewDidChange:(HPGrowingTextView *)hpGrowingTextView { // Clean the carriage return added on return press if ([self.textMessage isEqualToString:@"\n"]) @@ -75,7 +89,7 @@ self.textMessage = nil; } - [super growingTextViewDidChange:growingTextView]; + [super growingTextViewDidChange:hpGrowingTextView]; if (self.rightInputToolbarButton.isEnabled && self.rightInputToolbarButton.isHidden) { @@ -95,18 +109,22 @@ } } -- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height +- (void)growingTextView:(HPGrowingTextView *)hpGrowingTextView willChangeHeight:(float)height { - // FIXME GFO: Check whether mainToolbarHeightConstraint can be removed. If yes, remove it and remove - // this overidden method, the original one should be fine. - // Update height of the main toolbar (message composer) - self.mainToolbarHeightConstraint.constant = height + (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant); + CGFloat updatedHeight = height + (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant); + + if (updatedHeight < self.mainToolbarMinHeightConstraint.constant) + { + updatedHeight = self.mainToolbarMinHeightConstraint.constant; + } + + self.mainToolbarHeightConstraint.constant = updatedHeight; // Update toolbar superview if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:heightDidChanged:completion:)]) { - [self.delegate roomInputToolbarView:self heightDidChanged:self.mainToolbarHeightConstraint.constant completion:nil]; + [self.delegate roomInputToolbarView:self heightDidChanged:updatedHeight completion:nil]; } } diff --git a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib index 4dca876d5..4ad6f40ab 100644 --- a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib +++ b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.xib @@ -9,31 +9,40 @@ - + - + - + - + + + + + + + + + + - + - + - + - + @@ -42,11 +51,11 @@