Apply MatrixKit PR changes

This commit is contained in:
ismailgulek
2021-12-09 16:57:43 +03:00
parent 8093844aea
commit 4fc6c75cf2
15 changed files with 161 additions and 69 deletions
@@ -437,4 +437,11 @@ typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
*/
- (void)setBubbleTableViewContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
/**
Handle typing notification.
@param typing Flag indicating whether the user is typing or not.
*/
- (void)handleTypingNotification:(BOOL)typing;
@end
@@ -80,6 +80,11 @@
*/
@property (nonatomic, readonly) BOOL hasLink;
/**
Whether the data has a thread root in its components.
*/
@property (nonatomic, readonly) BOOL hasThreadRoot;
/**
Event formatter
*/
@@ -607,6 +607,22 @@
return NO;
}
- (BOOL)hasThreadRoot
{
@synchronized (bubbleComponents)
{
for (MXKRoomBubbleComponent *component in bubbleComponents)
{
if (component.thread)
{
return YES;
}
}
}
return NO;
}
- (MXKRoomBubbleComponentDisplayFix)displayFix
{
MXKRoomBubbleComponentDisplayFix displayFix = MXKRoomBubbleComponentDisplayFixNone;
@@ -19,6 +19,8 @@
#import "MXKEventFormatter.h"
#import "MXKURLPreviewDataProtocol.h"
@class MXThread;
/**
Flags to indicate if a fix is required at the display time.
*/
@@ -103,6 +105,11 @@ typedef enum : NSUInteger {
*/
@property (nonatomic, readonly) BOOL showEncryptionBadge;
/**
Thread for the bubble component. Should only exist for thread root events.
*/
@property (nonatomic, readonly) MXThread *thread;
/**
Create a new `MXKRoomBubbleComponent` object based on a `MXEvent` instance.
@@ -18,6 +18,13 @@
#import "MXEvent+MatrixKit.h"
#import "MXKSwiftHeader.h"
#import <MatrixSDK/MatrixSDK.h>
@interface MXKRoomBubbleComponent ()
@property (nonatomic, readwrite) MXThread *thread;
@end
@implementation MXKRoomBubbleComponent
@@ -62,6 +69,8 @@
_showEncryptionBadge = [self shouldShowWarningBadgeForEvent:event roomState:(MXRoomState*)roomState session:session];
[self updateLinkWithRoomState:roomState];
self.thread = [session.threadingService threadWithId:event.eventId];
}
return self;
}
@@ -169,6 +169,11 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
*/
@property (nonatomic) NSString *partialTextMessage;
/**
The current thread id for the data source. If provided, data source displays the specified thread, otherwise the whole room messages.
*/
@property (nonatomic, readonly) NSString *threadId;
#pragma mark - Configuration
/**
The text formatter applied on the events.
@@ -269,10 +274,15 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param roomId the id of the room to get data from.
@param initialEventId the id of the event where to start the timeline.
@param threadId the id of the thread to load.
@param mxSession the Matrix session to get data from.
@param onComplete a block providing the newly created instance.
*/
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete;
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId
initialEventId:(NSString*)initialEventId
threadId:(NSString*)threadId
andMatrixSession:(MXSession*)mxSession
onComplete:(void (^)(id roomDataSource))onComplete;
/**
Asynchronously create a data source to peek into a room.
@@ -306,10 +316,14 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param roomId the id of the room to get data from.
@param initialEventId the id of the event where to start the timeline.
@param threadId the id of the thread to initialize.
@param mxSession the Matrix session to get data from.
@return the newly created instance.
*/
- (instancetype)initWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId andMatrixSession:(MXSession*)mxSession;
- (instancetype)initWithRoomId:(NSString*)roomId
initialEventId:(NSString*)initialEventId
threadId:(NSString*)threadId
andMatrixSession:(MXSession*)mxSession;
/**
Initialise the data source to peek into a room.
@@ -678,6 +692,20 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
*/
+ (dispatch_queue_t)processingQueue;
/**
Decides whether an event should be considered for asynchronous event processing.
Default implementation checks for `filterMessagesWithURL` and undecryptable events sent before the user joined.
Subclasses must call super at some point.
@param event event to be processed or not
@param roomState the state of the room when the event fired
@param direction the direction of the event
@return YES to process the event, NO otherwise
*/
- (BOOL)shouldQueueEventForProcessing:(MXEvent*)event
roomState:(MXRoomState*)roomState
direction:(MXTimelineDirection)direction;
#pragma mark - Bubble collapsing
/**
@@ -204,6 +204,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
@property (nonatomic, readwrite) MXRoom *secondaryRoom;
@property (nonatomic, strong) MXEventTimeline *secondaryTimeline;
@property (nonatomic, readwrite) NSString *threadId;
@end
@@ -215,9 +216,9 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
[self ensureSessionStateForDataSource:roomDataSource initialEventId:nil andMatrixSession:mxSession onComplete:onComplete];
}
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete
{
MXKRoomDataSource *roomDataSource = [[self alloc] initWithRoomId:roomId initialEventId:initialEventId andMatrixSession:mxSession];
MXKRoomDataSource *roomDataSource = [[self alloc] initWithRoomId:roomId initialEventId:initialEventId threadId:threadId andMatrixSession:mxSession];
[self ensureSessionStateForDataSource:roomDataSource initialEventId:initialEventId andMatrixSession:mxSession onComplete:onComplete];
}
@@ -347,7 +348,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
return self;
}
- (instancetype)initWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId2 andMatrixSession:(MXSession*)mxSession
- (instancetype)initWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId2 threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession
{
self = [self initWithRoomId:roomId andMatrixSession:mxSession];
if (self)
@@ -357,6 +358,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
initialEventId = initialEventId2;
_isLive = NO;
}
_threadId = threadId;
}
return self;
@@ -364,7 +366,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
- (instancetype)initWithPeekingRoom:(MXPeekingRoom*)peekingRoom2 andInitialEventId:(NSString*)theInitialEventId
{
self = [self initWithRoomId:peekingRoom2.roomId initialEventId:theInitialEventId andMatrixSession:peekingRoom2.mxSession];
self = [self initWithRoomId:peekingRoom2.roomId initialEventId:theInitialEventId threadId:nil andMatrixSession:peekingRoom2.mxSession];
if (self)
{
peekingRoom = peekingRoom2;
@@ -1289,6 +1291,34 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
}
- (BOOL)shouldQueueEventForProcessing:(MXEvent*)event roomState:(MXRoomState*)roomState direction:(MXTimelineDirection)direction
{
if (self.filterMessagesWithURL)
{
// Check whether the event has a value for the 'url' key in its content.
if (!event.getMediaURLs.count)
{
// ignore the event
return NO;
}
}
// Check for undecryptable messages that were sent while the user was not in the room and hide them
if ([MXKAppSettings standardAppSettings].hidePreJoinedUndecryptableEvents
&& direction == MXTimelineDirectionBackwards)
{
[self checkForPreJoinUTDWithEvent:event roomState:roomState];
// Hide pre joint UTD events
if (self.shouldStopBackPagination)
{
return NO;
}
}
return YES;
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
@@ -1425,7 +1455,11 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
// Launch the pagination
MXWeakify(self);
paginationRequest = [_timeline paginate:numItems direction:direction onlyFromStore:onlyFromStore complete:^{
paginationRequest = [_timeline paginate:numItems
direction:direction
onlyFromStore:onlyFromStore
// threadId:_threadId
complete:^{
MXStrongifyAndReturnIfNil(self);
@@ -1489,7 +1523,11 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
dispatch_group_enter(dispatchGroup);
// Launch the pagination
MXWeakify(self);
secondaryPaginationRequest = [_secondaryTimeline paginate:numItems direction:direction onlyFromStore:onlyFromStore complete:^{
secondaryPaginationRequest = [_secondaryTimeline paginate:numItems
direction:direction
onlyFromStore:onlyFromStore
// threadId:_threadId
complete:^{
MXStrongifyAndReturnIfNil(self);
@@ -1676,11 +1714,11 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
// Make the request to the homeserver
if (isEmote)
{
[_room sendEmote:sanitizedText formattedText:html localEcho:&localEchoEvent success:success failure:failure];
[_room sendEmote:sanitizedText formattedText:html threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
}
else
{
[_room sendTextMessage:sanitizedText formattedText:html localEcho:&localEchoEvent success:success failure:failure];
[_room sendTextMessage:sanitizedText formattedText:html threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
}
if (localEchoEvent)
@@ -1821,7 +1859,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
{
__block MXEvent *localEchoEvent = nil;
[_room sendImage:imageData withImageSize:imageSize mimeType:mimetype andThumbnail:thumbnail localEcho:&localEchoEvent success:success failure:failure];
[_room sendImage:imageData withImageSize:imageSize mimeType:mimetype andThumbnail:thumbnail threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
if (localEchoEvent)
{
@@ -1841,7 +1879,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
{
__block MXEvent *localEchoEvent = nil;
[_room sendVideoAsset:videoAsset withThumbnail:videoThumbnail localEcho:&localEchoEvent success:success failure:failure];
[_room sendVideoAsset:videoAsset withThumbnail:videoThumbnail threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
if (localEchoEvent)
{
@@ -1855,7 +1893,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
{
__block MXEvent *localEchoEvent = nil;
[_room sendAudioFile:audioFileLocalURL mimeType:mimeType localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
[_room sendAudioFile:audioFileLocalURL mimeType:mimeType threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
if (localEchoEvent)
{
@@ -1874,7 +1912,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
{
__block MXEvent *localEchoEvent = nil;
[_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType duration:duration samples:samples localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
[_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType duration:duration samples:samples threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
if (localEchoEvent)
{
@@ -1889,7 +1927,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
{
__block MXEvent *localEchoEvent = nil;
[_room sendFile:fileLocalURL mimeType:mimeType localEcho:&localEchoEvent success:success failure:failure];
[_room sendFile:fileLocalURL mimeType:mimeType threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
if (localEchoEvent)
{
@@ -1904,7 +1942,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
__block MXEvent *localEchoEvent = nil;
// Make the request to the homeserver
[_room sendMessageWithContent:msgContent localEcho:&localEchoEvent success:success failure:failure];
[_room sendMessageWithContent:msgContent threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
if (localEchoEvent)
{
@@ -1919,7 +1957,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
__block MXEvent *localEchoEvent = nil;
// Make the request to the homeserver
[_room sendEventOfType:eventTypeString content:msgContent localEcho:&localEchoEvent success:success failure:failure];
[_room sendEventOfType:eventTypeString content:msgContent threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure];
if (localEchoEvent)
{
@@ -1946,7 +1984,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
{
// We try here to resent an encrypted event
// Note: we keep the existing local echo.
[_room sendEventOfType:kMXEventTypeStringRoomEncrypted content:event.wireContent localEcho:&event success:success failure:failure];
[_room sendEventOfType:kMXEventTypeStringRoomEncrypted content:event.wireContent threadId:self.threadId localEcho:&event success:success failure:failure];
}
else if ([event.type isEqualToString:kMXEventTypeStringRoomMessage])
{
@@ -1955,7 +1993,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
if ([msgType isEqualToString:kMXMessageTypeText] || [msgType isEqualToString:kMXMessageTypeEmote])
{
// Resend the Matrix event by reusing the existing echo
[_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
[_room sendMessageWithContent:event.content threadId:self.threadId localEcho:&event success:success failure:failure];
}
else if ([msgType isEqualToString:kMXMessageTypeImage])
{
@@ -1998,7 +2036,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
else
{
// Resend the Matrix event by reusing the existing echo
[_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
[_room sendMessageWithContent:event.content threadId:self.threadId localEcho:&event success:success failure:failure];
}
}
else if ([msgType isEqualToString:kMXMessageTypeAudio])
@@ -2009,7 +2047,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
if (!contentURL || ![contentURL hasPrefix:kMXMediaUploadIdPrefix])
{
// Resend the Matrix event by reusing the existing echo
[_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
[_room sendMessageWithContent:event.content threadId:self.threadId localEcho:&event success:success failure:failure];
return;
}
@@ -2049,7 +2087,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
else
{
// Resend the Matrix event by reusing the existing echo
[_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
[_room sendMessageWithContent:event.content threadId:self.threadId localEcho:&event success:success failure:failure];
}
}
else if ([msgType isEqualToString:kMXMessageTypeFile])
@@ -2085,7 +2123,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
else
{
// Resend the Matrix event by reusing the existing echo
[_room sendMessageWithContent:event.content localEcho:&event success:success failure:failure];
[_room sendMessageWithContent:event.content threadId:self.threadId localEcho:&event success:success failure:failure];
}
}
else
@@ -2782,27 +2820,9 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
MXLogVerbose(@"[MXKRoomDataSource][%p] queueEventForProcessing: %@", self, event.eventId);
}
if (self.filterMessagesWithURL)
if (![self shouldQueueEventForProcessing:event roomState:roomState direction:direction])
{
// Check whether the event has a value for the 'url' key in its content.
if (!event.getMediaURLs.count)
{
// Ignore the event
return;
}
}
// Check for undecryptable messages that were sent while the user was not in the room and hide them
if ([MXKAppSettings standardAppSettings].hidePreJoinedUndecryptableEvents
&& direction == MXTimelineDirectionBackwards)
{
[self checkForPreJoinUTDWithEvent:event roomState:roomState];
// Hide pre joint UTD events
if (self.shouldStopBackPagination)
{
return;
}
return;
}
MXKQueuedEvent *queuedEvent = [[MXKQueuedEvent alloc] initWithEvent:event andRoomState:roomState direction:direction];
@@ -329,11 +329,11 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
// Check first whether the event has been redacted
NSString *redactedInfo = nil;
BOOL isRedacted = (event.redactedBecause != nil);
BOOL isRedacted = event.isRedactedEvent;
if (isRedacted)
{
// Check whether redacted information is required
if (_settings.showRedactionsInRoomHistory)
// Check whether the event is a thread root or redacted information is required
if ([mxSession.threadingService isEventThreadRoot:event] || _settings.showRedactionsInRoomHistory)
{
MXLogDebug(@"[MXKEventFormatter] Redacted event %@ (%@)", event.description, event.redactedBecause);
@@ -1256,7 +1256,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
NSString *body;
BOOL isHTML = NO;
NSString *eventThreadIdentifier = event.threadIdentifier;
NSString *eventThreadId = event.threadId;
// Use the HTML formatted string if provided
if ([event.content[@"format"] isEqualToString:kMXRoomMessageFormatHTML])
@@ -1264,17 +1264,17 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
isHTML =YES;
MXJSONModelSetString(body, event.content[@"formatted_body"]);
}
else if (eventThreadIdentifier)
else if (eventThreadId && !RiotSettings.shared.enableThreads)
{
isHTML = YES;
MXJSONModelSetString(body, event.content[@"body"]);
MXEvent *threadRootEvent = [mxSession.store eventWithEventId:eventThreadIdentifier
MXEvent *threadRootEvent = [mxSession.store eventWithEventId:eventThreadId
inRoom:event.roomId];
NSString *threadRootEventContent;
MXJSONModelSetString(threadRootEventContent, threadRootEvent.content[@"body"]);
body = [NSString stringWithFormat:@"<mx-reply><blockquote><a href=\"%@\">In reply to</a> <a href=\"%@\">%@</a><br>%@</blockquote></mx-reply>%@",
[MXTools permalinkToEvent:eventThreadIdentifier inRoom:event.roomId],
[MXTools permalinkToEvent:eventThreadId inRoom:event.roomId],
[MXTools permalinkToUserWithUserId:threadRootEvent.sender],
threadRootEvent.sender,
threadRootEventContent,
@@ -1382,7 +1382,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
// This helps us insert the emote prefix in the right place
NSDictionary *relatesTo;
MXJSONModelSetDictionary(relatesTo, event.content[@"m.relates_to"]);
if ([relatesTo[@"m.in_reply_to"] isKindOfClass:NSDictionary.class] || event.isInThread)
if ([relatesTo[@"m.in_reply_to"] isKindOfClass:NSDictionary.class] || (event.isInThread && !RiotSettings.shared.enableThreads))
{
[attributedDisplayText enumerateAttribute:kMXKToolsBlockquoteMarkAttribute
inRange:NSMakeRange(0, attributedDisplayText.length)
@@ -1720,7 +1720,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
NSString *html = htmlString;
// Special treatment for "In reply to" message
if (event.isReplyEvent || event.isInThread)
if (event.isReplyEvent || (event.isInThread && !RiotSettings.shared.enableThreads))
{
html = [self renderReplyTo:html withRoomState:roomState];
}
@@ -2046,7 +2046,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
textColor = _errorTextColor;
}
// Check whether the message is highlighted.
else if (event.mxkIsHighlighted || (event.isInThread && ![event.sender isEqualToString:mxSession.myUserId]))
else if (event.mxkIsHighlighted || (event.isInThread && !RiotSettings.shared.enableThreads && ![event.sender isEqualToString:mxSession.myUserId]))
{
textColor = _bingTextColor;
}
@@ -2110,7 +2110,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
{
font = _callNoticesTextFont;
}
else if (event.mxkIsHighlighted || (event.isInThread && ![event.sender isEqualToString:mxSession.myUserId]))
else if (event.mxkIsHighlighted || (event.isInThread && !RiotSettings.shared.enableThreads && ![event.sender isEqualToString:mxSession.myUserId]))
{
font = _bingTextFont;
}
@@ -168,7 +168,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
@property (nonatomic) UIImage *picturePlaceholder;
/**
The list of the temporary subviews that should be removed before reusing the cell (nil by default).
The list of the temporary subviews that should be removed before reusing the cell (empty array by default).
*/
@property (nonatomic) NSMutableArray<UIView*> *tmpSubviews;
@@ -121,6 +121,7 @@ static BOOL _disableLongPressGestureOnEvent;
self.readReceiptsAlignment = ReadReceiptAlignmentLeft;
_allTextHighlighted = NO;
_isAutoAnimatedGif = NO;
_tmpSubviews = [NSMutableArray array];
}
- (void)awakeFromNib
@@ -1005,14 +1006,11 @@ static BOOL _disableLongPressGestureOnEvent;
self.bubbleInfoContainer.hidden = YES;
// Remove temporary subviews
if (self.tmpSubviews)
for (UIView *view in self.tmpSubviews)
{
for (UIView *view in self.tmpSubviews)
{
[view removeFromSuperview];
}
self.tmpSubviews = nil;
[view removeFromSuperview];
}
[self.tmpSubviews removeAllObjects];
// Remove potential overlay subviews
if (self.bubbleOverlayContainer)