Fix Room members: Add a specific section INVITED

#132
This commit is contained in:
giomfo
2016-04-08 17:26:42 +02:00
parent eb2b2ffe0c
commit eef696b65c
13 changed files with 417 additions and 364 deletions
@@ -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)
@@ -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 <UISearchBarDelegate>
@interface RoomParticipantsViewController : MXKViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
{
@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
@@ -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;
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9532" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="RoomParticipantsViewController">
<connections>
<outlet property="searchBarHeader" destination="Zm7-AB-ZtE" id="6ee-P0-twi"/>
<outlet property="searchBarHeaderBorder" destination="gcy-W7-89G" id="tsy-SP-KaJ"/>
<outlet property="searchBarView" destination="bsq-3U-VjV" id="x3M-wX-RW8"/>
<outlet property="tableView" destination="kNf-Ll-jvH" id="uzM-uQ-peQ"/>
<outlet property="view" destination="iN0-l3-epB" id="csR-cn-S4h"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zm7-AB-ZtE">
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
<subviews>
<searchBar contentMode="redraw" searchBarStyle="minimal" translatesAutoresizingMaskIntoConstraints="NO" id="bsq-3U-VjV">
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
<textInputTraits key="textInputTraits" returnKeyType="done"/>
<connections>
<outlet property="delegate" destination="-1" id="UYv-bz-JBZ"/>
</connections>
</searchBar>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gcy-W7-89G">
<rect key="frame" x="0.0" y="43" width="600" height="1"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="Rka-an-qn3"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="gcy-W7-89G" firstAttribute="leading" secondItem="Zm7-AB-ZtE" secondAttribute="leading" id="4Yn-dN-O2U"/>
<constraint firstItem="bsq-3U-VjV" firstAttribute="leading" secondItem="Zm7-AB-ZtE" secondAttribute="leading" id="6ze-Az-ymf"/>
<constraint firstAttribute="bottom" secondItem="bsq-3U-VjV" secondAttribute="bottom" id="KDW-SI-sG6"/>
<constraint firstAttribute="trailing" secondItem="bsq-3U-VjV" secondAttribute="trailing" id="ZlE-SL-UfQ"/>
<constraint firstAttribute="trailing" secondItem="gcy-W7-89G" secondAttribute="trailing" id="hqD-vA-OM5"/>
<constraint firstAttribute="bottom" secondItem="gcy-W7-89G" secondAttribute="bottom" id="ibU-h7-mHt"/>
<constraint firstAttribute="height" constant="44" id="kSM-fg-IHB"/>
<constraint firstItem="bsq-3U-VjV" firstAttribute="top" secondItem="Zm7-AB-ZtE" secondAttribute="top" id="qpF-Za-XTL"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="onDrag" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="kNf-Ll-jvH">
<rect key="frame" x="0.0" y="44" width="600" height="556"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<connections>
<outlet property="dataSource" destination="-1" id="tlI-w1-VJw"/>
<outlet property="delegate" destination="-1" id="xcS-Zy-x2X"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Zm7-AB-ZtE" secondAttribute="trailing" id="0W7-Iv-Cs1"/>
<constraint firstAttribute="trailing" secondItem="kNf-Ll-jvH" secondAttribute="trailing" id="1KS-nO-Jys"/>
<constraint firstItem="Zm7-AB-ZtE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Irh-6y-0cw"/>
<constraint firstItem="kNf-Ll-jvH" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hfq-4u-4J8"/>
<constraint firstAttribute="bottom" secondItem="kNf-Ll-jvH" secondAttribute="bottom" id="jLY-ml-Psl"/>
<constraint firstItem="Zm7-AB-ZtE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="sUb-hD-qXJ"/>
<constraint firstItem="kNf-Ll-jvH" firstAttribute="top" secondItem="Zm7-AB-ZtE" secondAttribute="bottom" id="tYv-VV-8dI"/>
</constraints>
</view>
</objects>
</document>