mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-18 07:28:28 +02:00
Merge MatrixKit develop with commit hash: b85b736313bec0592bd1cabc68035d97f5331137
This commit is contained in:
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket 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 "MXKRoomBubbleCellDataWithAppendingMode.h"
|
||||
|
||||
static NSAttributedString *messageSeparator = nil;
|
||||
|
||||
@implementation MXKRoomBubbleCellDataWithAppendingMode
|
||||
|
||||
#pragma mark - MXKRoomBubbleCellDataStoring
|
||||
|
||||
- (instancetype)initWithEvent:(MXEvent *)event andRoomState:(MXRoomState *)roomState andRoomDataSource:(MXKRoomDataSource *)roomDataSource2
|
||||
{
|
||||
self = [super initWithEvent:event andRoomState:roomState andRoomDataSource:roomDataSource2];
|
||||
if (self)
|
||||
{
|
||||
// Set default settings
|
||||
self.maxComponentCount = 10;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)addEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState
|
||||
{
|
||||
// We group together text messages from the same user (attachments are not merged).
|
||||
if ([event.sender isEqualToString:self.senderId] && (self.attachment == nil) && (self.bubbleComponents.count < self.maxComponentCount))
|
||||
{
|
||||
// Attachments (image, video, sticker ...) cannot be added here
|
||||
if ([roomDataSource.eventFormatter isSupportedAttachment:event])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Check sender information
|
||||
NSString *eventSenderName = [roomDataSource.eventFormatter senderDisplayNameForEvent:event withRoomState:roomState];
|
||||
NSString *eventSenderAvatar = [roomDataSource.eventFormatter senderAvatarUrlForEvent:event withRoomState:roomState];
|
||||
if ((self.senderDisplayName || eventSenderName) &&
|
||||
([self.senderDisplayName isEqualToString:eventSenderName] == NO))
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
if ((self.senderAvatarUrl || eventSenderAvatar) &&
|
||||
([self.senderAvatarUrl isEqualToString:eventSenderAvatar] == NO))
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Take into account here the rendered bubbles pagination
|
||||
if (roomDataSource.bubblesPagination == MXKRoomDataSourceBubblesPaginationPerDay)
|
||||
{
|
||||
// Event must be sent the same day than the existing bubble.
|
||||
NSString *bubbleDateString = [roomDataSource.eventFormatter dateStringFromDate:self.date withTime:NO];
|
||||
NSString *eventDateString = [roomDataSource.eventFormatter dateStringFromEvent:event withTime:NO];
|
||||
if (bubbleDateString && eventDateString && ![bubbleDateString isEqualToString:eventDateString])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new message component
|
||||
MXKRoomBubbleComponent *addedComponent = [[MXKRoomBubbleComponent alloc] initWithEvent:event roomState:roomState eventFormatter:roomDataSource.eventFormatter session:self.mxSession];
|
||||
if (addedComponent)
|
||||
{
|
||||
[self addComponent:addedComponent];
|
||||
}
|
||||
// else the event is ignored, we consider it as handled
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)mergeWithBubbleCellData:(id<MXKRoomBubbleCellDataStoring>)bubbleCellData
|
||||
{
|
||||
if ([self hasSameSenderAsBubbleCellData:bubbleCellData])
|
||||
{
|
||||
MXKRoomBubbleCellData *cellData = (MXKRoomBubbleCellData*)bubbleCellData;
|
||||
// Only text messages are merged (Attachments are not merged).
|
||||
if ((self.attachment == nil) && (cellData.attachment == nil))
|
||||
{
|
||||
// Take into account here the rendered bubbles pagination
|
||||
if (roomDataSource.bubblesPagination == MXKRoomDataSourceBubblesPaginationPerDay)
|
||||
{
|
||||
// bubble components must be sent the same day than self.
|
||||
NSString *selfDateString = [roomDataSource.eventFormatter dateStringFromDate:self.date withTime:NO];
|
||||
NSString *bubbleDateString = [roomDataSource.eventFormatter dateStringFromDate:bubbleCellData.date withTime:NO];
|
||||
if (![bubbleDateString isEqualToString:selfDateString])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Add all components of the provided message
|
||||
for (MXKRoomBubbleComponent* component in cellData.bubbleComponents)
|
||||
{
|
||||
[self addComponent:component];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSAttributedString*)attributedTextMessageWithHighlightedEvent:(NSString*)eventId tintColor:(UIColor*)tintColor
|
||||
{
|
||||
// Create attributed string
|
||||
NSMutableAttributedString *customAttributedTextMsg;
|
||||
NSAttributedString *componentString;
|
||||
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
for (MXKRoomBubbleComponent* component in bubbleComponents)
|
||||
{
|
||||
componentString = component.attributedTextMessage;
|
||||
|
||||
if (componentString)
|
||||
{
|
||||
if ([component.event.eventId isEqualToString:eventId])
|
||||
{
|
||||
NSMutableAttributedString *customComponentString = [[NSMutableAttributedString alloc] initWithAttributedString:componentString];
|
||||
UIColor *color = tintColor ? tintColor : [UIColor lightGrayColor];
|
||||
[customComponentString addAttribute:NSBackgroundColorAttributeName value:color range:NSMakeRange(0, customComponentString.length)];
|
||||
componentString = customComponentString;
|
||||
}
|
||||
|
||||
if (!customAttributedTextMsg)
|
||||
{
|
||||
customAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:componentString];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append attributed text
|
||||
[customAttributedTextMsg appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
[customAttributedTextMsg appendAttributedString:componentString];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return customAttributedTextMsg;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)prepareBubbleComponentsPosition
|
||||
{
|
||||
// Set position of the first component
|
||||
[super prepareBubbleComponentsPosition];
|
||||
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
// Check whether the position of other components need to be refreshed
|
||||
if (!self.attachment && shouldUpdateComponentsPosition && bubbleComponents.count > 1)
|
||||
{
|
||||
// Init attributed string with the first text component not nil.
|
||||
MXKRoomBubbleComponent *component = bubbleComponents.firstObject;
|
||||
CGFloat positionY = component.position.y;
|
||||
NSMutableAttributedString *attributedString;
|
||||
NSUInteger index = 0;
|
||||
|
||||
for (; index < bubbleComponents.count; index++)
|
||||
{
|
||||
component = [bubbleComponents objectAtIndex:index];
|
||||
|
||||
component.position = CGPointMake(0, positionY);
|
||||
|
||||
if (component.attributedTextMessage)
|
||||
{
|
||||
attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:component.attributedTextMessage];
|
||||
[attributedString appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (index++; index < bubbleComponents.count; index++)
|
||||
{
|
||||
// Append the next text component
|
||||
component = [bubbleComponents objectAtIndex:index];
|
||||
|
||||
if (component.attributedTextMessage)
|
||||
{
|
||||
[attributedString appendAttributedString:component.attributedTextMessage];
|
||||
|
||||
// Compute the height of the resulting string
|
||||
CGFloat cumulatedHeight = [self rawTextHeight:attributedString];
|
||||
|
||||
// Deduce the position of the beginning of this component
|
||||
CGFloat positionY = MXKROOMBUBBLECELLDATA_TEXTVIEW_DEFAULT_VERTICAL_INSET + (cumulatedHeight - [self rawTextHeight:component.attributedTextMessage]);
|
||||
|
||||
component.position = CGPointMake(0, positionY);
|
||||
|
||||
[attributedString appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply the current vertical position on this empty component.
|
||||
component.position = CGPointMake(0, positionY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldUpdateComponentsPosition = NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSString*)textMessage
|
||||
{
|
||||
NSString *rawText = nil;
|
||||
|
||||
if (self.attributedTextMessage)
|
||||
{
|
||||
// Append all components text message
|
||||
NSMutableString *currentTextMsg;
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
for (MXKRoomBubbleComponent* component in bubbleComponents)
|
||||
{
|
||||
if (component.textMessage == nil)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!currentTextMsg)
|
||||
{
|
||||
currentTextMsg = [NSMutableString stringWithString:component.textMessage];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append text message
|
||||
[currentTextMsg appendString:@"\n"];
|
||||
[currentTextMsg appendString:component.textMessage];
|
||||
}
|
||||
}
|
||||
}
|
||||
rawText = currentTextMsg;
|
||||
}
|
||||
|
||||
return rawText;
|
||||
}
|
||||
|
||||
- (void)setAttributedTextMessage:(NSAttributedString *)inAttributedTextMessage
|
||||
{
|
||||
super.attributedTextMessage = inAttributedTextMessage;
|
||||
|
||||
// Position of each components should be computed again
|
||||
shouldUpdateComponentsPosition = YES;
|
||||
}
|
||||
|
||||
- (NSAttributedString*)attributedTextMessage
|
||||
{
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
if (self.hasAttributedTextMessage && !attributedTextMessage.length)
|
||||
{
|
||||
// Create attributed string
|
||||
NSMutableAttributedString *currentAttributedTextMsg;
|
||||
|
||||
for (MXKRoomBubbleComponent* component in bubbleComponents)
|
||||
{
|
||||
if (component.attributedTextMessage)
|
||||
{
|
||||
if (!currentAttributedTextMsg)
|
||||
{
|
||||
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:component.attributedTextMessage];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append attributed text
|
||||
[currentAttributedTextMsg appendAttributedString:[MXKRoomBubbleCellDataWithAppendingMode messageSeparator]];
|
||||
[currentAttributedTextMsg appendAttributedString:component.attributedTextMessage];
|
||||
}
|
||||
}
|
||||
}
|
||||
self.attributedTextMessage = currentAttributedTextMsg;
|
||||
}
|
||||
}
|
||||
|
||||
return attributedTextMessage;
|
||||
}
|
||||
|
||||
- (void)setMaxTextViewWidth:(CGFloat)inMaxTextViewWidth
|
||||
{
|
||||
CGFloat previousMaxWidth = self.maxTextViewWidth;
|
||||
|
||||
[super setMaxTextViewWidth:inMaxTextViewWidth];
|
||||
|
||||
// Check change
|
||||
if (previousMaxWidth != self.maxTextViewWidth)
|
||||
{
|
||||
// Position of each components should be computed again
|
||||
shouldUpdateComponentsPosition = YES;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
+ (NSAttributedString *)messageSeparator
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if(messageSeparator == nil)
|
||||
{
|
||||
messageSeparator = [[NSAttributedString alloc] initWithString:@"\n\n" attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
|
||||
NSFontAttributeName: [UIFont systemFontOfSize:4]}];
|
||||
}
|
||||
}
|
||||
return messageSeparator;
|
||||
}
|
||||
|
||||
#pragma mark - Privates
|
||||
|
||||
- (void)addComponent:(MXKRoomBubbleComponent*)addedComponent
|
||||
{
|
||||
@synchronized(bubbleComponents)
|
||||
{
|
||||
// Check date of existing components to insert this new one
|
||||
NSUInteger index = bubbleComponents.count;
|
||||
|
||||
// Component without date is added at the end by default
|
||||
if (addedComponent.date)
|
||||
{
|
||||
while (index)
|
||||
{
|
||||
MXKRoomBubbleComponent *msgComponent = [bubbleComponents objectAtIndex:(--index)];
|
||||
if (msgComponent.date && [msgComponent.date compare:addedComponent.date] != NSOrderedDescending)
|
||||
{
|
||||
// New component will be inserted here
|
||||
index ++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert new component
|
||||
[bubbleComponents insertObject:addedComponent atIndex:index];
|
||||
|
||||
// Indicate that the data's text message layout should be recomputed.
|
||||
[self invalidateTextLayout];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user