Merge commit '3d672a05b2a7117ade2e4e87bd2b5762063d7922' into feature/3977_merge_element_1_9_13

# Conflicts:
#	Config/AppVersion.xcconfig
#	Podfile.lock
#	Riot/Modules/Application/LegacyAppDelegate.m
#	Riot/Modules/Authentication/AuthenticationCoordinator.swift
#	Riot/Modules/Authentication/Legacy/LegacyAuthenticationCoordinator.swift
#	Riot/Modules/LaunchLoading/LaunchLoadingView.swift
#	Riot/Modules/LaunchLoading/LaunchLoadingView.xib
#	Riot/Modules/MatrixKit/Models/Account/MXKAccount.m
#	Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m
#	Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellProvider.m
#	Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellProvider.m
#	Riot/Modules/TabBar/MasterTabBarController.m
#	fastlane/Fastfile
This commit is contained in:
Frank Rotermund
2022-12-19 14:36:30 +01:00
245 changed files with 5346 additions and 1952 deletions
@@ -374,11 +374,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer
- (void)resetDeviceId;
#pragma mark - Sync filter
/**
Check if the homeserver supports room members lazy loading.
@param completion the check result.
*/
- (void)supportLazyLoadOfRoomMembers:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion;
/**
Call this method at an appropriate time to attempt dehydrating to a new backup device
@@ -897,6 +897,9 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
MXStrongifyAndReturnIfNil(self);
self->mxSession = nil;
NSString *myUserId = self.mxSession.myUser.userId;
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
[[NSNotificationCenter defaultCenter] removeObserver:self->sessionStateObserver];
self->sessionStateObserver = nil;
@@ -1684,6 +1687,14 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
NSString *myUserId = self.mxSession.myUser.userId;
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
}
// If we cannot resolve this error by retrying, exit early
BOOL isRetryableError = [error.domain isEqualToString:NSURLErrorDomain] || [MXHTTPOperation urlResponseFromError:error] != nil;
if (!isRetryableError)
{
MXLogDebug(@"[MXKAccount] Initial sync will not be retried");
return;
}
// Check if it is a network connectivity issue
AFNetworkReachabilityManager *networkReachabilityManager = [AFNetworkReachabilityManager sharedManager];
@@ -1691,7 +1702,6 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
if (networkReachabilityManager.isReachable)
{
// The problem is not the network
// If we have network, we retry immediately, otherwise the server may clear any cache it has computed thus far
[self launchInitialServerSync];
}
@@ -2085,14 +2095,15 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
#pragma mark - Sync filter
- (void)supportLazyLoadOfRoomMembers:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion
- (void)supportLazyLoadOfRoomMembersWithMatrixVersion:(MXMatrixVersions *)matrixVersions
completion:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion
{
void(^onUnsupportedLazyLoadOfRoomMembers)(NSError *) = ^(NSError *error) {
completion(NO);
};
// Check if the server supports LL sync filter
MXFilterJSONModel *filter = [self syncFilterWithLazyLoadOfRoomMembers:YES];
MXFilterJSONModel *filter = [self syncFilterWithLazyLoadOfRoomMembers:YES supportsNotificationsForThreads:NO];
[mxSession.store filterIdForFilter:filter success:^(NSString * _Nullable filterId) {
if (filterId)
@@ -2103,8 +2114,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
else
{
// Check the Matrix versions supported by the HS
[self.mxSession supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
if (matrixVersions)
{
if (matrixVersions.supportLazyLoadMembers)
{
// The HS supports LL
@@ -2114,8 +2125,11 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
{
onUnsupportedLazyLoadOfRoomMembers(nil);
}
} failure:onUnsupportedLazyLoadOfRoomMembers];
}
else
{
completion(NO);
}
}
} failure:onUnsupportedLazyLoadOfRoomMembers];
}
@@ -2130,28 +2144,42 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Check settings
BOOL syncWithLazyLoadOfRoomMembersSetting = [MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers;
if (syncWithLazyLoadOfRoomMembersSetting)
{
// Check if the server supports LL sync filter before enabling it
[self supportLazyLoadOfRoomMembers:^(BOOL supportLazyLoadOfRoomMembers) {
void(^buildSyncFilter)(MXMatrixVersions *) = ^(MXMatrixVersions *matrixVersions) {
BOOL supportsNotificationsForThreads = matrixVersions ? matrixVersions.supportsNotificationsForThreads : NO;
if (syncWithLazyLoadOfRoomMembersSetting)
{
// Check if the server supports LL sync filter before enabling it
[self supportLazyLoadOfRoomMembersWithMatrixVersion:matrixVersions completion:^(BOOL supportLazyLoadOfRoomMembers) {
if (supportLazyLoadOfRoomMembers)
{
completion([self syncFilterWithLazyLoadOfRoomMembers:YES]);
}
else
{
// No support from the HS
// Disable the setting. That will avoid to make a request at every startup
[MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers = NO;
completion([self syncFilterWithLazyLoadOfRoomMembers:NO]);
}
}];
}
else
{
completion([self syncFilterWithLazyLoadOfRoomMembers:NO]);
}
if (supportLazyLoadOfRoomMembers)
{
completion([self syncFilterWithLazyLoadOfRoomMembers:YES
supportsNotificationsForThreads:supportsNotificationsForThreads]);
}
else
{
// No support from the HS
// Disable the setting. That will avoid to make a request at every startup
[MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers = NO;
completion([self syncFilterWithLazyLoadOfRoomMembers:NO
supportsNotificationsForThreads:supportsNotificationsForThreads]);
}
}];
}
else
{
completion([self syncFilterWithLazyLoadOfRoomMembers:NO supportsNotificationsForThreads:supportsNotificationsForThreads]);
}
};
[mxSession supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
buildSyncFilter(matrixVersions);
} failure:^(NSError *error) {
MXLogWarning(@"[MXAccount] buildSyncFilter: failed to get supported versions: %@", error);
buildSyncFilter(nil);
}];
}
/**
@@ -2160,7 +2188,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
@param syncWithLazyLoadOfRoomMembers enable LL support.
@return the sync filter to use.
*/
- (MXFilterJSONModel *)syncFilterWithLazyLoadOfRoomMembers:(BOOL)syncWithLazyLoadOfRoomMembers
- (MXFilterJSONModel *)syncFilterWithLazyLoadOfRoomMembers:(BOOL)syncWithLazyLoadOfRoomMembers supportsNotificationsForThreads:(BOOL)supportsNotificationsForThreads
{
MXFilterJSONModel *syncFilter;
NSUInteger limit = 10;
@@ -2195,11 +2223,11 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Set that limit in the filter
if (syncWithLazyLoadOfRoomMembers)
{
syncFilter = [MXFilterJSONModel syncFilterForLazyLoadingWithMessageLimit:limit];
syncFilter = [MXFilterJSONModel syncFilterForLazyLoadingWithMessageLimit:limit unreadThreadNotifications:supportsNotificationsForThreads];
}
else
{
syncFilter = [MXFilterJSONModel syncFilterWithMessageLimit:limit];
syncFilter = [MXFilterJSONModel syncFilterWithMessageLimit:limit unreadThreadNotifications:supportsNotificationsForThreads];
}
// TODO: We could extend the filter to match other settings (self.showAllEventsInRoomHistory,
@@ -518,7 +518,6 @@
- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset
{
static UITextView* measurementTextView = nil;
static UITextView* measurementTextViewWithoutInset = nil;
@@ -527,24 +526,23 @@
if (!measurementTextView)
{
measurementTextView = [[UITextView alloc] init];
measurementTextViewWithoutInset = [[UITextView alloc] init];
// Remove the container inset: this operation impacts only the vertical margin.
// Note: consider textContainer.lineFragmentPadding to remove horizontal margin
measurementTextViewWithoutInset.textContainerInset = UIEdgeInsetsZero;
}
// Select the right text view for measurement
UITextView *selectedTextView = (removeVerticalInset ? measurementTextViewWithoutInset : measurementTextView);
selectedTextView.frame = CGRectMake(0, 0, _maxTextViewWidth, 0);
selectedTextView.attributedText = attributedText;
// Force the layout manager to layout the text, fixes problems starting iOS 16
[selectedTextView.layoutManager ensureLayoutForTextContainer:selectedTextView.textContainer];
CGSize size = [selectedTextView sizeThatFits:selectedTextView.frame.size];
// Manage the case where a string attribute has a single paragraph with a left indent
// In this case, [UITextView sizeThatFits] ignores the indent and return the width
// of the text only.
@@ -557,8 +555,10 @@
{
size.width = size.width + paragraphStyle.headIndent;
}
return size;
}
return CGSizeZero;
}
@@ -985,8 +985,19 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
else if (nil == localEcho)
{
// Process here incoming events, and outgoing events sent from another device.
[self queueEventForProcessing:event withRoomState:roomState direction:MXTimelineDirectionForwards];
[self processQueuedEvents:nil];
if (self.threadId == nil && event.isInThread)
{
NSInteger index = [self indexOfCellDataWithEventId:event.relatesTo.eventId];
if (index != NSNotFound)
{
[self reloadNotifying:NO];
}
}
else
{
[self queueEventForProcessing:event withRoomState:roomState direction:MXTimelineDirectionForwards];
[self processQueuedEvents:nil];
}
}
}
}];
@@ -1373,6 +1384,11 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
// ignore the event
return NO;
}
// Ignore voice message related to an actual voice broadcast.
if (event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] != nil) {
return NO;
}
}
// Check for undecryptable messages that were sent while the user was not in the room and hide them
@@ -2358,15 +2374,61 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
// Update cell data we have received a read receipt for
NSArray *readEventIds = receiptEvent.readReceiptEventIds;
for (NSString* eventId in readEventIds)
if (RiotSettings.shared.enableThreads)
{
MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
if (cellData)
NSArray *readThreadIds = receiptEvent.readReceiptThreadIds;
for (int i = 0 ; i < readEventIds.count ; i++)
{
NSString *eventId = readEventIds[i];
MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
if (cellData)
{
if ([readThreadIds[i] isEqualToString:kMXEventUnthreaded])
{
// Unthreaded RR must be propagated through all threads.
[self.mxSession.threadingService allThreadsInRoomWithId:self.roomId onlyParticipated:NO completion:^(NSArray<id<MXThreadProtocol>> *threads) {
NSMutableArray *threadIds = [NSMutableArray arrayWithObject:kMXEventTimelineMain];
for (id<MXThreadProtocol> thread in threads)
{
[threadIds addObject:thread.id];
}
for (NSString *threadId in threadIds)
{
@synchronized(self->bubbles)
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:eventId threadId:threadId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
}
}];
}
else
{
NSString *threadId = readThreadIds[i];
@synchronized(self->bubbles)
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:eventId threadId:threadId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
}
}
}
}
else
{
// If
for (NSString *eventId in readEventIds)
{
MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
@synchronized(self->bubbles)
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:eventId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
[self addReadReceiptsForEvent:eventId threadId:kMXEventTimelineMain inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
@@ -3512,7 +3574,10 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
@autoreleasepool
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:queuedEvent.event.eventId inCellDatas:self->bubblesSnapshot startingAtCellData:self->eventIdToBubbleMap[queuedEvent.event.eventId] completion:^{
[self addReadReceiptsForEvent:queuedEvent.event.eventId
threadId:queuedEvent.event.threadId
inCellDatas:self->bubblesSnapshot
startingAtCellData:self->eventIdToBubbleMap[queuedEvent.event.eventId] completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
@@ -3667,16 +3732,22 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
If the event is not displayed, read receipts will be added to a previous displayed message.
@param eventId the id of the event.
@param threadId the Id of the thread related of the event.
@param cellDatas the working array of cell datas.
@param cellData the original cell data the event belongs to.
@param completion completion block
*/
- (void)addReadReceiptsForEvent:(NSString*)eventId inCellDatas:(NSArray<id<MXKRoomBubbleCellDataStoring>>*)cellDatas startingAtCellData:(id<MXKRoomBubbleCellDataStoring>)cellData completion:(void (^)(void))completion
- (void)addReadReceiptsForEvent:(NSString*)eventId
threadId:(NSString *)threadId
inCellDatas:(NSArray<id<MXKRoomBubbleCellDataStoring>>*)cellDatas
startingAtCellData:(id<MXKRoomBubbleCellDataStoring>)cellData
completion:(void (^)(void))completion
{
if (self.showBubbleReceipts)
{
if (self.room)
{
[self.room getEventReceipts:eventId sorted:YES completion:^(NSArray<MXReceiptData *> * _Nonnull readReceipts) {
[self.room getEventReceipts:eventId threadId:threadId sorted:YES completion:^(NSArray<MXReceiptData *> * _Nonnull readReceipts) {
if (readReceipts.count)
{
NSInteger cellDataIndex = [cellDatas indexOfObject:cellData];
@@ -3686,6 +3757,14 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
}
}
if (!RiotSettings.shared.enableThreads)
{
// If threads are disabled, we may have several threaded RR with same userId
// but different threadId within the same timeline.
// We just need to keep the latest one.
[self clearDuplicatedReadReceiptsInCellDatas:cellDatas];
}
if (completion)
{
completion();
@@ -3771,6 +3850,45 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
}
}
/**
Clear all potential duplicated RR with same user ID within a given list of cell data.
This is needed for client with threads disabled in order to clean threaded RRs.
@param cellDatas the working array of cell datas.
*/
- (void)clearDuplicatedReadReceiptsInCellDatas:(NSArray<id<MXKRoomBubbleCellDataStoring>>*)cellDatas
{
NSMutableSet<NSString *> *seenUserIds = [NSMutableSet set];
for (id<MXKRoomBubbleCellDataStoring> cellData in cellDatas.reverseObjectEnumerator)
{
if ([cellData isKindOfClass:MXKRoomBubbleCellData.class])
{
MXKRoomBubbleCellData *roomBubbleCellData = (MXKRoomBubbleCellData*)cellData;
for (MXKRoomBubbleComponent *component in roomBubbleCellData.bubbleComponents)
{
if (component.attributedTextMessage)
{
if (roomBubbleCellData.readReceipts[component.event.eventId])
{
NSArray<MXReceiptData*> *currentReadReceipts = roomBubbleCellData.readReceipts[component.event.eventId];
NSMutableArray<MXReceiptData*> *newReadReceipts = [NSMutableArray array];
for (MXReceiptData *readReceipt in currentReadReceipts)
{
if (![seenUserIds containsObject:readReceipt.userId])
{
[newReadReceipts addObject:readReceipt];
[seenUserIds addObject:readReceipt.userId];
}
}
[self updateCellData:roomBubbleCellData withReadReceipts:newReadReceipts forEventId:component.event.eventId];
}
}
}
}
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section