element-ios/Riot/ViewController/MasterTabBarController.m
Giom Foret 9c67c0200c Prepare UX Rework:
- Define the 4 tabs: Home, Fav, People and Rooms
2017-04-06 14:27:45 +02:00

538 lines
20 KiB
Objective-C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright 2017 Vector Creations 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 "MasterTabBarController.h"
#import "UnifiedSearchViewController.h"
#import "RecentsDataSource.h"
#import "AppDelegate.h"
@interface MasterTabBarController ()
{
// Array of `MXSession` instances.
NSMutableArray *mxSessionArray;
// Tell whether the authentication screen is preparing.
BOOL isAuthViewControllerPreparing;
// Observer that checks when the Authentification view controller has gone.
id authViewControllerObserver;
// The parameters to pass to the Authentification view controller.
NSDictionary *authViewControllerRegistrationParameters;
// The recents data source shared between all the view controllers of the tab bar.
RecentsDataSource *recentsDataSource;
// The current unified search screen if any
UnifiedSearchViewController *unifiedSearchViewController;
// Current alert (if any).
MXKAlert *currentAlert;
}
@end
@implementation MasterTabBarController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Retrieve the all view controllers
_homeViewController = [self.viewControllers objectAtIndex:TABBAR_HOME_INDEX];
_favouritesViewController = [self.viewControllers objectAtIndex:TABBAR_FAVOURITES_INDEX];
_peopleViewController = [self.viewControllers objectAtIndex:TABBAR_PEOPLE_INDEX];
_roomsViewController = [self.viewControllers objectAtIndex:TABBAR_ROOMS_INDEX];
// Sanity check
NSAssert(_homeViewController && _favouritesViewController && _peopleViewController && _roomsViewController, @"Something wrong in Main.storyboard");
self.tabBar.tintColor = kRiotColorGreen;
// Initialize here the data sources if a matrix session has been already set.
[self initializeDataSources];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Check whether we're not logged in
if (![MXKAccountManager sharedManager].accounts.count)
{
[self showAuthenticationScreen];
}
else
{
// Check whether the user has been already prompted to send crash reports.
// (Check whether 'enableCrashReport' flag has been set once)
if (![[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"])
{
[self promptUserBeforeUsingGoogleAnalytics];
}
}
if (unifiedSearchViewController)
{
[unifiedSearchViewController destroy];
unifiedSearchViewController = nil;
}
}
- (void)dealloc
{
mxSessionArray = nil;
_homeViewController = nil;
_favouritesViewController = nil;
_peopleViewController = nil;
_roomsViewController = nil;
if (currentAlert)
{
[currentAlert dismiss:NO];
currentAlert = nil;
}
if (authViewControllerObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:authViewControllerObserver];
authViewControllerObserver = nil;
}
}
#pragma mark -
- (NSArray*)mxSessions
{
return [NSArray arrayWithArray:mxSessionArray];
}
- (void)initializeDataSources
{
MXSession *mainSession = mxSessionArray.firstObject;
if (mainSession)
{
// Init the recents data source
recentsDataSource = [[RecentsDataSource alloc] initWithMatrixSession:mainSession];
[_homeViewController displayList:recentsDataSource];
[_favouritesViewController displayList:recentsDataSource];
[_peopleViewController displayDirectRooms:recentsDataSource];
[_roomsViewController displayList:recentsDataSource];
// Check whether there are others sessions
NSArray* mxSessions = self.mxSessions;
if (mxSessions.count > 1)
{
for (MXSession *mxSession in mxSessions)
{
if (mxSession != mainSession)
{
// Add the session to the recents data source
[recentsDataSource addMatrixSession:mxSession];
}
}
}
}
}
- (void)addMatrixSession:(MXSession *)mxSession
{
// Check whether the controller'€™s view is loaded into memory.
if (_homeViewController)
{
// Check whether the data sources have been initialized.
if (!recentsDataSource)
{
// Add first the session. The updated sessions list will be used during data sources initialization.
mxSessionArray = [NSMutableArray array];
[mxSessionArray addObject:mxSession];
// Prepare data sources and return
[self initializeDataSources];
return;
}
else
{
// Add the session to the existing data sources
[recentsDataSource addMatrixSession:mxSession];
}
}
if (!mxSessionArray)
{
mxSessionArray = [NSMutableArray array];
}
[mxSessionArray addObject:mxSession];
}
- (void)removeMatrixSession:(MXSession *)mxSession
{
[recentsDataSource removeMatrixSession:mxSession];
// Check whether there are others sessions
if (!recentsDataSource.mxSessions.count)
{
[_homeViewController displayList:nil];
[_favouritesViewController displayList:nil];
[_peopleViewController displayDirectRooms:nil];
[_roomsViewController displayList:nil];
[recentsDataSource destroy];
recentsDataSource = nil;
}
[mxSessionArray removeObject:mxSession];
}
- (void)showAuthenticationScreen
{
// Check whether an authentication screen is not already shown or preparing
if (!self.authViewController && !isAuthViewControllerPreparing)
{
isAuthViewControllerPreparing = YES;
[[AppDelegate theDelegate] restoreInitialDisplay:^{
[self performSegueWithIdentifier:@"showAuth" sender:self];
}];
}
}
- (void)showAuthenticationScreenWithRegistrationParameters:(NSDictionary *)parameters
{
if (self.authViewController)
{
NSLog(@"[MasterTabBarController] Universal link: Forward registration parameter to the existing AuthViewController");
self.authViewController.externalRegistrationParameters = parameters;
}
else
{
NSLog(@"[MasterTabBarController] Universal link: Logout current sessions and open AuthViewController to complete the registration");
// Keep a ref on the params
authViewControllerRegistrationParameters = parameters;
// And do a logout out. It will then display AuthViewController
[[AppDelegate theDelegate] logout];
}
}
- (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession
{
if (_selectedRoomId && [_selectedRoomId isEqualToString:roomId]
&& _selectedEventId && [_selectedEventId isEqualToString:eventId]
&& _selectedRoomSession && _selectedRoomSession == matrixSession)
{
// Nothing to do
return;
}
_selectedRoomId = roomId;
_selectedEventId = eventId;
_selectedRoomSession = matrixSession;
if (roomId && matrixSession)
{
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
}
else
{
[self releaseSelectedItem];
}
}
- (void)showRoomPreview:(RoomPreviewData *)roomPreviewData
{
_selectedRoomPreviewData = roomPreviewData;
_selectedRoomId = roomPreviewData.roomId;
_selectedRoomSession = roomPreviewData.mxSession;
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
}
- (void)selectContact:(MXKContact*)contact
{
_selectedContact = contact;
[self performSegueWithIdentifier:@"showContactDetails" sender:self];
}
- (void)releaseSelectedItem
{
_selectedRoomId = nil;
_selectedEventId = nil;
_selectedRoomSession = nil;
if (_currentRoomViewController)
{
// If the displayed data is not a preview, let the manager release the room data source
// (except if the view controller has the room data source ownership).
if (!_currentRoomViewController.roomPreviewData && _currentRoomViewController.roomDataSource && !_currentRoomViewController.hasRoomDataSourceOwnership)
{
MXSession *mxSession = _currentRoomViewController.roomDataSource.mxSession;
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession];
// Let the manager release live room data sources where the user is in
[roomDataSourceManager closeRoomDataSource:_currentRoomViewController.roomDataSource forceClose:NO];
}
[_currentRoomViewController destroy];
_currentRoomViewController = nil;
}
_selectedContact = nil;
if (_currentContactDetailViewController)
{
[_currentContactDetailViewController destroy];
_currentContactDetailViewController = nil;
}
}
- (void)dismissUnifiedSearch:(BOOL)animated completion:(void (^)(void))completion
{
if (unifiedSearchViewController)
{
[self.navigationController dismissViewControllerAnimated:animated completion:completion];
}
else if (completion)
{
completion();
}
}
#pragma mark -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showRoomDetails"] || [[segue identifier] isEqualToString:@"showContactDetails"])
{
UINavigationController *navigationController = [segue destinationViewController];
// Release existing Room view controller (if any)
if (_currentRoomViewController)
{
// If the displayed data is not a preview, let the manager release the room data source
// (except if the view controller has the room data source ownership).
if (!_currentRoomViewController.roomPreviewData && _currentRoomViewController.roomDataSource && !_currentRoomViewController.hasRoomDataSourceOwnership)
{
MXSession *mxSession = _currentRoomViewController.roomDataSource.mxSession;
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession];
[roomDataSourceManager closeRoomDataSource:_currentRoomViewController.roomDataSource forceClose:NO];
}
[_currentRoomViewController destroy];
_currentRoomViewController = nil;
}
else if (_currentContactDetailViewController)
{
[_currentContactDetailViewController destroy];
_currentContactDetailViewController = nil;
}
if ([[segue identifier] isEqualToString:@"showRoomDetails"])
{
// Replace the rootviewcontroller with a room view controller
// Get the RoomViewController from the storyboard
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
navigationController.viewControllers = @[_currentRoomViewController];
if (!_selectedRoomPreviewData)
{
MXKRoomDataSource *roomDataSource;
// Check whether an event has been selected from messages or files search tab.
MXEvent *selectedSearchEvent = unifiedSearchViewController.selectedSearchEvent;
MXSession *selectedSearchEventSession = unifiedSearchViewController.selectedSearchEventSession;
if (!selectedSearchEvent)
{
if (!_selectedEventId)
{
// LIVE: Show the room live timeline managed by MXKRoomDataSourceManager
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:_selectedRoomSession];
roomDataSource = [roomDataSourceManager roomDataSourceForRoom:_selectedRoomId create:YES];
}
else
{
// Open the room on the requested event
roomDataSource = [[RoomDataSource alloc] initWithRoomId:_selectedRoomId initialEventId:_selectedEventId andMatrixSession:_selectedRoomSession];
[roomDataSource finalizeInitialization];
// Give the data source ownership to the room view controller.
_currentRoomViewController.hasRoomDataSourceOwnership = YES;
}
}
else
{
// Search result: Create a temp timeline from the selected event
roomDataSource = [[RoomDataSource alloc] initWithRoomId:selectedSearchEvent.roomId initialEventId:selectedSearchEvent.eventId andMatrixSession:selectedSearchEventSession];
[roomDataSource finalizeInitialization];
// Give the data source ownership to the room view controller.
_currentRoomViewController.hasRoomDataSourceOwnership = YES;
}
[_currentRoomViewController displayRoom:roomDataSource];
}
else
{
[_currentRoomViewController displayRoomPreview:_selectedRoomPreviewData];
_selectedRoomPreviewData = nil;
}
}
else
{
// Replace the rootviewcontroller with a contact details view controller
_currentContactDetailViewController = [ContactDetailsViewController contactDetailsViewController];
_currentContactDetailViewController.enableVoipCall = NO;
_currentContactDetailViewController.contact = _selectedContact;
navigationController.viewControllers = @[_currentContactDetailViewController];
}
if (self.splitViewController)
{
// Refresh selected cell without scrolling the selected cell (We suppose it's visible here)
[self refreshCurrentSelectedCell:NO];
if (_currentRoomViewController)
{
_currentRoomViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
_currentRoomViewController.navigationItem.leftItemsSupplementBackButton = YES;
}
else
{
_currentContactDetailViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
_currentContactDetailViewController.navigationItem.leftItemsSupplementBackButton = YES;
}
}
}
else
{
// Keep ref on destinationViewController
[super prepareForSegue:segue sender:sender];
if ([[segue identifier] isEqualToString:@"showAuth"])
{
// Keep ref on the authentification view controller while it is displayed
// ie until we get the notification about a new account
_authViewController = segue.destinationViewController;
isAuthViewControllerPreparing = NO;
authViewControllerObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
_authViewController = nil;
[[NSNotificationCenter defaultCenter] removeObserver:authViewControllerObserver];
authViewControllerObserver = nil;
}];
// Forward parameters if any
if (authViewControllerRegistrationParameters)
{
_authViewController.externalRegistrationParameters = authViewControllerRegistrationParameters;
authViewControllerRegistrationParameters = nil;
}
}
else if ([[segue identifier] isEqualToString:@"showUnifiedSearch"])
{
unifiedSearchViewController= segue.destinationViewController;
for (MXSession *session in mxSessionArray)
{
[unifiedSearchViewController addMatrixSession:session];
}
}
}
// Hide back button title
self.navigationController.topViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
// Made the actual selected view controller update its selected cell.
- (void)refreshCurrentSelectedCell:(BOOL)forceVisible
{
UIViewController *selectedViewController = self.selectedViewController;
if ([selectedViewController respondsToSelector:@selector(refreshCurrentSelectedCell:)])
{
[(id)selectedViewController refreshCurrentSelectedCell:forceVisible];
}}
#pragma mark -
- (void)promptUserBeforeUsingGoogleAnalytics
{
NSLog(@"[MasterTabBarController]: Invite the user to send crash reports");
__weak typeof(self) weakSelf = self;
[currentAlert dismiss:NO];
NSString *appDisplayName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
currentAlert = [[MXKAlert alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"google_analytics_use_prompt", @"Vector", nil), appDisplayName]
message:nil
style:MXKAlertStyleAlert];
currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"no"]
style:MXKAlertActionStyleDefault
handler:^(MXKAlert *alert) {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableCrashReport"];
[[NSUserDefaults standardUserDefaults] synchronize];
if (weakSelf)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf->currentAlert = nil;
}
}];
[currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"yes"]
style:MXKAlertActionStyleDefault
handler:^(MXKAlert *alert) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"enableCrashReport"];
[[NSUserDefaults standardUserDefaults] synchronize];
if (weakSelf)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf->currentAlert = nil;
}
[[AppDelegate theDelegate] startGoogleAnalytics];
}];
currentAlert.mxkAccessibilityIdentifier = @"HomeVCUseGoogleAnalyticsAlert";
[currentAlert showInViewController:self];
}
@end