diff --git a/Vector.xcodeproj/project.pbxproj b/Vector.xcodeproj/project.pbxproj index 0acaba6b5..049e4defa 100644 --- a/Vector.xcodeproj/project.pbxproj +++ b/Vector.xcodeproj/project.pbxproj @@ -209,6 +209,9 @@ F03DE2A51D0EFA6A00E8B65C /* AttachmentsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F03DE2A41D0EFA6A00E8B65C /* AttachmentsViewController.m */; }; F046528D1E250B0A00EA4E77 /* ContactsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F046528C1E250B0A00EA4E77 /* ContactsTableViewController.m */; }; F046528F1E28439E00EA4E77 /* ContactsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F046528E1E28439E00EA4E77 /* ContactsTableViewController.xib */; }; + F04652931E28E0E300EA4E77 /* add_participant.png in Resources */ = {isa = PBXBuildFile; fileRef = F04652901E28E0E300EA4E77 /* add_participant.png */; }; + F04652941E28E0E300EA4E77 /* add_participant@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F04652911E28E0E300EA4E77 /* add_participant@2x.png */; }; + F04652951E28E0E300EA4E77 /* add_participant@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F04652921E28E0E300EA4E77 /* add_participant@3x.png */; }; F047DBB51C576F2200952DA2 /* AuthenticationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F047DBB41C576F2200952DA2 /* AuthenticationViewController.xib */; }; F047DBB91C576F6600952DA2 /* AuthInputsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F047DBB71C576F6600952DA2 /* AuthInputsView.m */; }; F047DBBA1C576F6600952DA2 /* AuthInputsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F047DBB81C576F6600952DA2 /* AuthInputsView.xib */; }; @@ -644,6 +647,9 @@ F046528B1E250B0A00EA4E77 /* ContactsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsTableViewController.h; sourceTree = ""; }; F046528C1E250B0A00EA4E77 /* ContactsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsTableViewController.m; sourceTree = ""; }; F046528E1E28439E00EA4E77 /* ContactsTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactsTableViewController.xib; sourceTree = ""; }; + F04652901E28E0E300EA4E77 /* add_participant.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = add_participant.png; sourceTree = ""; }; + F04652911E28E0E300EA4E77 /* add_participant@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "add_participant@2x.png"; sourceTree = ""; }; + F04652921E28E0E300EA4E77 /* add_participant@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "add_participant@3x.png"; sourceTree = ""; }; F047DBB41C576F2200952DA2 /* AuthenticationViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AuthenticationViewController.xib; sourceTree = ""; }; F047DBB61C576F6600952DA2 /* AuthInputsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthInputsView.h; sourceTree = ""; }; F047DBB71C576F6600952DA2 /* AuthInputsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AuthInputsView.m; sourceTree = ""; }; @@ -1144,6 +1150,9 @@ F03BF5B41D8BF5B1002EF6A7 /* Images */ = { isa = PBXGroup; children = ( + F04652901E28E0E300EA4E77 /* add_participant.png */, + F04652911E28E0E300EA4E77 /* add_participant@2x.png */, + F04652921E28E0E300EA4E77 /* add_participant@3x.png */, F04ACE001E154C540000B970 /* riot_icon.png */, F04ACE011E154C540000B970 /* riot_icon@2x.png */, F04ACE021E154C540000B970 /* riot_icon@3x.png */, @@ -1793,6 +1802,7 @@ files = ( F0D2D9881C197DCB007B8C96 /* RoomIncomingTextMsgBubbleCell.xib in Resources */, F03BF6CB1D8BF5B1002EF6A7 /* settings_icon.png in Resources */, + F04652931E28E0E300EA4E77 /* add_participant.png in Resources */, F03BF6791D8BF5B1002EF6A7 /* chevron@3x.png in Resources */, F03BF64B1D8BF5B1002EF6A7 /* admin_icon@3x.png in Resources */, F09EAFB61DD2109B009C7EFB /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib in Resources */, @@ -1828,6 +1838,7 @@ 7165A25C1C05CD42003635D7 /* SegmentedViewController.xib in Resources */, F03BF65F1D8BF5B1002EF6A7 /* call_speaker_off_icon@2x.png in Resources */, F0A4B2F11E0073A30072D355 /* animatedLogo-1.png in Resources */, + F04652941E28E0E300EA4E77 /* add_participant@2x.png in Resources */, F03BF6B41D8BF5B1002EF6A7 /* priorityLow@2x.png in Resources */, F08294691DB503FE00CEAB63 /* direct_icon@2x.png in Resources */, F04ACE041E154C540000B970 /* riot_icon@2x.png in Resources */, @@ -1889,6 +1900,7 @@ F0BE3DF21C6CE28300AC3111 /* RoomMemberDetailsViewController.xib in Resources */, F09EAF9C1DD2109B009C7EFB /* RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.xib in Resources */, F023A0161D9034FE00C517FB /* call_video_mute_on_icon.png in Resources */, + F04652951E28E0E300EA4E77 /* add_participant@3x.png in Resources */, F03BF66A1D8BF5B1002EF6A7 /* camera_capture.png in Resources */, F0AF11F61D1029CF00FEE52F /* RoomIdOrAliasTableViewCell.xib in Resources */, F08714CC1DB9EFEE0075F633 /* directChatOff@3x.png in Resources */, diff --git a/Vector/Assets/Images/add_participant.png b/Vector/Assets/Images/add_participant.png new file mode 100755 index 000000000..1ec5cdeb1 Binary files /dev/null and b/Vector/Assets/Images/add_participant.png differ diff --git a/Vector/Assets/Images/add_participant@2x.png b/Vector/Assets/Images/add_participant@2x.png new file mode 100755 index 000000000..f9c99cef9 Binary files /dev/null and b/Vector/Assets/Images/add_participant@2x.png differ diff --git a/Vector/Assets/Images/add_participant@3x.png b/Vector/Assets/Images/add_participant@3x.png new file mode 100755 index 000000000..3e5df6479 Binary files /dev/null and b/Vector/Assets/Images/add_participant@3x.png differ diff --git a/Vector/Assets/en.lproj/Vector.strings b/Vector/Assets/en.lproj/Vector.strings index 0ec762f92..dea8cb022 100644 --- a/Vector/Assets/en.lproj/Vector.strings +++ b/Vector/Assets/en.lproj/Vector.strings @@ -95,7 +95,7 @@ "room_creation_keep_private" = "Keep private"; "room_creation_make_private" = "Make private"; "room_creation_wait_for_creation" = "A room is already being created. Please wait."; -"room_creation_invite_another_user" = "Search / invite by name, email, id"; +"room_creation_invite_another_user" = "Search / invite by User ID, Name or email"; // Room recents "room_recents_directory" = "DIRECTORY"; @@ -111,6 +111,8 @@ "search_messages" = "Messages"; "search_people" = "People"; "search_files" = "Files"; +"search_default_placeholder" = "Search..."; +"search_people_placeholder" = "Search by User ID, Name or email"; // Directory "directory_cell_title" = "Browse directory"; @@ -136,7 +138,7 @@ "room_participants_invite_prompt_title" = "Invite?"; "room_participants_invite_prompt_msg" = "Are you sure you want to invite %@ to this chat?"; "room_participants_filter_room_members" = "Filter room members"; -"room_participants_invite_another_user" = "Search / invite by name, email, id"; +"room_participants_invite_another_user" = "Search / invite by User ID, Name or email"; "room_participants_invite_malformed_id_title" = "Invite Error"; "room_participants_invite_malformed_id" = "Malformed ID. Should be an email address or a Matrix ID like '@localpart:domain'"; "room_participants_invited_section" = "INVITED"; diff --git a/Vector/ViewController/ContactsTableViewController.h b/Vector/ViewController/ContactsTableViewController.h index ca463b2a8..746caaea7 100644 --- a/Vector/ViewController/ContactsTableViewController.h +++ b/Vector/ViewController/ContactsTableViewController.h @@ -84,6 +84,18 @@ */ @property (nonatomic) BOOL forceMatrixIdInDisplayName; +/** + The type of standard accessory view the contact cells should use + Default is UITableViewCellAccessoryNone. + */ +@property (nonatomic) UITableViewCellAccessoryType contactCellAccessoryType; + +/** + An image used to create a custom accessy view on the right side of the contact cells. + If set, use custom view. ignore accessoryType + */ +@property (nonatomic) UIImage *contactCellAccessoryImage; + /** The dictionary of the ignored local contacts, the keys are their email. Empty by default. */ diff --git a/Vector/ViewController/ContactsTableViewController.m b/Vector/ViewController/ContactsTableViewController.m index d50c9f244..e75226c58 100644 --- a/Vector/ViewController/ContactsTableViewController.m +++ b/Vector/ViewController/ContactsTableViewController.m @@ -122,6 +122,8 @@ isMultiUseNameByDisplayName = nil; + _contactCellAccessoryImage = nil; + [super destroy]; } @@ -466,6 +468,8 @@ contactCell.accessoryView = nil; contactCell.contentView.alpha = 1; contactCell.userInteractionEnabled = YES; + contactCell.accessoryType = UITableViewCellAccessoryNone; + contactCell.accessoryView = nil; } MXKContact *contact; @@ -502,16 +506,17 @@ { [contactCell render:contact]; - // The search displays contacts to invite. Add a plus icon to the cell - // in order to make it more understandable for the end user + // The search displays contacts to invite. if (indexPath.section == filteredLocalContactsSection || indexPath.section == filteredMatrixContactsSection) { - contactCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"plus_icon"]]; + // Add the right accessory view if any + contactCell.accessoryType = self.contactCellAccessoryType; + contactCell.accessoryView = [[UIImageView alloc] initWithImage:self.contactCellAccessoryImage]; } else if (indexPath.section == searchInputSection) { // This is the text entered by the user - // Check whether the search input is a valid email or a Matrix user ID before adding the plus icon. + // Check whether the search input is a valid email or a Matrix user ID before adding the accessory view. if (![MXTools isEmailAddress:currentSearchText] && ![MXTools isMatrixUserIdentifier:currentSearchText]) { contactCell.contentView.alpha = 0.5; @@ -519,7 +524,9 @@ } else { - contactCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"plus_icon"]]; + // Add the right accessory view if any + contactCell.accessoryType = self.contactCellAccessoryType; + contactCell.accessoryView = [[UIImageView alloc] initWithImage:self.contactCellAccessoryImage]; } } } diff --git a/Vector/ViewController/HomeViewController.m b/Vector/ViewController/HomeViewController.m index 28f7c5b62..799d39f68 100644 --- a/Vector/ViewController/HomeViewController.m +++ b/Vector/ViewController/HomeViewController.m @@ -46,7 +46,7 @@ HomeFilesSearchViewController *filesSearchViewController; MXKSearchDataSource *filesSearchDataSource; - ContactsTableViewController *contactsViewController; + ContactsTableViewController *peopleSearchViewController; MXKContact *selectedContact; // Display a gradient view above the screen @@ -104,9 +104,10 @@ // Add search People tab [titles addObject: NSLocalizedStringFromTable(@"search_people", @"Vector", nil)]; - contactsViewController = [ContactsTableViewController contactsTableViewController]; - contactsViewController.contactsTableViewControllerDelegate = self; - [viewControllers addObject:contactsViewController]; + peopleSearchViewController = [ContactsTableViewController contactsTableViewController]; + peopleSearchViewController.contactsTableViewControllerDelegate = self; + peopleSearchViewController.contactCellAccessoryType = UITableViewCellAccessoryDisclosureIndicator; + [viewControllers addObject:peopleSearchViewController]; // add Files tab [titles addObject: NSLocalizedStringFromTable(@"search_files", @"Vector", nil)]; @@ -129,6 +130,7 @@ [self initializeDataSources]; self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone; + self.searchBar.placeholder = NSLocalizedStringFromTable(@"search_default_placeholder", @"Vector", nil); } - (void)dealloc @@ -511,9 +513,9 @@ { self.backgroundImageView.hidden = ((messagesSearchDataSource.serverCount != 0) || !messagesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0)); } - else if (self.selectedViewController == contactsViewController) + else if (self.selectedViewController == peopleSearchViewController) { - self.backgroundImageView.hidden = (([contactsViewController.tableView numberOfRowsInSection:0] != 0) || (self.keyboardHeight == 0)); + self.backgroundImageView.hidden = (([peopleSearchViewController.tableView numberOfRowsInSection:0] != 0) || (self.keyboardHeight == 0)); } else if (self.selectedViewController == filesSearchViewController) { @@ -546,6 +548,15 @@ if (!self.searchBarHidden) { + if (self.selectedViewController == peopleSearchViewController) + { + self.searchBar.placeholder = NSLocalizedStringFromTable(@"search_people_placeholder", @"Vector", nil); + } + else + { + self.searchBar.placeholder = NSLocalizedStringFromTable(@"search_default_placeholder", @"Vector", nil); + } + [self updateSearch]; } } @@ -1108,9 +1119,9 @@ }); } } - else if (self.selectedViewController == contactsViewController) + else if (self.selectedViewController == peopleSearchViewController) { - [contactsViewController searchWithPattern:self.searchBar.text forceReset:NO]; + [peopleSearchViewController searchWithPattern:self.searchBar.text forceReset:NO]; } else if (self.selectedViewController == filesSearchViewController) { @@ -1138,7 +1149,7 @@ { [messagesSearchDataSource searchMessages:nil force:NO]; } - [contactsViewController searchWithPattern:nil forceReset:NO]; + [peopleSearchViewController searchWithPattern:nil forceReset:NO]; if (filesSearchDataSource.searchText.length) { [filesSearchDataSource searchMessages:nil force:NO]; @@ -1157,7 +1168,7 @@ // As the public room search is local, it can be updated on each text change [self updateSearch]; } - else if (self.selectedViewController == contactsViewController) + else if (self.selectedViewController == peopleSearchViewController) { // As the contact search is local, it can be updated on each text change [self updateSearch]; diff --git a/Vector/ViewController/RoomParticipantsViewController.m b/Vector/ViewController/RoomParticipantsViewController.m index 16f5d8e42..64c87e7a4 100644 --- a/Vector/ViewController/RoomParticipantsViewController.m +++ b/Vector/ViewController/RoomParticipantsViewController.m @@ -495,7 +495,7 @@ addParticipantButtonImageView.backgroundColor = [UIColor clearColor]; addParticipantButtonImageView.contentMode = UIViewContentModeCenter; - addParticipantButtonImageView.image = [UIImage imageNamed:@"create_room"]; + addParticipantButtonImageView.image = [UIImage imageNamed:@"add_participant"]; CGFloat side = 78.0f; NSLayoutConstraint* widthConstraint = [NSLayoutConstraint constraintWithItem:addParticipantButtonImageView @@ -545,12 +545,14 @@ - (void)onAddParticipantButtonPressed { - // Push the contacts table screen. + // Push the contacts picker. contactsPickerViewController = [ContactsTableViewController contactsTableViewController]; // Set delegate to handle action on member (start chat, mention) contactsPickerViewController.contactsTableViewControllerDelegate = self; contactsPickerViewController.forceMatrixIdInDisplayName = YES; + // Add a plus icon to the contact cell in the contacts picker, in order to make it more understandable for the end user. + contactsPickerViewController.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"]; // List all the participants by their matrix user id, or a room 3pid invite token to ignore them during the contacts search. [contactsPickerViewController.ignoredContactsByMatrixId removeAllObjects]; diff --git a/Vector/ViewController/StartChatViewController.h b/Vector/ViewController/StartChatViewController.h index fa9d2ee05..4fbfe617f 100644 --- a/Vector/ViewController/StartChatViewController.h +++ b/Vector/ViewController/StartChatViewController.h @@ -19,7 +19,7 @@ /** 'StartChatViewController' instance is used to prepare new room creation. */ -@interface StartChatViewController : ContactsTableViewController +@interface StartChatViewController : ContactsTableViewController @property (weak, nonatomic) IBOutlet UIView *searchBarHeader; @property (weak, nonatomic) IBOutlet UISearchBar *searchBarView; diff --git a/Vector/ViewController/StartChatViewController.m b/Vector/ViewController/StartChatViewController.m index 32aac3af9..3f8b4a11c 100644 --- a/Vector/ViewController/StartChatViewController.m +++ b/Vector/ViewController/StartChatViewController.m @@ -67,6 +67,13 @@ // Prepare room participants participants = [NSMutableArray array]; + + // Assign itself as delegate + self.contactsTableViewControllerDelegate = self; + + // Add a plus icon to the contact cell when a search session is in progress, + // in order to make it more understandable for the end user. + self.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];; } - (void)viewDidLoad @@ -269,14 +276,14 @@ { NSInteger count = 0; - if (section == participantsSection) - { - count = participants.count + 1; - } - else + if (_isAddParticipantSearchBarEditing) { count = [super tableView:self.tableView numberOfRowsInSection:section]; } + else if (section == participantsSection) + { + count = participants.count + 1; + } return count; } @@ -285,7 +292,11 @@ { UITableViewCell *cell; - if (indexPath.section == participantsSection) + if (_isAddParticipantSearchBarEditing) + { + cell = [super tableView:self.tableView cellForRowAtIndexPath:indexPath]; + } + else if (indexPath.section == participantsSection) { ContactTableViewCell* participantCell = [tableView dequeueReusableCellWithIdentifier:@"ParticipantTableViewCellId" forIndexPath:indexPath]; @@ -317,10 +328,6 @@ cell = participantCell; } - else - { - cell = [super tableView:self.tableView cellForRowAtIndexPath:indexPath]; - } return cell; } @@ -345,7 +352,7 @@ { CGFloat height = 0.0; - if (section != participantsSection) + if (_isAddParticipantSearchBarEditing) { height = [super tableView:self.tableView heightForHeaderInSection:section]; } @@ -355,32 +362,15 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - NSInteger row = indexPath.row; - MXKContact *mxkContact; - - if (indexPath.section == searchInputSection) + if (_isAddParticipantSearchBarEditing) { - mxkContact = [[MXKContact alloc] initMatrixContactWithDisplayName:currentSearchText andMatrixID:nil]; + [super tableView:tableView didSelectRowAtIndexPath:indexPath]; } - else if (indexPath.section == filteredLocalContactsSection) + else { - mxkContact = filteredLocalContacts[row]; + // Do nothing + [tableView deselectRowAtIndexPath:indexPath animated:YES]; } - else if (indexPath.section == filteredMatrixContactsSection) - { - mxkContact = filteredMatrixContacts[row]; - } - - if (mxkContact) - { - // Update here the mutable list of participants - [participants addObject:mxkContact]; - - // Refresh display by leaving search session - [self searchBarCancelButtonClicked:_searchBarView]; - } - - [tableView deselectRowAtIndexPath:indexPath animated:YES]; } - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath @@ -648,4 +638,18 @@ [searchBar resignFirstResponder]; } +#pragma mark - ContactsTableViewControllerDelegate + +- (void)contactsTableViewController:(ContactsTableViewController *)contactsTableViewController didSelectContact:(MXKContact*)contact +{ + if (contact) + { + // Update here the mutable list of participants + [participants addObject:contact]; + } + + // Refresh display by leaving search session + [self searchBarCancelButtonClicked:_searchBarView]; +} + @end