Merge pull request #909 from vector-im/local_contacts_methods

Enhancement - Improve the people invite screens.
This commit is contained in:
giomfo 2017-01-09 09:40:13 +01:00 committed by GitHub
commit f3562b4a41
12 changed files with 309 additions and 191 deletions

View file

@ -210,6 +210,9 @@
F047DBB51C576F2200952DA2 /* AuthenticationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F047DBB41C576F2200952DA2 /* AuthenticationViewController.xib */; };
F047DBB91C576F6600952DA2 /* AuthInputsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F047DBB71C576F6600952DA2 /* AuthInputsView.m */; };
F047DBBA1C576F6600952DA2 /* AuthInputsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F047DBB81C576F6600952DA2 /* AuthInputsView.xib */; };
F04ACE031E154C540000B970 /* riot_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = F04ACE001E154C540000B970 /* riot_icon.png */; };
F04ACE041E154C540000B970 /* riot_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F04ACE011E154C540000B970 /* riot_icon@2x.png */; };
F04ACE051E154C540000B970 /* riot_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F04ACE021E154C540000B970 /* riot_icon@3x.png */; };
F056417B1C7C9FD7002276ED /* TableViewCellWithButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F05641791C7C9FD7002276ED /* TableViewCellWithButton.m */; };
F056417C1C7C9FD7002276ED /* TableViewCellWithButton.xib in Resources */ = {isa = PBXBuildFile; fileRef = F056417A1C7C9FD7002276ED /* TableViewCellWithButton.xib */; };
F05895001B8B7E6600B73E85 /* RoomBubbleCellData.m in Sources */ = {isa = PBXBuildFile; fileRef = F05894FF1B8B7E6600B73E85 /* RoomBubbleCellData.m */; };
@ -642,6 +645,9 @@
F047DBB61C576F6600952DA2 /* AuthInputsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthInputsView.h; sourceTree = "<group>"; };
F047DBB71C576F6600952DA2 /* AuthInputsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AuthInputsView.m; sourceTree = "<group>"; };
F047DBB81C576F6600952DA2 /* AuthInputsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AuthInputsView.xib; sourceTree = "<group>"; };
F04ACE001E154C540000B970 /* riot_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = riot_icon.png; sourceTree = "<group>"; };
F04ACE011E154C540000B970 /* riot_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "riot_icon@2x.png"; sourceTree = "<group>"; };
F04ACE021E154C540000B970 /* riot_icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "riot_icon@3x.png"; sourceTree = "<group>"; };
F05641781C7C9FD7002276ED /* TableViewCellWithButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewCellWithButton.h; path = TableViewCell/TableViewCellWithButton.h; sourceTree = "<group>"; };
F05641791C7C9FD7002276ED /* TableViewCellWithButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewCellWithButton.m; path = TableViewCell/TableViewCellWithButton.m; sourceTree = "<group>"; };
F056417A1C7C9FD7002276ED /* TableViewCellWithButton.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewCellWithButton.xib; path = TableViewCell/TableViewCellWithButton.xib; sourceTree = "<group>"; };
@ -1138,6 +1144,9 @@
F03BF5B41D8BF5B1002EF6A7 /* Images */ = {
isa = PBXGroup;
children = (
F04ACE001E154C540000B970 /* riot_icon.png */,
F04ACE011E154C540000B970 /* riot_icon@2x.png */,
F04ACE021E154C540000B970 /* riot_icon@3x.png */,
F0A4B2EB1E0073A30072D355 /* animatedLogo-0.png */,
F0A4B2EC1E0073A30072D355 /* animatedLogo-1.png */,
F0A4B2ED1E0073A30072D355 /* animatedLogo-2.png */,
@ -1747,7 +1756,6 @@
};
F094A9BD1B78D8F000B1FBBF = {
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 884E442RN2;
TestTargetID = F094A9A11B78D8F000B1FBBF;
};
};
@ -1815,6 +1823,7 @@
F0A4B2F11E0073A30072D355 /* animatedLogo-1.png in Resources */,
F03BF6B41D8BF5B1002EF6A7 /* priorityLow@2x.png in Resources */,
F08294691DB503FE00CEAB63 /* direct_icon@2x.png in Resources */,
F04ACE041E154C540000B970 /* riot_icon@2x.png in Resources */,
F09EAFA01DD2109B009C7EFB /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.xib in Resources */,
F09EAF0B1DCCEE1D009C7EFB /* e2e_verified@3x.png in Resources */,
F03BF6971D8BF5B1002EF6A7 /* leave@3x.png in Resources */,
@ -1942,6 +1951,7 @@
F09EAFA61DD2109B009C7EFB /* RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.xib in Resources */,
325F6A431C21D20F00C12F51 /* DirectoryRecentTableViewCell.xib in Resources */,
F03BF68C1D8BF5B1002EF6A7 /* favouriteOff.png in Resources */,
F04ACE031E154C540000B970 /* riot_icon.png in Resources */,
F003AA7C1C68A1F6008B430C /* ExpandedRoomTitleView.xib in Resources */,
F03BF6751D8BF5B1002EF6A7 /* camera_switch@3x.png in Resources */,
F03BF6D01D8BF5B1002EF6A7 /* shrink_icon@3x.png in Resources */,
@ -2006,6 +2016,7 @@
F0CC4DCB1C4E594C003BBE45 /* MediaAlbumContentViewController.xib in Resources */,
F0C34B721C15CA2E00C36F09 /* RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib in Resources */,
F022285E1C64E356000AF23C /* RoomViewController.xib in Resources */,
F04ACE051E154C540000B970 /* riot_icon@3x.png in Resources */,
F03BF6BF1D8BF5B1002EF6A7 /* search_bg.png in Resources */,
F03BF69B1D8BF5B1002EF6A7 /* main_alias_icon.png in Resources */,
F0A4B2F31E0073A30072D355 /* animatedLogo-3.png in Resources */,
@ -2400,7 +2411,7 @@
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = 884E442RN2;
DEVELOPMENT_TEAM = "";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
@ -2421,7 +2432,7 @@
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = 884E442RN2;
DEVELOPMENT_TEAM = "";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -562,7 +562,7 @@
directChatsIndex = sectionCount++;
}
// Else check whether the contact has been instantiated with an email or a matrix id
else if ([MXTools isEmailAddress:_contact.displayName])
else if ((!_contact.isMatrixContact && _contact.emailAddresses.count) || [MXTools isEmailAddress:_contact.displayName])
{
directChatsIndex = sectionCount++;
}
@ -878,7 +878,20 @@
// Prepare the invited participant data
NSArray *inviteArray;
NSArray *invite3PIDArray;
NSString *participantId = _contact.displayName;
NSString *participantId;
if (_contact.emailAddresses.count)
{
// This is a local contact, consider the first email by default.
// TODO: Prompt the user to select the right email.
MXKEmail *email = _contact.emailAddresses.firstObject;
participantId = email.emailAddress;
}
else
{
// This is the text filled by the user.
participantId = _contact.displayName;
}
// Is it an email or a Matrix user ID?
if ([MXTools isEmailAddress:participantId])
@ -908,7 +921,7 @@
invite3PIDArray = @[invite3PID];
}
else
else //if ([MXTools isMatrixUserIdentifier:participantId])
{
inviteArray = @[participantId];
}

View file

@ -152,18 +152,18 @@
- (void)refreshContactsList
{
// Retrieve all known matrix users
// Retrieve all the known matrix users
NSArray *contacts = [NSArray arrayWithArray:[MXKContactManager sharedManager].matrixContacts];
// Retrieve all known email addresses from local contacts
NSArray *localEmailContacts = [MXKContactManager sharedManager].localEmailContacts;
// Retrieve all the local contacts with methods
NSArray *localContactsWithMethods = [MXKContactManager sharedManager].localContactsWithMethods;
matrixContacts = [NSMutableArray arrayWithCapacity:(contacts.count + localEmailContacts.count)];
matrixContacts = [NSMutableArray arrayWithCapacity:(contacts.count + localContactsWithMethods.count)];
// Add first email contacts
if (localEmailContacts.count)
if (localContactsWithMethods.count)
{
[matrixContacts addObjectsFromArray:localEmailContacts];
[matrixContacts addObjectsFromArray:localContactsWithMethods];
}
if (contacts.count)
@ -330,16 +330,9 @@
}
// Disambiguate the display name when it appears several times.
if (contact.displayName && [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)])
if (contact.displayName)
{
NSArray *identifiers = contact.matrixIdentifiers;
if (identifiers.count)
{
NSString *participantId = identifiers.firstObject;
NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, participantId];
contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId];
}
participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)];
}
[participantCell render:contact];

View file

@ -16,8 +16,6 @@
#import <MatrixKit/MatrixKit.h>
#import "ContactTableViewCell.h"
#import "SegmentedViewController.h"
@class Contact;

View file

@ -30,6 +30,8 @@
#import "MXCallManager.h"
#import "ContactTableViewCell.h"
@interface RoomParticipantsViewController ()
{
// Search session
@ -67,6 +69,9 @@
// Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar.
id kAppDelegateDidTapStatusBarNotificationObserver;
// Observe kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification to refresh the search result on new matrix enabled contact.
id kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver;
}
@end
@ -418,6 +423,21 @@
{
_isAddParticipantSearchBarEditing = isAddParticipantsSearchBarEditing;
if (isAddParticipantsSearchBarEditing)
{
kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKContactManagerDidUpdateLocalContactMatrixIDsNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
// Refresh search result display.
[self.tableView reloadData];
}];
}
else if (kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver];
kMXKContactManagerDidUpdateLocalContactMatrixIDsNotificationObserver = nil;
}
// Switch the display between search result and participants list
[self.tableView reloadData];
}
@ -925,6 +945,8 @@
participantCell.userInteractionEnabled = YES;
participantCell.thumbnailBadgeView.hidden = YES;
participantCell.showMatrixIdInDisplayName = NO;
}
participantCell.mxRoom = self.mxRoom;
@ -932,7 +954,7 @@
MXKContact *mxkContact;
Contact* contact;
// oneself dedicated cell
// Oneself dedicated cell
if ((indexPath.section == participantsSection && userContact && indexPath.row == 0) && !_isAddParticipantSearchBarEditing)
{
contact = userContact;
@ -954,6 +976,7 @@
mxkContact = invitableAddressBookContacts[indexPath.row];
participantCell.selectionStyle = UITableViewCellSelectionStyleDefault;
participantCell.showMatrixIdInDisplayName = YES;
}
}
else if (indexPath.section == invitableSectionMatrixContacts)
@ -963,21 +986,7 @@
mxkContact = invitableMatrixContacts[indexPath.row];
participantCell.selectionStyle = UITableViewCellSelectionStyleDefault;
// Append the matrix identifier (if any) to the display name.
NSArray *identifiers = mxkContact.matrixIdentifiers;
if (identifiers.count)
{
NSString *participantId = identifiers.firstObject;
// Check whether the display name is not already the matrix id
if (![mxkContact.displayName isEqualToString:participantId])
{
NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", mxkContact.displayName, participantId];
mxkContact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId];
}
}
participantCell.showMatrixIdInDisplayName = YES;
}
}
else
@ -1016,40 +1025,14 @@
if (index < participants.count)
{
contact = participants[index];
// Sanity check
if (contact && contact.mxMember.userId)
{
// Disambiguate the display name when it appears several times.
NSString *disambiguatedDisplayName;
if (self.isAddParticipantSearchBarEditing)
{
// Consider here the dictionary which lists all the display names of the search result.
if ([isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)])
{
disambiguatedDisplayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, contact.mxMember.userId];
}
}
else
{
// Update the display name by considering the current room state.
disambiguatedDisplayName = [self.mxRoom.state memberName:contact.mxMember.userId];
if ([disambiguatedDisplayName isEqualToString:contact.displayName])
{
disambiguatedDisplayName = nil;
}
}
if (disambiguatedDisplayName)
{
MXRoomMember* mxMember = contact.mxMember;
contact = [[Contact alloc] initMatrixContactWithDisplayName:disambiguatedDisplayName andMatrixID:mxMember.userId];
contact.mxMember = mxMember;
}
}
mxkContact = contact;
// Disambiguate the display name when it appears several times in the search result.
if (self.isAddParticipantSearchBarEditing && contact.mxMember.userId)
{
// Consider here the dictionary which lists all the display names of the search result.
participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)];
}
}
participantCell.selectionStyle = UITableViewCellSelectionStyleNone;
@ -1094,6 +1077,12 @@
participantCell.thumbnailBadgeView.image = [UIImage imageNamed:@"mod_icon"];
participantCell.thumbnailBadgeView.hidden = NO;
}
// When no search is in progress, update the contact display name by considering the current room state.
if (!self.isAddParticipantSearchBarEditing && contact.mxMember.userId)
{
participantCell.contactDisplayNameLabel.text = [self.mxRoom.state memberName:contact.mxMember.userId];
}
}
}
@ -1484,9 +1473,11 @@
strongSelf->currentAlert = nil;
NSArray *identifiers = contact.matrixIdentifiers;
NSString *participantId;
if (identifiers.count)
{
NSString *participantId = identifiers.firstObject;
participantId = identifiers.firstObject;
// Invite this user if a room is defined
[strongSelf addPendingActionMask];
@ -1510,8 +1501,18 @@
}
else
{
// This is the text entered by the user, or a local email contact
NSString *participantId = contact.displayName;
if (contact.emailAddresses.count)
{
// This is a local contact, consider the first email by default.
// TODO: Prompt the user to select the right email.
MXKEmail *email = contact.emailAddresses.firstObject;
participantId = email.emailAddress;
}
else
{
// This is the text filled by the user.
participantId = contact.displayName;
}
// Is it an email or a Matrix user ID?
if ([MXTools isEmailAddress:participantId])
@ -1535,7 +1536,7 @@
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
else
else //if ([MXTools isMatrixUserIdentifier:participantId])
{
[strongSelf addPendingActionMask];
[strongSelf.mxRoom inviteUser:participantId success:^{
@ -1646,31 +1647,22 @@
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
// Update search results.
NSMutableArray<MXKContact*> *addressBookContacts;
NSMutableArray<MXKContact*> *matrixContacts;
NSMutableArray<Contact*> *participantsArray;
NSMutableArray<Contact*> *invitedParticipantsArray;
NSUInteger index;
MXKContact *contact;
searchText = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (currentSearchText.length && [searchText hasPrefix:currentSearchText])
if (!currentSearchText.length || [searchText hasPrefix:currentSearchText] == NO)
{
addressBookContacts = invitableAddressBookContacts;
matrixContacts = invitableMatrixContacts;
participantsArray = filteredActualParticipants;
invitedParticipantsArray = filteredInvitedParticipants;
}
else
{
// Retrieve all known email addresses from local contacts
addressBookContacts = [NSMutableArray arrayWithArray:[MXKContactManager sharedManager].localEmailContacts];
// Retrieve all the local contacts with emails
invitableAddressBookContacts = [NSMutableArray arrayWithArray:[MXKContactManager sharedManager].localContactsWithMethods];
// Retrieve all known matrix users
NSArray *allMatrixContacts = [MXKContactManager sharedManager].matrixContacts;
matrixContacts = [NSMutableArray arrayWithCapacity:allMatrixContacts.count];
invitableMatrixContacts = [NSMutableArray arrayWithCapacity:allMatrixContacts.count];
// Matrix ids: split contacts with several ids, and remove the current participants.
for (MXKContact* contact in allMatrixContacts)
for (contact in allMatrixContacts)
{
NSArray *identifiers = contact.matrixIdentifiers;
if (identifiers.count > 1)
@ -1680,7 +1672,7 @@
if ([contactsById objectForKey:userId] == nil)
{
MXKContact *splitContact = [[MXKContact alloc] initMatrixContactWithDisplayName:contact.displayName andMatrixID:userId];
[matrixContacts addObject:splitContact];
[invitableMatrixContacts addObject:splitContact];
}
}
}
@ -1689,14 +1681,14 @@
NSString *userId = identifiers.firstObject;
if ([contactsById objectForKey:userId] == nil)
{
[matrixContacts addObject:contact];
[invitableMatrixContacts addObject:contact];
}
}
}
// Copy participants and invited participants
participantsArray = [actualParticipants copy];
invitedParticipantsArray = [invitedParticipants copy];
filteredActualParticipants = [NSMutableArray arrayWithArray:actualParticipants];
filteredInvitedParticipants = [NSMutableArray arrayWithArray:invitedParticipants];
}
currentSearchText = searchText;
@ -1707,64 +1699,94 @@
isMultiUseNameByDisplayName = [NSMutableDictionary dictionary];
// Update invitable contacts list:
invitableAddressBookContacts = [NSMutableArray array];
invitableMatrixContacts = [NSMutableArray array];
if (currentSearchText.length)
{
for (MXKContact* contact in addressBookContacts)
for (index = 0; index < invitableAddressBookContacts.count;)
{
if ([contact hasPrefix:currentSearchText])
contact = invitableAddressBookContacts[index];
if (![contact hasPrefix:currentSearchText])
{
[invitableAddressBookContacts removeObjectAtIndex:index];
}
else
{
// Ignore the contact if it corresponds to the search input
if (!isValidInput || [contact.displayName isEqualToString:currentSearchText] == NO)
if (isValidInput && [contact.displayName isEqualToString:currentSearchText])
{
[invitableAddressBookContacts addObject:contact];
[invitableAddressBookContacts removeObjectAtIndex:index];
}
else
{
index++;
}
}
}
for (MXKContact* contact in matrixContacts)
for (index = 0; index < invitableMatrixContacts.count;)
{
if ([contact hasPrefix:currentSearchText])
contact = invitableMatrixContacts[index];
if (![contact hasPrefix:currentSearchText])
{
[invitableMatrixContacts removeObjectAtIndex:index];
}
else
{
// Ignore the contact if it corresponds to the search input
if (!isValidInput || [contact.displayName isEqualToString:currentSearchText] == NO)
if (isValidInput && [contact.displayName isEqualToString:currentSearchText])
{
[invitableMatrixContacts removeObjectAtIndex:index];
}
else
{
[invitableMatrixContacts addObject:contact];
isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
index++;
}
}
}
// Sort the refreshed lists of the invitable contacts
[self sortAlphabeticallyInvitableContacts:invitableAddressBookContacts];
[self sortInvitableMatrixContacts];
}
// Update filtered participants list
filteredActualParticipants = [NSMutableArray array];
for (Contact *contact in participantsArray)
{
if ([contact matchedWithPatterns:@[currentSearchText]])
// Update filtered participants list
for (index = 0; index < filteredActualParticipants.count;)
{
[filteredActualParticipants addObject:contact];
isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
contact = filteredActualParticipants[index];
if (![contact matchedWithPatterns:@[currentSearchText]])
{
[filteredActualParticipants removeObjectAtIndex:index];
}
else
{
isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
index++;
}
}
// Update filtered invited participants list
for (index = 0; index < filteredInvitedParticipants.count;)
{
contact = filteredInvitedParticipants[index];
if (![contact matchedWithPatterns:@[currentSearchText]])
{
[filteredInvitedParticipants removeObjectAtIndex:index];
}
else
{
isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
index++;
}
}
}
// Update filtered invited participants list
filteredInvitedParticipants = [NSMutableArray array];
for (Contact *contact in invitedParticipantsArray)
else
{
if ([contact matchedWithPatterns:@[currentSearchText]])
{
[filteredInvitedParticipants addObject:contact];
isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
}
invitableAddressBookContacts = nil;
invitableMatrixContacts = nil;
filteredActualParticipants = nil;
filteredInvitedParticipants = nil;
}
// Refresh display

View file

@ -421,16 +421,9 @@
contact = participants[index];
// Disambiguate the display name when it appears several times.
if (contact.displayName && [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)])
if (contact.displayName)
{
NSArray *identifiers = contact.matrixIdentifiers;
if (identifiers.count)
{
NSString *participantId = identifiers.firstObject;
NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, participantId];
contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId];
}
participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)];
}
}
}
@ -454,9 +447,7 @@
// Check whether the display name is not already the matrix id
if (![contact.displayName isEqualToString:participantId])
{
NSString *displayName = [NSString stringWithFormat:@"%@ (%@)", contact.displayName, participantId];
contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:participantId];
participantCell.showMatrixIdInDisplayName = YES;
}
}
}
@ -600,8 +591,21 @@
}
else
{
// This is a text entered by the user, or a local email contact
NSString *participantId = contact.displayName;
// This is a text entered by the user, or a local contact
NSString *participantId;
if (contact.emailAddresses.count)
{
// This is a local contact, consider the first email by default.
// TODO: Prompt the user to select the right email.
MXKEmail *email = contact.emailAddresses.firstObject;
participantId = email.emailAddress;
}
else
{
// This is the text filled by the user.
participantId = contact.displayName;
}
// Is it an email or a Matrix user ID?
if ([MXTools isEmailAddress:participantId])
@ -756,12 +760,12 @@
NSArray *matrixContacts = [NSMutableArray arrayWithArray:[MXKContactManager sharedManager].matrixContacts];
// Retrieve all known email addresses from local contacts
NSArray *localEmailContacts = [MXKContactManager sharedManager].localEmailContacts;
NSArray *localContactsWithMethods = [MXKContactManager sharedManager].localContactsWithMethods;
searchProcessingContacts = [NSMutableArray arrayWithCapacity:(matrixContacts.count + localEmailContacts.count)];
searchProcessingContacts = [NSMutableArray arrayWithCapacity:(matrixContacts.count + localContactsWithMethods.count)];
// Add first email contacts
for (MXKContact* contact in localEmailContacts)
for (MXKContact* contact in localContactsWithMethods)
{
// Remove the current emails listed in participants.
if ([participantsById objectForKey:contact.displayName] == nil)

View file

@ -14,21 +14,24 @@
limitations under the License.
*/
#import <MatrixSDK/MatrixSDK.h>
#import "MXKTableViewCell.h"
#import "MXKCellRendering.h"
#import "MXKImageView.h"
#import <MatrixKit/MatrixKit.h>
/**
'ContactTableCell' extends MXKTableViewCell.
*/
@interface ContactTableViewCell : MXKTableViewCell <MXKCellRendering>
{
@protected
/**
The current displayed contact.
*/
MXKContact *contact;
}
@property (nonatomic) IBOutlet MXKImageView *thumbnailView;
@property (nonatomic) IBOutlet UIImageView *thumbnailBadgeView;
@property (nonatomic) IBOutlet UILabel *contactDisplayNameLabel;
@property (nonatomic) IBOutlet UILabel *lastPresenceLabel;
@property (nonatomic) IBOutlet UILabel *contactInformationLabel;
@property (nonatomic) IBOutlet UIView *customAccessoryView;
@property (nonatomic) BOOL showCustomAccessoryView;
@ -36,6 +39,11 @@
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *customAccessViewWidthConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *customAccessoryViewLeadingConstraint;
/**
Tell whether the matrix id should be added in the contact display name (NO by default)
*/
@property (nonatomic) BOOL showMatrixIdInDisplayName;
// The room where the contact is.
// It is used to display the member information (like invitation)
// This property is OPTIONAL.

View file

@ -23,13 +23,8 @@
#import "AvatarGenerator.h"
#import "Tools.h"
#import "MXKContactManager.h"
@interface ContactTableViewCell()
{
// The current displayed contact.
MXKContact *contact;
/**
The observer of the presence for matrix user.
*/
@ -45,7 +40,10 @@
[super awakeFromNib];
// apply the vector colours
self.lastPresenceLabel.textColor = kVectorTextColorGray;
self.contactInformationLabel.textColor = kVectorTextColorGray;
// Clear the default background color of a MXKImageView instance
self.thumbnailView.backgroundColor = [UIColor clearColor];
}
- (void)layoutSubviews
@ -73,6 +71,16 @@
}
}
- (void)setShowMatrixIdInDisplayName:(BOOL)showMatrixIdInDisplayName
{
_showMatrixIdInDisplayName = showMatrixIdInDisplayName;
if (contact)
{
[self refreshContactDisplayName];
}
}
#pragma mark - MXKCellRendering
// returns the first matrix id of the contact
@ -100,9 +108,6 @@
mxPresenceObserver = nil;
}
// Clear the default background color of a MXKImageView instance
self.thumbnailView.backgroundColor = [UIColor clearColor];
// Sanity check: accept only object of MXKContact classes or sub-classes
NSParameterAssert([cellData isKindOfClass:[MXKContact class]]);
contact = (MXKContact*)cellData;
@ -113,7 +118,7 @@
{
self.thumbnailView.image = nil;
self.contactDisplayNameLabel.text = nil;
self.lastPresenceLabel.text = nil;
self.contactInformationLabel.text = nil;
return;
}
@ -121,26 +126,32 @@
// Be warned when the thumbnail is updated
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onThumbnailUpdate:) name:kMXKContactThumbnailUpdateNotification object:nil];
// Observe contact presence change
mxPresenceObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKContactManagerMatrixUserPresenceChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
NSString* matrixId = self.firstMatrixId;
if (matrixId && [matrixId isEqualToString:notif.object])
{
[self refreshContactPresence];
}
}];
[self refreshContactThumbnail];
if (!contact.isMatrixContact)
[self refreshContactDisplayName];
if (contact.isMatrixContact)
{
// Observe contact presence change
mxPresenceObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKContactManagerMatrixUserPresenceChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
NSString* matrixId = self.firstMatrixId;
if (matrixId && [matrixId isEqualToString:notif.object])
{
[self refreshContactPresence];
}
}];
[self refreshContactPresence];
}
else
{
// Refresh matrix info of the contact
[[MXKContactManager sharedManager] updateMatrixIDsForLocalContact:contact];
[self refreshLocalContactInformation];
}
[self refreshContactDisplayName];
[self refreshContactPresence];
[self refreshContactThumbnail];
}
+ (CGFloat)heightForCellData:(MXKCellData*)cellData withMaximumWidth:(CGFloat)maxWidth
@ -176,16 +187,20 @@
if (!image)
{
NSString* matrixId = self.firstMatrixId;
NSArray *identifiers = contact.matrixIdentifiers;
if (matrixId)
if (identifiers.count)
{
image = [AvatarGenerator generateAvatarForMatrixItem:matrixId withDisplayName:contact.displayName];
image = [AvatarGenerator generateAvatarForMatrixItem:identifiers.firstObject withDisplayName:contact.displayName];
}
else if (contact.isThirdPartyInvite)
{
image = [AvatarGenerator generateAvatarForText:contact.displayName];
}
else if ((!contact.isMatrixContact && contact.phoneNumbers.count && !contact.emailAddresses.count))
{
image = [AvatarGenerator imageFromText:@"#" withBackgroundColor:kVectorColorGreen];
}
else
{
image = [AvatarGenerator imageFromText:@"@" withBackgroundColor:kVectorColorGreen];
@ -198,6 +213,56 @@
- (void)refreshContactDisplayName
{
self.contactDisplayNameLabel.text = contact.displayName;
// Check whether the matrix identifier must be displayed.
if (_showMatrixIdInDisplayName)
{
// Append the matrix identifier to the display name.
NSArray *identifiers = contact.matrixIdentifiers;
if (identifiers.count)
{
NSString *userId = identifiers.firstObject;
// Check whether the display name is not already the matrix id
if (![contact.displayName isEqualToString:userId])
{
// Update the display name by adding the matrix id
NSMutableAttributedString *displayNameLabelText = [[NSMutableAttributedString alloc] initWithString:contact.displayName];
NSRange strRange = NSMakeRange(0, displayNameLabelText.length);
[displayNameLabelText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17 weight:UIFontWeightMedium] range:strRange];
NSMutableAttributedString *userIdStr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%@)", userId]];
strRange = NSMakeRange(0, userIdStr.length);
[userIdStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17] range:strRange];
[displayNameLabelText appendAttributedString:userIdStr];
self.contactDisplayNameLabel.attributedText = displayNameLabelText;
}
}
}
}
- (void)refreshLocalContactInformation
{
NSArray *identifiers = contact.matrixIdentifiers;
if (identifiers.count)
{
self.thumbnailBadgeView.image = [UIImage imageNamed:@"riot_icon"];
self.thumbnailBadgeView.hidden = NO;
}
else
{
self.thumbnailBadgeView.hidden = YES;
}
// Display the first contact method in sub label.
NSString *subLabelText = nil;
if (contact.emailAddresses.count)
{
MXKEmail* email = contact.emailAddresses.firstObject;
subLabelText = email.emailAddress;
}
self.contactInformationLabel.text = subLabelText;
}
- (void)refreshContactPresence
@ -227,7 +292,7 @@
presenceText = NSLocalizedStringFromTable(@"room_participants_offline", @"Vector", nil);
}
self.lastPresenceLabel.text = presenceText;
self.contactInformationLabel.text = presenceText;
}
#pragma mark - events
@ -246,4 +311,4 @@
}
}
@end
@end

View file

@ -1,8 +1,12 @@
<?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">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@ -16,7 +20,7 @@
<subviews>
<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"/>
<color key="backgroundColor" red="0.89720267057418823" green="0.89720267057418823" blue="0.89720267057418823" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="42" id="7Ys-gS-ja8"/>
<constraint firstAttribute="height" constant="42" id="WPC-tL-hnM"/>
@ -35,21 +39,21 @@
<constraint firstAttribute="height" constant="21" id="vCd-fx-d5z"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="last presence" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dQt-mN-T6b" userLabel="Last presence">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="info label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dQt-mN-T6b">
<rect key="frame" x="69" y="39" width="531" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="e6p-DU-3ny"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ogo-Qt-u2C" userLabel="Custom accessory view">
<rect key="frame" x="563" y="25" width="24" height="24"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="pDU-SS-0mb"/>
<constraint firstAttribute="height" constant="24" id="w2M-nj-D56"/>
@ -69,17 +73,17 @@
<constraint firstItem="RX5-eD-c3c" firstAttribute="top" secondItem="e2Q-sr-Kz4" secondAttribute="top" constant="5" id="xrs-nE-h6t"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Ogo-Qt-u2C" firstAttribute="centerY" secondItem="L2L-l5-wPx" secondAttribute="centerY" id="LYX-FJ-cz3"/>
<constraint firstAttribute="trailing" secondItem="Ogo-Qt-u2C" secondAttribute="trailing" constant="13" id="cWl-2f-cvI"/>
</constraints>
<connections>
<outlet property="contactDisplayNameLabel" destination="Lg1-xQ-AGn" id="xKB-Pw-12c"/>
<outlet property="contactInformationLabel" destination="dQt-mN-T6b" id="IKZ-wv-xVD"/>
<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="thumbnailBadgeView" destination="e2Q-sr-Kz4" id="kMn-et-a0z"/>
<outlet property="thumbnailView" destination="RX5-eD-c3c" id="GBi-K9-LhK"/>
</connections>