diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 02ffc499d..00f76e787 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -410,6 +410,7 @@ F0E05A021E963103004B83FB /* FavouritesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E059FF1E963103004B83FB /* FavouritesViewController.m */; }; F0E05A031E963103004B83FB /* RoomsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E05A011E963103004B83FB /* RoomsViewController.m */; }; F0E05A061E9682E9004B83FB /* ContactsDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E05A051E9682E9004B83FB /* ContactsDataSource.m */; }; + F0E05A0B1E9CCEBF004B83FB /* RecentsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0E05A0A1E9CCEBF004B83FB /* RecentsViewController.xib */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -949,6 +950,7 @@ F0E05A011E963103004B83FB /* RoomsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomsViewController.m; sourceTree = ""; }; F0E05A041E9682E9004B83FB /* ContactsDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsDataSource.h; sourceTree = ""; }; F0E05A051E9682E9004B83FB /* ContactsDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsDataSource.m; sourceTree = ""; }; + F0E05A0A1E9CCEBF004B83FB /* RecentsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RecentsViewController.xib; sourceTree = ""; }; F9D678EF54918C036FDEDBF9 /* Pods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1414,6 +1416,7 @@ F083BC371E7009EC00A9B29C /* MediaPickerViewController.xib */, F083BC381E7009EC00A9B29C /* RecentsViewController.h */, F083BC391E7009EC00A9B29C /* RecentsViewController.m */, + F0E05A0A1E9CCEBF004B83FB /* RecentsViewController.xib */, F083BC3A1E7009EC00A9B29C /* RoomFilesSearchViewController.h */, F083BC3B1E7009EC00A9B29C /* RoomFilesSearchViewController.m */, F083BC3C1E7009EC00A9B29C /* RoomFilesViewController.h */, @@ -1951,6 +1954,7 @@ F083BDAF1E7009ED00A9B29C /* plus_icon@3x.png in Resources */, F083BDD91E7009ED00A9B29C /* start_chat@3x.png in Resources */, F083BE411E7009ED00A9B29C /* RoomIncomingEncryptedTextMsgBubbleCell.xib in Resources */, + F0E05A0B1E9CCEBF004B83FB /* RecentsViewController.xib in Resources */, F083BD5F1E7009ED00A9B29C /* details_icon.png in Resources */, F083BE241E7009ED00A9B29C /* RoomViewController.xib in Resources */, F083BE7B1E7009ED00A9B29C /* RoomInputToolbarView.xib in Resources */, diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index ce689aee0..15e8dbe88 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -116,22 +116,23 @@ "room_creation_invite_another_user" = "Search / invite by User ID, Name or email"; // Room recents -"room_recents_directory" = "ROOM DIRECTORY"; -"room_recents_favourites" = "FAVOURITES"; -"room_recents_conversations" = "ROOMS"; -"room_recents_low_priority" = "LOW PRIORITY"; -"room_recents_invites" = "INVITES"; +"room_recents_directory_section" = "ROOM DIRECTORY"; +"room_recents_favourites_section" = "FAVOURITES (%tu)"; +"room_recents_favourites_section_default" = "FAVOURITES"; +"room_recents_conversations_section" = "ROOMS (%tu)"; +"room_recents_conversations_section_default" = "ROOMS"; +"room_recents_low_priority_section" = "LOW PRIORITY (%tu)"; +"room_recents_low_priority_section_default" = "LOW PRIORITY"; +"room_recents_invites_section" = "INVITES (%tu)"; +"room_recents_invites_section_default" = "INVITES"; "room_recents_start_chat_with" = "Start chat"; "room_recents_create_empty_room" = "Create room"; // People tab "people_invites_section" = "INVITES (%tu)"; +"people_invites_section_default" = "INVITES"; "people_conversation_section" = "CONVERSATIONS (%tu)"; -"people_address_book_section" = "LOCAL CONTACTS (%tu)"; -"people_address_book_matrix_users_toggle" = "Matrix users only"; -"people_matrix_users_section" = "KNOWN CONTACTS (%tu)"; -"people_matrix_users_default_section" = "KNOWN CONTACTS (-)"; -"people_matrix_users_search_prompt" = "Too many contacts, please use the search field"; +"people_conversation_section_default" = "CONVERSATIONS"; // Search "search_rooms" = "Rooms"; @@ -152,9 +153,10 @@ // Contacts "contacts_address_book_section" = "LOCAL CONTACTS (%tu)"; +"contacts_address_book_section_default" = "LOCAL CONTACTS"; "contacts_address_book_matrix_users_toggle" = "Matrix users only"; "contacts_matrix_users_section" = "KNOWN CONTACTS (%tu)"; -"contacts_matrix_users_default_section" = "KNOWN CONTACTS (-)"; +"contacts_matrix_users_section_default" = "KNOWN CONTACTS"; "contacts_matrix_users_search_prompt" = "Too many contacts, please use the search field"; // Chat participants diff --git a/Riot/Model/Contact/ContactsDataSource.h b/Riot/Model/Contact/ContactsDataSource.h index f03c4b239..868ce94fa 100644 --- a/Riot/Model/Contact/ContactsDataSource.h +++ b/Riot/Model/Contact/ContactsDataSource.h @@ -60,6 +60,14 @@ */ - (CGFloat)heightForHeaderInSection:(NSInteger)section; +/** + Get the title of the header of the specified section. + + @param section the section index. + @return the section title. + */ +- (NSString *)titleForHeaderInSection:(NSInteger)section; + /** Get the section header view. @@ -75,6 +83,10 @@ - (void)forceRefresh; #pragma mark - Configuration +/** + Tell whether the sections are shrinkable. NO by default. + */ +@property (nonatomic) BOOL areSectionsShrinkable; /** Tell whether the matrix id should be added by default in the matrix contact display name (NO by default). diff --git a/Riot/Model/Contact/ContactsDataSource.m b/Riot/Model/Contact/ContactsDataSource.m index 3113ddbe9..85ea41028 100644 --- a/Riot/Model/Contact/ContactsDataSource.m +++ b/Riot/Model/Contact/ContactsDataSource.m @@ -69,6 +69,7 @@ _forceMatrixIdInDisplayName = NO; + _areSectionsShrinkable = NO; shrinkedSectionsBitMask = 0; hideNonMatrixEnabledContacts = NO; @@ -601,11 +602,47 @@ return 0; } +- (NSString *)titleForHeaderInSection:(NSInteger)section +{ + NSString* sectionTitle = nil; + NSUInteger count = 0; + + if (section == filteredLocalContactsSection) + { + count = filteredLocalContacts.count; + + if (count) + { + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"contacts_address_book_section", @"Vector", nil), count]; + } + else + { + sectionTitle = NSLocalizedStringFromTable(@"contacts_address_book_section_default", @"Vector", nil); + } + } + else //if (section == filteredMatrixContactsSection) + { + sectionTitle = NSLocalizedStringFromTable(@"contacts_matrix_users_section_default", @"Vector", nil); + + if (currentSearchText.length) + { + count = filteredMatrixContacts.count; + + if (count) + { + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"contacts_matrix_users_section", @"Vector", nil), count]; + } + } + } + + return sectionTitle; +} + - (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame { UIView* sectionHeader; - NSInteger sectionBitwise = -1; + NSInteger sectionBitwise = 0; sectionHeader = [[UIView alloc] initWithFrame:frame]; sectionHeader.backgroundColor = kRiotColorLightGrey; @@ -615,35 +652,31 @@ frame.size.width = sectionHeader.frame.size.width - 10; frame.size.height = 20; UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame]; + headerLabel.text = [self titleForHeaderInSection:section]; headerLabel.font = [UIFont boldSystemFontOfSize:15.0]; headerLabel.backgroundColor = [UIColor clearColor]; [sectionHeader addSubview:headerLabel]; - if (section == filteredLocalContactsSection) + if (_areSectionsShrinkable) { - headerLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"contacts_address_book_section", @"Vector", nil), filteredLocalContacts.count]; - - sectionBitwise = CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE; - } - else //if (section == filteredMatrixContactsSection) - { - if (currentSearchText.length) + if (section == filteredLocalContactsSection) { - headerLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"contacts_matrix_users_section", @"Vector", nil), filteredMatrixContacts.count]; - - // This section is collapsable only if it is not empty - if (filteredMatrixContacts.count) - { - sectionBitwise = CONTACTSDATASOURCE_KNOWNCONTACTS_BITWISE; - } + sectionBitwise = CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE; } - else + else //if (section == filteredMatrixContactsSection) { - headerLabel.text = NSLocalizedStringFromTable(@"contacts_matrix_users_default_section", @"Vector", nil); + if (currentSearchText.length) + { + // This section is collapsable only if it is not empty + if (filteredMatrixContacts.count) + { + sectionBitwise = CONTACTSDATASOURCE_KNOWNCONTACTS_BITWISE; + } + } } } - if (sectionBitwise != -1) + if (sectionBitwise) { // Add shrink button UIButton *shrinkButton = [UIButton buttonWithType:UIButtonTypeCustom]; @@ -876,8 +909,8 @@ shrinkedSectionsBitMask |= selectedSectionBit; } - // Refresh - [self forceRefresh]; + // Inform the delegate about the update + [self.delegate dataSource:self didCellChange:nil]; } } diff --git a/Riot/Model/RoomList/RecentsDataSource.h b/Riot/Model/RoomList/RecentsDataSource.h index 46947cefe..2c1e56c81 100644 --- a/Riot/Model/RoomList/RecentsDataSource.h +++ b/Riot/Model/RoomList/RecentsDataSource.h @@ -44,8 +44,6 @@ typedef enum : NSUInteger @property (nonatomic) NSInteger conversationSection; @property (nonatomic) NSInteger lowPrioritySection; -@property (nonatomic) NSInteger sectionsCount; - /** Set the delegate by specifying the selected display mode. */ diff --git a/Riot/Model/RoomList/RecentsDataSource.m b/Riot/Model/RoomList/RecentsDataSource.m index 357859aa5..953a256ec 100644 --- a/Riot/Model/RoomList/RecentsDataSource.m +++ b/Riot/Model/RoomList/RecentsDataSource.m @@ -48,7 +48,7 @@ @end @implementation RecentsDataSource -@synthesize directorySection, invitesSection, favoritesSection, conversationSection, lowPrioritySection, sectionsCount; +@synthesize directorySection, invitesSection, favoritesSection, conversationSection, lowPrioritySection; @synthesize hiddenCellIndexPath, droppingCellIndexPath, droppingCellBackGroundView; - (instancetype)init @@ -66,7 +66,6 @@ favoritesSection = -1; conversationSection = -1; lowPrioritySection = -1; - sectionsCount = 0; _areSectionsShrinkable = NO; shrinkedSectionsBitMask = 0; @@ -203,13 +202,41 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + NSInteger sectionsCount = 0; + // Check whether all data sources are ready before rendering recents if (self.state == MXKDataSourceStateReady) { - // Return the last updated number of sections. - return sectionsCount; + directorySection = favoritesSection = conversationSection = lowPrioritySection = invitesSection = -1; + + if (invitesCellDataArray.count > 0) + { + invitesSection = sectionsCount++; + } + + if (favoriteCellDataArray.count > 0) + { + favoritesSection = sectionsCount++; + } + + if (conversationCellDataArray.count > 0) + { + conversationSection = sectionsCount++; + } + + if (_recentsDataSourceMode == RecentsDataSourceModeRooms) + { + // Add the directory section after "ROOMS" + directorySection = sectionsCount++; + } + + if (lowPriorityCellDataArray.count > 0) + { + lowPrioritySection = sectionsCount++; + } } - return 0; + + return sectionsCount; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section @@ -251,89 +278,173 @@ return count; } -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (NSString *)titleForHeaderInSection:(NSInteger)section { - UIView *sectionHeader = nil; + NSString* sectionTitle = nil; + NSUInteger count = 0; - if (section < sectionsCount) + if (section == favoritesSection) { - NSString* sectionTitle = @""; - NSInteger sectionBitwise = 0; - UIImageView *chevronView; + count = favoriteCellDataArray.count; - if (section == favoritesSection) + if (count) { - sectionTitle = NSLocalizedStringFromTable(@"room_recents_favourites", @"Vector", nil); - sectionBitwise = _areSectionsShrinkable ? RECENTSDATASOURCE_SECTION_FAVORITES : 0; + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_recents_favourites_section", @"Vector", nil), count]; } - else if (section == conversationSection) + else { - sectionTitle = NSLocalizedStringFromTable(@"room_recents_conversations", @"Vector", nil); - sectionBitwise = _areSectionsShrinkable ? RECENTSDATASOURCE_SECTION_CONVERSATIONS : 0; + sectionTitle = NSLocalizedStringFromTable(@"room_recents_favourites_section_default", @"Vector", nil); } - else if (section == directorySection) + } + else if (section == conversationSection) + { + count = conversationCellDataArray.count; + + if (_recentsDataSourceMode == RecentsDataSourceModePeople) { - sectionTitle = NSLocalizedStringFromTable(@"room_recents_directory", @"Vector", nil); - sectionBitwise = _areSectionsShrinkable ? RECENTSDATASOURCE_SECTION_CONVERSATIONS : 0; - } - else if (section == lowPrioritySection) - { - sectionTitle = NSLocalizedStringFromTable(@"room_recents_low_priority", @"Vector", nil); - sectionBitwise = _areSectionsShrinkable ? RECENTSDATASOURCE_SECTION_LOWPRIORITY : 0; - } - else if (section == invitesSection) - { - sectionTitle = NSLocalizedStringFromTable(@"room_recents_invites", @"Vector", nil); - sectionBitwise = _areSectionsShrinkable ? RECENTSDATASOURCE_SECTION_INVITES : 0; - } - - sectionHeader = [[UIView alloc] initWithFrame:frame]; - sectionHeader.backgroundColor = kRiotColorLightGrey; - - if (sectionBitwise) - { - // Add shrink button - UIButton *shrinkButton = [UIButton buttonWithType:UIButtonTypeCustom]; - frame.origin.x = frame.origin.y = 0; - shrinkButton.frame = frame; - shrinkButton.backgroundColor = [UIColor clearColor]; - [shrinkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - shrinkButton.tag = sectionBitwise; - [sectionHeader addSubview:shrinkButton]; - sectionHeader.userInteractionEnabled = YES; - - // Add shrink icon - UIImage *chevron; - if (shrinkedSectionsBitMask & sectionBitwise) + if (count) { - chevron = [UIImage imageNamed:@"disclosure_icon"]; + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"people_conversation_section", @"Vector", nil), count]; } else { - chevron = [UIImage imageNamed:@"shrink_icon"]; + sectionTitle = NSLocalizedStringFromTable(@"people_conversation_section_default", @"Vector", nil); + } + } + else + { + if (count) + { + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_recents_conversations_section", @"Vector", nil), count]; + } + else + { + sectionTitle = NSLocalizedStringFromTable(@"room_recents_conversations_section_default", @"Vector", nil); } - chevronView = [[UIImageView alloc] initWithImage:chevron]; - chevronView.contentMode = UIViewContentModeCenter; - frame = chevronView.frame; - frame.origin.x = sectionHeader.frame.size.width - frame.size.width - 16; - frame.origin.y = (sectionHeader.frame.size.height - frame.size.height) / 2; - chevronView.frame = frame; - [sectionHeader addSubview:chevronView]; - chevronView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin); } - - // Add label - frame = sectionHeader.frame; - frame.origin.x = 20; - frame.origin.y = 5; - frame.size.width = chevronView ? chevronView.frame.origin.x - 10 : sectionHeader.frame.size.width - 10; - frame.size.height -= 10; - UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame]; - headerLabel.font = [UIFont boldSystemFontOfSize:15.0]; - headerLabel.backgroundColor = [UIColor clearColor]; - headerLabel.text = sectionTitle; - [sectionHeader addSubview:headerLabel]; } + else if (section == directorySection) + { + sectionTitle = NSLocalizedStringFromTable(@"room_recents_directory_section", @"Vector", nil); + } + else if (section == lowPrioritySection) + { + count = lowPriorityCellDataArray.count; + + if (count) + { + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_recents_low_priority_section", @"Vector", nil), count]; + } + else + { + sectionTitle = NSLocalizedStringFromTable(@"room_recents_low_priority_section_default", @"Vector", nil); + } + } + else if (section == invitesSection) + { + count = invitesCellDataArray.count; + + if (_recentsDataSourceMode == RecentsDataSourceModePeople) + { + if (count) + { + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"people_invites_section", @"Vector", nil), count]; + } + else + { + sectionTitle = NSLocalizedStringFromTable(@"people_invites_section_default", @"Vector", nil); + } + } + else + { + if (count) + { + sectionTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_recents_invites_section", @"Vector", nil), count]; + } + else + { + sectionTitle = NSLocalizedStringFromTable(@"room_recents_invites_section_default", @"Vector", nil); + } + } + } + + return sectionTitle; +} + +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +{ + UIView *sectionHeader = [[UIView alloc] initWithFrame:frame]; + sectionHeader.backgroundColor = kRiotColorLightGrey; + NSInteger sectionBitwise = 0; + UIImageView *chevronView; + + if (_areSectionsShrinkable) + { + if (section == favoritesSection) + { + sectionBitwise = RECENTSDATASOURCE_SECTION_FAVORITES; + } + else if (section == conversationSection) + { + sectionBitwise = RECENTSDATASOURCE_SECTION_CONVERSATIONS; + } + else if (section == directorySection) + { + sectionBitwise = RECENTSDATASOURCE_SECTION_CONVERSATIONS; + } + else if (section == lowPrioritySection) + { + sectionBitwise = RECENTSDATASOURCE_SECTION_LOWPRIORITY; + } + else if (section == invitesSection) + { + sectionBitwise = RECENTSDATASOURCE_SECTION_INVITES; + } + } + + if (sectionBitwise) + { + // Add shrink button + UIButton *shrinkButton = [UIButton buttonWithType:UIButtonTypeCustom]; + frame.origin.x = frame.origin.y = 0; + shrinkButton.frame = frame; + shrinkButton.backgroundColor = [UIColor clearColor]; + [shrinkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + shrinkButton.tag = sectionBitwise; + [sectionHeader addSubview:shrinkButton]; + sectionHeader.userInteractionEnabled = YES; + + // Add shrink icon + UIImage *chevron; + if (shrinkedSectionsBitMask & sectionBitwise) + { + chevron = [UIImage imageNamed:@"disclosure_icon"]; + } + else + { + chevron = [UIImage imageNamed:@"shrink_icon"]; + } + chevronView = [[UIImageView alloc] initWithImage:chevron]; + chevronView.contentMode = UIViewContentModeCenter; + frame = chevronView.frame; + frame.origin.x = sectionHeader.frame.size.width - frame.size.width - 16; + frame.origin.y = (sectionHeader.frame.size.height - frame.size.height) / 2; + chevronView.frame = frame; + [sectionHeader addSubview:chevronView]; + chevronView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin); + } + + // Add label + frame = sectionHeader.frame; + frame.origin.x = 20; + frame.origin.y = 5; + frame.size.width = chevronView ? chevronView.frame.origin.x - 10 : sectionHeader.frame.size.width - 10; + frame.size.height -= 10; + UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame]; + headerLabel.font = [UIFont boldSystemFontOfSize:15.0]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.text = [self titleForHeaderInSection:section]; + [sectionHeader addSubview:headerLabel]; return sectionHeader; } @@ -547,7 +658,6 @@ [lowPriorityCellDataArray removeAllObjects]; directorySection = favoritesSection = conversationSection = lowPrioritySection = invitesSection = -1; - sectionsCount = 0; if (displayedRecentsDataSourceArray.count > 0) { @@ -624,23 +734,22 @@ id recentCellDataStoring = [recentsDataSource cellDataAtIndex:index]; MXRoom* room = recentCellDataStoring.roomSummary.room; - // Keep only the invites and the rooms without tag - if (room.state.membership == MXMembershipInvite) + // Consider only non direct rooms. + if (!room.isDirect) { - [invitesCellDataArray addObject:recentCellDataStoring]; - } - else if (!room.accountData.tags.count) - { - [conversationCellDataArray addObject:recentCellDataStoring]; + // Keep only the invites and the rooms without tag + if (room.state.membership == MXMembershipInvite) + { + [invitesCellDataArray addObject:recentCellDataStoring]; + } + else if (!room.accountData.tags.count) + { + [conversationCellDataArray addObject:recentCellDataStoring]; + } } } } - if (invitesCellDataArray.count > 0) - { - invitesSection = sectionsCount++; - } - if (favoriteCellDataArray.count > 0) { // Sort them according to their tag order @@ -649,18 +758,6 @@ return [session compareRoomsByTag:kMXRoomTagFavourite room1:recentCellData1.roomSummary.room room2:recentCellData2.roomSummary.room]; }]; - favoritesSection = sectionsCount++; - } - - if (conversationCellDataArray.count > 0) - { - conversationSection = sectionsCount++; - - if (_recentsDataSourceMode == RecentsDataSourceModeRooms) - { - // Add the directory section after "ROOMS" - directorySection = sectionsCount++; - } } if (lowPriorityCellDataArray.count > 0) @@ -671,7 +768,6 @@ return [session compareRoomsByTag:kMXRoomTagLowPriority room1:recentCellData1.roomSummary.room room2:recentCellData2.roomSummary.room]; }]; - lowPrioritySection = sectionsCount++; } } } diff --git a/Riot/Model/RoomList/UnifiedSearchRecentsDataSource.m b/Riot/Model/RoomList/UnifiedSearchRecentsDataSource.m index fe5302db8..1fd5d15c8 100644 --- a/Riot/Model/RoomList/UnifiedSearchRecentsDataSource.m +++ b/Riot/Model/RoomList/UnifiedSearchRecentsDataSource.m @@ -70,9 +70,12 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + NSInteger sectionsCount = 0; + // Check whether all data sources are ready before rendering recents if (self.state == MXKDataSourceStateReady) { + sectionsCount = [super numberOfSectionsInTableView:tableView]; NSInteger sectionsOffset = 0; if (roomIdOrAlias.length) @@ -87,7 +90,7 @@ if (_hideRecents) { self.invitesSection = self.favoritesSection = self.conversationSection = self.lowPrioritySection = -1; - self.sectionsCount = 0; + sectionsCount = sectionsOffset; } else { @@ -107,12 +110,10 @@ { self.lowPrioritySection += sectionsOffset; } + sectionsCount += sectionsOffset; } - - self.sectionsCount += sectionsOffset; - return self.sectionsCount; } - return 0; + return sectionsCount; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section @@ -141,26 +142,7 @@ if (section != searchedRoomIdOrAliasSection) { - if (section == self.directorySection) - { - sectionHeader = [[UIView alloc] initWithFrame:frame]; - sectionHeader.backgroundColor = kRiotColorLightGrey; - - // Add label - frame.origin.x = 20; - frame.origin.y = 5; - frame.size.width = sectionHeader.frame.size.width - 10; - frame.size.height -= 10; - UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame]; - headerLabel.font = [UIFont boldSystemFontOfSize:15.0]; - headerLabel.backgroundColor = [UIColor clearColor]; - headerLabel.text = NSLocalizedStringFromTable(@"room_recents_directory", @"Vector", nil); - [sectionHeader addSubview:headerLabel]; - } - else - { - sectionHeader = [super viewForHeaderInSection:section withFrame:frame]; - } + sectionHeader = [super viewForHeaderInSection:section withFrame:frame]; } return sectionHeader; diff --git a/Riot/ViewController/PeopleViewController.m b/Riot/ViewController/PeopleViewController.m index ae2dcc9b0..77eb2632b 100644 --- a/Riot/ViewController/PeopleViewController.m +++ b/Riot/ViewController/PeopleViewController.m @@ -40,24 +40,6 @@ @implementation PeopleViewController -#pragma mark - Class methods - -//+ (UINib *)nib -//{ -// return [UINib nibWithNibName:NSStringFromClass([PeopleViewController class]) -// bundle:[NSBundle bundleForClass:[PeopleViewController class]]]; -//} -// -//+ (instancetype)contactsTableViewController -//{ -// return [[[self class] alloc] initWithNibName:NSStringFromClass([PeopleViewController class]) -// bundle:[NSBundle bundleForClass:[PeopleViewController class]]]; -//} - -#pragma mark - - - - - (void)finalizeInit { [super finalizeInit]; @@ -140,75 +122,8 @@ - (void)dataSource:(MXKDataSource *)dataSource didCellChange:(id)changes { - // Check whether the data source is the direct rooms data source. - if (dataSource == self.dataSource) - { - // Retrieve the new number of sections related to direct rooms - NSInteger sectionNb = [self.dataSource numberOfSectionsInTableView:self.recentsTableView]; - - if (directRoomsSectionNumber == sectionNb) - { - // Refresh the sections related to the direct rooms in the table view - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, directRoomsSectionNumber)]; - [self.recentsTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - } - else if (directRoomsSectionNumber < sectionNb) - { - // Refresh the sections related to the direct rooms in the table view - [self.recentsTableView beginUpdates]; - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, directRoomsSectionNumber)]; - [self.recentsTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(directRoomsSectionNumber, (sectionNb - directRoomsSectionNumber))]; - [self.recentsTableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - [self.recentsTableView endUpdates]; - } - else - { - // Refresh the sections related to the direct rooms in the table view - [self.recentsTableView beginUpdates]; - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionNb)]; - [self.recentsTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(sectionNb, (directRoomsSectionNumber - sectionNb))]; - [self.recentsTableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - [self.recentsTableView endUpdates]; - } - - directRoomsSectionNumber = sectionNb; - } - else if (dataSource == contactsDataSource) - { - // Retrieve the new number of sections related to contacts - NSInteger sectionNb = [contactsDataSource numberOfSectionsInTableView:self.recentsTableView]; - - if (contactsSectionNumber == sectionNb) - { - // Refresh the sections related to the contacts in the table view - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(directRoomsSectionNumber, contactsSectionNumber)]; - [self.recentsTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - } - else if (contactsSectionNumber < sectionNb) - { - // Refresh the sections related to the contacts in the table view - [self.recentsTableView beginUpdates]; - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(directRoomsSectionNumber, contactsSectionNumber)]; - [self.recentsTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange((directRoomsSectionNumber + contactsSectionNumber), (sectionNb - contactsSectionNumber))]; - [self.recentsTableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - [self.recentsTableView endUpdates]; - } - else - { - // Refresh the sections related to the contacts in the table view - [self.recentsTableView beginUpdates]; - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(directRoomsSectionNumber, sectionNb)]; - [self.recentsTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange((directRoomsSectionNumber + sectionNb), (contactsSectionNumber - sectionNb))]; - [self.recentsTableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationNone]; - [self.recentsTableView endUpdates]; - } - - contactsSectionNumber = sectionNb; - } + // Refresh the full table + [self refreshRecentsTable]; } #pragma mark - UITableView data source @@ -217,6 +132,7 @@ { // Retrieve the current number of sections related to the direct rooms. // Sanity check: check whether the recents data source is correctly configured. + directRoomsSectionNumber = 0; if ([self.dataSource isKindOfClass:RecentsDataSource.class]) { RecentsDataSource *recentsDataSource = (RecentsDataSource*)self.dataSource; diff --git a/Riot/ViewController/RecentsViewController.h b/Riot/ViewController/RecentsViewController.h index 642c21960..abbc690c0 100644 --- a/Riot/ViewController/RecentsViewController.h +++ b/Riot/ViewController/RecentsViewController.h @@ -31,17 +31,33 @@ MXKAlert *currentAlert; } +@property (weak, nonatomic) IBOutlet UIView *stickyHeadersTopContainer; +@property (weak, nonatomic) IBOutlet UIView *stickyHeadersBottomContainer; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *stickyHeadersTopContainerHeightConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *stickyHeadersBottomContainerHeightConstraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *stickyHeadersBottomContainerBottomConstraint; + /** If YES, the table view will scroll at the top on the next data source refresh. It comes back to NO after each refresh. */ @property (nonatomic) BOOL shouldScrollToTopOnRefresh; +/** + Tell whether the sticky headers are enabled. NO by default. + */ +@property (nonatomic) BOOL enableStickyHeaders; + /** The Google Analytics Instance screen name (Default is "RecentsScreen"). */ @property (nonatomic) NSString *screenName; +/** + Refresh the recents table display. + */ +- (void)refreshRecentsTable; + /** Refresh the cell selection in the table. diff --git a/Riot/ViewController/RecentsViewController.m b/Riot/ViewController/RecentsViewController.m index 288caf4ee..069226846 100644 --- a/Riot/ViewController/RecentsViewController.m +++ b/Riot/ViewController/RecentsViewController.m @@ -67,6 +67,22 @@ @implementation RecentsViewController +#pragma mark - Class methods + ++ (UINib *)nib +{ + return [UINib nibWithNibName:NSStringFromClass([RecentsViewController class]) + bundle:[NSBundle bundleForClass:[RecentsViewController class]]]; +} + ++ (instancetype)recentListViewController +{ + return [[[self class] alloc] initWithNibName:NSStringFromClass([RecentsViewController class]) + bundle:[NSBundle bundleForClass:[RecentsViewController class]]]; +} + +#pragma mark - + - (void)awakeFromNib { [super awakeFromNib]; @@ -89,6 +105,8 @@ // Set default screen name _screenName = @"RecentsScreen"; + _enableStickyHeaders = NO; + // Set itself as delegate by default. self.delegate = self; } @@ -98,6 +116,17 @@ [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. + // Adjust Bottom constraint to take into account tabBar. + [NSLayoutConstraint deactivateConstraints:@[_stickyHeadersBottomContainerBottomConstraint]]; + _stickyHeadersBottomContainerBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:self.stickyHeadersBottomContainer + attribute:NSLayoutAttributeBottom + multiplier:1.0f + constant:0.0f]; + [NSLayoutConstraint activateConstraints:@[_stickyHeadersBottomContainerBottomConstraint]]; + self.recentsTableView.accessibilityIdentifier = @"RecentsVCTableView"; // Register here the customized cell view class used to render recents @@ -243,6 +272,25 @@ } } +#pragma mark - Override MXKRecentListViewController + +- (void)setKeyboardHeight:(CGFloat)keyboardHeight +{ + // Deduce the bottom constraint for the table view (Don't forget the potential tabBar) + CGFloat tableViewBottomConst = keyboardHeight - self.bottomLayoutGuide.length; + // Check whether the keyboard is over the tabBar + if (tableViewBottomConst < 0) + { + tableViewBottomConst = 0; + } + + // Update constraints + _stickyHeadersBottomContainerBottomConstraint.constant = tableViewBottomConst; + + // Force layout immediately to take into account new constraint + [self.view layoutIfNeeded]; +} + #pragma mark - - (void)refreshCurrentSelectedCell:(BOOL)forceVisible diff --git a/Riot/ViewController/RecentsViewController.xib b/Riot/ViewController/RecentsViewController.xib new file mode 100644 index 000000000..d4e3e59e5 --- /dev/null +++ b/Riot/ViewController/RecentsViewController.xib @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/ViewController/RoomParticipantsViewController.m b/Riot/ViewController/RoomParticipantsViewController.m index 3dd931f35..0fd839f48 100644 --- a/Riot/ViewController/RoomParticipantsViewController.m +++ b/Riot/ViewController/RoomParticipantsViewController.m @@ -595,6 +595,7 @@ // Prepare its data source ContactsDataSource *contactsDataSource = [[ContactsDataSource alloc] init]; + contactsDataSource.areSectionsShrinkable = YES; contactsDataSource.displaySearchInputInContactsList = YES; contactsDataSource.forceMatrixIdInDisplayName = YES; // Add a plus icon to the contact cell in the contacts picker, in order to make it more understandable for the end user. diff --git a/Riot/ViewController/StartChatViewController.m b/Riot/ViewController/StartChatViewController.m index a9b70e1e1..47f82c85d 100644 --- a/Riot/ViewController/StartChatViewController.m +++ b/Riot/ViewController/StartChatViewController.m @@ -77,6 +77,7 @@ // 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, diff --git a/Riot/ViewController/UnifiedSearchViewController.m b/Riot/ViewController/UnifiedSearchViewController.m index 9ecdf1e87..249efb3a8 100644 --- a/Riot/ViewController/UnifiedSearchViewController.m +++ b/Riot/ViewController/UnifiedSearchViewController.m @@ -211,6 +211,7 @@ // Init the search for people peopleSearchDataSource = [[ContactsDataSource alloc] init]; + peopleSearchDataSource.areSectionsShrinkable = YES; peopleSearchDataSource.displaySearchInputInContactsList = YES; peopleSearchDataSource.contactCellAccessoryType = UITableViewCellAccessoryDisclosureIndicator; [peopleSearchViewController displayList:peopleSearchDataSource];