Skip to content

Commit

Permalink
Merge pull request #7512 from vector-im/nimau/PSB308_sent_confirmatio…
Browse files Browse the repository at this point in the history
…n_icon

Fix: Calculation of the frame for a component of a bubble
  • Loading branch information
nimau committed Apr 20, 2023
2 parents f23575e + e3ae9ca commit ffc1a43
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 17 deletions.
38 changes: 24 additions & 14 deletions Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m
Original file line number Diff line number Diff line change
Expand Up @@ -600,36 +600,47 @@ - (CGRect)componentFrameInContentViewForIndex:(NSInteger)componentIndex
}
else if (roomBubbleTableViewCell.messageTextView)
{
// Force the textView used underneath to layout its frame properly
[roomBubbleTableViewCell setNeedsLayout];
[roomBubbleTableViewCell layoutIfNeeded];

// Compute the height
CGFloat textMessageHeight = 0;

if ([bubbleCellData isKindOfClass:[RoomBubbleCellData class]])
{
RoomBubbleCellData *roomBubbleCellData = (RoomBubbleCellData*)bubbleCellData;

if (!roomBubbleCellData.attachment && selectedComponent.attributedTextMessage)
{
textMessageHeight = [roomBubbleCellData rawTextHeight:selectedComponent.attributedTextMessage];
// Get the width of messageTextView to compute the needed height
CGFloat maxTextWidth = CGRectGetWidth(roomBubbleTableViewCell.messageTextView.bounds);

// Compute text message height
textMessageHeight = [roomBubbleCellData rawTextHeight:selectedComponent.attributedTextMessage withMaxWidth:maxTextWidth];
}
}

selectedComponentPositionY = selectedComponent.position.y;


// Get the messageText frame in the cell content view (as the messageTextView may be inside a stackView and not directly a child of the tableViewCell)
UITextView *messageTextView = roomBubbleTableViewCell.messageTextView;
CGRect messageTextViewFrame = [messageTextView convertRect:messageTextView.bounds toView:roomBubbleTableViewCell.contentView];

if (textMessageHeight > 0)
{
selectedComponentHeight = textMessageHeight;
}
else
{
selectedComponentHeight = roomBubbleTableViewCell.frame.size.height - selectedComponentPositionY;
// if we don't have a height, use the messageTextView height without the text container vertical insets to stay aligned with the text.
selectedComponentHeight = CGRectGetHeight(messageTextViewFrame) - messageTextView.textContainerInset.top - messageTextView.textContainerInset.bottom;
}

// Force the textView used underneath to layout its frame properly
[roomBubbleTableViewCell setNeedsLayout];
[roomBubbleTableViewCell layoutIfNeeded];

selectedComponenContentViewYOffset = roomBubbleTableViewCell.messageTextView.frame.origin.y;
// Get the vertical position of the messageTextView relative to the contentView
selectedComponenContentViewYOffset = CGRectGetMinY(messageTextViewFrame);

// Get the position of the component inside the messageTextView
selectedComponentPositionY = selectedComponent.position.y;
}

if (roomBubbleTableViewCell.attachmentView || roomBubbleTableViewCell.messageTextView)
{
CGFloat x = 0;
Expand Down Expand Up @@ -801,8 +812,7 @@ - (IBAction)onReceiptContainerTap:(UITapGestureRecognizer *)sender

- (void)addTickView:(UIView *)tickView atIndex:(NSInteger)index
{
CGRect componentFrame = [self componentFrameInContentViewForIndex: index];

CGRect componentFrame = [self componentFrameInContentViewForIndex:index];
tickView.frame = CGRectMake(self.contentView.bounds.size.width - tickView.frame.size.width - 2 * PlainRoomCellLayoutConstants.readReceiptsViewRightMargin, CGRectGetMaxY(componentFrame) - tickView.frame.size.height, tickView.frame.size.width, tickView.frame.size.height);

[self.contentView addSubview:tickView];
Expand Down
9 changes: 9 additions & 0 deletions Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@
*/
- (CGFloat)rawTextHeight:(NSAttributedString*)attributedText;

/**
Return the raw height of the provided text by removing any vertical margin/inset and constraining the width.
@param attributedText the attributed text to measure
@param maxTextViewWidth the maximum text width
@return the computed height
*/
- (CGFloat)rawTextHeight:(NSAttributedString*)attributedText withMaxWidth:(CGFloat)maxTextViewWidth;

/**
Return the content size of a text view initialized with the provided attributed text.
CAUTION: This method runs only on main thread.
Expand Down
17 changes: 14 additions & 3 deletions Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m
Original file line number Diff line number Diff line change
Expand Up @@ -500,23 +500,34 @@ - (NSInteger)bubbleComponentIndexForEventId:(NSString *)eventId

// Return the raw height of the provided text by removing any margin
- (CGFloat)rawTextHeight: (NSAttributedString*)attributedText
{
return [self rawTextHeight:attributedText withMaxWidth:_maxTextViewWidth];
}

// Return the raw height of the provided text by removing any vertical margin/inset and constraining the width.
- (CGFloat)rawTextHeight: (NSAttributedString*)attributedText withMaxWidth:(CGFloat)maxTextViewWidth
{
__block CGSize textSize;
if ([NSThread currentThread] != [NSThread mainThread])
{
dispatch_sync(dispatch_get_main_queue(), ^{
textSize = [self textContentSize:attributedText removeVerticalInset:YES];
textSize = [self textContentSize:attributedText removeVerticalInset:YES maxTextViewWidth:maxTextViewWidth];
});
}
else
{
textSize = [self textContentSize:attributedText removeVerticalInset:YES];
textSize = [self textContentSize:attributedText removeVerticalInset:YES maxTextViewWidth:maxTextViewWidth];
}

return textSize.height;
}

- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset
{
return [self textContentSize:attributedText removeVerticalInset:removeVerticalInset maxTextViewWidth:_maxTextViewWidth];
}

- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset maxTextViewWidth:(CGFloat)maxTextViewWidth
{
static UITextView* measurementTextView = nil;
static UITextView* measurementTextViewWithoutInset = nil;
Expand All @@ -536,7 +547,7 @@ - (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInse
// Select the right text view for measurement
UITextView *selectedTextView = (removeVerticalInset ? measurementTextViewWithoutInset : measurementTextView);

selectedTextView.frame = CGRectMake(0, 0, _maxTextViewWidth, 0);
selectedTextView.frame = CGRectMake(0, 0, maxTextViewWidth, 0);
selectedTextView.attributedText = attributedText;

// Force the layout manager to layout the text, fixes problems starting iOS 16
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ class TextMessageOutgoingWithoutSenderInfoBubbleCell: TextMessageBaseBubbleCell,
self.textMessageContentView?.bubbleBackgroundView?.backgroundColor = theme.roomCellOutgoingBubbleBackgroundColor
}

override func render(_ cellData: MXKCellData!) {
// This cell displays an outgoing message without any sender information.
// However, we need to set the following properties to our cellData, otherwise, to make room for the timestamp, a whitespace could be added when calculating the position of the components.
// If we don't, the component frame calculation will not work for this cell.
(cellData as? RoomBubbleCellData)?.shouldHideSenderName = false
(cellData as? RoomBubbleCellData)?.shouldHideSenderInformation = false
super.render(cellData)
}

// MARK: - Private

private func setupBubbleConstraints() {
Expand Down
1 change: 1 addition & 0 deletions changelog.d/pr-7512.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix the position of the send confirmation icon.

0 comments on commit ffc1a43

Please sign in to comment.