diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.h b/Riot/Modules/Room/CellData/RoomBubbleCellData.h index fd62967b4..a8317df00 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.h +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.h @@ -65,4 +65,19 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) */ @property(nonatomic, readonly) NSInteger selectedComponentIndex; +/** + Return additional content height (read receipts, reactions). + */ +@property(nonatomic, readonly) CGFloat additionalContentHeight; + +/** + Indicate to update additional content height. + */ +- (void)setNeedsUpdateAdditionalContentHeight; + +/** + Update additional content height if needed. + */ +- (void)updateAdditionalContentHeightIfNeeded; + @end diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index 6b62b990c..0637c96e1 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -29,6 +29,8 @@ static NSAttributedString *timestampVerticalWhitespace = nil; @interface RoomBubbleCellData() @property(nonatomic, readonly) BOOL addVerticalWhitespaceForSelectedComponentTimestamp; +@property(nonatomic, readwrite) CGFloat additionalContentHeight; +@property(nonatomic) BOOL shouldUpdateAdditionalContentHeight; @end @@ -106,6 +108,8 @@ static NSAttributedString *timestampVerticalWhitespace = nil; shouldUpdateComponentsPosition = NO; } + + [self updateAdditionalContentHeightIfNeeded]; } - (NSAttributedString*)attributedTextMessage @@ -380,6 +384,99 @@ static NSAttributedString *timestampVerticalWhitespace = nil; } } +- (CGFloat)computeAdditionalHeight +{ + CGFloat height = 0; + + for (MXKRoomBubbleComponent *bubbleComponent in self.bubbleComponents) + { + NSString *eventId = bubbleComponent.event.eventId; + + height+= [self reactionHeightForEventId:eventId]; + height+= [self readReceiptHeightForEventId:eventId]; + } + + return height; +} + +- (void)updateAdditionalContentHeightIfNeeded; +{ + if (self.shouldUpdateAdditionalContentHeight) + { + void(^updateAdditionalHeight)(void) = ^() { + self.additionalContentHeight = [self computeAdditionalHeight]; + }; + + // The additional height depends on the room read receipts and reactions view which must be calculated on the main thread. + // Check here the current thread, this is just a sanity check because this method is called during the rendering step + // which takes place on the main thread. + if ([NSThread currentThread] != [NSThread mainThread]) + { + NSLog(@"[RoomBubbleCellData] prepareBubbleComponentsPosition called on wrong thread"); + dispatch_sync(dispatch_get_main_queue(), ^{ + updateAdditionalHeight(); + }); + } + else + { + updateAdditionalHeight(); + } + + self.shouldUpdateAdditionalContentHeight = NO; + } +} + +- (void)setNeedsUpdateAdditionalContentHeight +{ + self.shouldUpdateAdditionalContentHeight = YES; +} + +- (CGFloat)reactionHeightForEventId:(NSString*)eventId +{ + CGFloat height = 0; + + NSUInteger reactionCount = self.reactions[eventId].reactions.count; + + MXAggregatedReactions *aggregatedReactions = self.reactions[eventId]; + + if (reactionCount) + { + CGFloat bubbleReactionsViewWidth = self.maxTextViewWidth - 4; + + CGSize fittingSize = UILayoutFittingCompressedSize; + fittingSize.width = bubbleReactionsViewWidth; + + static BubbleReactionsView *bubbleReactionsView; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleReactionsView = [BubbleReactionsView new]; + }); + + bubbleReactionsView.frame = CGRectMake(0, 0, bubbleReactionsViewWidth, 1.0); + BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId]; + bubbleReactionsView.viewModel = viemModel; + [bubbleReactionsView setNeedsLayout]; + [bubbleReactionsView layoutIfNeeded]; + + height = [bubbleReactionsView systemLayoutSizeFittingSize:fittingSize].height + RoomBubbleCellLayout.reactionsViewTopMargin; + } + + return height; +} + +- (CGFloat)readReceiptHeightForEventId:(NSString*)eventId +{ + CGFloat height = 0; + + if (self.readReceipts[eventId].count) + { + height = RoomBubbleCellLayout.readReceiptsViewHeight + RoomBubbleCellLayout.readReceiptsViewTopMargin; + } + + return height; +} + - (void)setContainsLastMessage:(BOOL)containsLastMessage { // Check whether there is something to do