diff --git a/Vector.xcodeproj/project.pbxproj b/Vector.xcodeproj/project.pbxproj index a863cd896..498cbb54b 100644 --- a/Vector.xcodeproj/project.pbxproj +++ b/Vector.xcodeproj/project.pbxproj @@ -181,6 +181,7 @@ F09EE0081C5134BE0078712F /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F09EE0001C5134BE0078712F /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m */; }; F09EE0091C5134BE0078712F /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F09EE0011C5134BE0078712F /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib */; }; F0A1CD221B9F4BBA00F9C15C /* RoomParticipantsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0A1CD211B9F4BBA00F9C15C /* RoomParticipantsViewController.m */; }; + F0A2413A1CB7E28F00E150C3 /* RoomParticipantsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0A241391CB7E28F00E150C3 /* RoomParticipantsViewController.xib */; }; F0BE3DF01C6CE17200AC3111 /* RoomMemberDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0BE3DEF1C6CE17200AC3111 /* RoomMemberDetailsViewController.m */; }; F0BE3DF21C6CE28300AC3111 /* RoomMemberDetailsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0BE3DF11C6CE28300AC3111 /* RoomMemberDetailsViewController.xib */; }; F0C34B611C15C28300C36F09 /* RoomOutgoingAttachmentBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0C34B561C15C28300C36F09 /* RoomOutgoingAttachmentBubbleCell.m */; }; @@ -467,6 +468,7 @@ F09EE0011C5134BE0078712F /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib; sourceTree = ""; }; F0A1CD201B9F4BBA00F9C15C /* RoomParticipantsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomParticipantsViewController.h; sourceTree = ""; }; F0A1CD211B9F4BBA00F9C15C /* RoomParticipantsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomParticipantsViewController.m; sourceTree = ""; }; + F0A241391CB7E28F00E150C3 /* RoomParticipantsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomParticipantsViewController.xib; sourceTree = ""; }; F0BE3DEE1C6CE17200AC3111 /* RoomMemberDetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMemberDetailsViewController.h; sourceTree = ""; }; F0BE3DEF1C6CE17200AC3111 /* RoomMemberDetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMemberDetailsViewController.m; sourceTree = ""; }; F0BE3DF11C6CE28300AC3111 /* RoomMemberDetailsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomMemberDetailsViewController.xib; sourceTree = ""; }; @@ -916,6 +918,7 @@ 32D200871C16C2B100A4E396 /* HomeViewController.m */, F0A1CD201B9F4BBA00F9C15C /* RoomParticipantsViewController.h */, F0A1CD211B9F4BBA00F9C15C /* RoomParticipantsViewController.m */, + F0A241391CB7E28F00E150C3 /* RoomParticipantsViewController.xib */, F0CC4DC71C4E594C003BBE45 /* MediaAlbumContentViewController.h */, F0CC4DC81C4E594C003BBE45 /* MediaAlbumContentViewController.m */, F0CC4DC91C4E594C003BBE45 /* MediaAlbumContentViewController.xib */, @@ -1289,6 +1292,7 @@ F0026B561C916E68001D2C04 /* leave@2x.png in Resources */, F094AA2C1B78E42600B1FBBF /* Vector.strings in Resources */, F0F83FC11C93089500E7D322 /* video_icon.png in Resources */, + F0A2413A1CB7E28F00E150C3 /* RoomParticipantsViewController.xib in Resources */, F0026B521C916E68001D2C04 /* favouriteOff.png in Resources */, 32A887221C89B9580037DC17 /* SimpleRoomTitleView.xib in Resources */, F02528FD1C11B6FC00E1FE1B /* selection_untick.png in Resources */, diff --git a/Vector/Assets/en.lproj/Vector.strings b/Vector/Assets/en.lproj/Vector.strings index 9d4169158..8ffce9b9d 100644 --- a/Vector/Assets/en.lproj/Vector.strings +++ b/Vector/Assets/en.lproj/Vector.strings @@ -108,13 +108,13 @@ "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"; + "room_participants_active" = "Online"; -"room_participants_invite" = "Invite"; -"room_participants_leave" = "Left"; -"room_participants_ban" = "Banned"; "room_participants_active_less_1_hour" = "Offline"; "room_participants_active_less_x_hours" = "Offline %luh ago"; "room_participants_active_less_x_days" = "Offline %lu days ago"; +"room_participants_offline" = "Offline"; "room_participants_action_invite" = "Invite"; "room_participants_action_leave" = "Leave this room"; diff --git a/Vector/Utils/VectorDesignValues.h b/Vector/Utils/VectorDesignValues.h index c2ffe5a29..215a0cacb 100644 --- a/Vector/Utils/VectorDesignValues.h +++ b/Vector/Utils/VectorDesignValues.h @@ -29,7 +29,7 @@ extern UIColor *kVectorColorGreen; extern UIColor *kVectorColorLightGreen; extern UIColor *kVectorColorLightGrey; -extern UIColor *kVectorColorSiver; +extern UIColor *kVectorColorSilver; extern UIColor *kVectorColorOrange; #pragma mark - Vector Text Colors diff --git a/Vector/Utils/VectorDesignValues.m b/Vector/Utils/VectorDesignValues.m index daebf258f..101946f03 100644 --- a/Vector/Utils/VectorDesignValues.m +++ b/Vector/Utils/VectorDesignValues.m @@ -19,7 +19,7 @@ UIColor *kVectorColorGreen; UIColor *kVectorColorLightGreen; UIColor *kVectorColorLightGrey; -UIColor *kVectorColorSiver; +UIColor *kVectorColorSilver; UIColor *kVectorColorOrange; UIColor *kVectorTextColorBlack; @@ -43,7 +43,7 @@ NSInteger const kVectorRoomAdminLevel = 100; // Colors as defined by the design kVectorColorGreen = [UIColor colorWithRed:(98.0/255.0) green:(206.0/255.0) blue:(156.0/255.0) alpha:1.0]; kVectorColorLightGrey = [UIColor colorWithRed:(242.0 / 255.0) green:(242.0 / 255.0) blue:(242.0 / 255.0) alpha:1.0]; - kVectorColorSiver = [UIColor colorWithRed:(199.0 / 255.0) green:(199.0 / 255.0) blue:(204.0 / 255.0) alpha:1.0]; + kVectorColorSilver = [UIColor colorWithRed:(199.0 / 255.0) green:(199.0 / 255.0) blue:(204.0 / 255.0) alpha:1.0]; kVectorTextColorBlack = [UIColor colorWithRed:(60.0 / 255.0) green:(60.0 / 255.0) blue:(60.0 / 255.0) alpha:1.0]; kVectorTextColorRed = [UIColor colorWithRed:(255.0 / 255.0) green:(0.0 / 255.0) blue:(100.0 / 255.0) alpha:1.0]; diff --git a/Vector/ViewController/RoomMemberDetailsViewController.m b/Vector/ViewController/RoomMemberDetailsViewController.m index 3f62ca356..1abcd7a12 100644 --- a/Vector/ViewController/RoomMemberDetailsViewController.m +++ b/Vector/ViewController/RoomMemberDetailsViewController.m @@ -196,22 +196,7 @@ NSString* presenceText = nil; - if (self.mxRoomMember.membership != MXMembershipJoin) - { - if (self.mxRoomMember.membership == MXMembershipInvite) - { - presenceText = NSLocalizedStringFromTable(@"room_participants_invite", @"Vector", nil); - } - else if (self.mxRoomMember.membership == MXMembershipLeave) - { - presenceText = NSLocalizedStringFromTable(@"room_participants_leave", @"Vector", nil); - } - else if (self.mxRoomMember.membership == MXMembershipBan) - { - presenceText = NSLocalizedStringFromTable(@"room_participants_ban", @"Vector", nil); - } - } - else if (self.mxRoomMember.userId) + if (self.mxRoomMember.userId) { MXUser *user = [self.mxRoom.mxSession userWithUserId:self.mxRoomMember.userId]; if (user) diff --git a/Vector/ViewController/RoomParticipantsViewController.h b/Vector/ViewController/RoomParticipantsViewController.h index e998478a2..6ee53fc9d 100644 --- a/Vector/ViewController/RoomParticipantsViewController.h +++ b/Vector/ViewController/RoomParticipantsViewController.h @@ -22,10 +22,9 @@ /** 'RoomParticipantsViewController' instance is used to edit members of the room defined by the property 'mxRoom'. - - When this property is nil, the view controller is able to handle a list of participants without room reference. + When this property is nil, the view controller empty. */ -@interface RoomParticipantsViewController : MXKTableViewController +@interface RoomParticipantsViewController : MXKViewController { @protected /** @@ -37,12 +36,18 @@ Section indexes */ NSInteger searchResultSection; - NSInteger participantsSection; + NSInteger membersSection; + NSInteger invitedSection; /** - Mutable list of participants + The current list of joined members. */ - NSMutableArray *mutableParticipants; + NSMutableArray *actualMembers; + + /** + The current list of invited members. + */ + NSMutableArray *invitedMembers; /** Store MXKContact instance by matrix user id @@ -50,6 +55,11 @@ NSMutableDictionary *mxkContactsById; } +@property (weak, nonatomic) IBOutlet UITableView *tableView; +@property (weak, nonatomic) IBOutlet UIView *searchBarHeader; +@property (weak, nonatomic) IBOutlet UISearchBar *searchBarView; +@property (weak, nonatomic) IBOutlet UIView *searchBarHeaderBorder; + /** A matrix room (nil by default). */ @@ -65,14 +75,5 @@ */ @property (nonatomic) SegmentedViewController *segmentedViewController; - -/** - Customize the UITableViewCell before rendering it. - - @param contactCell the cell to customize. - @param indexPath path of the cell in the tableview. - */ -- (void)customizeContactCell:(ContactTableViewCell*)contactCell atIndexPath:(NSIndexPath *)indexPath; - @end diff --git a/Vector/ViewController/RoomParticipantsViewController.m b/Vector/ViewController/RoomParticipantsViewController.m index 46b93e130..0b4e76d34 100644 --- a/Vector/ViewController/RoomParticipantsViewController.m +++ b/Vector/ViewController/RoomParticipantsViewController.m @@ -30,10 +30,8 @@ @interface RoomParticipantsViewController () { - // Add participants section - MXKTableViewCellWithSearchBar *addParticipantsSearchBarCell; - NSString *addParticipantsSearchText; - + // Search session + NSString *currentSearchText; UIView* searchBarSeparator; // Search result section @@ -42,7 +40,7 @@ MXKAlert *currentAlert; // Mask view while processing a request - UIActivityIndicatorView * pendingMaskSpinnerView; + UIActivityIndicatorView *pendingMaskSpinnerView; // The members events listener. id membersListener; @@ -57,17 +55,6 @@ @implementation RoomParticipantsViewController -- (void)setNavBarButtons -{ - // this viewController can be displayed - // 1- with a "standard" push mode - // 2- within a segmentedViewController i.e. inside another viewcontroller - // so, we need to use the parent controller when it is required. - UIViewController* topViewController = (self.parentViewController) ? self.parentViewController : self; - topViewController.navigationItem.rightBarButtonItem = nil; - topViewController.navigationItem.leftBarButtonItem = nil; -} - - (void)viewDidLoad { [super viewDidLoad]; @@ -87,31 +74,34 @@ [self addMatrixSession:mxSession]; } - addParticipantsSearchBarCell = [[MXKTableViewCellWithSearchBar alloc] init]; - addParticipantsSearchBarCell.contentView.backgroundColor = [UIColor whiteColor]; - addParticipantsSearchBarCell.mxkSearchBar.searchBarStyle = UISearchBarStyleMinimal; - addParticipantsSearchBarCell.mxkSearchBar.returnKeyType = UIReturnKeyDone; - addParticipantsSearchBarCell.mxkSearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone; - addParticipantsSearchBarCell.mxkSearchBar.delegate = self; - addParticipantsSearchBarCell.mxkSearchBar.placeholder = NSLocalizedStringFromTable(@"room_participants_invite_another_user", @"Vector", nil); - [self refreshSearchBarItemsColor:addParticipantsSearchBarCell.mxkSearchBar]; - _isAddParticipantSearchBarEditing = NO; - if (! mutableParticipants) + if (!actualMembers) { - mutableParticipants = [NSMutableArray array]; + actualMembers = [NSMutableArray array]; + } + if (!invitedMembers) + { + invitedMembers = [NSMutableArray array]; } - if (! mxkContactsById) + if (!mxkContactsById) { mxkContactsById = [NSMutableDictionary dictionary]; } - - // ensure that the separator line is not displayed - self.tableView.separatorColor = [UIColor clearColor]; - self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; + + _searchBarView.placeholder = NSLocalizedStringFromTable(@"room_participants_invite_another_user", @"Vector", nil); + [self refreshSearchBarItemsColor:_searchBarView]; + + _searchBarHeaderBorder.backgroundColor = kVectorColorSilver; + + // Search bar header is hidden when no room is provided + _searchBarHeader.hidden = (self.mxRoom == nil); + [self setNavBarButtons]; + + // Hide line separators of empty cells + self.tableView.tableFooterView = [[UIView alloc] init]; } // this method is called when the viewcontroller is displayed inside another one. @@ -143,11 +133,11 @@ _mxRoom = nil; - addParticipantsSearchBarCell = nil; filteredParticipants = nil; mxkContactsById = nil; - mutableParticipants = nil; + actualMembers = nil; + invitedMembers = nil; if (currentAlert) { @@ -185,10 +175,7 @@ } // cancel any pending search - if (addParticipantsSearchBarCell.mxkSearchBar) - { - [self searchBarCancelButtonClicked:addParticipantsSearchBarCell.mxkSearchBar]; - } + [self searchBarCancelButtonClicked:_searchBarView]; } #pragma mark - @@ -246,7 +233,7 @@ MXRoomMember *mxMember = [self.mxRoom.state memberWithUserId:event.stateKey]; if (mxMember) { - [self addRoomMemberToParticipants:mxMember]; + [self handleRoomMember:mxMember]; } } @@ -271,33 +258,50 @@ } // Refresh participants display (if visible) - if (participantsSection != -1) + if (membersSection != -1 || invitedSection != -1) { - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange (participantsSection, 1)]; - [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; + [self.tableView reloadData]; } } }]; } + // Search bar header is hidden when no room is provided + _searchBarHeader.hidden = (self.mxRoom == nil); + [self.tableView reloadData]; } - (void)setIsAddParticipantSearchBarEditing:(BOOL)isAddParticipantsSearchBarEditing { - _isAddParticipantSearchBarEditing = isAddParticipantsSearchBarEditing; - - // Switch the display between search result and participants list - [self.tableView reloadData]; + if (_isAddParticipantSearchBarEditing != isAddParticipantsSearchBarEditing) + { + _isAddParticipantSearchBarEditing = isAddParticipantsSearchBarEditing; + + // Switch the display between search result and participants list + [self.tableView reloadData]; + } } #pragma mark - Internals +- (void)setNavBarButtons +{ + // this viewController can be displayed + // 1- with a "standard" push mode + // 2- within a segmentedViewController i.e. inside another viewcontroller + // so, we need to use the parent controller when it is required. + UIViewController* topViewController = (self.parentViewController) ? self.parentViewController : self; + topViewController.navigationItem.rightBarButtonItem = nil; + topViewController.navigationItem.leftBarButtonItem = nil; +} + - (void)refreshParticipantsFromRoomMembers { // Flush existing participants list - mutableParticipants = [NSMutableArray array]; + actualMembers = [NSMutableArray array]; + invitedMembers = [NSMutableArray array]; mxkContactsById = [NSMutableDictionary dictionary]; userMatrixId = nil; @@ -320,7 +324,7 @@ } else { - [self addRoomMemberToParticipants:mxMember]; + [self handleRoomMember:mxMember]; } } @@ -331,7 +335,7 @@ } } -- (void)addRoomMemberToParticipants:(MXRoomMember*)mxMember +- (void)handleRoomMember:(MXRoomMember*)mxMember { // Remove previous occurrence of this member (if any) [self removeParticipantByKey:mxMember.userId]; @@ -373,7 +377,7 @@ contact.mxMember = mxMember; [mxkContactsById setObject:contact forKey:mxMember.userId]; - [self addContactToParticipants:contact withKey:mxMember.userId isAdmin:isAdmin]; + [self handleContact:contact withKey:mxMember.userId isAdmin:isAdmin isInvited:(mxMember.membership == MXMembershipInvite)]; } } @@ -386,20 +390,23 @@ contact.isThirdPartyInvite = YES; mxkContactsById[roomThirdPartyInvite.token] = contact; - [self addContactToParticipants:contact withKey:roomThirdPartyInvite.token isAdmin:NO]; + [self handleContact:contact withKey:roomThirdPartyInvite.token isAdmin:NO isInvited:YES]; } } -- (void)addContactToParticipants:(Contact*)theContact withKey:(NSString*)key isAdmin:(BOOL)isAdmin +- (void)handleContact:(Contact*)contact withKey:(NSString*)key isAdmin:(BOOL)isAdmin isInvited:(BOOL)isInvited { + // Select the right array + NSMutableArray *memberIds = (isInvited ? invitedMembers : actualMembers); + // Add this participant (admin is in first position, the other are sorted in alphabetical order by trimming special character ('@', '_'...). NSUInteger index = 0; NSCharacterSet *specialCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"_!~`@#$%^&*-+();:={}[],.<>?\\/\"\'"]; - NSString *trimmedDisplayName = [theContact.displayName stringByTrimmingCharactersInSet:specialCharacterSet]; + NSString *trimmedDisplayName = [contact.displayName stringByTrimmingCharactersInSet:specialCharacterSet]; if (isAdmin) { // Check whether there is other admin - for (NSString *userId in mutableParticipants) + for (NSString *userId in memberIds) { if ([self.mxRoom.state memberNormalizedPowerLevel:userId] == 1) { @@ -409,7 +416,7 @@ NSString *trimmedContactName = [contact.displayName stringByTrimmingCharactersInSet:specialCharacterSet]; if (!trimmedContactName.length) { - if (trimmedDisplayName.length || [theContact.displayName compare:contact.displayName options:NSCaseInsensitiveSearch] != NSOrderedDescending) + if (trimmedDisplayName.length || [contact.displayName compare:contact.displayName options:NSCaseInsensitiveSearch] != NSOrderedDescending) { break; } @@ -425,7 +432,7 @@ } else { - for (NSString *userId in mutableParticipants) + for (NSString *userId in memberIds) { // Pass admin(s) if ([self.mxRoom.state memberNormalizedPowerLevel:userId] == 1) @@ -440,7 +447,7 @@ NSString *trimmedContactName = [contact.displayName stringByTrimmingCharactersInSet:specialCharacterSet]; if (!trimmedContactName.length) { - if (trimmedDisplayName.length || [theContact.displayName compare:contact.displayName options:NSCaseInsensitiveSearch] != NSOrderedDescending) + if (trimmedDisplayName.length || [contact.displayName compare:contact.displayName options:NSCaseInsensitiveSearch] != NSOrderedDescending) { break; } @@ -456,19 +463,30 @@ } // Add this participant - [mutableParticipants insertObject:key atIndex:index]; + [memberIds insertObject:key atIndex:index]; } // key is a room member user id or a room 3pid invite token - (void)removeParticipantByKey:(NSString*)key { - if (mutableParticipants.count) + if (actualMembers.count) { - NSUInteger index = [mutableParticipants indexOfObject:key]; + NSUInteger index = [actualMembers indexOfObject:key]; if (index != NSNotFound) { [mxkContactsById removeObjectForKey:key]; - [mutableParticipants removeObjectAtIndex:index]; + [actualMembers removeObjectAtIndex:index]; + return; + } + } + + if (invitedMembers.count) + { + NSUInteger index = [invitedMembers indexOfObject:key]; + if (index != NSNotFound) + { + [mxkContactsById removeObjectForKey:key]; + [invitedMembers removeObjectAtIndex:index]; } } } @@ -503,7 +521,7 @@ { NSInteger count = 0; - searchResultSection = participantsSection = -1; + searchResultSection = membersSection = invitedSection = -1; if (_isAddParticipantSearchBarEditing) { @@ -511,7 +529,15 @@ } else { - participantsSection = count++; + if (userMatrixId || actualMembers.count) + { + membersSection = count++; + } + + if (invitedMembers.count) + { + invitedSection = count++; + } } return count; @@ -525,134 +551,126 @@ { count = filteredParticipants.count; } - else if (section == participantsSection) + else if (section == membersSection) { - count = mutableParticipants.count; + count = actualMembers.count; if (userMatrixId) { count++; } } + else if (section == invitedSection) + { + count = invitedMembers.count; + } return count; } -- (void)customizeContactCell:(ContactTableViewCell*)contactCell atIndexPath:(NSIndexPath*) indexPath -{ - // TODO by the inherited class -} - - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - UITableViewCell *cell = nil; + ContactTableViewCell* participantCell = [tableView dequeueReusableCellWithIdentifier:[ContactTableViewCell defaultReuseIdentifier]]; - if ((indexPath.section == searchResultSection) || (indexPath.section == participantsSection)) + if (!participantCell) { - ContactTableViewCell* participantCell = [tableView dequeueReusableCellWithIdentifier:[ContactTableViewCell defaultReuseIdentifier]]; + participantCell = [[ContactTableViewCell alloc] init]; + } + else + { + // Restore default values + participantCell.accessoryView = nil; + participantCell.contentView.alpha = 1; + participantCell.userInteractionEnabled = YES; + } + + participantCell.mxRoom = self.mxRoom; + + Contact *contact = nil; + + // oneself dedicated cell + if ((indexPath.section == membersSection && userMatrixId && indexPath.row == 0)) + { + contact = [mxkContactsById objectForKey:userMatrixId]; - if (!participantCell) + if (!contact) { - participantCell = [[ContactTableViewCell alloc] init]; - } - else - { - // Restore default values - participantCell.accessoryView = nil; - participantCell.contentView.alpha = 1; - participantCell.userInteractionEnabled = YES; - } - - participantCell.mxRoom = self.mxRoom; - - Contact *contact = nil; - - // oneself dedicated cell - if ((indexPath.section == participantsSection && userMatrixId && indexPath.row == 0)) - { - contact = [mxkContactsById objectForKey:userMatrixId]; + // Check whether user is admin + BOOL isAdmin = ([self.mxRoom.state memberNormalizedPowerLevel:userMatrixId] == 1); - if (!contact) + NSString *displayName = NSLocalizedStringFromTable(@"you", @"Vector", nil); + if (isAdmin) { - // Check whether user is admin - BOOL isAdmin = ([self.mxRoom.state memberNormalizedPowerLevel:userMatrixId] == 1); - - NSString *displayName = NSLocalizedStringFromTable(@"you", @"Vector", nil); - if (isAdmin) - { - displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_participants_admin_name", @"Vector", nil), displayName]; - } - - contact = [[Contact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:userMatrixId]; - contact.mxMember = [self.mxRoom.state memberWithUserId:userMatrixId]; - [mxkContactsById setObject:contact forKey:userMatrixId]; + displayName = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_participants_admin_name", @"Vector", nil), displayName]; } + + contact = [[Contact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:userMatrixId]; + contact.mxMember = [self.mxRoom.state memberWithUserId:userMatrixId]; + [mxkContactsById setObject:contact forKey:userMatrixId]; } - else if (indexPath.section == searchResultSection) + + participantCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + else if (indexPath.section == searchResultSection) + { + contact = filteredParticipants[indexPath.row]; + + participantCell.selectionStyle = UITableViewCellSelectionStyleDefault; + } + else + { + NSInteger index = indexPath.row; + NSArray *memberIds; + + if (indexPath.section == membersSection) { - contact = filteredParticipants[indexPath.row]; - } - else - { - NSInteger index = indexPath.row; + memberIds = actualMembers; if (userMatrixId) { index --; } + } + else + { + memberIds = invitedMembers; + } + + if (index < memberIds.count) + { + NSString *userId = memberIds[index]; + contact = [mxkContactsById objectForKey:userId]; - if (index < mutableParticipants.count) + if (!contact) { - NSString *userId = mutableParticipants[index]; - contact = [mxkContactsById objectForKey:userId]; - - if (!contact) + // Create this missing contact + // Look for the corresponding MXUser + NSArray *sessions = self.mxSessions; + MXUser *mxUser; + for (MXSession *session in sessions) { - // Create this missing contact - // Look for the corresponding MXUser - NSArray *sessions = self.mxSessions; - MXUser *mxUser; - for (MXSession *session in sessions) + mxUser = [session userWithUserId:userId]; + if (mxUser) { - mxUser = [session userWithUserId:userId]; - if (mxUser) - { - contact = [[Contact alloc] initMatrixContactWithDisplayName:((mxUser.displayname.length > 0) ? mxUser.displayname : userId) andMatrixID:userId]; - contact.mxMember = [self.mxRoom.state memberWithUserId:userId]; - break; - } + contact = [[Contact alloc] initMatrixContactWithDisplayName:((mxUser.displayname.length > 0) ? mxUser.displayname : userId) andMatrixID:userId]; + contact.mxMember = [self.mxRoom.state memberWithUserId:userId]; + break; } - - if (contact) - { - [mxkContactsById setObject:contact forKey:userId]; - } - + } + + if (contact) + { + [mxkContactsById setObject:contact forKey:userId]; } } } - if (indexPath.section == searchResultSection) - { - participantCell.selectionStyle = UITableViewCellSelectionStyleDefault; - participantCell.bottomLineSeparator.hidden = ((indexPath.row+1) != filteredParticipants.count); - } - else - { - participantCell.selectionStyle = UITableViewCellSelectionStyleNone; - - if (userMatrixId) - { - participantCell.bottomLineSeparator.hidden = ((indexPath.row) != mutableParticipants.count); - } - else - { - participantCell.bottomLineSeparator.hidden = ((indexPath.row+1) != mutableParticipants.count); - } - } - - [self customizeContactCell:participantCell atIndexPath:indexPath]; + participantCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + if (contact) + { [participantCell 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 if (indexPath.section == searchResultSection) @@ -678,11 +696,9 @@ participantCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"plus_icon"]]; } } - - cell = participantCell; } - return cell; + return participantCell; } - (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath @@ -694,12 +710,26 @@ - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { - return addParticipantsSearchBarCell.contentView.frame.size.height; + if (section == invitedSection) + { + return 30.0; + } + return 0; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { - return addParticipantsSearchBarCell.contentView; + if (section == invitedSection) + { + UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 30)]; + + label.text = [NSString stringWithFormat:@" %@", NSLocalizedStringFromTable(@"room_participants_invited_section", @"Vector", nil)]; + label.font = [UIFont boldSystemFontOfSize:15.0]; + label.backgroundColor = kVectorColorLightGrey; + + return label; + } + return nil; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath @@ -709,6 +739,12 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + // Sanity check + if (!self.mxRoom) + { + return; + } + NSInteger row = indexPath.row; if (indexPath.section == searchResultSection) @@ -719,52 +755,48 @@ // Try to invite what he typed MXKContact *contact = filteredParticipants[row]; - // Invite this user if a room is defined - if (self.mxRoom) + // Invite this user + NSString *participantId = contact.displayName; + + // Is it an email or a Matrix user ID? + if ([MXTools isEmailAddress:participantId]) { - NSString *participantId = contact.displayName; - - // Is it an email or a Matrix user ID? - if ([MXTools isEmailAddress:participantId]) - { - [self addPendingActionMask]; - [self.mxRoom inviteUserByEmail:participantId success:^{ - - [self removePendingActionMask]; - - // Refresh display by leaving search session - [self searchBarCancelButtonClicked:addParticipantsSearchBarCell.mxkSearchBar]; - - } failure:^(NSError *error) { - - [self removePendingActionMask]; - - NSLog(@"[RoomParticipantsVC] Invite be email %@ failed", participantId); - // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; - }]; - } - else - { - [self addPendingActionMask]; - [self.mxRoom inviteUser:participantId success:^{ - - [self removePendingActionMask]; - - // Refresh display by leaving search session - [self searchBarCancelButtonClicked:addParticipantsSearchBarCell.mxkSearchBar]; - - } failure:^(NSError *error) { - - [self removePendingActionMask]; - - NSLog(@"[RoomParticipantsVC] Invite %@ failed", participantId); - // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; - }]; - } + [self addPendingActionMask]; + [self.mxRoom inviteUserByEmail:participantId success:^{ + + [self removePendingActionMask]; + + // Refresh display by leaving search session + [self searchBarCancelButtonClicked:_searchBarView]; + + } failure:^(NSError *error) { + + [self removePendingActionMask]; + + NSLog(@"[RoomParticipantsVC] Invite be email %@ failed", participantId); + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; + } + else + { + [self addPendingActionMask]; + [self.mxRoom inviteUser:participantId success:^{ + + [self removePendingActionMask]; + + // Refresh display by leaving search session + [self searchBarCancelButtonClicked:_searchBarView]; + + } failure:^(NSError *error) { + + [self removePendingActionMask]; + + NSLog(@"[RoomParticipantsVC] Invite %@ failed", participantId); + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; } - // TODO handle here the case where self.mxRoom is undefined. } else if (row < filteredParticipants.count) { @@ -779,87 +811,83 @@ [mxkContactsById setObject:contact forKey:participantId]; // Invite this user if a room is defined - if (self.mxRoom) - { - [self addPendingActionMask]; - [self.mxRoom inviteUser:participantId success:^{ + [self addPendingActionMask]; + [self.mxRoom inviteUser:participantId success:^{ + + [self removePendingActionMask]; - [self removePendingActionMask]; - - // Refresh display by leaving search session - [self searchBarCancelButtonClicked:addParticipantsSearchBarCell.mxkSearchBar]; - - } failure:^(NSError *error) { - - [self removePendingActionMask]; - - NSLog(@"[RoomParticipantsVC] Invite %@ failed", participantId); - // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; - }]; - } - else - { - // Update here the mutable list of participants - [mutableParticipants addObject:participantId]; // Refresh display by leaving search session - [self searchBarCancelButtonClicked:addParticipantsSearchBarCell.mxkSearchBar]; - } + [self searchBarCancelButtonClicked:_searchBarView]; + + } failure:^(NSError *error) { + + [self removePendingActionMask]; + + NSLog(@"[RoomParticipantsVC] Invite %@ failed", participantId); + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; } else { // This is a local email contact NSString *emailAddress = contact.displayName; - // Invite this user if a room is defined - if (self.mxRoom) + // Sanity check + if ([MXTools isEmailAddress:emailAddress]) { - // Sanity check - if ([MXTools isEmailAddress:emailAddress]) - { - [self addPendingActionMask]; - [self.mxRoom inviteUserByEmail:emailAddress success:^{ - - [self removePendingActionMask]; - - // Refresh display by leaving search session - [self searchBarCancelButtonClicked:addParticipantsSearchBarCell.mxkSearchBar]; - - } failure:^(NSError *error) { - - [self removePendingActionMask]; - - NSLog(@"[RoomParticipantsVC] Invite be email %@ failed", emailAddress); - // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; - }]; - } + // Invite this user if a room is defined + [self addPendingActionMask]; + [self.mxRoom inviteUserByEmail:emailAddress success:^{ + + [self removePendingActionMask]; + + // Refresh display by leaving search session + [self searchBarCancelButtonClicked:_searchBarView]; + + } failure:^(NSError *error) { + + [self removePendingActionMask]; + + NSLog(@"[RoomParticipantsVC] Invite be email %@ failed", emailAddress); + // Alert user + [[AppDelegate theDelegate] showErrorAsAlert:error]; + }]; } - // TODO handle here the case where self.mxRoom is undefined. } } } - else if (indexPath.section == participantsSection) + else { Contact *contact; // oneself dedicated cell - if (userMatrixId && indexPath.row == 0) + if (indexPath.section == membersSection && userMatrixId && indexPath.row == 0) { contact = [mxkContactsById objectForKey:userMatrixId]; } else { NSInteger index = indexPath.row; + NSArray *memberIds; - if (userMatrixId) + if (indexPath.section == membersSection) { - index --; + memberIds = actualMembers; + + if (userMatrixId) + { + index --; + } + } + else + { + memberIds = invitedMembers; } - if (index < mutableParticipants.count) + if (index < memberIds.count) { - NSString *userId = mutableParticipants[index]; + NSString *userId = memberIds[index]; contact = [mxkContactsById objectForKey:userId]; } } @@ -894,8 +922,8 @@ { NSMutableArray* actions = [[NSMutableArray alloc] init]; - // add the swipe to delete on search and participants section - if (indexPath.section == participantsSection) + // add the swipe to delete only on participants sections + if (indexPath.section == membersSection || indexPath.section == invitedSection) { NSString* title = @" "; @@ -920,7 +948,7 @@ NSUInteger section = path.section; NSUInteger row = path.row; - if (section == participantsSection) + if (section == membersSection || section == invitedSection) { __weak typeof(self) weakSelf = self; @@ -930,7 +958,7 @@ currentAlert = nil; } - if (userMatrixId && (0 == row)) + if (section == membersSection && userMatrixId && (0 == row)) { // Leave ? currentAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil) @@ -981,14 +1009,25 @@ } else { - if (userMatrixId) + NSMutableArray *memberIds; + + if (section == membersSection) { - row --; + memberIds = actualMembers; + + if (userMatrixId) + { + row --; + } + } + else + { + memberIds = invitedMembers; } - if (row < mutableParticipants.count) + if (row < memberIds.count) { - NSString *memberUserId = mutableParticipants[row]; + NSString *memberUserId = memberIds[row]; MXKContact *contact = [mxkContactsById objectForKey:memberUserId]; // Kick ? @@ -1021,7 +1060,7 @@ [strongSelf removePendingActionMask]; [strongSelf->mxkContactsById removeObjectForKey:memberUserId]; - [strongSelf->mutableParticipants removeObjectAtIndex:row]; + [memberIds removeObjectAtIndex:row]; // Refresh display [strongSelf.tableView reloadData]; @@ -1122,7 +1161,7 @@ NSMutableArray *contacts; - if (addParticipantsSearchText.length && [searchText hasPrefix:addParticipantsSearchText]) + if (currentSearchText.length && [searchText hasPrefix:currentSearchText]) { contacts = filteredParticipants; } @@ -1150,7 +1189,7 @@ { for (NSString *userId in identifiers) { - if (!mutableParticipants || [mutableParticipants indexOfObject:userId] == NSNotFound) + if ([actualMembers indexOfObject:userId] == NSNotFound && [invitedMembers indexOfObject:userId] == NSNotFound) { if (![userId isEqualToString:userMatrixId]) { @@ -1164,7 +1203,7 @@ else if (identifiers.count) { NSString *userId = identifiers.firstObject; - if (!mutableParticipants || [mutableParticipants indexOfObject:userId] == NSNotFound) + if ([actualMembers indexOfObject:userId] == NSNotFound || [invitedMembers indexOfObject:userId] == NSNotFound) { if (![userId isEqualToString:userMatrixId]) { @@ -1174,7 +1213,7 @@ } } } - addParticipantsSearchText = searchText; + currentSearchText = searchText; filteredParticipants = [NSMutableArray array]; NSMutableArray *indexArray = [NSMutableArray array]; @@ -1191,7 +1230,7 @@ for (MXKContact* contact in contacts) { - if ([contact matchedWithPatterns:@[addParticipantsSearchText]]) + if ([contact matchedWithPatterns:@[currentSearchText]]) { [filteredParticipants addObject:contact]; [indexArray addObject:[NSIndexPath indexPathForRow:index++ inSection:0]]; @@ -1216,8 +1255,6 @@ [MXKAppSettings standardAppSettings].syncLocalContacts = YES; } - [self refreshSearchBarItemsColor:searchBar]; - return YES; } @@ -1236,7 +1273,7 @@ - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { - searchBar.text = addParticipantsSearchText = nil; + searchBar.text = currentSearchText = nil; filteredParticipants = nil; self.isAddParticipantSearchBarEditing = NO; diff --git a/Vector/ViewController/RoomParticipantsViewController.xib b/Vector/ViewController/RoomParticipantsViewController.xib new file mode 100644 index 000000000..d969c6347 --- /dev/null +++ b/Vector/ViewController/RoomParticipantsViewController.xib @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Vector/Views/Contact/ContactTableViewCell.h b/Vector/Views/Contact/ContactTableViewCell.h index d1f1594c8..705155e1a 100644 --- a/Vector/Views/Contact/ContactTableViewCell.h +++ b/Vector/Views/Contact/ContactTableViewCell.h @@ -28,8 +28,6 @@ @property (strong, nonatomic) IBOutlet MXKImageView *thumbnailView; @property (strong, nonatomic) IBOutlet UILabel *contactDisplayNameLabel; @property (weak, nonatomic) IBOutlet UILabel *lastPresenceLabel; -@property (weak, nonatomic) IBOutlet UIView *bottomLineSeparator; -@property (weak, nonatomic) IBOutlet UIView *topLineSeparator; @property (weak, nonatomic) IBOutlet UIView *customAccessoryView; @property (nonatomic) BOOL showCustomAccessoryView; diff --git a/Vector/Views/Contact/ContactTableViewCell.m b/Vector/Views/Contact/ContactTableViewCell.m index 5bee69628..845aee9ab 100644 --- a/Vector/Views/Contact/ContactTableViewCell.m +++ b/Vector/Views/Contact/ContactTableViewCell.m @@ -47,8 +47,6 @@ self.thumbnailView.clipsToBounds = YES; // apply the vector colours - self.bottomLineSeparator.backgroundColor = kVectorColorSiver; - self.topLineSeparator.backgroundColor = kVectorColorSiver; self.lastPresenceLabel.textColor = kVectorTextColorGray; } @@ -198,29 +196,8 @@ { NSString* presenceText = nil; NSString* matrixId = [self getFirstMatrixId]; - MXRoomMember* member = nil; - if (self.mxRoom && matrixId) - { - member = [self.mxRoom.state memberWithUserId:matrixId]; - } - - if (member && (member.membership != MXMembershipJoin)) - { - if (member.membership == MXMembershipInvite) - { - presenceText = NSLocalizedStringFromTable(@"room_participants_invite", @"Vector", nil); - } - else if (member.membership == MXMembershipLeave) - { - presenceText = NSLocalizedStringFromTable(@"room_participants_leave", @"Vector", nil); - } - else if (member.membership == MXMembershipBan) - { - presenceText = NSLocalizedStringFromTable(@"room_participants_ban", @"Vector", nil); - } - } - else if (matrixId) + if (matrixId) { MXUser *user = nil; @@ -268,7 +245,7 @@ } else if (contact.isThirdPartyInvite) { - presenceText = NSLocalizedStringFromTable(@"room_participants_invite", @"Vector", nil); + presenceText = NSLocalizedStringFromTable(@"room_participants_offline", @"Vector", nil); } self.lastPresenceLabel.text = presenceText; diff --git a/Vector/Views/Contact/ContactTableViewCell.xib b/Vector/Views/Contact/ContactTableViewCell.xib index 24d28534b..88777d516 100644 --- a/Vector/Views/Contact/ContactTableViewCell.xib +++ b/Vector/Views/Contact/ContactTableViewCell.xib @@ -1,8 +1,8 @@ - + - + @@ -14,20 +14,6 @@ - - - - - - - - - - - - - - @@ -76,24 +62,16 @@ - - - - - - - - diff --git a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m index c04407990..31efdd1ab 100644 --- a/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m +++ b/Vector/Views/RoomInputToolbar/RoomInputToolbarView.m @@ -63,7 +63,7 @@ self.rightInputToolbarButton.hidden = YES; - self.separatorView.backgroundColor = kVectorColorSiver; + self.separatorView.backgroundColor = kVectorColorSilver; // Custom the growingTextView display growingTextView.layer.cornerRadius = 0; diff --git a/Vector/Views/RoomList/RecentTableViewCell.m b/Vector/Views/RoomList/RecentTableViewCell.m index 9855c39f3..0e5019477 100644 --- a/Vector/Views/RoomList/RecentTableViewCell.m +++ b/Vector/Views/RoomList/RecentTableViewCell.m @@ -69,7 +69,7 @@ } else { - self.bingIndicator.backgroundColor = kVectorColorSiver; + self.bingIndicator.backgroundColor = kVectorColorSilver; self.lastEventDate.textColor = kVectorTextColorGray; } }