230 lines
9.7 KiB
Objective-C
230 lines
9.7 KiB
Objective-C
/*
|
|
Copyright 2018-2024 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
#import "RoomSelectedStickerBubbleCell.h"
|
|
|
|
#import "RoomEncryptedDataBubbleCell.h"
|
|
|
|
#import "RoomIncomingAttachmentBubbleCell.h"
|
|
#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
|
|
#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
|
|
#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
|
|
#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
|
|
|
|
#import "ThemeService.h"
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
@implementation RoomSelectedStickerBubbleCell
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
[super awakeFromNib];
|
|
|
|
// define arrow mask
|
|
CAShapeLayer *arrowMaskLayer = [[CAShapeLayer alloc] init];
|
|
arrowMaskLayer.frame = self.arrowView.bounds;
|
|
CGSize viewSize = self.arrowView.frame.size;
|
|
UIBezierPath *path = [[UIBezierPath alloc] init];
|
|
[path moveToPoint:CGPointMake(0, viewSize.height)]; // arrow left bottom point
|
|
[path addLineToPoint:CGPointMake(viewSize.width / 2, 0)]; // arrow head
|
|
[path addLineToPoint:CGPointMake(viewSize.width, viewSize.height)]; // arrow right bottom point
|
|
[path closePath]; // arrow top side
|
|
arrowMaskLayer.path = path.CGPath;
|
|
self.arrowView.layer.mask = arrowMaskLayer;
|
|
|
|
self.arrowView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
|
|
self.descriptionView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
|
|
[self.descriptionView.layer setCornerRadius:10];
|
|
}
|
|
|
|
- (void)render:(MXKCellData *)cellData
|
|
{
|
|
[self prepareRender:cellData];
|
|
|
|
if (bubbleData)
|
|
{
|
|
// Retrieve the component which stores the sticker (Only one component is handled by the bubble in case of sticker).
|
|
MXKRoomBubbleComponent *component = bubbleData.bubbleComponents.firstObject;
|
|
|
|
// Handle the pagination and the sender information
|
|
// Look for the original cell class to extract the constraints value.
|
|
Class<MXKCellRendering> modelCellViewClass = nil;
|
|
if (bubbleData.shouldHideSenderInformation)
|
|
{
|
|
modelCellViewClass = bubbleData.isEncryptedRoom ? RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
|
|
|
|
self.paginationTitleView.hidden = YES;
|
|
self.pictureView.hidden = YES;
|
|
self.userNameLabel.hidden = YES;
|
|
self.userNameTapGestureMaskView.userInteractionEnabled = NO;
|
|
}
|
|
else
|
|
{
|
|
if (bubbleData.isPaginationFirstBubble)
|
|
{
|
|
modelCellViewClass = bubbleData.isEncryptedRoom ? RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class;
|
|
|
|
self.paginationTitleView.hidden = NO;
|
|
self.paginationLabel.text = [[bubbleData.eventFormatter dateStringFromDate:bubbleData.date withTime:NO] uppercaseString];
|
|
}
|
|
else
|
|
{
|
|
modelCellViewClass = bubbleData.isEncryptedRoom ? RoomIncomingEncryptedAttachmentBubbleCell.class : RoomIncomingAttachmentBubbleCell.class;
|
|
|
|
self.paginationTitleView.hidden = YES;
|
|
}
|
|
|
|
// Hanlde sender avatar (Supposed his avatar is stored unencrypted on Matrix media repo)
|
|
self.pictureView.hidden = NO;
|
|
|
|
self.pictureView.enableInMemoryCache = YES;
|
|
[self.pictureView setImageURI:bubbleData.senderAvatarUrl
|
|
withType:nil
|
|
andImageOrientation:UIImageOrientationUp
|
|
toFitViewSize:self.pictureView.frame.size
|
|
withMethod:MXThumbnailingMethodCrop
|
|
previewImage:bubbleData.senderAvatarPlaceholder ? bubbleData.senderAvatarPlaceholder : self.picturePlaceholder
|
|
mediaManager:bubbleData.mxSession.mediaManager];
|
|
|
|
// Display sender's name except if the name appears in the displayed text (see emote and membership events)
|
|
if (bubbleData.shouldHideSenderName == NO)
|
|
{
|
|
self.userNameLabel.text = bubbleData.senderDisplayName;
|
|
self.userNameLabel.hidden = NO;
|
|
self.userNameTapGestureMaskView.userInteractionEnabled = YES;
|
|
}
|
|
else
|
|
{
|
|
self.userNameLabel.hidden = YES;
|
|
self.userNameTapGestureMaskView.userInteractionEnabled = NO;
|
|
}
|
|
}
|
|
|
|
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
|
|
|
|
[timelineConfiguration.currentStyle.cellLayoutUpdater updateLayoutForSelectedStickerCell:self];
|
|
|
|
// Retrieve the suitable content size for the attachment thumbnail
|
|
CGSize contentSize = bubbleData.contentSize;
|
|
// Update image view frame in order to center loading wheel (if any)
|
|
CGRect frame = self.attachmentView.frame;
|
|
frame.size.width = contentSize.width;
|
|
frame.size.height = contentSize.height;
|
|
self.attachmentView.frame = frame;
|
|
// Retrieve the MIME type
|
|
NSString *mimetype = nil;
|
|
if (bubbleData.attachment.thumbnailInfo)
|
|
{
|
|
mimetype = bubbleData.attachment.thumbnailInfo[@"mimetype"];
|
|
}
|
|
else if (bubbleData.attachment.contentInfo)
|
|
{
|
|
mimetype = bubbleData.attachment.contentInfo[@"mimetype"];
|
|
}
|
|
|
|
// Display the sticker
|
|
self.attachmentView.backgroundColor = [UIColor clearColor];
|
|
[self.attachmentView setAttachmentThumb:bubbleData.attachment];
|
|
|
|
// Set the description
|
|
NSAttributedString *description = component.attributedTextMessage;
|
|
if (description.length)
|
|
{
|
|
self.descriptionContainerView.hidden = NO;
|
|
self.descriptionLabel.attributedText = description;
|
|
}
|
|
else
|
|
{
|
|
self.descriptionContainerView.hidden = YES;
|
|
}
|
|
|
|
// Adjust Attachment width constant
|
|
self.attachViewWidthConstraint.constant = contentSize.width;
|
|
|
|
// Handle the encryption view
|
|
if (bubbleData.isEncryptedRoom)
|
|
{
|
|
// Set the right device info icon
|
|
self.encryptionStatusView.hidden = NO;
|
|
self.encryptionStatusView.image = [RoomEncryptedDataBubbleCell encryptionIconForBubbleComponent:component];
|
|
}
|
|
else
|
|
{
|
|
self.encryptionStatusView.hidden = YES;
|
|
}
|
|
|
|
// Hide by default the info container
|
|
self.bubbleInfoContainer.hidden = YES;
|
|
|
|
// Adjust the layout according to the original cell, the one used to display the sticker unselected.
|
|
if ([modelCellViewClass nib])
|
|
{
|
|
MXKRoomBubbleTableViewCell* cell= (MXKRoomBubbleTableViewCell*)[[modelCellViewClass nib] instantiateWithOwner:nil options:nil].firstObject;
|
|
|
|
if (cell.userNameLabel)
|
|
{
|
|
frame = cell.userNameLabel.frame;
|
|
self.userNameLabelTopConstraint.constant = frame.origin.y;
|
|
}
|
|
frame = cell.attachmentView.frame;
|
|
self.attachViewLeadingConstraint.constant = frame.origin.x;
|
|
self.attachViewTopConstraint.constant = cell.attachViewTopConstraint.constant;
|
|
self.attachViewBottomConstraint.constant = cell.attachViewBottomConstraint.constant;
|
|
self.bubbleInfoContainerTopConstraint.constant = cell.bubbleInfoContainerTopConstraint.constant;
|
|
}
|
|
}
|
|
}
|
|
|
|
+ (CGFloat)heightForCellData:(MXKCellData*)cellData withMaximumWidth:(CGFloat)maxWidth
|
|
{
|
|
// Sanity check: accept only object of MXKRoomBubbleCellData classes or sub-classes
|
|
NSParameterAssert([cellData isKindOfClass:[MXKRoomBubbleCellData class]]);
|
|
MXKRoomBubbleCellData *bubbleData = (MXKRoomBubbleCellData*)cellData;
|
|
|
|
// Look for the original cell class to extract the constraints value.
|
|
Class modelCellViewClass = nil;
|
|
if (bubbleData.shouldHideSenderInformation)
|
|
{
|
|
modelCellViewClass = bubbleData.isEncryptedRoom ? RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
|
|
}
|
|
else
|
|
{
|
|
if (bubbleData.isPaginationFirstBubble)
|
|
{
|
|
modelCellViewClass = bubbleData.isEncryptedRoom ? RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class;
|
|
}
|
|
else
|
|
{
|
|
modelCellViewClass = bubbleData.isEncryptedRoom ? RoomIncomingEncryptedAttachmentBubbleCell.class : RoomIncomingAttachmentBubbleCell.class;
|
|
}
|
|
}
|
|
|
|
CGFloat rowHeight = [modelCellViewClass heightForCellData:cellData withMaximumWidth:maxWidth];
|
|
|
|
// Finalize the cell height by adding the height of the description.
|
|
// Retrieve the component which stores the sticker (Only one component is handled by the bubble in case of sticker).
|
|
MXKRoomBubbleComponent *component = bubbleData.bubbleComponents.firstObject;
|
|
NSAttributedString *description = component.attributedTextMessage;
|
|
if (description.length)
|
|
{
|
|
RoomSelectedStickerBubbleCell* cell = (RoomSelectedStickerBubbleCell*)[self cellWithOriginalXib];
|
|
CGRect frame = cell.frame;
|
|
frame.size.width = maxWidth;
|
|
frame.size.height = 300;
|
|
cell.frame = frame;
|
|
|
|
cell.descriptionLabel.attributedText = description;
|
|
[cell layoutIfNeeded];
|
|
|
|
rowHeight += cell.descriptionContainerView.frame.size.height + cell.descriptionContainerViewBottomConstraint.constant;
|
|
}
|
|
|
|
return rowHeight;
|
|
}
|
|
|
|
@end
|