2015-01-20 12:33:01 +00:00
/ *
Copyright 2014 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 "ContactsViewController.h"
2015-01-21 12:25:13 +00:00
// SDK api
2015-01-23 14:53:39 +00:00
# import "MatrixSDKHandler.h"
2015-01-21 12:25:13 +00:00
// application info
# import "AppDelegate.h"
// contacts management
2015-01-20 12:33:01 +00:00
# import "ContactManager.h"
2015-01-23 13:22:02 +00:00
# import "MXCContact.h"
# import "MXCEmail.h"
# import "MXCPhoneNumber.h"
2015-01-20 12:33:01 +00:00
2015-01-21 12:25:13 +00:00
// contact cell
2015-01-20 12:33:01 +00:00
# import "ContactTableCell.h"
2015-01-21 12:25:13 +00:00
// alert
2015-01-23 13:22:02 +00:00
# import "MXCAlert.h"
2015-01-20 17:40:55 +00:00
2015-01-26 17:06:13 +00:00
// settings
# import "AppSettings.h"
2015-01-28 07:25:34 +00:00
//
# import "ContactDetailsViewController.h"
2015-01-21 12:25:13 +00:00
NSString * const kInvitationMessage = @ "I'd like to chat with you with matrix. Please, visit the website http://matrix.org to have more information." ;
2015-01-20 17:40:55 +00:00
2015-01-26 17:06:13 +00:00
@ interface ContactsViewController ( ) {
// YES -> only matrix users
// NO -> display local contacts
BOOL displayMatrixUsers ;
// screenshot of the local contacts
NSMutableArray * localContacts ;
SectionedContacts * sectionedLocalContacts ;
// screenshot of the matrix users
NSMutableDictionary * matrixUserByMatrixID ;
SectionedContacts * sectionedMatrixContacts ;
2015-01-28 07:25:34 +00:00
// tap on thumbnail to display contact info
MXCContact * selectedContact ;
2015-01-27 14:43:57 +00:00
// Search
UISearchBar * contactsSearchBar ;
NSMutableArray * filteredContacts ;
SectionedContacts * sectionedFilteredContacts ;
BOOL searchBarShouldEndEditing ;
NSString * latestSearchedPattern ;
2015-01-26 17:06:13 +00:00
}
2015-01-27 14:43:57 +00:00
2015-01-23 13:22:02 +00:00
@ property ( strong , nonatomic ) MXCAlert * startChatMenu ;
2015-01-26 17:06:13 +00:00
@ property ( strong , nonatomic ) MXCAlert * allowContactSyncAlert ;
2015-01-26 14:18:58 +00:00
@ property ( weak , nonatomic ) IBOutlet UITableView * tableView ;
2015-01-26 17:06:13 +00:00
@ property ( weak , nonatomic ) IBOutlet UISegmentedControl * contactsControls ;
@ property ( strong , nonatomic ) IBOutlet UIActivityIndicatorView * activityIndicator ;
2015-01-20 17:40:55 +00:00
@ end
2015-01-20 12:33:01 +00:00
@ implementation ContactsViewController
- ( void ) viewDidLoad {
[ super viewDidLoad ] ;
2015-01-20 15:29:42 +00:00
// get the system collation titles
collationTitles = [ [ UILocalizedIndexedCollation currentCollation ] sectionTitles ] ;
2015-01-26 17:06:13 +00:00
// global init
displayMatrixUsers = ( 0 = = self . contactsControls . selectedSegmentIndex ) ;
matrixUserByMatrixID = [ [ NSMutableDictionary alloc ] init ] ;
// event listener
[ [ MatrixSDKHandler sharedHandler ] addObserver : self forKeyPath : @ "status" options : 0 context : nil ] ;
2015-01-27 14:43:57 +00:00
// add the search icon on the right
// need to add more buttons ?
UIBarButtonItem * searchButton = [ [ UIBarButtonItem alloc ] initWithBarButtonSystemItem : UIBarButtonSystemItemSearch target : self action : @ selector ( search : ) ] ;
self . navigationItem . rightBarButtonItems = @ [ searchButton ] ;
2015-01-26 17:06:13 +00:00
2015-01-26 10:05:53 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( onContactsRefresh : ) name : kContactManagerContactsListRefreshNotification object : nil ] ;
2015-01-20 12:33:01 +00:00
}
2015-01-27 14:43:57 +00:00
- ( void ) viewWillAppear : ( BOOL ) animated {
[ super viewWillAppear : animated ] ;
// required to reduce the tableview height while searching
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( onKeyboardWillShow : ) name : UIKeyboardWillShowNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( onKeyboardWillHide : ) name : UIKeyboardWillHideNotification object : nil ] ;
}
- ( void ) viewWillDisappear : ( BOOL ) animated {
[ super viewWillDisappear : animated ] ;
// Leave potential search session
if ( contactsSearchBar ) {
[ self searchBarCancelButtonClicked : contactsSearchBar ] ;
}
[ [ NSNotificationCenter defaultCenter ] removeObserver : self name : UIKeyboardWillHideNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] removeObserver : self name : UIKeyboardWillShowNotification object : nil ] ;
}
2015-01-26 17:06:13 +00:00
- ( void ) startActivityIndicator {
[ _activityIndicator . layer setCornerRadius : 5 ] ;
_activityIndicator . hidden = NO ;
[ _activityIndicator startAnimating ] ;
}
- ( void ) stopActivityIndicator {
[ _activityIndicator stopAnimating ] ;
_activityIndicator . hidden = YES ;
}
2015-01-27 14:43:57 +00:00
- ( void ) scrollToTop {
// stop any scrolling effect
[ UIView setAnimationsEnabled : NO ] ;
// before scrolling to the tableview top
self . tableView . contentOffset = CGPointMake ( - self . tableView . contentInset . left , - self . tableView . contentInset . top ) ;
[ UIView setAnimationsEnabled : YES ] ;
}
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
// should be called when resetting the application
// the contact manager warn there is a contacts list update
// but the Matrix SDK handler has no more userID -> so assume there is a reset
- ( void ) reset {
// Leave potential search session
if ( contactsSearchBar ) {
[ self searchBarCancelButtonClicked : contactsSearchBar ] ;
}
localContacts = nil ;
sectionedLocalContacts = nil ;
matrixUserByMatrixID = [ [ NSMutableDictionary alloc ] init ] ;;
sectionedMatrixContacts = nil ;
[ self . contactsControls setSelectedSegmentIndex : 0 ] ;
[ self . tableView reloadData ] ;
}
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
# pragma mark - Keyboard handling
- ( void ) onKeyboardWillShow : ( NSNotification * ) notif {
// get the keyboard size
NSValue * rectVal = notif . userInfo [ UIKeyboardFrameEndUserInfoKey ] ;
CGRect endRect = rectVal . CGRectValue ;
// IOS 8 triggers some unexpected keyboard events
if ( ( endRect . size . height = = 0 ) || ( endRect . size . width = = 0 ) ) {
return ;
}
CGFloat keyboardHeight = ( endRect . origin . y = = 0 ) ? endRect . size . width : endRect . size . height ;
// the tableview bottom inset must also be updated
UIEdgeInsets insets = self . tableView . contentInset ;
insets . bottom = keyboardHeight ;
// get the animation info
NSNumber * curveValue = [ [ notif userInfo ] objectForKey : UIKeyboardAnimationCurveUserInfoKey ] ;
UIViewAnimationCurve animationCurve = curveValue . intValue ;
// the duration is ignored but it is better to define it
double animationDuration = [ [ [ notif userInfo ] objectForKey : UIKeyboardAnimationDurationUserInfoKey ] doubleValue ] ;
[ UIView animateWithDuration : animationDuration delay : 0 options : UIViewAnimationOptionBeginFromCurrentState | ( animationCurve < < 16 ) animations : ^ {
// reduce the tableview height
self . tableView . contentInset = insets ;
[ self . view layoutIfNeeded ] ;
2015-01-27 07:26:46 +00:00
2015-01-27 14:43:57 +00:00
} completion : ^ ( BOOL finished ) {
} ] ;
}
2015-01-27 07:26:46 +00:00
2015-01-27 14:43:57 +00:00
- ( void ) onKeyboardWillHide : ( NSNotification * ) notif {
// get the keyboard size
NSValue * rectVal = notif . userInfo [ UIKeyboardFrameEndUserInfoKey ] ;
CGRect endRect = rectVal . CGRectValue ;
rectVal = notif . userInfo [ UIKeyboardFrameBeginUserInfoKey ] ;
CGRect beginRect = rectVal . CGRectValue ;
UIEdgeInsets insets = self . tableView . contentInset ;
insets . bottom = 0 ;
// do not animate if the both rect are the same
// but ensure that the fields are properly resetted
// e . g . when the user swipes to hide the keyboard
// this method is called with invalid rects
// animationDuration is ignored because of the animation curve
// use it to be sure that it will be broken with any new IOS update
if ( CGRectEqualToRect ( endRect , beginRect ) ) {
self . tableView . contentInset = insets ;
[ self . view layoutIfNeeded ] ;
} else {
// get the animation info
NSNumber * curveValue = [ [ notif userInfo ] objectForKey : UIKeyboardAnimationCurveUserInfoKey ] ;
UIViewAnimationCurve animationCurve = curveValue . intValue ;
// the duration is ignored but it is better to define it
double animationDuration = [ [ [ notif userInfo ] objectForKey : UIKeyboardAnimationDurationUserInfoKey ] doubleValue ] ;
// animate the keyboard closing
[ UIView animateWithDuration : animationDuration delay : 0 options : UIViewAnimationOptionBeginFromCurrentState | ( animationCurve < < 16 ) animations : ^ {
self . tableView . contentInset = insets ;
[ self . view layoutIfNeeded ] ;
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
} completion : ^ ( BOOL finished ) {
} ] ;
}
}
# pragma mark - UITableView delegate
- ( void ) updateSectionedLocalContacts {
[ self stopActivityIndicator ] ;
ContactManager * sharedManager = [ ContactManager sharedManager ] ;
if ( ! localContacts ) {
localContacts = sharedManager . contacts ;
}
if ( ! sectionedLocalContacts ) {
sectionedLocalContacts = [ sharedManager getSectionedContacts : sharedManager . contacts ] ;
}
}
- ( void ) updateSectionedMatrixContacts {
2015-02-12 10:16:28 +00:00
// Check whether mxSession is available in matrix handler
2015-01-27 14:43:57 +00:00
MatrixSDKHandler * mxHandler = [ MatrixSDKHandler sharedHandler ] ;
2015-02-12 10:16:28 +00:00
if ( ! mxHandler . mxSession ) {
2015-01-27 14:43:57 +00:00
[ self startActivityIndicator ] ;
sectionedMatrixContacts = nil ;
} else {
[ self stopActivityIndicator ] ;
2015-02-16 09:37:17 +00:00
NSArray * usersIDs = [ mxHandler oneToOneRoomMemberIDs ] ;
2015-01-27 14:43:57 +00:00
// return a MatrixIDs list of 1 : 1 room members
NSMutableArray * knownUserIDs = [ [ matrixUserByMatrixID allKeys ] mutableCopy ] ;
// list the contacts IDs
// avoid delete and create the same ones
// it could save thumbnail downloads
for ( NSString * userID in usersIDs ) {
//
MXUser * user = [ mxHandler . mxSession userWithUserId : userID ] ;
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
// sanity check
if ( user ) {
// managed UserID
[ knownUserIDs removeObject : userID ] ;
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
MXCContact * contact = [ matrixUserByMatrixID objectForKey : userID ] ;
// already defined
if ( contact ) {
contact . displayName = ( user . displayname . length > 0 ) ? user . displayname : user . userId ;
} else {
contact = [ [ MXCContact alloc ] initWithDisplayName : ( ( user . displayname . length > 0 ) ? user . displayname : user . userId ) matrixID : user . userId ] ;
[ matrixUserByMatrixID setValue : contact forKey : userID ] ;
2015-01-26 17:06:13 +00:00
}
}
}
2015-01-27 14:43:57 +00:00
// some userIDs don ' t exist anymore
for ( NSString * userID in knownUserIDs ) {
[ matrixUserByMatrixID removeObjectForKey : userID ] ;
2015-01-26 17:06:13 +00:00
}
2015-01-27 14:43:57 +00:00
sectionedMatrixContacts = [ [ ContactManager sharedManager ] getSectionedContacts : [ matrixUserByMatrixID allValues ] ] ;
}
}
- ( NSInteger ) numberOfSectionsInTableView : ( UITableView * ) tableView {
// search in progress
if ( contactsSearchBar ) {
return sectionedFilteredContacts . sectionedContacts . count ;
}
else if ( displayMatrixUsers ) {
[ self updateSectionedMatrixContacts ] ;
return sectionedMatrixContacts . sectionedContacts . count ;
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
} else {
[ self updateSectionedLocalContacts ] ;
2015-01-26 17:06:13 +00:00
return sectionedLocalContacts . sectionedContacts . count ;
2015-01-20 12:33:01 +00:00
}
}
- ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section {
2015-01-27 14:43:57 +00:00
SectionedContacts * sectionedContacts = contactsSearchBar ? sectionedFilteredContacts : ( displayMatrixUsers ? sectionedMatrixContacts : sectionedLocalContacts ) ;
2015-01-26 17:06:13 +00:00
2015-01-27 14:43:57 +00:00
return [ [ sectionedContacts . sectionedContacts objectAtIndex : section ] count ] ;
2015-01-20 12:33:01 +00:00
}
2015-01-21 09:48:38 +00:00
- ( CGFloat ) tableView : ( UITableView * ) tableView heightForRowAtIndexPath : ( NSIndexPath * ) indexPath {
return 50 ;
}
2015-01-20 12:33:01 +00:00
- ( NSString * ) tableView : ( UITableView * ) aTableView titleForHeaderInSection : ( NSInteger ) section {
2015-01-27 14:43:57 +00:00
SectionedContacts * sectionedContacts = contactsSearchBar ? sectionedFilteredContacts : ( displayMatrixUsers ? sectionedMatrixContacts : sectionedLocalContacts ) ;
2015-01-26 17:06:13 +00:00
2015-01-20 12:33:01 +00:00
if ( sectionedContacts . sectionTitles . count <= section ) {
return nil ;
}
else {
return ( NSString * ) [ sectionedContacts . sectionTitles objectAtIndex : section ] ;
}
}
2015-01-27 08:19:32 +00:00
- ( NSArray * ) sectionIndexTitlesForTableView : ( UITableView * ) aTableView {
2015-01-27 14:43:57 +00:00
// do not display the collation during a search
if ( contactsSearchBar ) {
return nil ;
} else {
[ self . tableView setSectionIndexColor : [ AppDelegate theDelegate ] . masterTabBarController . tabBar . tintColor ] ;
[ self . tableView setSectionIndexBackgroundColor : [ UIColor clearColor ] ] ;
return [ [ UILocalizedIndexedCollation currentCollation ] sectionIndexTitles ] ;
}
2015-01-20 15:29:42 +00:00
}
2015-01-27 08:19:32 +00:00
- ( NSInteger ) tableView : ( UITableView * ) aTableView sectionForSectionIndexTitle : ( NSString * ) title atIndex : ( NSInteger ) index {
2015-01-27 14:43:57 +00:00
SectionedContacts * sectionedContacts = contactsSearchBar ? sectionedFilteredContacts : ( displayMatrixUsers ? sectionedMatrixContacts : sectionedLocalContacts ) ;
2015-01-27 08:19:32 +00:00
NSUInteger section = [ sectionedContacts . sectionTitles indexOfObject : title ] ;
2015-01-20 15:29:42 +00:00
// undefined title -> jump to the first valid non empty section
if ( NSNotFound = = section ) {
NSUInteger systemCollationIndex = [ collationTitles indexOfObject : title ] ;
// find in the system collation
if ( NSNotFound ! = systemCollationIndex ) {
systemCollationIndex - - ;
while ( ( systemCollationIndex = = 0 ) && ( NSNotFound = = section ) ) {
NSString * systemTitle = [ collationTitles objectAtIndex : systemCollationIndex ] ;
section = [ sectionedContacts . sectionTitles indexOfObject : systemTitle ] ;
systemCollationIndex - - ;
}
}
}
return section ;
}
2015-01-20 12:33:01 +00:00
- ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath {
ContactTableCell * cell = [ tableView dequeueReusableCellWithIdentifier : @ "ContactCell" forIndexPath : indexPath ] ;
2015-01-27 14:43:57 +00:00
SectionedContacts * sectionedContacts = contactsSearchBar ? sectionedFilteredContacts : ( displayMatrixUsers ? sectionedMatrixContacts : sectionedLocalContacts ) ;
2015-01-20 12:33:01 +00:00
2015-01-23 13:22:02 +00:00
MXCContact * contact = nil ;
2015-01-20 12:33:01 +00:00
if ( indexPath . section < sectionedContacts . sectionedContacts . count ) {
NSArray * thisSection = [ sectionedContacts . sectionedContacts objectAtIndex : indexPath . section ] ;
if ( indexPath . row < thisSection . count ) {
contact = [ thisSection objectAtIndex : indexPath . row ] ;
}
}
2015-01-28 07:25:34 +00:00
// tap on matrix user thumbnail -> open a detailled sheet
UITapGestureRecognizer * tapGesture = nil ;
// check if it is already defined
// gesture in storyboard does not seem to work properly
// it always triggers a tap event on the first cell
for ( UIGestureRecognizer * gesture in cell . thumbnailView . gestureRecognizers ) {
if ( [ gesture isKindOfClass : [ UITapGestureRecognizer class ] ] ) {
tapGesture = ( UITapGestureRecognizer * ) gesture ;
break ;
}
}
// add it if it is not yet defined
if ( ! tapGesture ) {
UITapGestureRecognizer * tap = [ [ UITapGestureRecognizer alloc ] initWithTarget : self action : @ selector ( onContactThumbnailTap : ) ] ;
[ tap setNumberOfTouchesRequired : 1 ] ;
[ tap setNumberOfTapsRequired : 1 ] ;
[ tap setDelegate : self ] ;
[ cell . thumbnailView addGestureRecognizer : tap ] ;
}
2015-01-20 15:29:42 +00:00
cell . contact = contact ;
2015-01-21 09:48:38 +00:00
2015-01-20 12:33:01 +00:00
return cell ;
}
2015-01-20 17:40:55 +00:00
- ( void ) tableView : ( UITableView * ) tableView didSelectRowAtIndexPath : ( NSIndexPath * ) indexPath {
[ tableView deselectRowAtIndexPath : indexPath animated : YES ] ;
2015-01-27 14:43:57 +00:00
SectionedContacts * sectionedContacts = contactsSearchBar ? sectionedFilteredContacts : ( displayMatrixUsers ? sectionedMatrixContacts : sectionedLocalContacts ) ;
2015-01-23 13:22:02 +00:00
MXCContact * contact = nil ;
2015-01-20 17:40:55 +00:00
if ( indexPath . section < sectionedContacts . sectionedContacts . count ) {
NSArray * thisSection = [ sectionedContacts . sectionedContacts objectAtIndex : indexPath . section ] ;
if ( indexPath . row < thisSection . count ) {
contact = [ thisSection objectAtIndex : indexPath . row ] ;
}
}
2015-01-21 12:25:13 +00:00
__weak typeof ( self ) weakSelf = self ;
2015-01-20 17:40:55 +00:00
NSArray * matrixIDs = contact . matrixIdentifiers ;
2015-01-27 09:15:26 +00:00
2015-01-21 12:25:13 +00:00
// matrix user ?
2015-01-20 17:40:55 +00:00
if ( matrixIDs . count ) {
2015-01-27 09:15:26 +00:00
MatrixSDKHandler * mxHandler = [ MatrixSDKHandler sharedHandler ] ;
2015-01-20 17:40:55 +00:00
2015-02-12 10:16:28 +00:00
// display only if the mxSession is available in matrix SDK handler
if ( mxHandler . mxSession ) {
2015-01-27 09:15:26 +00:00
// only 1 matrix ID
if ( matrixIDs . count = = 1 ) {
NSString * matrixID = [ matrixIDs objectAtIndex : 0 ] ;
2015-01-27 15:27:13 +00:00
self . startChatMenu = [ [ MXCAlert alloc ] initWithTitle : [ NSString stringWithFormat : @ "Chat with %@" , matrixID ] message : nil style : MXCAlertStyleAlert ] ;
2015-01-20 17:40:55 +00:00
2015-01-27 09:15:26 +00:00
[ self . startChatMenu addActionWithTitle : @ "Cancel" style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
weakSelf . startChatMenu = nil ;
} ] ;
[ self . startChatMenu addActionWithTitle : @ "OK" style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
weakSelf . startChatMenu = nil ;
2015-02-13 14:16:30 +00:00
[ mxHandler startPrivateOneToOneRoomWithUserId : matrixID ] ;
2015-01-27 09:15:26 +00:00
} ] ;
} else {
2015-01-27 15:27:13 +00:00
self . startChatMenu = [ [ MXCAlert alloc ] initWithTitle : [ NSString stringWithFormat : @ "Chat with " ] message : nil style : MXCAlertStyleActionSheet ] ;
2015-01-27 09:15:26 +00:00
for ( NSString * matrixID in matrixIDs ) {
[ self . startChatMenu addActionWithTitle : matrixID style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
weakSelf . startChatMenu = nil ;
2015-02-13 14:16:30 +00:00
[ mxHandler startPrivateOneToOneRoomWithUserId : matrixID ] ;
2015-01-27 09:15:26 +00:00
} ] ;
}
[ self . startChatMenu addActionWithTitle : @ "Cancel" style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
weakSelf . startChatMenu = nil ;
} ] ;
}
[ self . startChatMenu showInViewController : self ] ;
}
2015-01-21 12:25:13 +00:00
} else {
// invite to use matrix
if ( ( [ MFMessageComposeViewController canSendText ] ? contact . emailAddresses . count : 0 ) + ( contact . phoneNumbers . count > 0 ) ) {
2015-01-23 13:22:02 +00:00
self . startChatMenu = [ [ MXCAlert alloc ] initWithTitle : [ NSString stringWithFormat : @ "Invite this user to use matrix with" ] message : nil style : MXCAlertStyleActionSheet ] ;
2015-01-21 12:25:13 +00:00
// check if the target can send SMSes
if ( [ MFMessageComposeViewController canSendText ] ) {
// list phonenumbers
2015-01-23 13:22:02 +00:00
for ( MXCPhoneNumber * phonenumber in contact . phoneNumbers ) {
2015-01-21 12:25:13 +00:00
2015-01-23 13:22:02 +00:00
[ self . startChatMenu addActionWithTitle : phonenumber . textNumber style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
2015-01-21 12:25:13 +00:00
weakSelf . startChatMenu = nil ;
// launch SMS composer
MFMessageComposeViewController * messageComposer = [ [ MFMessageComposeViewController alloc ] init ] ;
if ( messageComposer )
{
messageComposer . messageComposeDelegate = weakSelf ;
messageComposer . body = kInvitationMessage ;
messageComposer . recipients = [ NSArray arrayWithObject : phonenumber . textNumber ] ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ weakSelf presentViewController : messageComposer animated : YES completion : nil ] ;
} ) ;
}
} ] ;
}
}
// list emails
2015-01-23 13:22:02 +00:00
for ( MXCEmail * email in contact . emailAddresses ) {
2015-01-21 12:25:13 +00:00
2015-01-23 13:22:02 +00:00
[ self . startChatMenu addActionWithTitle : email . emailAddress style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
2015-01-21 12:25:13 +00:00
weakSelf . startChatMenu = nil ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
NSString * subject = [ @ "Matrix.org is magic" stringByAddingPercentEscapesUsingEncoding : NSUTF8StringEncoding ] ;
NSString * body = [ kInvitationMessage stringByAddingPercentEscapesUsingEncoding : NSUTF8StringEncoding ] ;
[ [ UIApplication sharedApplication ] openURL : [ NSURL URLWithString : [ NSString stringWithFormat : @ "mailto:%@?subject=%@&body=%@" , email . emailAddress , subject , body ] ] ] ;
} ) ;
} ] ;
}
2015-01-23 13:22:02 +00:00
[ self . startChatMenu addActionWithTitle : @ "Cancel" style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
2015-01-21 12:25:13 +00:00
weakSelf . startChatMenu = nil ;
} ] ;
[ self . startChatMenu showInViewController : self ] ;
}
2015-01-20 17:40:55 +00:00
}
}
2015-01-26 17:06:13 +00:00
# pragma mark - KVO
- ( void ) observeValueForKeyPath : ( NSString * ) keyPath ofObject : ( id ) object change : ( NSDictionary * ) change context : ( void * ) context {
if ( [ @ "status" isEqualToString : keyPath ] ) {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
if ( displayMatrixUsers ) {
2015-01-27 14:43:57 +00:00
if ( contactsSearchBar ) {
[ self updateSectionedMatrixContacts ] ;
latestSearchedPattern = nil ;
[ self searchBar : contactsSearchBar textDidChange : contactsSearchBar . text ] ;
} else {
[ self . tableView reloadData ] ;
}
2015-01-26 17:06:13 +00:00
}
} ) ;
}
}
2015-01-20 12:33:01 +00:00
# pragma mark - Actions
- ( void ) onContactsRefresh : ( NSNotification * ) notif {
2015-01-26 17:06:13 +00:00
localContacts = nil ;
sectionedLocalContacts = nil ;
2015-01-27 14:43:57 +00:00
// there is an user id
if ( [ [ MatrixSDKHandler sharedHandler ] userId ] ) {
[ self updateSectionedLocalContacts ] ;
//
if ( ! displayMatrixUsers ) {
if ( contactsSearchBar ) {
latestSearchedPattern = nil ;
[ self searchBar : contactsSearchBar textDidChange : contactsSearchBar . text ] ;
} else {
[ self . tableView reloadData ] ;
}
}
} else {
// the client could have been logged out
[ self reset ] ;
}
2015-01-20 12:33:01 +00:00
}
2015-01-26 17:06:13 +00:00
- ( IBAction ) onSegmentValueChange : ( id ) sender {
if ( sender = = self . contactsControls ) {
displayMatrixUsers = ( 0 = = self . contactsControls . selectedSegmentIndex ) ;
2015-01-27 14:43:57 +00:00
if ( contactsSearchBar ) {
if ( displayMatrixUsers ) {
[ self updateSectionedMatrixContacts ] ;
} else {
[ self updateSectionedLocalContacts ] ;
}
latestSearchedPattern = nil ;
[ self searchBar : contactsSearchBar textDidChange : contactsSearchBar . text ] ;
} else {
[ self . tableView reloadData ] ;
}
2015-01-26 17:06:13 +00:00
if ( ! displayMatrixUsers ) {
AppSettings * appSettings = [ AppSettings sharedSettings ] ;
2015-03-02 09:44:08 +00:00
if ( ! appSettings . syncLocalContacts ) {
2015-01-26 17:06:13 +00:00
__weak typeof ( self ) weakSelf = self ;
self . allowContactSyncAlert = [ [ MXCAlert alloc ] initWithTitle : @ "Allow local contacts synchronization ?" message : nil style : MXCAlertStyleAlert ] ;
2015-02-24 15:39:03 +00:00
[ self . allowContactSyncAlert addActionWithTitle : @ "No" style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
2015-01-26 17:06:13 +00:00
weakSelf . allowContactSyncAlert = nil ;
} ] ;
2015-02-24 15:39:03 +00:00
[ self . allowContactSyncAlert addActionWithTitle : @ "Yes" style : MXCAlertActionStyleDefault handler : ^ ( MXCAlert * alert ) {
2015-01-26 17:06:13 +00:00
weakSelf . allowContactSyncAlert = nil ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
appSettings . syncLocalContacts = YES ;
[ weakSelf . tableView reloadData ] ;
} ) ;
} ] ;
[ self . allowContactSyncAlert showInViewController : self ] ;
}
}
}
}
2015-01-27 14:43:57 +00:00
2015-01-28 07:25:34 +00:00
- ( IBAction ) onContactThumbnailTap : ( id ) sender {
if ( [ sender isKindOfClass : [ UITapGestureRecognizer class ] ] ) {
UIView * tappedView = ( ( UITapGestureRecognizer * ) sender ) . view ;
// search the parentce cell
while ( tappedView && ! [ tappedView isKindOfClass : [ ContactTableCell class ] ] ) {
tappedView = tappedView . superview ;
}
// find it ?
if ( [ tappedView isKindOfClass : [ ContactTableCell class ] ] ) {
MXCContact * contact = ( ( ContactTableCell * ) tappedView ) . contact ;
// open detailled sheet if there
if ( contact . matrixIdentifiers . count > 0 ) {
selectedContact = ( ( ContactTableCell * ) tappedView ) . contact ;
[ self performSegueWithIdentifier : @ "showContactDetails" sender : self ] ;
}
}
}
}
# pragma mark - Segues
- ( void ) prepareForSegue : ( UIStoryboardSegue * ) segue sender : ( id ) sender {
if ( [ segue . identifier isEqualToString : @ "showContactDetails" ] ) {
ContactDetailsViewController * contactDetailsViewController = segue . destinationViewController ;
contactDetailsViewController . contact = selectedContact ;
selectedContact = nil ;
}
}
2015-01-21 12:25:13 +00:00
# pragma mark MFMessageComposeViewControllerDelegate
- ( void ) messageComposeViewController : ( MFMessageComposeViewController * ) controller didFinishWithResult : ( MessageComposeResult ) result {
[ self dismissViewControllerAnimated : YES completion : nil ] ;
}
2015-01-27 14:43:57 +00:00
# pragma mark Search management
- ( void ) search : ( id ) sender {
if ( ! contactsSearchBar ) {
SectionedContacts * sectionedContacts = displayMatrixUsers ? sectionedMatrixContacts : sectionedLocalContacts ;
// Check whether there are data in which search
if ( sectionedContacts . sectionedContacts . count > 0 ) {
// Create search bar
contactsSearchBar = [ [ UISearchBar alloc ] initWithFrame : CGRectMake ( 0 , 0 , self . view . frame . size . width , 44 ) ] ;
contactsSearchBar . showsCancelButton = YES ;
contactsSearchBar . returnKeyType = UIReturnKeyDone ;
contactsSearchBar . delegate = self ;
contactsSearchBar . tintColor = [ AppDelegate theDelegate ] . masterTabBarController . tabBar . tintColor ;
searchBarShouldEndEditing = NO ;
// init the table content
latestSearchedPattern = @ "" ;
filteredContacts = [ ( displayMatrixUsers ? [ matrixUserByMatrixID allValues ] : localContacts ) mutableCopy ] ;
sectionedFilteredContacts = [ [ ContactManager sharedManager ] getSectionedContacts : filteredContacts ] ;
self . tableView . tableHeaderView = contactsSearchBar ;
[ self . tableView reloadData ] ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ contactsSearchBar becomeFirstResponder ] ;
} ) ;
}
} else {
[ self searchBarCancelButtonClicked : contactsSearchBar ] ;
}
}
# pragma mark - UISearchBarDelegate
- ( BOOL ) searchBarShouldBeginEditing : ( UISearchBar * ) searchBar {
searchBarShouldEndEditing = NO ;
return YES ;
}
- ( BOOL ) searchBarShouldEndEditing : ( UISearchBar * ) searchBar {
return searchBarShouldEndEditing ;
}
- ( NSArray * ) patternsFromText : ( NSString * ) text {
NSArray * items = [ text componentsSeparatedByString : @ " " ] ;
if ( items . count <= 1 ) {
return items ;
}
NSMutableArray * patterns = [ [ NSMutableArray alloc ] init ] ;
for ( NSString * item in items ) {
if ( item . length > 0 ) {
[ patterns addObject : item ] ;
}
}
return patterns ;
}
- ( void ) searchBar : ( UISearchBar * ) searchBar textDidChange : ( NSString * ) searchText {
if ( ( contactsSearchBar = = searchBar ) && ( ! [ latestSearchedPattern isEqualToString : searchText ] ) ) {
latestSearchedPattern = searchText ;
// contacts
NSArray * contacts = displayMatrixUsers ? [ matrixUserByMatrixID allValues ] : localContacts ;
// Update filtered list
if ( searchText . length && contacts . count ) {
filteredContacts = [ [ NSMutableArray alloc ] init ] ;
NSArray * patterns = [ self patternsFromText : searchText ] ;
for ( MXCContact * contact in contacts ) {
if ( [ contact matchedWithPatterns : patterns ] ) {
[ filteredContacts addObject : contact ] ;
}
}
} else {
filteredContacts = [ contacts mutableCopy ] ;
}
sectionedFilteredContacts = [ [ ContactManager sharedManager ] getSectionedContacts : filteredContacts ] ;
// Refresh display
[ self . tableView reloadData ] ;
[ self scrollToTop ] ;
}
}
- ( void ) searchBarSearchButtonClicked : ( UISearchBar * ) searchBar {
if ( contactsSearchBar = = searchBar ) {
// "Done" key has been pressed
searchBarShouldEndEditing = YES ;
[ contactsSearchBar resignFirstResponder ] ;
}
}
- ( void ) searchBarCancelButtonClicked : ( UISearchBar * ) searchBar {
if ( contactsSearchBar = = searchBar ) {
// Leave search
searchBarShouldEndEditing = YES ;
[ contactsSearchBar resignFirstResponder ] ;
contactsSearchBar = nil ;
filteredContacts = nil ;
sectionedFilteredContacts = nil ;
latestSearchedPattern = nil ;
self . tableView . tableHeaderView = nil ;
[ self . tableView reloadData ] ;
[ self scrollToTop ] ;
}
}
2015-01-20 12:33:01 +00:00
@ end