2014-12-23 17:51:49 +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 "MemberViewController.h"
# import "AppDelegate.h"
# import "MemberActionsCell.h"
# import "MediaManager.h"
@ interface MemberViewController ( ) {
id imageLoader ;
id membersListener ;
2014-12-24 07:59:25 +00:00
2014-12-24 10:06:54 +00:00
NSMutableArray * buttonsTitles ;
// mask view while processing a request
UIView * pendingRequestMask ;
2014-12-24 07:59:25 +00:00
UIActivityIndicatorView * pendingMaskSpinnerView ;
2014-12-23 17:51:49 +00:00
}
2014-12-24 10:06:54 +00:00
// graphical objects
@ property ( strong , nonatomic ) IBOutlet UITableView * tableView ;
@ property ( weak , nonatomic ) IBOutlet UIButton * memberThumbnailButton ;
@ property ( weak , nonatomic ) IBOutlet UITextView * roomMemberMID ;
2014-12-23 17:51:49 +00:00
@ property ( strong , nonatomic ) CustomAlert * actionMenu ;
2014-12-24 10:06:54 +00:00
- ( IBAction ) onButtonToggle : ( id ) sender ;
2014-12-23 17:51:49 +00:00
@ end
@ implementation MemberViewController
@ synthesize mxRoom ;
2014-12-24 10:06:54 +00:00
- ( void ) dealloc {
// close any pending actionsheet
if ( self . actionMenu ) {
[ self . actionMenu dismiss : NO ] ;
self . actionMenu = nil ;
}
if ( imageLoader ) {
[ MediaManager cancel : imageLoader ] ;
imageLoader = nil ;
}
if ( membersListener ) {
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
[ mxHandler . mxSession removeListener : membersListener ] ;
membersListener = nil ;
}
}
2014-12-23 17:51:49 +00:00
- ( void ) viewDidLoad {
[ super viewDidLoad ] ;
// remove the line separator color
self . tableView . separatorColor = [ UIColor clearColor ] ;
self . tableView . rowHeight = 44 ;
self . tableView . allowsSelection = NO ;
buttonsTitles = [ [ NSMutableArray alloc ] init ] ;
// ignore useless update
2014-12-24 10:06:54 +00:00
if ( _mxRoomMember ) {
2014-12-23 17:51:49 +00:00
[ self updateMemberInfo ] ;
}
}
- ( void ) viewWillAppear : ( BOOL ) animated {
[ super viewWillAppear : animated ] ;
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
NSArray * mxMembersEvents = @ [
kMXEventTypeStringRoomMember ,
kMXEventTypeStringRoomPowerLevels
] ;
2014-12-24 10:06:54 +00:00
// list on member updates
2014-12-23 17:51:49 +00:00
membersListener = [ mxHandler . mxSession listenToEventsOfTypes : mxMembersEvents onEvent : ^ ( MXEvent * event , MXEventDirection direction , id customObject ) {
// consider only live event
if ( direction = = MXEventDirectionForwards ) {
// Check the room Id ( if any )
if ( event . roomId && [ event . roomId isEqualToString : mxRoom . state . roomId ] = = NO ) {
// This event does not concern the current room members
return ;
}
// Hide potential action sheet
if ( self . actionMenu ) {
[ self . actionMenu dismiss : NO ] ;
self . actionMenu = nil ;
}
2014-12-24 07:59:25 +00:00
2014-12-24 10:06:54 +00:00
MXRoomMember * nextRoomMember = nil ;
2014-12-24 07:59:25 +00:00
// get the updated memmber
NSArray * membersList = [ self . mxRoom . state members ] ;
for ( MXRoomMember * member in membersList ) {
2014-12-24 10:06:54 +00:00
if ( [ member . userId isEqual : _mxRoomMember . userId ] ) {
nextRoomMember = member ;
2014-12-24 07:59:25 +00:00
break ;
}
}
2014-12-24 10:06:54 +00:00
// does the member still exist ?
if ( nextRoomMember ) {
// Refresh members list
_mxRoomMember = nextRoomMember ;
[ self updateMemberInfo ] ;
[ self . tableView reloadData ] ;
} else {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self . navigationController popToRootViewControllerAnimated : NO ] ;
[ [ AppDelegate theDelegate ] . masterTabBarController setVisibleRoomId : nil ] ;
[ [ AppDelegate theDelegate ] . masterTabBarController popRoomViewControllerAnimated : YES ] ;
} ) ;
}
2014-12-23 17:51:49 +00:00
}
} ] ;
}
- ( void ) viewWillDisappear : ( BOOL ) animated {
[ super viewWillDisappear : animated ] ;
if ( imageLoader ) {
[ MediaManager cancel : imageLoader ] ;
imageLoader = nil ;
}
if ( membersListener ) {
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
[ mxHandler . mxSession removeListener : membersListener ] ;
membersListener = nil ;
}
}
- ( void ) updateMemberInfo {
2014-12-24 10:06:54 +00:00
self . title = _mxRoomMember . displayname ? _mxRoomMember . displayname : _mxRoomMember . userId ;
2014-12-23 17:51:49 +00:00
// set the thumbnail info
[ [ self . memberThumbnailButton imageView ] setContentMode : UIViewContentModeScaleAspectFill ] ;
[ [ self . memberThumbnailButton imageView ] setClipsToBounds : YES ] ;
2014-12-24 15:30:51 +00:00
if ( _mxRoomMember . avatarUrl ) {
imageLoader = [ MediaManager loadPicture : _mxRoomMember . avatarUrl
success : ^ ( UIImage * image ) {
[ self . memberThumbnailButton setImage : image forState : UIControlStateNormal ] ;
[ self . memberThumbnailButton setImage : image forState : UIControlStateHighlighted ] ;
}
failure : ^ ( NSError * error ) {
NSLog ( @ "Failed to download image (%@): %@" , _mxRoomMember . avatarUrl , error ) ;
} ] ;
}
2014-12-23 17:51:49 +00:00
2014-12-24 10:06:54 +00:00
self . roomMemberMID . text = _mxRoomMember . userId ;
2014-12-23 17:51:49 +00:00
}
- ( void ) setRoomMember : ( MXRoomMember * ) aRoomMember {
// ignore useless update
2014-12-24 10:06:54 +00:00
if ( ! [ _mxRoomMember . userId isEqualToString : aRoomMember . userId ] ) {
_mxRoomMember = aRoomMember ;
2014-12-23 17:51:49 +00:00
}
}
# pragma mark - Table view data source
- ( NSInteger ) numberOfSectionsInTableView : ( UITableView * ) tableView {
return 1 ;
}
- ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section {
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
// Check user ' s power level before allowing an action ( kick , ban , . . . )
MXRoomPowerLevels * powerLevels = [ mxRoom . state powerLevels ] ;
2014-12-24 10:06:54 +00:00
NSUInteger memberPowerLevel = [ powerLevels powerLevelOfUserWithUserID : _mxRoomMember . userId ] ;
2014-12-23 17:51:49 +00:00
NSUInteger oneSelfPowerLevel = [ powerLevels powerLevelOfUserWithUserID : mxHandler . userId ] ;
[ buttonsTitles removeAllObjects ] ;
// Consider the case of the user himself
2014-12-24 10:06:54 +00:00
if ( [ _mxRoomMember . userId isEqualToString : mxHandler . userId ] ) {
2014-12-23 17:51:49 +00:00
[ buttonsTitles addObject : @ "Leave" ] ;
if ( oneSelfPowerLevel >= [ powerLevels minimumPowerLevelForSendingEventAsStateEvent : kMXEventTypeStringRoomPowerLevels ] ) {
[ buttonsTitles addObject : @ "Set power level" ] ;
}
} else {
// Consider membership of the selected member
2014-12-24 10:06:54 +00:00
switch ( _mxRoomMember . membership ) {
2014-12-23 17:51:49 +00:00
case MXMembershipInvite :
case MXMembershipJoin : {
// Check conditions to be able to kick someone
if ( oneSelfPowerLevel >= [ powerLevels kick ] && oneSelfPowerLevel >= memberPowerLevel ) {
[ buttonsTitles addObject : @ "Kick" ] ;
}
// Check conditions to be able to ban someone
if ( oneSelfPowerLevel >= [ powerLevels ban ] && oneSelfPowerLevel >= memberPowerLevel ) {
[ buttonsTitles addObject : @ "Ban" ] ;
}
break ;
}
case MXMembershipLeave : {
// Check conditions to be able to invite someone
if ( oneSelfPowerLevel >= [ powerLevels invite ] ) {
[ buttonsTitles addObject : @ "Invite" ] ;
}
// Check conditions to be able to ban someone
if ( oneSelfPowerLevel >= [ powerLevels ban ] && oneSelfPowerLevel >= memberPowerLevel ) {
[ buttonsTitles addObject : @ "Ban" ] ;
}
break ;
}
case MXMembershipBan : {
// Check conditions to be able to unban someone
if ( oneSelfPowerLevel >= [ powerLevels ban ] && oneSelfPowerLevel >= memberPowerLevel ) {
2014-12-24 07:59:25 +00:00
[ buttonsTitles addObject : @ "Unban" ] ;
2014-12-23 17:51:49 +00:00
}
break ;
}
default : {
break ;
}
}
// update power level
if ( oneSelfPowerLevel >= [ powerLevels minimumPowerLevelForSendingEventAsStateEvent : kMXEventTypeStringRoomPowerLevels ] ) {
[ buttonsTitles addObject : @ "Set power level" ] ;
}
2014-12-24 15:30:51 +00:00
// offer to start a new chat only if the room is not a 1 : 1 room with this user
// it does not make sense : it would open the same room
NSString * roomId = [ mxHandler getRoomStartedWithMember : _mxRoomMember ] ;
if ( ! [ roomId isEqualToString : mxRoom . state . roomId ] ) {
[ buttonsTitles addObject : @ "Start chat" ] ;
}
2014-12-23 17:51:49 +00:00
}
return ( buttonsTitles . count + 1 ) / 2 ;
}
- ( UITableViewCell * ) tableView : ( UITableView * ) aTableView cellForRowAtIndexPath : ( NSIndexPath * ) indexPath {
if ( self . tableView = = aTableView ) {
NSInteger row = indexPath . row ;
MemberActionsCell * memberActionsCell = ( MemberActionsCell * ) [ aTableView dequeueReusableCellWithIdentifier : @ "MemberActionsCell" forIndexPath : indexPath ] ;
NSString * leftTitle = nil ;
NSString * rightTitle = nil ;
if ( ( row * 2 ) < buttonsTitles . count ) {
leftTitle = [ buttonsTitles objectAtIndex : row * 2 ] ;
}
if ( ( ( row * 2 ) + 1 ) < buttonsTitles . count ) {
rightTitle = [ buttonsTitles objectAtIndex : ( row * 2 ) + 1 ] ;
}
[ memberActionsCell setLeftButtonText : leftTitle ] ;
[ memberActionsCell setRightButtonText : rightTitle ] ;
return memberActionsCell ;
}
return nil ;
}
# pragma mark - button management
2014-12-24 07:59:25 +00:00
- ( BOOL ) hasPendingAction {
return nil ! = pendingMaskSpinnerView ;
}
- ( void ) addPendingActionMask {
// add a spinner above the tableview to avoid that the user tap on any other button
pendingMaskSpinnerView = [ [ UIActivityIndicatorView alloc ] initWithActivityIndicatorStyle : UIActivityIndicatorViewStyleWhiteLarge ] ;
pendingMaskSpinnerView . backgroundColor = [ UIColor colorWithRed : 0.5 green : 0.5 blue : 0.5 alpha : 0.5 ] ;
pendingMaskSpinnerView . frame = self . tableView . frame ;
pendingMaskSpinnerView . autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin ;
// append it
[ self . tableView . superview addSubview : pendingMaskSpinnerView ] ;
// animate it
[ pendingMaskSpinnerView startAnimating ] ;
}
- ( void ) removePendingActionMask {
if ( pendingMaskSpinnerView ) {
[ pendingMaskSpinnerView removeFromSuperview ] ;
pendingMaskSpinnerView = nil ;
[ self . tableView reloadData ] ;
}
}
2014-12-24 10:06:54 +00:00
- ( void ) setUserPowerLevel : ( MXRoomMember * ) roomMember to : ( int ) value {
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
int currentPowerLevel = ( int ) ( [ mxHandler getPowerLevel : roomMember inRoom : self . mxRoom ] * 100 ) ;
// check if the power level has not yet been set to 0
if ( value ! = currentPowerLevel ) {
__weak typeof ( self ) weakSelf = self ;
[ weakSelf addPendingActionMask ] ;
// Reset user power level
[ self . mxRoom setPowerLevelOfUserWithUserID : roomMember . userId powerLevel : value success : ^ {
[ weakSelf removePendingActionMask ] ;
} failure : ^ ( NSError * error ) {
[ weakSelf removePendingActionMask ] ;
NSLog ( @ "Set user power (%@) failed: %@" , roomMember . userId , error ) ;
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
}
}
- ( void ) updateUserPowerLevel : ( MXRoomMember * ) roomMember {
2014-12-23 17:51:49 +00:00
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
__weak typeof ( self ) weakSelf = self ;
// Ask for userId to invite
self . actionMenu = [ [ CustomAlert alloc ] initWithTitle : @ "Power Level" message : nil style : CustomAlertStyleAlert ] ;
if ( ! [ mxHandler . userId isEqualToString : roomMember . userId ] ) {
self . actionMenu . cancelButtonIndex = [ self . actionMenu addActionWithTitle : @ "Reset to default" style : CustomAlertActionStyleDefault handler : ^ ( CustomAlert * alert ) {
weakSelf . actionMenu = nil ;
2014-12-24 10:06:54 +00:00
[ weakSelf setUserPowerLevel : roomMember to : 0 ] ;
2014-12-23 17:51:49 +00:00
} ] ;
}
[ self . actionMenu addTextFieldWithConfigurationHandler : ^ ( UITextField * textField ) {
textField . secureTextEntry = NO ;
textField . text = [ NSString stringWithFormat : @ "%d" , ( int ) ( [ mxHandler getPowerLevel : roomMember inRoom : weakSelf . mxRoom ] * 100 ) ] ;
textField . placeholder = nil ;
textField . keyboardType = UIKeyboardTypeDecimalPad ;
} ] ;
[ self . actionMenu addActionWithTitle : @ "OK" style : CustomAlertActionStyleDefault handler : ^ ( CustomAlert * alert ) {
UITextField * textField = [ alert textFieldAtIndex : 0 ] ;
weakSelf . actionMenu = nil ;
2014-12-24 10:06:54 +00:00
if ( textField . text . length > 0 ) {
[ weakSelf setUserPowerLevel : roomMember to : ( int ) [ textField . text integerValue ] ] ;
}
2014-12-23 17:51:49 +00:00
} ] ;
[ self . actionMenu showInViewController : self ] ;
}
- ( IBAction ) onButtonToggle : ( id ) sender {
if ( [ sender isKindOfClass : [ UIButton class ] ] ) {
2014-12-24 07:59:25 +00:00
// already a pending action
if ( [ self hasPendingAction ] ) {
return ;
}
2014-12-23 17:51:49 +00:00
NSString * text = ( ( UIButton * ) sender ) . titleLabel . text ;
if ( [ text isEqualToString : @ "Leave" ] ) {
2014-12-24 07:59:25 +00:00
[ self addPendingActionMask ] ;
2014-12-23 17:51:49 +00:00
[ self . mxRoom leave : ^ {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-24 10:06:54 +00:00
[ self . navigationController popToRootViewControllerAnimated : NO ] ;
[ [ AppDelegate theDelegate ] . masterTabBarController setVisibleRoomId : nil ] ;
2014-12-23 17:51:49 +00:00
[ [ AppDelegate theDelegate ] . masterTabBarController popRoomViewControllerAnimated : YES ] ;
} failure : ^ ( NSError * error ) {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-23 17:51:49 +00:00
NSLog ( @ "Leave room %@ failed: %@" , mxRoom . state . roomId , error ) ;
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
} else if ( [ text isEqualToString : @ "Set power level" ] ) {
2014-12-24 10:06:54 +00:00
[ self updateUserPowerLevel : _mxRoomMember ] ;
2014-12-23 17:51:49 +00:00
} else if ( [ text isEqualToString : @ "Kick" ] ) {
2014-12-24 07:59:25 +00:00
[ self addPendingActionMask ] ;
2014-12-24 10:06:54 +00:00
[ mxRoom kickUser : _mxRoomMember . userId
2014-12-23 17:51:49 +00:00
reason : nil
success : ^ {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-24 10:06:54 +00:00
[ self . navigationController popToRootViewControllerAnimated : YES ] ;
2014-12-23 17:51:49 +00:00
}
failure : ^ ( NSError * error ) {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-24 10:06:54 +00:00
NSLog ( @ "Kick %@ failed: %@" , _mxRoomMember . userId , error ) ;
2014-12-23 17:51:49 +00:00
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
} else if ( [ text isEqualToString : @ "Ban" ] ) {
2014-12-24 07:59:25 +00:00
[ self addPendingActionMask ] ;
2014-12-24 10:06:54 +00:00
[ mxRoom banUser : _mxRoomMember . userId
2014-12-23 17:51:49 +00:00
reason : nil
success : ^ {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-23 17:51:49 +00:00
}
failure : ^ ( NSError * error ) {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-24 10:06:54 +00:00
NSLog ( @ "Ban %@ failed: %@" , _mxRoomMember . userId , error ) ;
2014-12-23 17:51:49 +00:00
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
} else if ( [ text isEqualToString : @ "Invite" ] ) {
2014-12-24 07:59:25 +00:00
[ self addPendingActionMask ] ;
2014-12-24 10:06:54 +00:00
[ mxRoom inviteUser : _mxRoomMember . userId
2014-12-23 17:51:49 +00:00
success : ^ {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-23 17:51:49 +00:00
}
failure : ^ ( NSError * error ) {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-24 10:06:54 +00:00
NSLog ( @ "Invite %@ failed: %@" , _mxRoomMember . userId , error ) ;
2014-12-23 17:51:49 +00:00
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
} else if ( [ text isEqualToString : @ "Unban" ] ) {
2014-12-24 07:59:25 +00:00
[ self addPendingActionMask ] ;
2014-12-24 10:06:54 +00:00
[ mxRoom unbanUser : _mxRoomMember . userId
2014-12-23 17:51:49 +00:00
success : ^ {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-23 17:51:49 +00:00
}
failure : ^ ( NSError * error ) {
2014-12-24 07:59:25 +00:00
[ self removePendingActionMask ] ;
2014-12-24 10:06:54 +00:00
NSLog ( @ "Unban %@ failed: %@" , _mxRoomMember . userId , error ) ;
2014-12-23 17:51:49 +00:00
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
} else if ( [ text isEqualToString : @ "Start chat" ] ) {
2014-12-24 07:59:25 +00:00
[ self addPendingActionMask ] ;
2014-12-24 15:30:51 +00:00
2014-12-23 17:51:49 +00:00
MatrixHandler * mxHandler = [ MatrixHandler sharedHandler ] ;
2014-12-24 15:30:51 +00:00
NSString * roomId = [ mxHandler getRoomStartedWithMember : _mxRoomMember ] ;
2014-12-23 17:51:49 +00:00
2014-12-24 15:30:51 +00:00
// if the room has already been started
if ( roomId ) {
// open it
[ [ AppDelegate theDelegate ] . masterTabBarController showRoom : roomId ] ;
}
else {
// else create new room
[ mxHandler . mxRestClient createRoom : nil
visibility : kMXRoomVisibilityPrivate
roomAlias : nil
topic : nil
success : ^ ( MXCreateRoomResponse * response ) {
[ self removePendingActionMask ] ;
// add the user
[ mxHandler . mxRestClient inviteUser : _mxRoomMember . userId toRoom : response . roomId success : ^ {
// NSLog ( @ "%@ has been invited (roomId: %@)" , roomMember . userId , response . roomId ) ;
} failure : ^ ( NSError * error ) {
NSLog ( @ "%@ invitation failed (roomId: %@): %@" , _mxRoomMember . userId , response . roomId , error ) ;
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
// Open created room
[ [ AppDelegate theDelegate ] . masterTabBarController showRoom : response . roomId ] ;
2014-12-23 17:51:49 +00:00
} failure : ^ ( NSError * error ) {
2014-12-24 15:30:51 +00:00
[ self removePendingActionMask ] ;
NSLog ( @ "Create room failed: %@" , error ) ;
2014-12-23 17:51:49 +00:00
// Alert user
[ [ AppDelegate theDelegate ] showErrorAsAlert : error ] ;
} ] ;
2014-12-24 15:30:51 +00:00
}
2014-12-23 17:51:49 +00:00
}
}
}
@ end