element-ios/Riot/ViewController/RoomMemberDetailsViewController.m
Giom Foret 88b20c3ffa Bug Fix - [Direct Chat] No placeholder avatar and display name from the member details view
#923

- Remove the "Direct Chat" section in the room member details view of the current user.
- Handle correctly tap on “Start new chat” cell
2017-03-13 15:11:08 +01:00

966 lines
38 KiB
Objective-C

/*
Copyright 2016 OpenMarket Ltd
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 "RoomMemberDetailsViewController.h"
#import "AppDelegate.h"
#import "RoomMemberTitleView.h"
#import "RiotDesignValues.h"
#import "RageShakeManager.h"
#import "AvatarGenerator.h"
#import "Tools.h"
#import "TableViewCellWithButton.h"
#import "RoomTableViewCell.h"
#import "EncryptionInfoView.h"
#define TABLEVIEW_ROW_CELL_HEIGHT 46
#define TABLEVIEW_SECTION_HEADER_HEIGHT 28
#define TABLEVIEW_SECTION_HEADER_HEIGHT_WHEN_HIDDEN 0.01f
@interface RoomMemberDetailsViewController ()
{
RoomMemberTitleView* memberTitleView;
/**
List of the admin actions on this member.
*/
NSMutableArray<NSNumber*> *adminActionsArray;
NSInteger adminToolsIndex;
/**
List of the basic actions on this member.
*/
NSMutableArray<NSNumber*> *otherActionsArray;
NSInteger otherActionsIndex;
/**
List of the direct chats (room ids) with this member.
*/
NSMutableArray<NSString*> *directChatsArray;
NSInteger directChatsIndex;
/**
Devices
*/
NSArray<MXDeviceInfo *> *devicesArray;
NSInteger devicesIndex;
EncryptionInfoView *encryptionInfoView;
/**
Observe UIApplicationWillChangeStatusBarOrientationNotification to hide/show bubbles bg.
*/
id UIApplicationWillChangeStatusBarOrientationNotificationObserver;
}
@end
@implementation RoomMemberDetailsViewController
#pragma mark - Class methods
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass(self.class)
bundle:[NSBundle bundleForClass:self.class]];
}
+ (instancetype)roomMemberDetailsViewController
{
return [[[self class] alloc] initWithNibName:NSStringFromClass(self.class)
bundle:[NSBundle bundleForClass:self.class]];
}
#pragma mark -
- (void)finalizeInit
{
[super finalizeInit];
// Setup `MXKViewControllerHandling` properties
self.defaultBarTintColor = kRiotNavBarTintColor;
self.enableBarTintColorStatusChange = NO;
self.rageShakeManager = [RageShakeManager sharedManager];
adminActionsArray = [[NSMutableArray alloc] init];
otherActionsArray = [[NSMutableArray alloc] init];
directChatsArray = [[NSMutableArray alloc] init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.memberHeaderView.backgroundColor = kRiotColorLightGrey;
self.roomMemberNameLabel.textColor = kRiotTextColorBlack;
self.roomMemberStatusLabel.textColor = kRiotColorGreen;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.roomMemberNameLabelMask addGestureRecognizer:tap];
self.roomMemberNameLabelMask.userInteractionEnabled = YES;
self.navigationItem.titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 40)];
memberTitleView = [RoomMemberTitleView roomMemberTitleView];
self.memberThumbnail = memberTitleView.memberAvatar;
// Add tap to show the room member avatar in fullscreen
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.memberThumbnail addGestureRecognizer:tap];
self.memberThumbnail.userInteractionEnabled = YES;
// Need to listen tap gesture on the area part of the avatar image that is outside
// of the navigation bar, its parent but smaller view.
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.roomMemberAvatarMask addGestureRecognizer:tap];
self.roomMemberAvatarMask.userInteractionEnabled = YES;
// Add the title view and define edge constraints
memberTitleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.navigationItem.titleView addSubview:memberTitleView];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.0f];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:memberTitleView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.navigationItem.titleView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]];
// Register collection view cell class
[self.tableView registerClass:TableViewCellWithButton.class forCellReuseIdentifier:[TableViewCellWithButton defaultReuseIdentifier]];
[self.tableView registerClass:RoomTableViewCell.class forCellReuseIdentifier:[RoomTableViewCell defaultReuseIdentifier]];
[self.tableView registerClass:DeviceTableViewCell.class forCellReuseIdentifier:[DeviceTableViewCell defaultReuseIdentifier]];
// Hide line separators of empty cells
self.tableView.tableFooterView = [[UIView alloc] init];
// Observe UIApplicationWillChangeStatusBarOrientationNotification to hide/show bubbles bg.
UIApplicationWillChangeStatusBarOrientationNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillChangeStatusBarOrientationNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
NSNumber *orientation = (NSNumber*)(notif.userInfo[UIApplicationStatusBarOrientationUserInfoKey]);
self.bottomImageView.hidden = (orientation.integerValue == UIInterfaceOrientationLandscapeLeft || orientation.integerValue == UIInterfaceOrientationLandscapeRight);
}];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Screen tracking (via Google Analytics)
id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker];
if (tracker)
{
[tracker set:kGAIScreenName value:@"RoomMemberDetails"];
[tracker send:[[GAIDictionaryBuilder createScreenView] build]];
}
// Hide the bottom border of the navigation bar to display the expander header
[self hideNavigationBarBorder:YES];
// Handle here the bottom image visibility
UIInterfaceOrientation screenOrientation = [[UIApplication sharedApplication] statusBarOrientation];
self.bottomImageView.hidden = (screenOrientation == UIInterfaceOrientationLandscapeLeft || screenOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Restore navigation bar display
[self hideNavigationBarBorder:NO];
self.bottomImageView.hidden = YES;
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// Restore navigation bar display
[self hideNavigationBarBorder:NO];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(coordinator.transitionDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// Hide the bottom border of the navigation bar
[self hideNavigationBarBorder:YES];
});
}
- (void)destroy
{
[super destroy];
adminActionsArray = nil;
otherActionsArray = nil;
directChatsArray = nil;
devicesArray = nil;
if (UIApplicationWillChangeStatusBarOrientationNotificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:UIApplicationWillChangeStatusBarOrientationNotificationObserver];
UIApplicationWillChangeStatusBarOrientationNotificationObserver = nil;
}
[memberTitleView removeFromSuperview];
memberTitleView = nil;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
// Check here whether a subview has been added or removed
if (encryptionInfoView)
{
if (!encryptionInfoView.superview)
{
// Reset
encryptionInfoView = nil;
// Reload the full table to take into account a potential change on a device status.
[self updateMemberInfo];
}
}
if (memberTitleView)
{
// Adjust the header height by taking into account the actual position of the member avatar in title view
// This position depends automatically on the screen orientation.
CGRect memberAvatarFrame = memberTitleView.memberAvatar.frame;
CGPoint memberAvatarActualPosition = [memberTitleView convertPoint:memberAvatarFrame.origin toView:self.view];
CGFloat avatarHeaderHeight = memberAvatarActualPosition.y + memberAvatarFrame.size.height;
if (_roomMemberAvatarHeaderBackgroundHeightConstraint.constant != avatarHeaderHeight)
{
_roomMemberAvatarHeaderBackgroundHeightConstraint.constant = avatarHeaderHeight;
// Force the layout of the header
[self.memberHeaderView layoutIfNeeded];
}
}
}
#pragma mark -
- (UIImage*)picturePlaceholder
{
if (self.mxRoomMember)
{
// Use the vector style placeholder
return [AvatarGenerator generateAvatarForMatrixItem:self.mxRoomMember.userId withDisplayName:self.mxRoomMember.displayname];
}
return [UIImage imageNamed:@"placeholder"];
}
- (void)updateMemberInfo
{
if (self.mxRoomMember)
{
self.roomMemberNameLabel.text = self.mxRoomMember.displayname ? self.mxRoomMember.displayname : self.mxRoomMember.userId;
// Update member badge
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
if (powerLevel >= kRiotRoomAdminLevel)
{
memberTitleView.memberBadge.image = [UIImage imageNamed:@"admin_icon"];
memberTitleView.memberBadge.hidden = NO;
}
else if (powerLevel >= kRiotRoomModeratorLevel)
{
memberTitleView.memberBadge.image = [UIImage imageNamed:@"mod_icon"];
memberTitleView.memberBadge.hidden = NO;
}
else
{
memberTitleView.memberBadge.hidden = YES;
}
NSString* presenceText;
if (self.mxRoomMember.userId)
{
MXUser *user = [self.mxRoom.mxSession userWithUserId:self.mxRoomMember.userId];
presenceText = [Tools presenceText:user];
}
self.roomMemberStatusLabel.text = presenceText;
// Retrieve the existing direct chats
[directChatsArray removeAllObjects];
NSArray *directRoomIds = self.mainSession.directRooms[self.mxRoomMember.userId];
// Check whether the room is still existing
for (NSString* directRoomId in directRoomIds)
{
if ([self.mainSession roomWithRoomId:directRoomId])
{
[directChatsArray addObject:directRoomId];
}
}
// Retrieve member's devices
[self.mxRoom.mxSession.crypto devicesForUser:self.mxRoomMember.userId complete:^(NSArray<MXDeviceInfo *> *devices) {
devicesArray = devices;
// Reload the full table to take into account a potential change on a device status.
[super updateMemberInfo];
}];
}
// Complete data update and reload table view
[super updateMemberInfo];
}
#pragma mark - Hide/Show navigation bar border
- (void)hideNavigationBarBorder:(BOOL)isHidden
{
// Consider the main navigation controller if the current view controller is embedded inside a split view controller.
UINavigationController *mainNavigationController = self.navigationController;
if (self.splitViewController && self.splitViewController.isCollapsed && self.splitViewController.viewControllers.count)
{
mainNavigationController = self.splitViewController.viewControllers.firstObject;
}
if (isHidden)
{
// The default shadow image is nil. When non-nil, this property represents a custom shadow image to show instead
// of the default. For a custom shadow image to be shown, a custom background image must also be set with the
// setBackgroundImage:forBarMetrics: method. If the default background image is used, then the default shadow
// image will be used regardless of the value of this property.
[mainNavigationController.navigationBar setShadowImage:[[UIImage alloc] init]];
[mainNavigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
}
else
{
// Restore default navigationbar settings
[mainNavigationController.navigationBar setShadowImage:nil];
[mainNavigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
}
}
#pragma mark - TableView data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger sectionCount = 0;
BOOL isOneself = NO;
// Check user's power level before allowing an action (kick, ban, ...)
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
NSInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
[adminActionsArray removeAllObjects];
[otherActionsArray removeAllObjects];
// Consider the case of the user himself
if ([self.mxRoomMember.userId isEqualToString:self.mainSession.myUser.userId])
{
isOneself = YES;
[otherActionsArray addObject:@(MXKRoomMemberDetailsActionLeave)];
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomPowerLevels])
{
// Check whether the user is admin (in this case he may reduce his power level to become moderator or less, EXCEPT if he is the only admin).
if (oneSelfPowerLevel >= kRiotRoomAdminLevel)
{
NSArray *levelValues = powerLevels.users.allValues;
NSUInteger adminCount = 0;
for (NSNumber *valueNumber in levelValues)
{
if ([valueNumber unsignedIntegerValue] >= kRiotRoomAdminLevel)
{
adminCount ++;
}
}
if (adminCount > 1)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetModerator)];
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetDefaultPowerLevel)];
}
}
// Check whether the user is moderator (in this case he may reduce his power level to become normal user).
else if (oneSelfPowerLevel >= kRiotRoomModeratorLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetDefaultPowerLevel)];
}
}
}
else if (self.mxRoomMember)
{
// Enumerate admin actions
switch (self.mxRoomMember.membership)
{
case MXMembershipInvite:
case MXMembershipJoin:
{
// update power level
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomPowerLevels] && oneSelfPowerLevel > memberPowerLevel)
{
// Check whether user is admin
if (oneSelfPowerLevel >= kRiotRoomAdminLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetAdmin)];
}
// Check whether the member may become moderator
if (oneSelfPowerLevel >= kRiotRoomModeratorLevel && memberPowerLevel < kRiotRoomModeratorLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetModerator)];
}
if (memberPowerLevel >= kRiotRoomModeratorLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetDefaultPowerLevel)];
}
}
// Check conditions to be able to kick someone
if (oneSelfPowerLevel >= [powerLevels kick] && oneSelfPowerLevel > memberPowerLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionKick)];
}
// Check conditions to be able to ban someone
if (oneSelfPowerLevel >= [powerLevels ban] && oneSelfPowerLevel > memberPowerLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionBan)];
}
break;
}
case MXMembershipLeave:
{
// Check conditions to be able to invite someone
if (oneSelfPowerLevel >= [powerLevels invite])
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionInvite)];
}
// Check conditions to be able to ban someone
if (oneSelfPowerLevel >= [powerLevels ban] && oneSelfPowerLevel > memberPowerLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionBan)];
}
break;
}
case MXMembershipBan:
{
// Check conditions to be able to unban someone
if (oneSelfPowerLevel >= [powerLevels ban] && oneSelfPowerLevel > memberPowerLevel)
{
[adminActionsArray addObject:@(MXKRoomMemberDetailsActionUnban)];
}
break;
}
default:
{
break;
}
}
// List the other actions
if (self.enableVoipCall)
{
// Offer voip call options
[otherActionsArray addObject:@(MXKRoomMemberDetailsActionStartVoiceCall)];
[otherActionsArray addObject:@(MXKRoomMemberDetailsActionStartVideoCall)];
}
// Check whether the option Ignore may be presented
if (self.mxRoomMember.membership == MXMembershipJoin)
{
// is he already ignored ?
if (![self.mainSession isUserIgnored:self.mxRoomMember.userId])
{
[otherActionsArray addObject:@(MXKRoomMemberDetailsActionIgnore)];
}
else
{
[otherActionsArray addObject:@(MXKRoomMemberDetailsActionUnignore)];
}
}
if (self.enableMention)
{
// Add mention option
[otherActionsArray addObject:@(MXKRoomMemberDetailsActionMention)];
}
}
adminToolsIndex = otherActionsIndex = directChatsIndex = devicesIndex = -1;
if (otherActionsArray.count)
{
otherActionsIndex = sectionCount++;
}
if (adminActionsArray.count)
{
adminToolsIndex = sectionCount++;
}
if (!isOneself)
{
directChatsIndex = sectionCount++;
}
if (devicesArray.count)
{
devicesIndex = sectionCount++;
}
return sectionCount;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == adminToolsIndex)
{
return adminActionsArray.count;
}
else if (section == otherActionsIndex)
{
return otherActionsArray.count;
}
else if (section == directChatsIndex)
{
return (directChatsArray.count + 1);
}
else if (section == devicesIndex)
{
return (devicesArray.count);
}
return 0;
}
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == adminToolsIndex)
{
return NSLocalizedStringFromTable(@"room_participants_action_section_admin_tools", @"Vector", nil);
}
else if (section == directChatsIndex)
{
return NSLocalizedStringFromTable(@"room_participants_action_section_direct_chats", @"Vector", nil);
}
else if (section == devicesIndex)
{
return NSLocalizedStringFromTable(@"room_participants_action_section_devices", @"Vector", nil);
}
return nil;
}
- (NSString*)actionButtonTitle:(MXKRoomMemberDetailsAction)action
{
NSString *title;
switch (action)
{
case MXKRoomMemberDetailsActionInvite:
title = NSLocalizedStringFromTable(@"room_participants_action_invite", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionLeave:
title = NSLocalizedStringFromTable(@"room_participants_action_leave", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionKick:
title = NSLocalizedStringFromTable(@"room_participants_action_remove", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionBan:
title = NSLocalizedStringFromTable(@"room_participants_action_ban", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionUnban:
title = NSLocalizedStringFromTable(@"room_participants_action_unban", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionIgnore:
title = NSLocalizedStringFromTable(@"room_participants_action_ignore", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionUnignore:
title = NSLocalizedStringFromTable(@"room_participants_action_unignore", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionSetDefaultPowerLevel:
title = NSLocalizedStringFromTable(@"room_participants_action_set_default_power_level", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionSetModerator:
title = NSLocalizedStringFromTable(@"room_participants_action_set_moderator", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionSetAdmin:
title = NSLocalizedStringFromTable(@"room_participants_action_set_admin", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionStartChat:
title = NSLocalizedStringFromTable(@"room_participants_action_start_chat", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionStartVoiceCall:
title = NSLocalizedStringFromTable(@"room_participants_action_start_voice_call", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionStartVideoCall:
title = NSLocalizedStringFromTable(@"room_participants_action_start_video_call", @"Vector", nil);
break;
case MXKRoomMemberDetailsActionMention:
title = NSLocalizedStringFromTable(@"room_participants_action_mention", @"Vector", nil);
break;
default:
break;
}
return title;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
if (indexPath.section == adminToolsIndex || indexPath.section == otherActionsIndex)
{
TableViewCellWithButton *cellWithButton = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath];
NSNumber *actionNumber;
if (indexPath.section == adminToolsIndex && indexPath.row < adminActionsArray.count)
{
actionNumber = [adminActionsArray objectAtIndex:indexPath.row];
}
else if (indexPath.section == otherActionsIndex && indexPath.row < otherActionsArray.count)
{
actionNumber = [otherActionsArray objectAtIndex:indexPath.row];
}
if (actionNumber)
{
NSString *title = [self actionButtonTitle:actionNumber.unsignedIntegerValue];
[cellWithButton.mxkButton setTitle:title forState:UIControlStateNormal];
[cellWithButton.mxkButton setTitle:title forState:UIControlStateHighlighted];
if (actionNumber.unsignedIntegerValue == MXKRoomMemberDetailsActionKick)
{
[cellWithButton.mxkButton setTitleColor:kRiotColorPinkRed forState:UIControlStateNormal];
[cellWithButton.mxkButton setTitleColor:kRiotColorPinkRed forState:UIControlStateHighlighted];
}
else
{
[cellWithButton.mxkButton setTitleColor:kRiotTextColorBlack forState:UIControlStateNormal];
[cellWithButton.mxkButton setTitleColor:kRiotTextColorBlack forState:UIControlStateHighlighted];
}
[cellWithButton.mxkButton addTarget:self action:@selector(onActionButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
cellWithButton.mxkButton.tag = actionNumber.unsignedIntegerValue;
}
cell = cellWithButton;
}
else if (indexPath.section == directChatsIndex)
{
RoomTableViewCell *roomCell = [tableView dequeueReusableCellWithIdentifier:[RoomTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
if (indexPath.row < directChatsArray.count)
{
MXRoom *room = [self.mainSession roomWithRoomId:directChatsArray[indexPath.row]];
if (room)
{
[roomCell render:room];
}
roomCell.directRoomIcon.hidden = NO;
roomCell.encryptedRoomIcon.hidden = !room.state.isEncrypted;
}
else
{
roomCell.directRoomIcon.hidden = YES;
roomCell.avatarImageView.image = [UIImage imageNamed:@"start_chat"];
roomCell.avatarImageView.backgroundColor = [UIColor clearColor];
roomCell.avatarImageView.userInteractionEnabled = NO;
roomCell.titleLabel.text = NSLocalizedStringFromTable(@"room_participants_action_start_new_chat", @"Vector", nil);
}
cell = roomCell;
}
else if (indexPath.section == devicesIndex)
{
DeviceTableViewCell *deviceCell = [tableView dequeueReusableCellWithIdentifier:[DeviceTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
deviceCell.selectionStyle = UITableViewCellSelectionStyleNone;
if (indexPath.row < devicesArray.count)
{
MXDeviceInfo *deviceInfo = devicesArray[indexPath.row];
[deviceCell render:deviceInfo];
deviceCell.delegate = self;
// Display here the Verify and Block buttons except if the device is the current one.
deviceCell.verifyButton.hidden = deviceCell.blockButton.hidden = [deviceInfo.deviceId isEqualToString:self.mxRoom.mxSession.matrixRestClient.credentials.deviceId];
}
cell = deviceCell;
}
else
{
// Create a fake cell to prevent app from crashing
cell = [[UITableViewCell alloc] init];
}
return cell;
}
#pragma mark - UITableView delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == directChatsIndex)
{
return [RoomTableViewCell cellHeight];
}
else if (indexPath.section == devicesIndex)
{
if (indexPath.row < devicesArray.count)
{
return [DeviceTableViewCell cellHeightWithDeviceInfo:devicesArray[indexPath.row] andCellWidth:self.tableView.frame.size.width];
}
}
return TABLEVIEW_ROW_CELL_HEIGHT;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == otherActionsIndex)
{
return TABLEVIEW_SECTION_HEADER_HEIGHT_WHEN_HIDDEN;
}
return TABLEVIEW_SECTION_HEADER_HEIGHT;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
if (indexPath.section == directChatsIndex)
{
if (indexPath.row < directChatsArray.count)
{
// Open this room
[[AppDelegate theDelegate] showRoom:directChatsArray[indexPath.row] andEventId:nil withMatrixSession:self.mainSession];
}
else
{
// Create a new direct chat with the member
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = MXKRoomMemberDetailsActionStartChat;
[super onActionButtonPressed:button];
}
}
else
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (selectedCell && [selectedCell isKindOfClass:TableViewCellWithButton.class])
{
TableViewCellWithButton *cell = (TableViewCellWithButton*)selectedCell;
[self onActionButtonPressed:cell.mxkButton];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - Action
- (void)onActionButtonPressed:(id)sender
{
if ([sender isKindOfClass:[UIButton class]])
{
// already a pending action
if ([self hasPendingAction])
{
return;
}
UIButton *button = (UIButton*)sender;
switch (button.tag)
{
case MXKRoomMemberDetailsActionSetDefaultPowerLevel:
{
[self setPowerLevel:self.mxRoom.state.powerLevels.usersDefault promptUser:YES];
break;
}
case MXKRoomMemberDetailsActionSetModerator:
{
[self setPowerLevel:kRiotRoomModeratorLevel promptUser:YES];
break;
}
case MXKRoomMemberDetailsActionSetAdmin:
{
[self setPowerLevel:kRiotRoomAdminLevel promptUser:YES];
break;
}
default:
{
[super onActionButtonPressed:sender];
}
}
}
}
- (void)handleTapGesture:(UITapGestureRecognizer*)tapGestureRecognizer
{
UIView *view = tapGestureRecognizer.view;
if (view == self.roomMemberNameLabelMask && self.mxRoomMember.displayname)
{
if ([self.roomMemberNameLabel.text isEqualToString:self.mxRoomMember.displayname])
{
// Display room member matrix id
self.roomMemberNameLabel.text = self.mxRoomMember.userId;
}
else
{
// Restore display name
self.roomMemberNameLabel.text = self.mxRoomMember.displayname;
}
}
else if (view == self.memberThumbnail || view == self.roomMemberAvatarMask)
{
// Show the avatar in full screen
__block MXKImageView * avatarFullScreenView = [[MXKImageView alloc] initWithFrame:CGRectZero];
avatarFullScreenView.stretchable = YES;
[avatarFullScreenView setRightButtonTitle:[NSBundle mxk_localizedStringForKey:@"ok"] handler:^(MXKImageView* imageView, NSString* buttonTitle) {
[avatarFullScreenView dismissSelection];
[avatarFullScreenView removeFromSuperview];
avatarFullScreenView = nil;
}];
NSString *avatarURL = nil;
if (self.mxRoomMember.avatarUrl)
{
avatarURL = [self.mainSession.matrixRestClient urlOfContent:self.mxRoomMember.avatarUrl];
}
[avatarFullScreenView setImageURL:avatarURL
withType:nil
andImageOrientation:UIImageOrientationUp
previewImage:self.memberThumbnail.image];
[avatarFullScreenView showFullScreen];
}
}
#pragma mark -
- (void)deviceTableViewCell:(DeviceTableViewCell*)deviceTableViewCell updateDeviceVerification:(MXDeviceVerification)verificationStatus
{
if (verificationStatus == MXDeviceVerified)
{
// Prompt the user before marking as verified the device.
encryptionInfoView = [[EncryptionInfoView alloc] initWithDeviceInfo:deviceTableViewCell.deviceInfo andMatrixSession:self.mxRoom.mxSession];
[encryptionInfoView onButtonPressed:encryptionInfoView.verifyButton];
// Add shadow on added view
encryptionInfoView.layer.cornerRadius = 5;
encryptionInfoView.layer.shadowOffset = CGSizeMake(0, 1);
encryptionInfoView.layer.shadowOpacity = 0.5f;
// Add the view and define edge constraints
[self.view addSubview:encryptionInfoView];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:10.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:-10.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:encryptionInfoView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:-10.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:encryptionInfoView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:10.0f]];
[self.view setNeedsUpdateConstraints];
}
else
{
[self.mxRoom.mxSession.crypto setDeviceVerification:verificationStatus
forDevice:deviceTableViewCell.deviceInfo.deviceId
ofUser:self.mxRoomMember.userId
success:^{
[self updateMemberInfo];
} failure:nil];
}
}
@end