Merge pull request #1417 from vector-im/user_directory

User directory
This commit is contained in:
manuroe
2017-07-28 15:50:17 +02:00
committed by GitHub
12 changed files with 139 additions and 35 deletions
-1
View File
@@ -114,7 +114,6 @@
"contacts_address_book_matrix_users_toggle" = "Nur Matrix-Nutzer";
"contacts_address_book_no_contact" = "Keine lokalen Kontakte";
"contacts_address_book_permission_required" = "Berechtigungen benötigt um auf lokale Kontakte zuzugreifen";
"contacts_matrix_users_section" = "BEKANNTE KONTAKTE";
// Chat participants
"room_participants_title" = "Teilnehmer";
"room_participants_add_participant" = "Teilnehmer hinzufügen";
+2 -1
View File
@@ -167,7 +167,8 @@
"contacts_address_book_no_contact" = "No local contacts";
"contacts_address_book_permission_required" = "Permission required to access local contacts";
"contacts_address_book_permission_denied" = "You didn't allow Riot to access your local contacts";
"contacts_matrix_users_section" = "KNOWN CONTACTS";
"contacts_user_directory_section" = "USER DIRECTORY";
"contacts_user_directory_offline_section" = "USER DIRECTORY (offline)";
// Chat participants
"room_participants_title" = "Participants";
-1
View File
@@ -131,7 +131,6 @@
"contacts_address_book_no_contact" = "Aucun contact local";
"contacts_address_book_permission_required" = "Permissions requises pour accéder aux contacts locaux";
"contacts_address_book_permission_denied" = "Vous n'avez pas autorisé Riot à accéder à vos contacts locaux";
"contacts_matrix_users_section" = "CONTACTS CONNUS";
// Chat participants
"room_participants_title" = "Membres";
"room_participants_add_participant" = "Ajouter un membre";
-1
View File
@@ -161,7 +161,6 @@
"contacts_address_book_no_contact" = "Geen lokale contacten";
"contacts_address_book_permission_required" = "Permissie vereist voor toegang tot de lokale contacten";
"contacts_address_book_permission_denied" = "Je hebt Riot geen toegang tot je lokale contacten toegestaan";
"contacts_matrix_users_section" = "BEKENDE CONTACTEN";
// Chat participants
"room_participants_title" = "Deelnemers";
+19
View File
@@ -16,6 +16,20 @@
#import <MatrixKit/MatrixKit.h>
/**
The state of the users search from the homeserver user directory.
*/
typedef enum : NSUInteger
{
ContactsDataSourceUserDirectoryStateLoading,
ContactsDataSourceUserDirectoryStateLoadedButLimited,
ContactsDataSourceUserDirectoryStateLoaded,
// The search is based on local known matrix contacts
ContactsDataSourceUserDirectoryStateOfflineLoading,
ContactsDataSourceUserDirectoryStateOfflineLoaded
} ContactsDataSourceUserDirectoryState;
/**
'ContactsDataSource' is a base class to handle contacts in Riot.
*/
@@ -145,4 +159,9 @@
*/
@property (nonatomic, readonly) MXKContact *searchInputContact;
/**
The state of the users search from the homeserver user directory.
*/
@property (nonatomic, readonly) ContactsDataSourceUserDirectoryState userDirectoryState;
@end
+95 -10
View File
@@ -20,7 +20,7 @@
#import "RiotDesignValues.h"
#define CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE 0x01
#define CONTACTSDATASOURCE_KNOWNCONTACTS_BITWISE 0x02
#define CONTACTSDATASOURCE_USERDIRECTORY_BITWISE 0x02
#define CONTACTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT 30.0
#define CONTACTSDATASOURCE_LOCALCONTACTS_SECTION_HEADER_HEIGHT 65.0
@@ -33,6 +33,9 @@
NSString *searchProcessingText;
NSMutableArray<MXKContact*> *searchProcessingLocalContacts;
NSMutableArray<MXKContact*> *searchProcessingMatrixContacts;
// The current request to the homeserver user directory
MXHTTPOperation *hsUserDirectoryOperation;
BOOL forceSearchResultRefresh;
@@ -115,6 +118,9 @@
localContactsCheckboxContainer = nil;
localContactsCheckbox = nil;
[hsUserDirectoryOperation cancel];
hsUserDirectoryOperation = nil;
[super destroy];
}
@@ -145,6 +151,13 @@
}
- (void)searchWithPattern:(NSString *)searchText forceReset:(BOOL)forceRefresh
{
// If possible, always start a new search by asking the homeserver user directory
BOOL hsUserDirectory = (self.mxSession.state != MXSessionStateHomeserverNotReachable);
[self searchWithPattern:searchText forceReset:forceRefresh hsUserDirectory:hsUserDirectory];
}
- (void)searchWithPattern:(NSString *)searchText forceReset:(BOOL)forceRefresh hsUserDirectory:(BOOL)hsUserDirectory
{
// Update search results.
searchText = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
@@ -161,11 +174,59 @@
shrinkedSectionsBitMask = 0;
}
}
else if (forceRefresh || !searchProcessingText.length || [searchText hasPrefix:searchProcessingText] == NO)
else if (forceRefresh || ![searchText isEqualToString:searchProcessingText])
{
// Prepare on the main thread the arrays used to initialize the search on the processing queue.
unfilteredLocalContacts = [self unfilteredLocalContactsArray];
unfilteredMatrixContacts = [self unfilteredMatrixContactsArray];
if (!hsUserDirectory)
{
_userDirectoryState = ContactsDataSourceUserDirectoryStateOfflineLoading;
unfilteredMatrixContacts = [self unfilteredMatrixContactsArray];
}
else if (![searchText isEqualToString:searchProcessingText])
{
_userDirectoryState = ContactsDataSourceUserDirectoryStateLoading;
// Make a search on the homeserver user directory
[filteredMatrixContacts removeAllObjects];
filteredMatrixContacts = nil;
// Cancel previous operation
if (hsUserDirectoryOperation)
{
[hsUserDirectoryOperation cancel];
hsUserDirectoryOperation = nil;
}
hsUserDirectoryOperation = [self.mxSession.matrixRestClient searchUsers:searchText limit:50 success:^(MXUserSearchResponse *userSearchResponse) {
filteredMatrixContacts = [NSMutableArray arrayWithCapacity:userSearchResponse.results.count];
// Keep the response order as the hs ordered users by relevance
for (MXUser *mxUser in userSearchResponse.results)
{
MXKContact *contact = [[MXKContact alloc] initMatrixContactWithDisplayName:mxUser.displayname andMatrixID:mxUser.userId];
[filteredMatrixContacts addObject:contact];
}
hsUserDirectoryOperation = nil;
_userDirectoryState = userSearchResponse.limited ? ContactsDataSourceUserDirectoryStateLoadedButLimited : ContactsDataSourceUserDirectoryStateLoaded;
// And inform the delegate about the update
[self.delegate dataSource:self didCellChange:nil];
} failure:^(NSError *error) {
// Ignore connection cancellation error
if ((![error.domain isEqualToString:NSURLErrorDomain] || error.code != NSURLErrorCancelled))
{
// But for other errors, launch a local search
NSLog(@"[ContactsDataSource] [MXRestClient searchUsers] returns an error. Do a search on local known contacts");
[self searchWithPattern:searchText forceReset:forceRefresh hsUserDirectory:NO];
}
}];
}
// Disclose the sections
shrinkedSectionsBitMask = 0;
@@ -239,7 +300,12 @@
// Update the filtered contacts.
currentSearchText = searchProcessingText;
filteredLocalContacts = searchProcessingLocalContacts;
filteredMatrixContacts = searchProcessingMatrixContacts;
if (!hsUserDirectory)
{
filteredMatrixContacts = searchProcessingMatrixContacts;
_userDirectoryState = ContactsDataSourceUserDirectoryStateOfflineLoaded;
}
if (!self.forceMatrixIdInDisplayName)
{
@@ -435,7 +501,7 @@
// Display a default cell when no local contacts is available.
count = filteredLocalContacts.count ? filteredLocalContacts.count : 1;
}
else if (section == filteredMatrixContactsSection && !(shrinkedSectionsBitMask & CONTACTSDATASOURCE_KNOWNCONTACTS_BITWISE))
else if (section == filteredMatrixContactsSection && !(shrinkedSectionsBitMask & CONTACTSDATASOURCE_USERDIRECTORY_BITWISE))
{
// Display a default cell when no contacts is available.
count = filteredMatrixContacts.count ? filteredMatrixContacts.count : 1;
@@ -534,7 +600,15 @@
// Check whether a search session is in progress
if (currentSearchText.length)
{
tableViewCell.textLabel.text = NSLocalizedStringFromTable(@"search_no_result", @"Vector", nil);
if (indexPath.section == filteredMatrixContactsSection &&
(_userDirectoryState == ContactsDataSourceUserDirectoryStateLoading || _userDirectoryState == ContactsDataSourceUserDirectoryStateOfflineLoading))
{
tableViewCell.textLabel.text = [NSBundle mxk_localizedStringForKey:@"search_searching"];
}
else
{
tableViewCell.textLabel.text = NSLocalizedStringFromTable(@"search_no_result", @"Vector", nil);
}
}
else if (indexPath.section == filteredLocalContactsSection)
{
@@ -643,7 +717,17 @@
}
else //if (section == filteredMatrixContactsSection)
{
title = NSLocalizedStringFromTable(@"contacts_matrix_users_section", @"Vector", nil);
switch (_userDirectoryState)
{
case ContactsDataSourceUserDirectoryStateOfflineLoading:
case ContactsDataSourceUserDirectoryStateOfflineLoaded:
title = NSLocalizedStringFromTable(@"contacts_user_directory_offline_section", @"Vector", nil);
break;
default:
title = NSLocalizedStringFromTable(@"contacts_user_directory_section", @"Vector", nil);
break;
}
if (currentSearchText.length)
{
@@ -653,7 +737,8 @@
if (count)
{
NSString *roomCount = [NSString stringWithFormat:@" %tu", count];
NSString *roomCountFormat = (_userDirectoryState == ContactsDataSourceUserDirectoryStateLoadedButLimited) ? @" > %tu" : @" %tu";
NSString *roomCount = [NSString stringWithFormat:roomCountFormat, count];
NSMutableAttributedString *mutableSectionTitle = [[NSMutableAttributedString alloc] initWithString:title
attributes:@{NSForegroundColorAttributeName : kRiotTextColorBlack,
@@ -705,7 +790,7 @@
// This section is collapsable only if it is not empty
if (filteredMatrixContacts.count)
{
sectionBitwise = CONTACTSDATASOURCE_KNOWNCONTACTS_BITWISE;
sectionBitwise = CONTACTSDATASOURCE_USERDIRECTORY_BITWISE;
}
}
}
@@ -928,7 +1013,7 @@
{
// Return the section header used when the section is shrinked
NSInteger savedShrinkedSectionsBitMask = shrinkedSectionsBitMask;
shrinkedSectionsBitMask = CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE | CONTACTSDATASOURCE_KNOWNCONTACTS_BITWISE;
shrinkedSectionsBitMask = CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE | CONTACTSDATASOURCE_USERDIRECTORY_BITWISE;
UIView *stickyHeader = [self viewForHeaderInSection:section withFrame:frame];
@@ -22,7 +22,7 @@
#import "AppDelegate.h"
#define CONTACTS_TABLEVC_LOCALCONTACTS_BITWISE 0x01
#define CONTACTS_TABLEVC_KNOWNCONTACTS_BITWISE 0x02
#define CONTACTS_TABLEVC_USERDIRECTORY_BITWISE 0x02
#define CONTACTS_TABLEVC_DEFAULT_SECTION_HEADER_HEIGHT 30.0
#define CONTACTS_TABLEVC_LOCALCONTACTS_SECTION_HEADER_HEIGHT 65.0
+7 -5
View File
@@ -50,11 +50,6 @@
contactsSectionNumber = 0;
self.screenName = @"People";
// Prepare its contacts data source
contactsDataSource = [[ContactsDataSource alloc] init];
contactsDataSource.contactCellAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
contactsDataSource.delegate = self;
}
- (void)viewDidLoad
@@ -151,6 +146,13 @@
recentsDataSource = (RecentsDataSource*)listDataSource;
}
if (!contactsDataSource)
{
// Prepare its contacts data source
contactsDataSource = [[ContactsDataSource alloc] initWithMatrixSession:listDataSource.mxSession];
contactsDataSource.contactCellAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
contactsDataSource.delegate = self;
}
}
#pragma mark - MXKDataSourceDelegate
@@ -615,7 +615,7 @@
contactsPickerViewController.contactsTableViewControllerDelegate = self;
// Prepare its data source
ContactsDataSource *contactsDataSource = [[ContactsDataSource alloc] init];
ContactsDataSource *contactsDataSource = [[ContactsDataSource alloc] initWithMatrixSession:self.mxRoom.mxSession];
contactsDataSource.areSectionsShrinkable = YES;
contactsDataSource.displaySearchInputInContactsList = YES;
contactsDataSource.forceMatrixIdInDisplayName = YES;
+1 -1
View File
@@ -2576,7 +2576,7 @@
contactsPickerViewController.contactsTableViewControllerDelegate = self;
// Prepare its data source
ContactsDataSource *contactsDataSource = [[ContactsDataSource alloc] init];
ContactsDataSource *contactsDataSource = [[ContactsDataSource alloc] initWithMatrixSession:self.roomDataSource.mxSession];
contactsDataSource.areSectionsShrinkable = YES;
contactsDataSource.displaySearchInputInContactsList = YES;
contactsDataSource.forceMatrixIdInDisplayName = YES;
+12 -12
View File
@@ -74,17 +74,6 @@
// Assign itself as delegate
self.contactsTableViewControllerDelegate = self;
// Prepare its data source
ContactsDataSource *dataSource = [[ContactsDataSource alloc] init];
dataSource.areSectionsShrinkable = YES;
dataSource.displaySearchInputInContactsList = YES;
dataSource.forceMatrixIdInDisplayName = YES;
// Add a plus icon to the contact cell when a search session is in progress,
// in order to make it more understandable for the end user.
dataSource.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];
[self displayList:dataSource];
}
- (void)viewDidLoad
@@ -121,7 +110,18 @@
{
[self addMatrixSession:mxSession];
}
// Prepare its data source
ContactsDataSource *dataSource = [[ContactsDataSource alloc] initWithMatrixSession:self.mainSession]; // TO TEST
dataSource.areSectionsShrinkable = YES;
dataSource.displaySearchInputInContactsList = YES;
dataSource.forceMatrixIdInDisplayName = YES;
// Add a plus icon to the contact cell when a search session is in progress,
// in order to make it more understandable for the end user.
dataSource.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];
[self displayList:dataSource];
cancelBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onButtonPressed:)];
self.navigationItem.leftBarButtonItem = cancelBarButtonItem;
@@ -211,7 +211,7 @@
[filesSearchViewController displaySearch:filesSearchDataSource];
// Init the search for people
peopleSearchDataSource = [[ContactsDataSource alloc] init];
peopleSearchDataSource = [[ContactsDataSource alloc] initWithMatrixSession:mainSession];
peopleSearchDataSource.areSectionsShrinkable = YES;
peopleSearchDataSource.displaySearchInputInContactsList = YES;
peopleSearchDataSource.contactCellAccessoryType = UITableViewCellAccessoryDisclosureIndicator;