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
+3 -3
View File
@@ -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";
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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];
@@ -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>
@@ -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;
+2 -25
View File
@@ -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;
+2 -24
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<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="9529"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@@ -14,20 +14,6 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="73"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KGN-cP-igr" userLabel="bottom separator">
<rect key="frame" x="13" y="73" width="587" height="1"/>
<color key="backgroundColor" red="1" green="0.42877345709999998" blue="0.42329320510000001" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="lUd-8E-WAj"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="AqX-al-ZBq" userLabel="top separator">
<rect key="frame" x="13" y="0.0" width="587" height="1"/>
<color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="hXb-Ib-cjB"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RX5-eD-c3c" userLabel="member avatar" customClass="MXKImageView">
<rect key="frame" x="13" y="15" width="42" height="42"/>
<color key="backgroundColor" white="0.89720269880000003" alpha="1" colorSpace="calibratedWhite"/>
@@ -76,24 +62,16 @@
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="KGN-cP-igr" firstAttribute="leading" secondItem="L2L-l5-wPx" secondAttribute="leading" constant="13" id="5Ts-MV-2Oe"/>
<constraint firstItem="AqX-al-ZBq" firstAttribute="top" secondItem="L2L-l5-wPx" secondAttribute="top" id="84t-i4-Nm1"/>
<constraint firstAttribute="trailing" secondItem="AqX-al-ZBq" secondAttribute="trailing" id="B9V-Y3-xKb"/>
<constraint firstItem="Ogo-Qt-u2C" firstAttribute="centerY" secondItem="L2L-l5-wPx" secondAttribute="centerY" id="LYX-FJ-cz3"/>
<constraint firstAttribute="trailing" secondItem="KGN-cP-igr" secondAttribute="trailing" id="P2b-NY-hCQ"/>
<constraint firstAttribute="trailing" secondItem="Ogo-Qt-u2C" secondAttribute="trailing" constant="13" id="cWl-2f-cvI"/>
<constraint firstAttribute="bottom" secondItem="KGN-cP-igr" secondAttribute="bottom" id="uIP-Xo-qav"/>
<constraint firstItem="AqX-al-ZBq" firstAttribute="leading" secondItem="L2L-l5-wPx" secondAttribute="leading" constant="13" id="wIj-F8-G1Q"/>
</constraints>
<connections>
<outlet property="bottomLineSeparator" destination="KGN-cP-igr" id="YUW-b2-GF8"/>
<outlet property="contactDisplayNameLabel" destination="Lg1-xQ-AGn" id="xKB-Pw-12c"/>
<outlet property="customAccessViewWidthConstraint" destination="pDU-SS-0mb" id="A22-tz-iIz"/>
<outlet property="customAccessoryView" destination="Ogo-Qt-u2C" id="Hec-bO-0Av"/>
<outlet property="customAccessoryViewLeadingConstraint" destination="cWl-2f-cvI" id="WSj-ru-Qxx"/>
<outlet property="lastPresenceLabel" destination="dQt-mN-T6b" id="FYZ-JD-0ck"/>
<outlet property="thumbnailView" destination="RX5-eD-c3c" id="GBi-K9-LhK"/>
<outlet property="topLineSeparator" destination="AqX-al-ZBq" id="jOZ-JS-FEQ"/>
</connections>
</tableViewCell>
</objects>
@@ -63,7 +63,7 @@
self.rightInputToolbarButton.hidden = YES;
self.separatorView.backgroundColor = kVectorColorSiver;
self.separatorView.backgroundColor = kVectorColorSilver;
// Custom the growingTextView display
growingTextView.layer.cornerRadius = 0;
+1 -1
View File
@@ -69,7 +69,7 @@
}
else
{
self.bingIndicator.backgroundColor = kVectorColorSiver;
self.bingIndicator.backgroundColor = kVectorColorSilver;
self.lastEventDate.textColor = kVectorTextColorGray;
}
}