291 lines
9.1 KiB
Objective-C
291 lines
9.1 KiB
Objective-C
/*
|
|
Copyright 2018-2024 New Vector Ltd.
|
|
Copyright 2017 Vector Creations Ltd
|
|
Copyright 2015 OpenMarket Ltd
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
#import "MXKRoomMemberTableViewCell.h"
|
|
|
|
@import MatrixSDK;
|
|
|
|
#import "MXKAccount.h"
|
|
#import "MXKImageView.h"
|
|
#import "MXKPieChartView.h"
|
|
#import "MXKRoomMemberCellDataStoring.h"
|
|
#import "MXKRoomMemberListDataSource.h"
|
|
#import "MXKTools.h"
|
|
|
|
#import "NSBundle+MatrixKit.h"
|
|
|
|
#import "MXKSwiftHeader.h"
|
|
|
|
@interface MXKRoomMemberTableViewCell ()
|
|
{
|
|
NSRange lastSeenRange;
|
|
|
|
MXKPieChartView* pieChartView;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MXKRoomMemberTableViewCell
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
[super awakeFromNib];
|
|
|
|
self.typingBadge.image = [NSBundle mxk_imageFromMXKAssetsBundleWithName:@"icon_keyboard"];
|
|
}
|
|
|
|
- (void)customizeTableViewCellRendering
|
|
{
|
|
[super customizeTableViewCellRendering];
|
|
|
|
self.pictureView.defaultBackgroundColor = [UIColor clearColor];
|
|
}
|
|
|
|
- (UIImage*)picturePlaceholder
|
|
{
|
|
return [NSBundle mxk_imageFromMXKAssetsBundleWithName:@"default-profile"];
|
|
}
|
|
|
|
- (void)render:(MXKCellData *)cellData
|
|
{
|
|
// Sanity check: accept only object of MXKRoomMemberCellData classes or sub-classes
|
|
NSParameterAssert([cellData isKindOfClass:[MXKRoomMemberCellData class]]);
|
|
|
|
MXKRoomMemberCellData *memberCellData = (MXKRoomMemberCellData*)cellData;
|
|
if (memberCellData)
|
|
{
|
|
mxSession = memberCellData.mxSession;
|
|
memberId = memberCellData.roomMember.userId;
|
|
|
|
self.userLabel.text = memberCellData.memberDisplayName;
|
|
|
|
// Disable by default activity update mechanism (This is required in case of a reused cell).
|
|
shouldUpdateActivityInfo = NO;
|
|
|
|
// User thumbnail
|
|
self.pictureView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder;
|
|
self.pictureView.enableInMemoryCache = YES;
|
|
// Consider here the member avatar is stored unencrypted on Matrix media repo
|
|
[self.pictureView setImageURI:memberCellData.roomMember.avatarUrl
|
|
withType:nil
|
|
andImageOrientation:UIImageOrientationUp
|
|
toFitViewSize:self.pictureView.frame.size
|
|
withMethod:MXThumbnailingMethodCrop
|
|
previewImage:self.picturePlaceholder
|
|
mediaManager:mxSession.mediaManager];
|
|
|
|
// Shade invited users
|
|
if (memberCellData.roomMember.membership == MXMembershipInvite)
|
|
{
|
|
for (UIView *view in self.subviews)
|
|
{
|
|
view.alpha = 0.3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (UIView *view in self.subviews)
|
|
{
|
|
view.alpha = 1;
|
|
}
|
|
}
|
|
|
|
// Display the power level pie
|
|
[self setPowerContainerValue:memberCellData.powerLevel];
|
|
|
|
// Prepare presence string and thumbnail border color
|
|
NSString* presenceText = nil;
|
|
UIColor* thumbnailBorderColor = nil;
|
|
|
|
// Customize banned and left (kicked) members
|
|
if (memberCellData.roomMember.membership == MXMembershipLeave || memberCellData.roomMember.membership == MXMembershipBan)
|
|
{
|
|
self.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0];
|
|
presenceText = (memberCellData.roomMember.membership == MXMembershipLeave) ? [VectorL10n membershipLeave] : [VectorL10n membershipBan];
|
|
}
|
|
else
|
|
{
|
|
self.backgroundColor = [UIColor whiteColor];
|
|
|
|
// get the user presence and his thumbnail border color
|
|
if (memberCellData.roomMember.membership == MXMembershipInvite)
|
|
{
|
|
thumbnailBorderColor = [UIColor lightGrayColor];
|
|
presenceText = [VectorL10n membershipInvite];
|
|
}
|
|
else
|
|
{
|
|
// Get the user that corresponds to this member
|
|
MXUser *user = [mxSession userWithUserId:memberId];
|
|
// existing user ?
|
|
if (user)
|
|
{
|
|
thumbnailBorderColor = [MXKAccount presenceColor:user.presence];
|
|
presenceText = [self lastActiveTime];
|
|
// Keep last seen range to update it
|
|
lastSeenRange = NSMakeRange(self.userLabel.text.length + 2, presenceText.length);
|
|
shouldUpdateActivityInfo = (presenceText.length != 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the thumbnail is defined
|
|
if (thumbnailBorderColor)
|
|
{
|
|
self.pictureView.layer.borderWidth = 2;
|
|
self.pictureView.layer.borderColor = thumbnailBorderColor.CGColor;
|
|
}
|
|
else
|
|
{
|
|
// remove the border
|
|
// else it draws black border
|
|
self.pictureView.layer.borderWidth = 0;
|
|
}
|
|
|
|
// and the presence text (if any)
|
|
if (presenceText)
|
|
{
|
|
NSString* extraText = [NSString stringWithFormat:@"(%@)", presenceText];
|
|
self.userLabel.text = [NSString stringWithFormat:@"%@ %@", self.userLabel.text, extraText];
|
|
|
|
NSRange range = [self.userLabel.text rangeOfString:extraText];
|
|
UIFont* font = self.userLabel.font;
|
|
|
|
// Create the attributes
|
|
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
font, NSFontAttributeName,
|
|
self.userLabel.textColor, NSForegroundColorAttributeName, nil];
|
|
|
|
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
font, NSFontAttributeName,
|
|
[UIColor lightGrayColor], NSForegroundColorAttributeName, nil];
|
|
|
|
// Create the attributed string (text + attributes)
|
|
NSMutableAttributedString *attributedText =[[NSMutableAttributedString alloc] initWithString:self.userLabel.text attributes:attrs];
|
|
[attributedText setAttributes:subAttrs range:range];
|
|
|
|
// Set it in our UILabel and we are done!
|
|
[self.userLabel setAttributedText:attributedText];
|
|
}
|
|
|
|
// Set typing badge visibility
|
|
if (memberCellData.isTyping)
|
|
{
|
|
self.typingBadge.hidden = NO;
|
|
[self.typingBadge.superview bringSubviewToFront:self.typingBadge];
|
|
}
|
|
else
|
|
{
|
|
self.typingBadge.hidden = YES;
|
|
}
|
|
}
|
|
}
|
|
|
|
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
|
|
{
|
|
// The height is fixed
|
|
return 50;
|
|
}
|
|
|
|
- (NSString*)lastActiveTime
|
|
{
|
|
NSString* lastActiveTime = nil;
|
|
|
|
// Get the user that corresponds to this member
|
|
MXUser *user = [mxSession userWithUserId:memberId];
|
|
if (user)
|
|
{
|
|
// Prepare last active ago string
|
|
lastActiveTime = [MXKTools formatSecondsIntervalFloored:(user.lastActiveAgo / 1000)];
|
|
|
|
// Check presence
|
|
switch (user.presence)
|
|
{
|
|
case MXPresenceOffline:
|
|
{
|
|
lastActiveTime = [VectorL10n offline];
|
|
break;
|
|
}
|
|
case MXPresenceUnknown:
|
|
{
|
|
lastActiveTime = nil;
|
|
break;
|
|
}
|
|
case MXPresenceOnline:
|
|
case MXPresenceUnavailable:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return lastActiveTime;
|
|
}
|
|
|
|
- (void)setPowerContainerValue:(CGFloat)progress
|
|
{
|
|
// no power level -> hide the pie
|
|
if (0 == progress)
|
|
{
|
|
self.powerContainer.hidden = YES;
|
|
return;
|
|
}
|
|
|
|
// display it
|
|
self.powerContainer.hidden = NO;
|
|
self.powerContainer.backgroundColor = [UIColor clearColor];
|
|
|
|
if (!pieChartView)
|
|
{
|
|
pieChartView = [[MXKPieChartView alloc] initWithFrame:self.powerContainer.bounds];
|
|
[self.powerContainer addSubview:pieChartView];
|
|
}
|
|
|
|
pieChartView.progress = progress;
|
|
}
|
|
|
|
- (void)updateActivityInfo
|
|
{
|
|
// Check whether update is required.
|
|
if (shouldUpdateActivityInfo)
|
|
{
|
|
NSString *lastSeen = [self lastActiveTime];
|
|
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.userLabel.attributedText];
|
|
if (lastSeen.length)
|
|
{
|
|
[attributedText replaceCharactersInRange:lastSeenRange withString:lastSeen];
|
|
|
|
// Update last seen range
|
|
lastSeenRange.length = lastSeen.length;
|
|
}
|
|
else
|
|
{
|
|
// remove presence info
|
|
lastSeenRange.location -= 1;
|
|
lastSeenRange.length += 2;
|
|
[attributedText deleteCharactersInRange:lastSeenRange];
|
|
|
|
shouldUpdateActivityInfo = NO;
|
|
}
|
|
|
|
[self.userLabel setAttributedText:attributedText];
|
|
}
|
|
}
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
[super layoutSubviews];
|
|
|
|
// Round image view
|
|
[_pictureView.layer setCornerRadius:_pictureView.frame.size.width / 2];
|
|
_pictureView.clipsToBounds = YES;
|
|
}
|
|
|
|
@end
|