mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 15:52:40 +00:00
1092 lines
38 KiB
Objective-C
1092 lines
38 KiB
Objective-C
/*
|
|
Copyright 2015 OpenMarket Ltd
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#import "HomeViewController.h"
|
|
|
|
#import "AppDelegate.h"
|
|
|
|
#import "RageShakeManager.h"
|
|
|
|
NSString *const kHomeViewControllerCreateRoomCellId = @"kHomeViewControllerCreateRoomCellId";
|
|
|
|
@interface HomeViewController ()
|
|
{
|
|
// Room creation section
|
|
NSInteger createRoomSection;
|
|
MXKRoomCreationView *createRoomView;
|
|
|
|
// Join room by alias section
|
|
NSInteger joinRoomSection;
|
|
MXKTableViewCellWithTextFieldAndButton* joinRoomCell;
|
|
|
|
// Public rooms sections
|
|
NSInteger publicRoomsFirstSection;
|
|
// Homeserver list
|
|
NSMutableArray *homeServers;
|
|
// All registered REST clients
|
|
NSMutableArray *restClients;
|
|
// REST clients by homeserver
|
|
NSMutableDictionary *restClientDict;
|
|
// Public rooms by homeserver
|
|
NSMutableDictionary *publicRoomsDict;
|
|
// Array of shrinked homeservers.
|
|
NSMutableArray *shrinkedHomeServers;
|
|
// Count current refresh requests
|
|
NSInteger refreshCount;
|
|
|
|
// List of public room names to highlight in displayed list
|
|
NSArray* highlightedPublicRooms;
|
|
|
|
// Search in public rooms
|
|
UIBarButtonItem *searchButton;
|
|
BOOL searchBarShouldEndEditing;
|
|
NSMutableDictionary *filteredPublicRoomsDict;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation HomeViewController
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
// Set rageShake handler
|
|
self.rageShakeManager = [RageShakeManager sharedManager];
|
|
|
|
// Prepare room creation section
|
|
createRoomView = [MXKRoomCreationView roomCreationView];
|
|
createRoomView.delegate = self;
|
|
|
|
// Init
|
|
highlightedPublicRooms = @[@"#matrix:matrix.org", @"#matrix-dev:matrix.org", @"#matrix-fr:matrix.org"]; // Add here a room name to highlight its display in public room list
|
|
|
|
// Adjust Top and Bottom constraints to take into account potential navBar and tabBar.
|
|
if ([NSLayoutConstraint respondsToSelector:@selector(deactivateConstraints:)])
|
|
{
|
|
[NSLayoutConstraint deactivateConstraints:@[_publicRoomsSearchBarTopConstraint, _tableViewBottomConstraint]];
|
|
}
|
|
else
|
|
{
|
|
[self.view removeConstraint:_publicRoomsSearchBarTopConstraint];
|
|
[self.view removeConstraint:_tableViewBottomConstraint];
|
|
}
|
|
|
|
_publicRoomsSearchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
|
|
attribute:NSLayoutAttributeBottom
|
|
relatedBy:NSLayoutRelationEqual
|
|
toItem:_publicRoomsSearchBar
|
|
attribute:NSLayoutAttributeTop
|
|
multiplier:1.0f
|
|
constant:0.0f];
|
|
|
|
_tableViewBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
|
|
attribute:NSLayoutAttributeTop
|
|
relatedBy:NSLayoutRelationEqual
|
|
toItem:self.tableView
|
|
attribute:NSLayoutAttributeBottom
|
|
multiplier:1.0f
|
|
constant:0.0f];
|
|
|
|
if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)])
|
|
{
|
|
[NSLayoutConstraint activateConstraints:@[_publicRoomsSearchBarTopConstraint, _tableViewBottomConstraint]];
|
|
}
|
|
else
|
|
{
|
|
[self.view addConstraint:_publicRoomsSearchBarTopConstraint];
|
|
[self.view addConstraint:_tableViewBottomConstraint];
|
|
}
|
|
|
|
// Hide search bar by default
|
|
_publicRoomsSearchBar.hidden = YES;
|
|
_publicRoomsSearchBarHeightConstraint.constant = 0;
|
|
[self.view setNeedsUpdateConstraints];
|
|
|
|
// Add search option in navigation bar
|
|
self.enableSearch = YES;
|
|
|
|
// Add an accessory view to the search bar in order to retrieve keyboard view.
|
|
_publicRoomsSearchBar.inputAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
|
|
}
|
|
|
|
- (void)didReceiveMemoryWarning
|
|
{
|
|
[super didReceiveMemoryWarning];
|
|
// Dispose of any resources that can be recreated.
|
|
}
|
|
|
|
- (void)dealloc{
|
|
highlightedPublicRooms = nil;
|
|
_publicRoomsSearchBar.inputAccessoryView = nil;
|
|
searchButton = nil;
|
|
|
|
[self destroy];
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
// Refresh all listed public rooms
|
|
[self refreshPublicRooms:nil];
|
|
}
|
|
|
|
- (void)viewWillDisappear:(BOOL)animated
|
|
{
|
|
[super viewWillDisappear:animated];
|
|
|
|
// Leave potential search session
|
|
if (!_publicRoomsSearchBar.isHidden)
|
|
{
|
|
[self searchBarCancelButtonClicked:_publicRoomsSearchBar];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Override MXKViewController
|
|
|
|
- (void)stopActivityIndicator
|
|
{
|
|
// Check whether public rooms refresh is in progress
|
|
if (refreshCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
[super stopActivityIndicator];
|
|
}
|
|
|
|
- (void)onKeyboardShowAnimationComplete
|
|
{
|
|
// Check first if the search bar is the first responder
|
|
UIView *keyboardView = _publicRoomsSearchBar.inputAccessoryView.superview;
|
|
if (!keyboardView)
|
|
{
|
|
// Check other potential first responder
|
|
keyboardView = joinRoomCell.inputAccessoryView.superview;
|
|
|
|
if (!keyboardView)
|
|
{
|
|
keyboardView = createRoomView.inputAccessoryView.superview;
|
|
}
|
|
}
|
|
|
|
// Report the keyboard view in order to track keyboard frame changes
|
|
self.keyboardView = keyboardView;
|
|
}
|
|
|
|
- (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
|
|
_tableViewBottomConstraint.constant = tableViewBottomConst;
|
|
|
|
// Force layout immediately to take into account new constraint
|
|
[self.view layoutIfNeeded];
|
|
}
|
|
|
|
- (void)destroy
|
|
{
|
|
[createRoomView removeFromSuperview];
|
|
[createRoomView destroy];
|
|
|
|
homeServers = nil;
|
|
restClients = nil;
|
|
restClientDict = nil;
|
|
publicRoomsDict = nil;
|
|
filteredPublicRoomsDict = nil;
|
|
shrinkedHomeServers = nil;
|
|
|
|
[super destroy];
|
|
}
|
|
|
|
- (void)addMatrixSession:(MXSession *)mxSession
|
|
{
|
|
[super addMatrixSession:mxSession];
|
|
|
|
// Report the related REST Client to retrieve public rooms
|
|
[self addRestClient:mxSession.matrixRestClient];
|
|
|
|
[self.tableView reloadData];
|
|
}
|
|
|
|
- (void)removeMatrixSession:(MXSession *)mxSession
|
|
{
|
|
[super removeMatrixSession:mxSession];
|
|
|
|
// Remove the related REST Client
|
|
if (mxSession.matrixRestClient)
|
|
{
|
|
[self removeRestClient:mxSession.matrixRestClient];
|
|
}
|
|
else
|
|
{
|
|
// Here the matrix session is closed, the rest client reference has been removed.
|
|
// Force a full refresh
|
|
[self refreshPublicRooms:nil];
|
|
}
|
|
|
|
[self.tableView reloadData];
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)addRestClient:(MXRestClient*)restClient
|
|
{
|
|
if (!restClient.homeserver)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!homeServers)
|
|
{
|
|
homeServers = [NSMutableArray array];
|
|
}
|
|
if (!restClients)
|
|
{
|
|
restClients = [NSMutableArray array];
|
|
}
|
|
if (!restClientDict)
|
|
{
|
|
restClientDict = [NSMutableDictionary dictionary];
|
|
}
|
|
|
|
if ([restClients indexOfObject:restClient] == NSNotFound)
|
|
{
|
|
[restClients addObject:restClient];
|
|
|
|
if ([homeServers indexOfObject:restClient.homeserver] == NSNotFound){
|
|
[homeServers addObject:restClient.homeserver];
|
|
[restClientDict setObject:restClient forKey:restClient.homeserver];
|
|
[self refreshPublicRooms:restClient];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)removeRestClient:(MXRestClient *)restClient
|
|
{
|
|
NSUInteger index = [restClients indexOfObject:restClient];
|
|
if (index != NSNotFound)
|
|
{
|
|
[restClients removeObjectAtIndex:index];
|
|
|
|
// Check whether this client was reported in rest client dictionary
|
|
for (NSString *homeserver in homeServers)
|
|
{
|
|
if ([restClientDict objectForKey:homeserver] == restClient)
|
|
{
|
|
[restClientDict removeObjectForKey:homeserver];
|
|
BOOL removeHomeServer = YES;
|
|
|
|
// Look for an other rest client for this homeserver (if any)
|
|
for (MXRestClient *client in restClients)
|
|
{
|
|
if ([client.homeserver isEqualToString:homeserver])
|
|
{
|
|
[restClientDict setObject:client forKey:homeserver];
|
|
removeHomeServer = NO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (removeHomeServer)
|
|
{
|
|
[homeServers removeObject:homeserver];
|
|
[publicRoomsDict removeObjectForKey:homeserver];
|
|
}
|
|
|
|
[self refreshPublicRooms:nil];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)setEnableSearch:(BOOL)enableSearch
|
|
{
|
|
if (enableSearch)
|
|
{
|
|
if (!searchButton)
|
|
{
|
|
searchButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(search:)];
|
|
}
|
|
|
|
// Add it in right bar items
|
|
NSArray *rightBarButtonItems = self.navigationItem.rightBarButtonItems;
|
|
self.navigationItem.rightBarButtonItems = rightBarButtonItems ? [rightBarButtonItems arrayByAddingObject:searchButton] : @[searchButton];
|
|
}
|
|
else
|
|
{
|
|
NSMutableArray *rightBarButtonItems = [NSMutableArray arrayWithArray: self.navigationItem.rightBarButtonItems];
|
|
[rightBarButtonItems removeObject:searchButton];
|
|
self.navigationItem.rightBarButtonItems = rightBarButtonItems;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Internals
|
|
|
|
- (void)removeClosedRestClients
|
|
{
|
|
// We check here all registered clients (Some of them may have been closed).
|
|
for (NSInteger index = 0; index < restClients.count; index ++)
|
|
{
|
|
MXRestClient *restClient = [restClients objectAtIndex:index];
|
|
if (!restClient.homeserver.length)
|
|
{
|
|
[self removeRestClient:restClient];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)refreshPublicRooms:(MXRestClient*)restClient
|
|
{
|
|
NSArray *selectedClients;
|
|
if (restClient) {
|
|
selectedClients = @[restClient];
|
|
} else {
|
|
// refresh registered clients by removing closed ones.
|
|
[self removeClosedRestClients];
|
|
|
|
// Consider only one client by homeserver.
|
|
selectedClients = restClientDict.allValues;
|
|
}
|
|
|
|
if (!selectedClients.count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
refreshCount += selectedClients.count;
|
|
[self startActivityIndicator];
|
|
|
|
if (!publicRoomsDict)
|
|
{
|
|
publicRoomsDict = [NSMutableDictionary dictionaryWithCapacity:restClientDict.count];
|
|
}
|
|
if (!shrinkedHomeServers)
|
|
{
|
|
shrinkedHomeServers = [NSMutableArray array];
|
|
}
|
|
|
|
for (NSInteger index = 0; index < selectedClients.count; index ++)
|
|
{
|
|
MXRestClient *restClient = [selectedClients objectAtIndex:index];
|
|
|
|
// Retrieve public rooms
|
|
[restClient publicRooms:^(NSArray *rooms){
|
|
NSArray *publicRooms = [rooms sortedArrayUsingComparator:^NSComparisonResult(id a, id b)
|
|
{
|
|
|
|
MXPublicRoom *firstRoom = (MXPublicRoom*)a;
|
|
MXPublicRoom *secondRoom = (MXPublicRoom*)b;
|
|
|
|
// Compare member count
|
|
if (firstRoom.numJoinedMembers < secondRoom.numJoinedMembers)
|
|
{
|
|
return NSOrderedDescending;
|
|
}
|
|
else if (firstRoom.numJoinedMembers > secondRoom.numJoinedMembers)
|
|
{
|
|
return NSOrderedAscending;
|
|
}
|
|
else
|
|
{
|
|
// Alphabetic order
|
|
return [firstRoom.displayname compare:secondRoom.displayname options:NSCaseInsensitiveSearch];
|
|
}
|
|
}];
|
|
|
|
if (publicRooms.count && restClient.homeserver)
|
|
{
|
|
[publicRoomsDict setObject:publicRooms forKey:restClient.homeserver];
|
|
}
|
|
|
|
refreshCount--;
|
|
if (refreshCount == 0)
|
|
{
|
|
[self publicRoomsDidRefresh];
|
|
}
|
|
}
|
|
failure:^(NSError *error){
|
|
NSLog(@"[HomeVC] Failed to get public rooms for %@: %@", restClient.homeserver, error);
|
|
//Alert user
|
|
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
|
|
|
refreshCount--;
|
|
if (refreshCount == 0)
|
|
{
|
|
[self publicRoomsDidRefresh];
|
|
}
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)publicRoomsDidRefresh
|
|
{
|
|
[self stopActivityIndicator];
|
|
|
|
// Refresh only the sections related to public rooms (in order to not dismiss potential keyboard).
|
|
NSInteger sectionNb = [self numberOfSectionsInTableView:self.tableView];
|
|
if (publicRoomsFirstSection != -1)
|
|
{
|
|
sectionNb -= publicRoomsFirstSection;
|
|
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange (publicRoomsFirstSection, sectionNb)];
|
|
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone];
|
|
}
|
|
}
|
|
|
|
- (IBAction)search:(id)sender
|
|
{
|
|
if (_publicRoomsSearchBar.isHidden)
|
|
{
|
|
// Check whether there are data in which search
|
|
if (publicRoomsDict.count)
|
|
{
|
|
// Show search bar
|
|
_publicRoomsSearchBar.hidden = NO;
|
|
_publicRoomsSearchBarHeightConstraint.constant = 44;
|
|
[self.view setNeedsUpdateConstraints];
|
|
|
|
searchBarShouldEndEditing = NO;
|
|
[_publicRoomsSearchBar becomeFirstResponder];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self searchBarCancelButtonClicked: _publicRoomsSearchBar];
|
|
}
|
|
|
|
[self.tableView reloadData];
|
|
}
|
|
|
|
- (void)dismissKeyboard
|
|
{
|
|
[createRoomView dismissKeyboard];
|
|
|
|
[joinRoomCell.mxkTextField resignFirstResponder];
|
|
|
|
if (_publicRoomsSearchBar)
|
|
{
|
|
[self searchBarCancelButtonClicked: _publicRoomsSearchBar];
|
|
}
|
|
}
|
|
|
|
#pragma mark - MXKRoomCreationView Delegate
|
|
|
|
- (void)roomCreationView:(MXKRoomCreationView *)creationView presentMXKAlert:(MXKAlert *)alert
|
|
{
|
|
[self dismissKeyboard];
|
|
[alert showInViewController:self];
|
|
}
|
|
|
|
- (void)roomCreationView:(MXKRoomCreationView *)creationView showRoom:(NSString *)roomId withMatrixSession:(MXSession *)mxSession
|
|
{
|
|
[[AppDelegate theDelegate].masterTabBarController showRoom:roomId withMatrixSession:mxSession];
|
|
}
|
|
|
|
#pragma mark - UITextField delegate
|
|
|
|
- (void)textFieldDidBeginEditing:(UITextField *)textField
|
|
{
|
|
if (textField == joinRoomCell.mxkTextField)
|
|
{
|
|
if (textField.text.length == 0)
|
|
{
|
|
textField.text = @"#";
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)textFieldDidEndEditing:(UITextField *)textField
|
|
{
|
|
if (textField == joinRoomCell.mxkTextField)
|
|
{
|
|
if (textField.text.length < 2)
|
|
{
|
|
// reset text field
|
|
textField.text = nil;
|
|
joinRoomCell.mxkButton.enabled = NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
|
{
|
|
// Auto complete room alias
|
|
if (textField == joinRoomCell.mxkTextField)
|
|
{
|
|
// Add # if none
|
|
if (!textField.text.length || textField.text.length == range.length)
|
|
{
|
|
if ([string hasPrefix:@"#"] == NO)
|
|
{
|
|
textField.text = [NSString stringWithFormat:@"#%@",string];
|
|
// Update Join button status
|
|
joinRoomCell.mxkButton.enabled = YES;
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)textFieldShouldReturn:(UITextField*) textField
|
|
{
|
|
// "Done" key has been pressed
|
|
[textField resignFirstResponder];
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark - Actions
|
|
|
|
- (IBAction)onButtonPressed:(id)sender
|
|
{
|
|
if (sender == joinRoomCell.mxkButton)
|
|
{
|
|
[self dismissKeyboard];
|
|
|
|
// Handle multi-sessions here
|
|
[[AppDelegate theDelegate] selectMatrixAccount:^(MXKAccount *selectedAccount)
|
|
{
|
|
// Disable button to prevent multiple request
|
|
joinRoomCell.mxkButton.enabled = NO;
|
|
|
|
NSString *roomAlias = joinRoomCell.mxkTextField.text;
|
|
// Remove white space from both ends
|
|
roomAlias = [roomAlias stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
|
|
// Check
|
|
if (roomAlias.length)
|
|
{
|
|
[selectedAccount.mxSession joinRoom:roomAlias success:^(MXRoom *room)
|
|
{
|
|
// Reset text fields
|
|
joinRoomCell.mxkTextField.text = nil;
|
|
// Show the room
|
|
[[AppDelegate theDelegate].masterTabBarController showRoom:room.state.roomId withMatrixSession:selectedAccount.mxSession];
|
|
} failure:^(NSError *error)
|
|
{
|
|
joinRoomCell.mxkButton.enabled = YES;
|
|
NSLog(@"[HomeVC] Failed to join room alias (%@): %@", roomAlias, error);
|
|
// Alert user
|
|
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
// Reset text fields
|
|
joinRoomCell.mxkTextField.text = nil;
|
|
}
|
|
}];
|
|
}
|
|
else if ([sender isKindOfClass:[UIButton class]])
|
|
{
|
|
UIButton *shrinkButton = (UIButton*)sender;
|
|
|
|
if (shrinkButton.tag < homeServers.count)
|
|
{
|
|
NSString *homeserver = [homeServers objectAtIndex:shrinkButton.tag];
|
|
|
|
NSUInteger index = [shrinkedHomeServers indexOfObject:homeserver];
|
|
if (index != NSNotFound)
|
|
{
|
|
// Disclose the public rooms list
|
|
[shrinkedHomeServers removeObjectAtIndex:index];
|
|
}
|
|
else
|
|
{
|
|
// Shrink the public rooms list from this homeserver.
|
|
[shrinkedHomeServers addObject:homeserver];
|
|
}
|
|
// Refresh table
|
|
[self.tableView reloadData];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - Table view data source
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
|
{
|
|
NSInteger count = 0;
|
|
|
|
createRoomSection = joinRoomSection = publicRoomsFirstSection = -1;
|
|
|
|
// Room creation and join room alias required a matrix session, besides these sections are hidden during search session.
|
|
if (self.mxSessions.count && _publicRoomsSearchBar.isHidden)
|
|
{
|
|
createRoomSection = count++;
|
|
joinRoomSection = count++;
|
|
}
|
|
|
|
if (homeServers.count)
|
|
{
|
|
publicRoomsFirstSection = count;
|
|
count += homeServers.count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
{
|
|
NSInteger count = 0;
|
|
|
|
if (section == createRoomSection)
|
|
{
|
|
count = 1;
|
|
}
|
|
else if (section == joinRoomSection)
|
|
{
|
|
count = 1;
|
|
}
|
|
else if (publicRoomsFirstSection != -1)
|
|
{
|
|
NSArray *publicRooms = nil;
|
|
NSInteger index = section - publicRoomsFirstSection;
|
|
if (index < homeServers.count)
|
|
{
|
|
NSString *homeserver = [homeServers objectAtIndex:index];
|
|
|
|
// Check whether the list is shrinked
|
|
if ([shrinkedHomeServers indexOfObject:homeserver] == NSNotFound)
|
|
{
|
|
if (filteredPublicRoomsDict)
|
|
{
|
|
publicRooms = [filteredPublicRoomsDict objectForKey:homeserver];
|
|
}
|
|
else
|
|
{
|
|
publicRooms = [publicRoomsDict objectForKey:homeserver];
|
|
}
|
|
}
|
|
}
|
|
|
|
count = publicRooms.count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (indexPath.section == createRoomSection)
|
|
{
|
|
return createRoomView.actualFrameHeight;
|
|
}
|
|
else if ((publicRoomsFirstSection != -1) && (indexPath.section >= publicRoomsFirstSection))
|
|
{
|
|
return 60;
|
|
}
|
|
return 44;
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
UITableViewCell *cell;
|
|
|
|
if (indexPath.section == createRoomSection)
|
|
{
|
|
[createRoomView removeFromSuperview];
|
|
// Update view data
|
|
createRoomView.mxSessions = self.mxSessions;
|
|
|
|
cell = [tableView dequeueReusableCellWithIdentifier:kHomeViewControllerCreateRoomCellId];
|
|
if (!cell)
|
|
{
|
|
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kHomeViewControllerCreateRoomCellId];
|
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
}
|
|
|
|
// Add creation view in full size
|
|
[cell.contentView addSubview:createRoomView];
|
|
[cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:cell.contentView
|
|
attribute:NSLayoutAttributeBottom
|
|
relatedBy:NSLayoutRelationEqual
|
|
toItem:createRoomView
|
|
attribute:NSLayoutAttributeBottom
|
|
multiplier:1.0f
|
|
constant:0.0f]];
|
|
[cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:cell.contentView
|
|
attribute:NSLayoutAttributeTop
|
|
relatedBy:NSLayoutRelationEqual
|
|
toItem:createRoomView
|
|
attribute:NSLayoutAttributeTop
|
|
multiplier:1.0f
|
|
constant:0.0f]];
|
|
[cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:cell.contentView
|
|
attribute:NSLayoutAttributeLeading
|
|
relatedBy:NSLayoutRelationEqual
|
|
toItem:createRoomView
|
|
attribute:NSLayoutAttributeLeading
|
|
multiplier:1.0f
|
|
constant:0.0f]];
|
|
[cell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:cell.contentView
|
|
attribute:NSLayoutAttributeTrailing
|
|
relatedBy:NSLayoutRelationEqual
|
|
toItem:createRoomView
|
|
attribute:NSLayoutAttributeTrailing
|
|
multiplier:1.0f
|
|
constant:0.0f]];
|
|
[cell.contentView setNeedsUpdateConstraints];
|
|
|
|
}
|
|
else if (indexPath.section == joinRoomSection)
|
|
{
|
|
// Report the current value (if any)
|
|
NSString *currentAlias = nil;
|
|
if (joinRoomCell)
|
|
{
|
|
currentAlias = joinRoomCell.mxkTextField.text;
|
|
}
|
|
|
|
joinRoomCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithTextFieldAndButton defaultReuseIdentifier]];
|
|
if (!joinRoomCell)
|
|
{
|
|
joinRoomCell = [[MXKTableViewCellWithTextFieldAndButton alloc] init];
|
|
}
|
|
|
|
joinRoomCell.mxkTextField.text = currentAlias;
|
|
joinRoomCell.mxkButton.enabled = (currentAlias.length != 0);
|
|
[joinRoomCell.mxkButton setTitle:NSLocalizedStringFromTable(@"join", @"MatrixConsole", nil) forState:UIControlStateNormal];
|
|
[joinRoomCell.mxkButton setTitle:NSLocalizedStringFromTable(@"join", @"MatrixConsole", nil) forState:UIControlStateHighlighted];
|
|
[joinRoomCell.mxkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
cell = joinRoomCell;
|
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
}
|
|
else
|
|
{
|
|
MXKPublicRoomTableViewCell *publicRoomCell = [tableView dequeueReusableCellWithIdentifier:[MXKPublicRoomTableViewCell defaultReuseIdentifier]];
|
|
if (!publicRoomCell)
|
|
{
|
|
publicRoomCell = [[MXKPublicRoomTableViewCell alloc] init];
|
|
}
|
|
|
|
MXPublicRoom *publicRoom;
|
|
NSInteger index = indexPath.section - publicRoomsFirstSection;
|
|
if (index < homeServers.count)
|
|
{
|
|
NSString *homeserver = [homeServers objectAtIndex:index];
|
|
NSArray *publicRooms = nil;
|
|
if (filteredPublicRoomsDict)
|
|
{
|
|
publicRooms = [filteredPublicRoomsDict objectForKey:homeserver];
|
|
}
|
|
else
|
|
{
|
|
publicRooms = [publicRoomsDict objectForKey:homeserver];
|
|
}
|
|
|
|
if (indexPath.row < publicRooms.count)
|
|
{
|
|
publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
|
}
|
|
}
|
|
|
|
if (publicRoom)
|
|
{
|
|
[publicRoomCell render:publicRoom];
|
|
// Highlight?
|
|
publicRoomCell.focused = (publicRoomCell.roomDisplayName.text && [highlightedPublicRooms indexOfObject:publicRoomCell.roomDisplayName.text] != NSNotFound);
|
|
}
|
|
|
|
cell = publicRoomCell;
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
#pragma mark - Table view delegate
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
|
{
|
|
// In case of search session, homeservers with no result are hidden.
|
|
if (filteredPublicRoomsDict)
|
|
{
|
|
NSInteger index = section - publicRoomsFirstSection;
|
|
if (index < homeServers.count)
|
|
{
|
|
NSString *homeserver = [homeServers objectAtIndex:index];
|
|
NSArray *publicRooms = [filteredPublicRoomsDict objectForKey:homeserver];
|
|
if (!publicRooms.count)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 40;
|
|
}
|
|
|
|
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
|
|
{
|
|
UIView *sectionHeader = [[UIView alloc] initWithFrame:[tableView rectForHeaderInSection:section]];
|
|
sectionHeader.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0];
|
|
UILabel *sectionLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, sectionHeader.frame.size.width - 10, sectionHeader.frame.size.height - 10)];
|
|
sectionLabel.font = [UIFont boldSystemFontOfSize:16];
|
|
sectionLabel.backgroundColor = [UIColor clearColor];
|
|
[sectionHeader addSubview:sectionLabel];
|
|
|
|
if (section == createRoomSection)
|
|
{
|
|
sectionLabel.text = NSLocalizedStringFromTable(@"create_room", @"MatrixConsole", nil);
|
|
}
|
|
else if (section == joinRoomSection)
|
|
{
|
|
sectionLabel.text = NSLocalizedStringFromTable(@"join_room", @"MatrixConsole", nil);
|
|
}
|
|
else
|
|
{
|
|
NSArray *publicRooms = nil;
|
|
NSString *homeserver;
|
|
NSInteger index = section - publicRoomsFirstSection;
|
|
if (index < homeServers.count)
|
|
{
|
|
homeserver = [homeServers objectAtIndex:index];
|
|
|
|
if (filteredPublicRoomsDict)
|
|
{
|
|
publicRooms = [filteredPublicRoomsDict objectForKey:homeserver];
|
|
}
|
|
else
|
|
{
|
|
publicRooms = [publicRoomsDict objectForKey:homeserver];
|
|
}
|
|
}
|
|
|
|
if (publicRooms)
|
|
{
|
|
sectionLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"public_room_section_title", @"MatrixConsole", nil), homeserver];
|
|
|
|
if (homeServers.count > 1)
|
|
{
|
|
// Add shrink button
|
|
UIButton *shrinkButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
CGRect frame = sectionHeader.frame;
|
|
frame.origin.x = frame.origin.y = 0;
|
|
shrinkButton.frame = frame;
|
|
shrinkButton.backgroundColor = [UIColor clearColor];
|
|
[shrinkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
|
shrinkButton.tag = index;
|
|
[sectionHeader addSubview:shrinkButton];
|
|
sectionHeader.userInteractionEnabled = YES;
|
|
|
|
// Add shrink icon
|
|
UIImage *chevron;
|
|
if ([shrinkedHomeServers indexOfObject:homeserver] != NSNotFound)
|
|
{
|
|
chevron = [UIImage imageNamed:@"disclosure"];
|
|
}
|
|
else
|
|
{
|
|
chevron =[UIImage imageNamed:@"shrink"];
|
|
}
|
|
UIImageView *chevronView = [[UIImageView alloc] initWithImage:chevron];
|
|
chevronView.contentMode = UIViewContentModeCenter;
|
|
frame = chevronView.frame;
|
|
frame.origin.x = sectionHeader.frame.size.width - frame.size.width - 8;
|
|
frame.origin.y = (sectionHeader.frame.size.height - frame.size.height) / 2;
|
|
chevronView.frame = frame;
|
|
[sectionHeader addSubview:chevronView];
|
|
chevronView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);
|
|
|
|
// Update label frame
|
|
frame = sectionHeader.frame;
|
|
frame.origin.x = 5;
|
|
frame.origin.y = 5;
|
|
frame.size.width = chevronView.frame.origin.x - 10;
|
|
frame.size.height -= 10;
|
|
sectionLabel.frame = frame;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sectionLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"public_room_empty_section_title", @"MatrixConsole", nil), homeserver];
|
|
}
|
|
}
|
|
|
|
return sectionHeader;
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (indexPath.section < publicRoomsFirstSection)
|
|
{
|
|
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
|
}
|
|
else
|
|
{
|
|
// Hide the keyboard when user select a room
|
|
[self dismissKeyboard];
|
|
|
|
// Handle multi-sessions here
|
|
[[AppDelegate theDelegate] selectMatrixAccount:^(MXKAccount *selectedAccount)
|
|
{
|
|
MXPublicRoom *publicRoom;
|
|
NSInteger index = indexPath.section - publicRoomsFirstSection;
|
|
if (index < homeServers.count)
|
|
{
|
|
NSString *homeserver = [homeServers objectAtIndex:index];
|
|
NSArray *publicRooms = nil;
|
|
if (filteredPublicRoomsDict)
|
|
{
|
|
publicRooms = [filteredPublicRoomsDict objectForKey:homeserver];
|
|
}
|
|
else
|
|
{
|
|
publicRooms = [publicRoomsDict objectForKey:homeserver];
|
|
}
|
|
|
|
if (indexPath.row < publicRooms.count)
|
|
{
|
|
publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
|
}
|
|
}
|
|
|
|
if (publicRoom)
|
|
{
|
|
// Check whether the user has already joined the selected public room
|
|
if ([selectedAccount.mxSession roomWithRoomId:publicRoom.roomId])
|
|
{
|
|
// Open selected room
|
|
[[AppDelegate theDelegate].masterTabBarController showRoom:publicRoom.roomId withMatrixSession:selectedAccount.mxSession];
|
|
}
|
|
else
|
|
{
|
|
// Join the selected room
|
|
UIActivityIndicatorView *loadingWheel = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
|
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
|
|
if (selectedCell)
|
|
{
|
|
CGPoint center = CGPointMake(selectedCell.frame.size.width / 2, selectedCell.frame.size.height / 2);
|
|
loadingWheel.center = center;
|
|
[selectedCell addSubview:loadingWheel];
|
|
}
|
|
[loadingWheel startAnimating];
|
|
[selectedAccount.mxSession joinRoom:publicRoom.roomId success:^(MXRoom *room)
|
|
{
|
|
// Show joined room
|
|
[loadingWheel stopAnimating];
|
|
[loadingWheel removeFromSuperview];
|
|
[[AppDelegate theDelegate].masterTabBarController showRoom:publicRoom.roomId withMatrixSession:selectedAccount.mxSession];
|
|
} failure:^(NSError *error)
|
|
{
|
|
NSLog(@"[HomeVC] Failed to join public room (%@): %@", publicRoom.displayname, error);
|
|
//Alert user
|
|
[loadingWheel stopAnimating];
|
|
[loadingWheel removeFromSuperview];
|
|
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
|
}];
|
|
}
|
|
|
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
}
|
|
}];
|
|
}
|
|
}
|
|
|
|
#pragma mark - UISearchBarDelegate
|
|
|
|
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
|
|
{
|
|
searchBarShouldEndEditing = NO;
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
|
|
{
|
|
return searchBarShouldEndEditing;
|
|
}
|
|
|
|
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
|
{
|
|
// Update filtered list
|
|
if (searchText.length)
|
|
{
|
|
if (filteredPublicRoomsDict)
|
|
{
|
|
[filteredPublicRoomsDict removeAllObjects];
|
|
}
|
|
else
|
|
{
|
|
filteredPublicRoomsDict = [NSMutableDictionary dictionaryWithCapacity:homeServers.count];
|
|
}
|
|
|
|
for (NSString *homeserver in homeServers)
|
|
{
|
|
NSArray *publicRooms = [publicRoomsDict objectForKey:homeserver];
|
|
|
|
NSMutableArray *filteredRooms = [NSMutableArray array];
|
|
for (MXPublicRoom *publicRoom in publicRooms)
|
|
{
|
|
if ([[publicRoom displayname] rangeOfString:searchText options:NSCaseInsensitiveSearch].location != NSNotFound)
|
|
{
|
|
[filteredRooms addObject:publicRoom];
|
|
}
|
|
}
|
|
|
|
if (filteredRooms.count)
|
|
{
|
|
[filteredPublicRoomsDict setObject:filteredRooms forKey:homeserver];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
filteredPublicRoomsDict = nil;
|
|
}
|
|
// Refresh display
|
|
[self.tableView reloadData];
|
|
if (filteredPublicRoomsDict.count)
|
|
{
|
|
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
|
|
}
|
|
}
|
|
|
|
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
|
|
{
|
|
// "Done" key has been pressed
|
|
searchBarShouldEndEditing = YES;
|
|
[searchBar resignFirstResponder];
|
|
}
|
|
|
|
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
|
{
|
|
// Leave search
|
|
searchBarShouldEndEditing = YES;
|
|
[searchBar resignFirstResponder];
|
|
|
|
_publicRoomsSearchBar.hidden = YES;
|
|
_publicRoomsSearchBarHeightConstraint.constant = 0;
|
|
[self.view setNeedsUpdateConstraints];
|
|
|
|
_publicRoomsSearchBar.text = nil;
|
|
|
|
filteredPublicRoomsDict = nil;
|
|
[self.tableView reloadData];
|
|
if (self.tableView.numberOfSections && [self tableView:self.tableView numberOfRowsInSection:0])
|
|
{
|
|
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
|
|
}
|
|
}
|
|
|
|
@end
|