mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-01 05:36:57 +02:00
Merge commit '80bda1906235b6007b98f18fb13681fff587f4a3' into feature/basis_update_192
# Conflicts: # Config/AppVersion.xcconfig # Config/BuildSettings.swift # DesignKit/Source/ColorsSwiftUI.swift # DesignKit/Source/FontsSwiftUI.swift # DesignKit/Source/ThemeV2.swift # DesignKit/Variants/Colors/Dark/DarkColors.swift # DesignKit/Variants/Colors/Light/LightColors.swift # Podfile.lock # Riot/Assets/de.lproj/InfoPlist.strings # Riot/Assets/de.lproj/Vector.strings # Riot/Assets/en.lproj/Vector.strings # Riot/Generated/Images.swift # Riot/Generated/Strings.swift # Riot/Managers/PushNotification/PushNotificationService.m # Riot/Managers/Settings/RiotSettings.swift # Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h # Riot/Modules/Common/Recents/RecentsViewController.m # Riot/Modules/Communities/Home/GroupHomeViewController.m # Riot/Modules/Room/RoomViewController.m # Riot/Modules/SetPinCode/PinCodePreferences.swift # Riot/Modules/Settings/SettingsViewController.m # Riot/Modules/TabBar/MasterTabBarController.h # Riot/Modules/TabBar/MasterTabBarController.m # Riot/Modules/TabBar/TabBarCoordinator.swift # fastlane/Fastfile # project.yml
This commit is contained in:
@@ -1625,11 +1625,15 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
|
||||
if (retry)
|
||||
{
|
||||
[self attemptDeviceDehydrationWithKeyData:keyData retry:NO success:success failure:failure];
|
||||
MXLogError(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: %@. Retrying.", error);
|
||||
MXLogErrorDetails(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: Retrying.", @{
|
||||
@"error": error ?: @"unknown"
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogError(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: %@", error);
|
||||
MXLogErrorDetails(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error", @{
|
||||
@"error": error ?: @"unknown"
|
||||
});
|
||||
|
||||
if (failure)
|
||||
{
|
||||
@@ -1779,7 +1783,9 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
|
||||
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[MXKAccount] onDateTimeFormatUpdate: event fetch failed: %@", error);
|
||||
MXLogErrorDetails(@"[MXKAccount] onDateTimeFormatUpdate: event fetch failed", @{
|
||||
@"error": error ?: @"unknown"
|
||||
});
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations 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 "MXKGroupCellDataStoring.h"
|
||||
|
||||
/**
|
||||
`MXKGroupCellData` modelised the data for a `MXKGroupTableViewCell` cell.
|
||||
*/
|
||||
@interface MXKGroupCellData : MXKCellData <MXKGroupCellDataStoring>
|
||||
|
||||
@end
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations 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 "MXKGroupCellData.h"
|
||||
|
||||
#import "MXKSessionGroupsDataSource.h"
|
||||
|
||||
@implementation MXKGroupCellData
|
||||
@synthesize group, groupsDataSource, groupDisplayname, sortingDisplayname;
|
||||
|
||||
- (instancetype)initWithGroup:(MXGroup*)theGroup andGroupsDataSource:(MXKSessionGroupsDataSource*)theGroupsDataSource
|
||||
{
|
||||
self = [self init];
|
||||
if (self)
|
||||
{
|
||||
groupsDataSource = theGroupsDataSource;
|
||||
[self updateWithGroup:theGroup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateWithGroup:(MXGroup*)theGroup
|
||||
{
|
||||
group = theGroup;
|
||||
|
||||
groupDisplayname = sortingDisplayname = group.profile.name;
|
||||
|
||||
if (!groupDisplayname.length)
|
||||
{
|
||||
groupDisplayname = group.groupId;
|
||||
// Ignore the prefix '+' of the group id during sorting.
|
||||
sortingDisplayname = [groupDisplayname substringFromIndex:1];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations 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 <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
#import "MXKCellData.h"
|
||||
|
||||
@class MXKSessionGroupsDataSource;
|
||||
|
||||
/**
|
||||
`MXKGroupCellDataStoring` defines a protocol a class must conform in order to store group cell data
|
||||
managed by `MXKSessionGroupsDataSource`.
|
||||
*/
|
||||
@protocol MXKGroupCellDataStoring <NSObject>
|
||||
|
||||
@property (nonatomic, weak, readonly) MXKSessionGroupsDataSource *groupsDataSource;
|
||||
|
||||
@property (nonatomic, readonly) MXGroup *group;
|
||||
|
||||
@property (nonatomic, readonly) NSString *groupDisplayname;
|
||||
@property (nonatomic, readonly) NSString *sortingDisplayname;
|
||||
|
||||
#pragma mark - Public methods
|
||||
/**
|
||||
Create a new `MXKCellData` object for a new group cell.
|
||||
|
||||
@param group the `MXGroup` object that has data about the group.
|
||||
@param groupsDataSource the `MXKSessionGroupsDataSource` object that will use this instance.
|
||||
@return the newly created instance.
|
||||
*/
|
||||
- (instancetype)initWithGroup:(MXGroup*)group andGroupsDataSource:(MXKSessionGroupsDataSource*)groupsDataSource;
|
||||
|
||||
/**
|
||||
The `MXKSessionGroupsDataSource` object calls this method when the group data has been updated.
|
||||
|
||||
@param group the updated group.
|
||||
*/
|
||||
- (void)updateWithGroup:(MXGroup*)group;
|
||||
|
||||
@end
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations 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 "MXKDataSource.h"
|
||||
#import "MXKGroupCellData.h"
|
||||
|
||||
/**
|
||||
Identifier to use for cells that display a group.
|
||||
*/
|
||||
extern NSString *const kMXKGroupCellIdentifier;
|
||||
|
||||
/**
|
||||
'MXKSessionGroupsDataSource' is a base class to handle the groups of a matrix session.
|
||||
A 'MXKSessionGroupsDataSource' instance provides the data source for `MXKGroupListViewController`.
|
||||
|
||||
A section is created to handle the invitations to a group, the first one if any.
|
||||
*/
|
||||
@interface MXKSessionGroupsDataSource : MXKDataSource <UITableViewDataSource>
|
||||
{
|
||||
@protected
|
||||
|
||||
/**
|
||||
The current list of the group invitations (sorted in the alphabetic order).
|
||||
This list takes into account potential filter defined by`patternsList`.
|
||||
*/
|
||||
NSMutableArray<MXKGroupCellData*> *groupsInviteCellDataArray;
|
||||
|
||||
/**
|
||||
The current displayed list of the joined groups (sorted in the alphabetic order).
|
||||
This list takes into account potential filter defined by`patternsList`.
|
||||
*/
|
||||
NSMutableArray<MXKGroupCellData*> *groupsCellDataArray;
|
||||
}
|
||||
|
||||
@property (nonatomic) NSInteger groupInvitesSection;
|
||||
@property (nonatomic) NSInteger joinedGroupsSection;
|
||||
|
||||
#pragma mark - Life cycle
|
||||
|
||||
/**
|
||||
Refresh all the groups summary.
|
||||
The group data are not synced with the server, use this method to refresh them according to your needs.
|
||||
|
||||
@param completion the block to execute when a request has been done for each group (whatever the result of the requests).
|
||||
You may specify nil for this parameter.
|
||||
*/
|
||||
- (void)refreshGroupsSummary:(void (^)(void))completion;
|
||||
|
||||
/**
|
||||
Filter the current groups list according to the provided patterns.
|
||||
When patterns are not empty, the search result is stored in `filteredGroupsCellDataArray`,
|
||||
this array provides then data for the cells served by `MXKSessionGroupsDataSource`.
|
||||
|
||||
@param patternsList the list of patterns (`NSString` instances) to match with. Set nil to cancel search.
|
||||
*/
|
||||
- (void)searchWithPatterns:(NSArray*)patternsList;
|
||||
|
||||
/**
|
||||
Get the data for the cell at the given index path.
|
||||
|
||||
@param indexPath the index of the cell in the table
|
||||
@return the cell data
|
||||
*/
|
||||
- (id<MXKGroupCellDataStoring>)cellDataAtIndex:(NSIndexPath*)indexPath;
|
||||
|
||||
/**
|
||||
Get the index path of the cell related to the provided groupId.
|
||||
|
||||
@param groupId the group identifier.
|
||||
@return indexPath the index of the cell (nil if not found).
|
||||
*/
|
||||
- (NSIndexPath*)cellIndexPathWithGroupId:(NSString*)groupId;
|
||||
|
||||
/**
|
||||
Leave the group displayed at the provided path.
|
||||
|
||||
@param indexPath the index of the group cell in the table
|
||||
*/
|
||||
- (void)leaveGroupAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@end
|
||||
@@ -1,611 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C
|
||||
|
||||
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 "MXKSessionGroupsDataSource.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
|
||||
#import "MXKConstants.h"
|
||||
|
||||
#import "MXKSwiftHeader.h"
|
||||
|
||||
#pragma mark - Constant definitions
|
||||
NSString *const kMXKGroupCellIdentifier = @"kMXKGroupCellIdentifier";
|
||||
|
||||
|
||||
@interface MXKSessionGroupsDataSource ()
|
||||
{
|
||||
/**
|
||||
Internal array used to regulate change notifications.
|
||||
Cell data changes are stored instantly in this array.
|
||||
We wait at least for 500 ms between two notifications of the delegate.
|
||||
*/
|
||||
NSMutableArray *internalCellDataArray;
|
||||
|
||||
/*
|
||||
Timer to not notify the delegate on every changes.
|
||||
*/
|
||||
NSTimer *timer;
|
||||
|
||||
/*
|
||||
Tells whether some changes must be notified.
|
||||
*/
|
||||
BOOL isDataChangePending;
|
||||
|
||||
/**
|
||||
Store the current search patterns list.
|
||||
*/
|
||||
NSArray* searchPatternsList;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MXKSessionGroupsDataSource
|
||||
|
||||
- (instancetype)initWithMatrixSession:(MXSession *)matrixSession
|
||||
{
|
||||
self = [super initWithMatrixSession:matrixSession];
|
||||
if (self)
|
||||
{
|
||||
internalCellDataArray = [NSMutableArray array];
|
||||
groupsCellDataArray = [NSMutableArray array];
|
||||
groupsInviteCellDataArray = [NSMutableArray array];
|
||||
|
||||
isDataChangePending = NO;
|
||||
|
||||
// Set default data and view classes
|
||||
[self registerCellDataClass:MXKGroupCellData.class forCellIdentifier:kMXKGroupCellIdentifier];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
groupsCellDataArray = nil;
|
||||
groupsInviteCellDataArray = nil;
|
||||
internalCellDataArray = nil;
|
||||
|
||||
searchPatternsList = nil;
|
||||
|
||||
[timer invalidate];
|
||||
timer = nil;
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
- (void)didMXSessionStateChange
|
||||
{
|
||||
if (MXSessionStateRunning <= self.mxSession.state)
|
||||
{
|
||||
// Check whether some data have been already load
|
||||
if (0 == internalCellDataArray.count)
|
||||
{
|
||||
[self loadData];
|
||||
}
|
||||
else if (self.mxSession.state == MXSessionStateRunning)
|
||||
{
|
||||
// Refresh the group data
|
||||
[self refreshGroupsSummary:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)refreshGroupsSummary:(void (^)(void))completion
|
||||
{
|
||||
MXLogDebug(@"[MXKSessionGroupsDataSource] refreshGroupsSummary");
|
||||
|
||||
__block NSUInteger count = internalCellDataArray.count;
|
||||
|
||||
if (count)
|
||||
{
|
||||
for (id<MXKGroupCellDataStoring> groupData in internalCellDataArray)
|
||||
{
|
||||
// Force the matrix session to refresh the group summary.
|
||||
[self.mxSession updateGroupSummary:groupData.group success:^{
|
||||
|
||||
if (completion && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
completion ();
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXLogDebug(@"[MXKSessionGroupsDataSource] refreshGroupsSummary: group summary update failed %@", groupData.group.groupId);
|
||||
|
||||
if (completion && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
completion ();
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
else if (completion)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchWithPatterns:(NSArray*)patternsList
|
||||
{
|
||||
if (patternsList.count)
|
||||
{
|
||||
searchPatternsList = patternsList;
|
||||
}
|
||||
else
|
||||
{
|
||||
searchPatternsList = nil;
|
||||
}
|
||||
|
||||
[self onCellDataChange];
|
||||
}
|
||||
|
||||
- (id<MXKGroupCellDataStoring>)cellDataAtIndex:(NSIndexPath*)indexPath
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData;
|
||||
|
||||
if (indexPath.section == _groupInvitesSection)
|
||||
{
|
||||
if (indexPath.row < groupsInviteCellDataArray.count)
|
||||
{
|
||||
groupData = groupsInviteCellDataArray[indexPath.row];
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == _joinedGroupsSection)
|
||||
{
|
||||
if (indexPath.row < groupsCellDataArray.count)
|
||||
{
|
||||
groupData = groupsCellDataArray[indexPath.row];
|
||||
}
|
||||
}
|
||||
|
||||
return groupData;
|
||||
}
|
||||
|
||||
- (NSIndexPath*)cellIndexPathWithGroupId:(NSString*)groupId
|
||||
{
|
||||
// Look for the cell
|
||||
if (_groupInvitesSection != -1)
|
||||
{
|
||||
for (NSInteger index = 0; index < groupsInviteCellDataArray.count; index ++)
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData = groupsInviteCellDataArray[index];
|
||||
if ([groupId isEqualToString:groupData.group.groupId])
|
||||
{
|
||||
// Got it
|
||||
return [NSIndexPath indexPathForRow:index inSection:_groupInvitesSection];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_joinedGroupsSection != -1)
|
||||
{
|
||||
for (NSInteger index = 0; index < groupsCellDataArray.count; index ++)
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData = groupsCellDataArray[index];
|
||||
if ([groupId isEqualToString:groupData.group.groupId])
|
||||
{
|
||||
// Got it
|
||||
return [NSIndexPath indexPathForRow:index inSection:_joinedGroupsSection];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Groups processing
|
||||
|
||||
- (void)loadData
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionNewGroupInviteNotification object:self.mxSession];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidJoinGroupNotification object:self.mxSession];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidLeaveGroupNotification object:self.mxSession];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdateGroupSummaryNotification object:self.mxSession];
|
||||
|
||||
// Reset the table
|
||||
[internalCellDataArray removeAllObjects];
|
||||
|
||||
// Retrieve the MXKCellData class to manage the data
|
||||
Class class = [self cellDataClassForCellIdentifier:kMXKGroupCellIdentifier];
|
||||
NSAssert([class conformsToProtocol:@protocol(MXKGroupCellDataStoring)], @"MXKSessionGroupsDataSource only manages MXKCellData that conforms to MXKGroupCellDataStoring protocol");
|
||||
|
||||
// Listen to MXSession groups changes
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNewGroupInvite:) name:kMXSessionNewGroupInviteNotification object:self.mxSession];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didJoinGroup:) name:kMXSessionDidJoinGroupNotification object:self.mxSession];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didLeaveGroup:) name:kMXSessionDidLeaveGroupNotification object:self.mxSession];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateGroup:) name:kMXSessionDidUpdateGroupSummaryNotification object:self.mxSession];
|
||||
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
NSArray *groups = self.mxSession.groups;
|
||||
for (MXGroup *group in groups)
|
||||
{
|
||||
id<MXKGroupCellDataStoring> cellData = [[class alloc] initWithGroup:group andGroupsDataSource:self];
|
||||
if (cellData)
|
||||
{
|
||||
[internalCellDataArray addObject:cellData];
|
||||
|
||||
// Force the matrix session to refresh the group summary.
|
||||
[self.mxSession updateGroupSummary:group success:nil failure:^(NSError *error) {
|
||||
MXLogDebug(@"[MXKSessionGroupsDataSource] loadData: group summary update failed %@", group.groupId);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
MXLogDebug(@"[MXKSessionGroupsDataSource] Loaded %tu groups in %.3fms", groups.count, [[NSDate date] timeIntervalSinceDate:startDate] * 1000);
|
||||
|
||||
[self sortCellData];
|
||||
[self onCellDataChange];
|
||||
}
|
||||
|
||||
- (void)didUpdateGroup:(NSNotification *)notif
|
||||
{
|
||||
MXGroup *group = notif.userInfo[kMXSessionNotificationGroupKey];
|
||||
if (group)
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:group.groupId];
|
||||
if (groupData)
|
||||
{
|
||||
[groupData updateWithGroup:group];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKSessionGroupsDataSource] didUpdateGroup: Cannot find the changed group for %@ (%@). It is probably not managed by this group data source", group.groupId, group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[self sortCellData];
|
||||
[self onCellDataChange];
|
||||
}
|
||||
|
||||
- (void)onNewGroupInvite:(NSNotification *)notif
|
||||
{
|
||||
MXGroup *group = notif.userInfo[kMXSessionNotificationGroupKey];
|
||||
if (group)
|
||||
{
|
||||
// Add the group if there is not yet a cell for it
|
||||
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:group.groupId];
|
||||
if (nil == groupData)
|
||||
{
|
||||
MXLogDebug(@"MXKSessionGroupsDataSource] Add new group invite: %@", group.groupId);
|
||||
|
||||
// Retrieve the MXKCellData class to manage the data
|
||||
Class class = [self cellDataClassForCellIdentifier:kMXKGroupCellIdentifier];
|
||||
|
||||
id<MXKGroupCellDataStoring> cellData = [[class alloc] initWithGroup:group andGroupsDataSource:self];
|
||||
if (cellData)
|
||||
{
|
||||
[internalCellDataArray addObject:cellData];
|
||||
|
||||
[self sortCellData];
|
||||
[self onCellDataChange];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didJoinGroup:(NSNotification *)notif
|
||||
{
|
||||
MXGroup *group = notif.userInfo[kMXSessionNotificationGroupKey];
|
||||
if (group)
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:group.groupId];
|
||||
if (groupData)
|
||||
{
|
||||
MXLogDebug(@"MXKSessionGroupsDataSource] Update joined room: %@", group.groupId);
|
||||
[groupData updateWithGroup:group];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"MXKSessionGroupsDataSource] Add new joined invite: %@", group.groupId);
|
||||
|
||||
// Retrieve the MXKCellData class to manage the data
|
||||
Class class = [self cellDataClassForCellIdentifier:kMXKGroupCellIdentifier];
|
||||
|
||||
id<MXKGroupCellDataStoring> cellData = [[class alloc] initWithGroup:group andGroupsDataSource:self];
|
||||
if (cellData)
|
||||
{
|
||||
[internalCellDataArray addObject:cellData];
|
||||
}
|
||||
}
|
||||
|
||||
[self sortCellData];
|
||||
[self onCellDataChange];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didLeaveGroup:(NSNotification *)notif
|
||||
{
|
||||
NSString *groupId = notif.userInfo[kMXSessionNotificationGroupIdKey];
|
||||
if (groupId)
|
||||
{
|
||||
[self removeGroup:groupId];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeGroup:(NSString*)groupId
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:groupId];
|
||||
if (groupData)
|
||||
{
|
||||
MXLogDebug(@"MXKSessionGroupsDataSource] Remove left group: %@", groupId);
|
||||
|
||||
[internalCellDataArray removeObject:groupData];
|
||||
|
||||
[self sortCellData];
|
||||
[self onCellDataChange];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onCellDataChange
|
||||
{
|
||||
isDataChangePending = NO;
|
||||
|
||||
// Check no notification was done recently.
|
||||
// Note: do not wait in case of search
|
||||
if (timer == nil || searchPatternsList)
|
||||
{
|
||||
[timer invalidate];
|
||||
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkPendingUpdate:) userInfo:nil repeats:NO];
|
||||
|
||||
// Prepare cell data array, and notify the delegate.
|
||||
[self prepareCellDataAndNotifyChanges];
|
||||
}
|
||||
else
|
||||
{
|
||||
isDataChangePending = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)checkPendingUpdate:(id)sender
|
||||
{
|
||||
[timer invalidate];
|
||||
timer = nil;
|
||||
|
||||
if (isDataChangePending)
|
||||
{
|
||||
[self onCellDataChange];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sortCellData
|
||||
{
|
||||
// Order alphabetically the groups
|
||||
[internalCellDataArray sortUsingComparator:^NSComparisonResult(id<MXKGroupCellDataStoring> cellData1, id<MXKGroupCellDataStoring> cellData2)
|
||||
{
|
||||
if (cellData1.sortingDisplayname.length && cellData2.sortingDisplayname.length)
|
||||
{
|
||||
return [cellData1.sortingDisplayname compare:cellData2.sortingDisplayname options:NSCaseInsensitiveSearch];
|
||||
}
|
||||
else if (cellData1.sortingDisplayname.length)
|
||||
{
|
||||
return NSOrderedAscending;
|
||||
}
|
||||
else if (cellData2.sortingDisplayname.length)
|
||||
{
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
return NSOrderedSame;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)prepareCellDataAndNotifyChanges
|
||||
{
|
||||
// Prepare the cell data arrays by considering the potential filter.
|
||||
[groupsInviteCellDataArray removeAllObjects];
|
||||
[groupsCellDataArray removeAllObjects];
|
||||
for (id<MXKGroupCellDataStoring> groupData in internalCellDataArray)
|
||||
{
|
||||
BOOL isKept = !searchPatternsList;
|
||||
|
||||
for (NSString* pattern in searchPatternsList)
|
||||
{
|
||||
if (groupData.groupDisplayname && [groupData.groupDisplayname rangeOfString:pattern options:NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
{
|
||||
isKept = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isKept)
|
||||
{
|
||||
if (groupData.group.membership == MXMembershipInvite)
|
||||
{
|
||||
[groupsInviteCellDataArray addObject:groupData];
|
||||
}
|
||||
else
|
||||
{
|
||||
[groupsCellDataArray addObject:groupData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update here data source state
|
||||
if (state != MXKDataSourceStateReady)
|
||||
{
|
||||
state = MXKDataSourceStateReady;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(dataSource:didStateChange:)])
|
||||
{
|
||||
[self.delegate dataSource:self didStateChange:state];
|
||||
}
|
||||
}
|
||||
|
||||
// And inform the delegate about the update
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
// Find the cell data that stores information about the given group id
|
||||
- (id<MXKGroupCellDataStoring>)cellDataWithGroupId:(NSString*)groupId
|
||||
{
|
||||
id<MXKGroupCellDataStoring> theGroupData;
|
||||
for (id<MXKGroupCellDataStoring> groupData in internalCellDataArray)
|
||||
{
|
||||
if ([groupData.group.groupId isEqualToString:groupId])
|
||||
{
|
||||
theGroupData = groupData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return theGroupData;
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
NSInteger count = 0;
|
||||
_groupInvitesSection = _joinedGroupsSection = -1;
|
||||
|
||||
// Check whether all data sources are ready before rendering groups.
|
||||
if (self.state == MXKDataSourceStateReady)
|
||||
{
|
||||
if (groupsInviteCellDataArray.count)
|
||||
{
|
||||
_groupInvitesSection = count++;
|
||||
}
|
||||
if (groupsCellDataArray.count)
|
||||
{
|
||||
_joinedGroupsSection = count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
if (section == _groupInvitesSection)
|
||||
{
|
||||
return groupsInviteCellDataArray.count;
|
||||
}
|
||||
else if (section == _joinedGroupsSection)
|
||||
{
|
||||
return groupsCellDataArray.count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
NSString* sectionTitle = nil;
|
||||
|
||||
if (section == _groupInvitesSection)
|
||||
{
|
||||
sectionTitle = [VectorL10n groupInviteSection];
|
||||
}
|
||||
else if (section == _joinedGroupsSection)
|
||||
{
|
||||
sectionTitle = [VectorL10n groupSection];
|
||||
}
|
||||
|
||||
return sectionTitle;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
id<MXKGroupCellDataStoring> groupData;
|
||||
|
||||
if (indexPath.section == _groupInvitesSection)
|
||||
{
|
||||
if (indexPath.row < groupsInviteCellDataArray.count)
|
||||
{
|
||||
groupData = groupsInviteCellDataArray[indexPath.row];
|
||||
}
|
||||
}
|
||||
else if (indexPath.section == _joinedGroupsSection)
|
||||
{
|
||||
if (indexPath.row < groupsCellDataArray.count)
|
||||
{
|
||||
groupData = groupsCellDataArray[indexPath.row];
|
||||
}
|
||||
}
|
||||
|
||||
if (groupData)
|
||||
{
|
||||
NSString *cellIdentifier = [self.delegate cellReuseIdentifierForCellData:groupData];
|
||||
if (cellIdentifier)
|
||||
{
|
||||
UITableViewCell<MXKCellRendering> *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
|
||||
|
||||
// Make sure we listen to user actions on the cell
|
||||
cell.delegate = self;
|
||||
|
||||
// Make the bubble display the data
|
||||
[cell render:groupData];
|
||||
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
// Return a fake cell to prevent app from crashing.
|
||||
return [[UITableViewCell alloc] init];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// Return NO if you do not want the specified item to be editable.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||
{
|
||||
[self leaveGroupAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)leaveGroupAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
id<MXKGroupCellDataStoring> cellData = [self cellDataAtIndex:indexPath];
|
||||
|
||||
if (cellData.group)
|
||||
{
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
[self.mxSession leaveGroup:cellData.group.groupId success:^{
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
// Refresh the table content
|
||||
typeof(self) self = weakSelf;
|
||||
[self removeGroup:cellData.group.groupId];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXLogDebug(@"[MXKSessionGroupsDataSource] Failed to leave group (%@)", cellData.group.groupId);
|
||||
|
||||
// Notify MatrixKit user
|
||||
NSString *myUserId = self.mxSession.myUser.userId;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -169,7 +169,6 @@ static NSString *const kMXAppGroupID = @"group.org.matrix";
|
||||
kMXEventTypeStringRoomMessageFeedback,
|
||||
kMXEventTypeStringRoomRedaction,
|
||||
kMXEventTypeStringRoomThirdPartyInvite,
|
||||
kMXEventTypeStringRoomRelatedGroups,
|
||||
kMXEventTypeStringReaction,
|
||||
kMXEventTypeStringCallInvite,
|
||||
kMXEventTypeStringCallAnswer,
|
||||
|
||||
@@ -221,5 +221,15 @@ typedef enum : NSUInteger {
|
||||
*/
|
||||
- (BOOL)dataSource:(MXKDataSource*)dataSource shouldDoAction:(NSString *)actionIdentifier inCell:(id<MXKCellRendering>)cell userInfo:(NSDictionary *)userInfo defaultValue:(BOOL)defaultValue;
|
||||
|
||||
/**
|
||||
Notify the delegate that invites count did change
|
||||
|
||||
@see `MXKCellRenderingDelegate` for more details.
|
||||
|
||||
@param dataSource the involved data source.
|
||||
@param invitesCount number of rooms in the invites section.
|
||||
*/
|
||||
- (void)dataSource:(MXKDataSource*)dataSource didUpdateInvitesCount:(NSUInteger)invitesCount;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -476,7 +476,9 @@ NSString *const kMXKAttachmentFileNameBase = @"attatchment";
|
||||
NSError *error;
|
||||
BOOL result = [NSFileManager.defaultManager removeItemAtPath:[temporaryDirectoryPath stringByAppendingPathComponent:filePath] error:&error];
|
||||
if (!result && error) {
|
||||
MXLogError(@"[MXKAttachment] Failed deleting temporary file with error: %@", error);
|
||||
MXLogErrorDetails(@"[MXKAttachment] Failed deleting temporary file with error", @{
|
||||
@"error": error ?: @"unknown"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#import "GeneratedInterface-Swift.h"
|
||||
|
||||
@implementation MXKRoomBubbleCellData
|
||||
@synthesize senderId, targetId, roomId, senderDisplayName, senderAvatarUrl, senderAvatarPlaceholder, targetDisplayName, targetAvatarUrl, targetAvatarPlaceholder, isEncryptedRoom, isPaginationFirstBubble, shouldHideSenderInformation, date, isIncoming, isAttachmentWithThumbnail, isAttachmentWithIcon, attachment, senderFlair;
|
||||
@synthesize senderId, targetId, roomId, senderDisplayName, senderAvatarUrl, senderAvatarPlaceholder, targetDisplayName, targetAvatarUrl, targetAvatarPlaceholder, isEncryptedRoom, isPaginationFirstBubble, shouldHideSenderInformation, date, isIncoming, isAttachmentWithThumbnail, isAttachmentWithIcon, attachment;
|
||||
@synthesize textMessage, attributedTextMessage, attributedTextMessageWithoutPositioningSpace;
|
||||
@synthesize shouldHideSenderName, isTyping, showBubbleDateTime, showBubbleReceipts, useCustomDateTimeLabel, useCustomReceipts, useCustomUnsentButton, hasNoDisplay;
|
||||
@synthesize tag;
|
||||
@@ -122,9 +122,6 @@
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// Reset any observer on publicised groups by user.
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
|
||||
roomDataSource = nil;
|
||||
bubbleComponents = nil;
|
||||
}
|
||||
@@ -450,58 +447,6 @@
|
||||
- (void)setShouldHideSenderInformation:(BOOL)inShouldHideSenderInformation
|
||||
{
|
||||
shouldHideSenderInformation = inShouldHideSenderInformation;
|
||||
|
||||
if (!shouldHideSenderInformation)
|
||||
{
|
||||
// Refresh the flair
|
||||
[self refreshSenderFlair];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)refreshSenderFlair
|
||||
{
|
||||
// Reset by default any observer on publicised groups by user.
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
|
||||
// Check first whether the room enabled the flair for some groups
|
||||
NSArray<NSString *> *roomRelatedGroups = roomDataSource.roomState.relatedGroups;
|
||||
if (roomRelatedGroups.count && senderId)
|
||||
{
|
||||
NSArray<NSString *> *senderPublicisedGroups;
|
||||
|
||||
senderPublicisedGroups = [self.mxSession publicisedGroupsForUser:senderId];
|
||||
|
||||
if (senderPublicisedGroups.count)
|
||||
{
|
||||
// Cross the 2 arrays to keep only the common group ids
|
||||
NSMutableArray *flair = [NSMutableArray arrayWithCapacity:roomRelatedGroups.count];
|
||||
|
||||
for (NSString *groupId in roomRelatedGroups)
|
||||
{
|
||||
if ([senderPublicisedGroups indexOfObject:groupId] != NSNotFound)
|
||||
{
|
||||
MXGroup *group = [roomDataSource groupWithGroupId:groupId];
|
||||
[flair addObject:group];
|
||||
}
|
||||
}
|
||||
|
||||
if (flair.count)
|
||||
{
|
||||
self.senderFlair = flair;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.senderFlair = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.senderFlair = nil;
|
||||
}
|
||||
|
||||
// Observe any change on publicised groups for the message sender
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXSessionUpdatePublicisedGroupsForUsers:) name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasThreadRoot
|
||||
@@ -573,46 +518,52 @@
|
||||
|
||||
- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset
|
||||
{
|
||||
static UITextView* measurementTextView = nil;
|
||||
static UITextView* measurementTextViewWithoutInset = nil;
|
||||
|
||||
if (attributedText.length)
|
||||
{
|
||||
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;
|
||||
|
||||
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.
|
||||
// So, add this indent afterwards
|
||||
NSRange textRange = NSMakeRange(0, attributedText.length);
|
||||
NSRange longestEffectiveRange;
|
||||
NSParagraphStyle *paragraphStyle = [attributedText attribute:NSParagraphStyleAttributeName atIndex:0 longestEffectiveRange:&longestEffectiveRange inRange:textRange];
|
||||
|
||||
if (NSEqualRanges(textRange, longestEffectiveRange))
|
||||
{
|
||||
size.width = size.width + paragraphStyle.headIndent;
|
||||
}
|
||||
|
||||
return size;
|
||||
if (attributedText.length == 0) {
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
return CGSizeZero;
|
||||
// Grab the default textContainer insets and lineFragmentPadding from a dummy text view.
|
||||
// This has no business being here but the refactoring effort would be too great (sceriu 05.09.2022)
|
||||
static UITextView* measurementTextView = nil;
|
||||
if (!measurementTextView)
|
||||
{
|
||||
measurementTextView = [[UITextView alloc] init];
|
||||
}
|
||||
|
||||
CGFloat verticalInset = measurementTextView.textContainerInset.top + measurementTextView.textContainerInset.bottom;
|
||||
CGFloat horizontalInset = measurementTextView.textContainer.lineFragmentPadding * 2;
|
||||
|
||||
CGSize size = [self sizeForAttributedString:attributedText fittingWidth:_maxTextViewWidth - horizontalInset];
|
||||
|
||||
// The result is expected to contain the textView textContainer's paddings. Add them back if necessary
|
||||
if (removeVerticalInset == NO) {
|
||||
size.height += verticalInset;
|
||||
}
|
||||
|
||||
size.width += horizontalInset;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/54497598/nsattributedstring-boundingrect-returns-wrong-height
|
||||
- (CGSize)sizeForAttributedString:(NSAttributedString *)attributedString fittingWidth:(CGFloat)width
|
||||
{
|
||||
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
|
||||
|
||||
CGRect boundingRect = CGRectMake(0.0, 0.0, width, CGFLOAT_MAX);
|
||||
|
||||
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:boundingRect.size];
|
||||
textContainer.lineFragmentPadding = 0;
|
||||
|
||||
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
|
||||
[layoutManager addTextContainer: textContainer];
|
||||
|
||||
[textStorage addLayoutManager:layoutManager];
|
||||
[layoutManager glyphRangeForBoundingRect:boundingRect inTextContainer:textContainer];
|
||||
|
||||
CGRect rect = [layoutManager usedRectForTextContainer:textContainer];
|
||||
|
||||
return CGRectIntegral(rect).size;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
@@ -1042,18 +993,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didMXSessionUpdatePublicisedGroupsForUsers:(NSNotification *)notif
|
||||
{
|
||||
// Retrieved the list of the concerned users
|
||||
NSArray<NSString*> *userIds = notif.userInfo[kMXSessionNotificationUserIdsArrayKey];
|
||||
if (userIds.count && self.senderId)
|
||||
{
|
||||
// Check whether the current sender is concerned.
|
||||
if ([userIds indexOfObject:self.senderId] != NSNotFound)
|
||||
{
|
||||
[self refreshSenderFlair];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -91,11 +91,6 @@
|
||||
*/
|
||||
@property (nonatomic) UIImage *targetAvatarPlaceholder;
|
||||
|
||||
/**
|
||||
The current sender flair (list of the publicised groups in the sender profile which matches the room flair settings)
|
||||
*/
|
||||
@property (nonatomic) NSArray<MXGroup*> *senderFlair;
|
||||
|
||||
/**
|
||||
Tell whether the room is encrypted.
|
||||
*/
|
||||
@@ -304,11 +299,6 @@ Update the event because its sent state changed or it is has been redacted.
|
||||
foregroundColor:(UIColor*)foregroundColor
|
||||
andFont:(UIFont*)patternFont;
|
||||
|
||||
/**
|
||||
Refresh the sender flair information
|
||||
*/
|
||||
- (void)refreshSenderFlair;
|
||||
|
||||
/**
|
||||
Indicate that the current text message layout is no longer valid and should be recomputed
|
||||
before presentation in a bubble cell. This could be due to the content changing, or the
|
||||
|
||||
@@ -100,11 +100,6 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
The queue of events that need to be processed in order to compute their display.
|
||||
*/
|
||||
NSMutableArray<MXKQueuedEvent*> *eventsToProcess;
|
||||
|
||||
/**
|
||||
The dictionary of the related groups that the current user did not join.
|
||||
*/
|
||||
NSMutableDictionary<NSString*, MXGroup*> *externalRelatedGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,11 +160,6 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
*/
|
||||
@property (nonatomic, readonly) NSInteger serverSyncEventCount;
|
||||
|
||||
/**
|
||||
The current text message partially typed in text input (use nil to reset it).
|
||||
*/
|
||||
@property (nonatomic) NSString *partialTextMessage;
|
||||
|
||||
/**
|
||||
The current attributed text message partially typed in text input (use nil to reset it).
|
||||
*/
|
||||
@@ -266,10 +256,11 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
the room data source is created.
|
||||
|
||||
@param roomId the id of the room to get data from.
|
||||
@param threadId the id of the thread to load. If provided, thread data source will be loaded from the room specified with `roomId`.
|
||||
@param mxSession the Matrix session to get data from.
|
||||
@param onComplete a block providing the newly created instance.
|
||||
*/
|
||||
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete;
|
||||
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete;
|
||||
|
||||
/**
|
||||
Asynchronously create adata source to serve data corresponding to an event in the
|
||||
@@ -311,10 +302,11 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
Initialise the data source to serve data corresponding to the passed room.
|
||||
|
||||
@param roomId the id of the room to get data from.
|
||||
@param threadId the id of the thread to initialize. If provided, thread data source will be initialized from the room specified with `roomId`.
|
||||
@param mxSession the Matrix session to get data from.
|
||||
@return the newly created instance.
|
||||
*/
|
||||
- (instancetype)initWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession;
|
||||
- (instancetype)initWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession threadId:(NSString*)threadId;
|
||||
|
||||
/**
|
||||
Initialise the data source to serve data corresponding to an event in the
|
||||
@@ -777,17 +769,6 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
*/
|
||||
- (void)collapseRoomBubble:(id<MXKRoomBubbleCellDataStoring>)bubbleData collapsed:(BOOL)collapsed;
|
||||
|
||||
#pragma mark - Groups
|
||||
|
||||
/**
|
||||
Get a MXGroup instance for a group.
|
||||
This method is used by the bubble to retrieve a related groups of the room.
|
||||
|
||||
@param groupId The identifier to the group.
|
||||
@return the MXGroup instance.
|
||||
*/
|
||||
- (MXGroup *)groupWithGroupId:(NSString*)groupId;
|
||||
|
||||
#pragma mark - Reactions
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,11 +87,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
The listener to receipts events in the room.
|
||||
*/
|
||||
id receiptsListener;
|
||||
|
||||
/**
|
||||
The listener to the related groups state events in the room.
|
||||
*/
|
||||
id relatedGroupsListener;
|
||||
|
||||
/**
|
||||
The listener to reactions changed in the room.
|
||||
@@ -213,9 +208,9 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
@implementation MXKRoomDataSource
|
||||
|
||||
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete
|
||||
+ (void)loadRoomDataSourceWithRoomId:(NSString*)roomId threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession onComplete:(void (^)(id roomDataSource))onComplete
|
||||
{
|
||||
MXKRoomDataSource *roomDataSource = [[self alloc] initWithRoomId:roomId andMatrixSession:mxSession];
|
||||
MXKRoomDataSource *roomDataSource = [[self alloc] initWithRoomId:roomId andMatrixSession:mxSession threadId:threadId];
|
||||
[self ensureSessionStateForDataSource:roomDataSource initialEventId:nil andMatrixSession:mxSession onComplete:onComplete];
|
||||
}
|
||||
|
||||
@@ -289,7 +284,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession
|
||||
- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession threadId:(NSString *)threadId
|
||||
{
|
||||
self = [super initWithMatrixSession:matrixSession];
|
||||
if (self)
|
||||
@@ -297,6 +292,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
MXLogVerbose(@"[MXKRoomDataSource][%p] initWithRoomId: %@", self, roomId);
|
||||
|
||||
_roomId = roomId;
|
||||
_threadId = threadId;
|
||||
_secondaryRoomEventTypes = @[
|
||||
kMXEventTypeStringCallInvite,
|
||||
kMXEventTypeStringCallCandidates,
|
||||
@@ -318,8 +314,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
eventsToProcess = [NSMutableArray array];
|
||||
eventIdToBubbleMap = [NSMutableDictionary dictionary];
|
||||
|
||||
externalRelatedGroups = [NSMutableDictionary dictionary];
|
||||
|
||||
_filterMessagesWithURL = NO;
|
||||
|
||||
emoteMessageSlashCommandPrefix = [NSString stringWithFormat:@"%@ ", kMXKSlashCmdEmote];
|
||||
@@ -375,7 +369,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
- (instancetype)initWithRoomId:(NSString*)roomId initialEventId:(NSString*)initialEventId2 threadId:(NSString*)threadId andMatrixSession:(MXSession*)mxSession
|
||||
{
|
||||
self = [self initWithRoomId:roomId andMatrixSession:mxSession];
|
||||
self = [self initWithRoomId:roomId andMatrixSession:mxSession threadId:threadId];
|
||||
if (self)
|
||||
{
|
||||
if (initialEventId2)
|
||||
@@ -383,7 +377,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
initialEventId = initialEventId2;
|
||||
_isLive = NO;
|
||||
}
|
||||
_threadId = threadId;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -471,8 +464,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
- (void)resetNotifying:(BOOL)notify
|
||||
{
|
||||
[externalRelatedGroups removeAllObjects];
|
||||
|
||||
if (roomDidFlushDataNotificationObserver)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:roomDidFlushDataNotificationObserver];
|
||||
@@ -515,9 +506,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
[_timeline removeListener:receiptsListener];
|
||||
receiptsListener = nil;
|
||||
|
||||
[_timeline removeListener:relatedGroupsListener];
|
||||
relatedGroupsListener = nil;
|
||||
}
|
||||
|
||||
if (_secondaryRoom && secondaryLiveEventsListener)
|
||||
@@ -565,6 +553,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
|
||||
self.room = nil;
|
||||
self.thread = nil;
|
||||
self.secondaryRoom = nil;
|
||||
}
|
||||
|
||||
@@ -596,13 +585,11 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Destroy - room id: %@", self, _roomId);
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Destroy - room id: %@ - thread id: %@", self, _roomId, _threadId);
|
||||
|
||||
[self unregisterScanManagerNotifications];
|
||||
[self unregisterReactionsChangeListener];
|
||||
[self unregisterEventEditsListener];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXEventDidChangeSentStateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXEventDidDecryptNotification object:nil];
|
||||
@@ -638,8 +625,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
[_timeline destroy];
|
||||
[_secondaryTimeline destroy];
|
||||
|
||||
externalRelatedGroups = nil;
|
||||
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
@@ -824,52 +809,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
[self setState:MXKDataSourceStateFailed];
|
||||
}
|
||||
}
|
||||
|
||||
if (_room && MXSessionStateRunning == self.mxSession.state)
|
||||
{
|
||||
// Flair handling: observe the update in the publicised groups by users when the flair is enabled in the room.
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
[self.room state:^(MXRoomState *roomState) {
|
||||
if (roomState.relatedGroups.count)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXSessionUpdatePublicisedGroupsForUsers:) name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
|
||||
// Get a fresh profile for all the related groups. Trigger a table refresh when all requests are done.
|
||||
__block NSUInteger count = roomState.relatedGroups.count;
|
||||
for (NSString *groupId in roomState.relatedGroups)
|
||||
{
|
||||
MXGroup *group = [self.mxSession groupWithGroupId:groupId];
|
||||
if (!group)
|
||||
{
|
||||
// Create a group instance for the groups that the current user did not join.
|
||||
group = [[MXGroup alloc] initWithGroupId:groupId];
|
||||
[self->externalRelatedGroups setObject:group forKey:groupId];
|
||||
}
|
||||
|
||||
// Refresh the group profile from server.
|
||||
[self.mxSession updateGroupProfile:group success:^{
|
||||
|
||||
if (self.delegate && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] group profile update failed %@", self, groupId);
|
||||
|
||||
if (self.delegate && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)initializeTimelineForThread
|
||||
@@ -980,16 +919,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
- (NSString *)partialTextMessage
|
||||
{
|
||||
return _room.partialTextMessage;
|
||||
}
|
||||
|
||||
- (void)setPartialTextMessage:(NSString *)partialTextMessage
|
||||
{
|
||||
_room.partialTextMessage = partialTextMessage;
|
||||
}
|
||||
|
||||
- (NSAttributedString *)partialAttributedTextMessage
|
||||
{
|
||||
return _room.partialAttributedTextMessage;
|
||||
@@ -1008,7 +937,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
[_timeline removeListener:liveEventsListener];
|
||||
[_timeline removeListener:redactionListener];
|
||||
[_timeline removeListener:receiptsListener];
|
||||
[_timeline removeListener:relatedGroupsListener];
|
||||
}
|
||||
|
||||
// Listen to live events only for live timeline
|
||||
@@ -1071,16 +999,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
[self didReceiveReceiptEvent:event roomState:roomState];
|
||||
}
|
||||
}];
|
||||
|
||||
// Flair handling: register a listener for the related groups state event in this room.
|
||||
relatedGroupsListener = [_timeline listenToEventsOfTypes:@[kMXEventTypeStringRoomRelatedGroups] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {
|
||||
|
||||
if (MXTimelineDirectionForwards == direction)
|
||||
{
|
||||
// The flair settings have been updated: flush the current bubble data and rebuild them.
|
||||
[self reload];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// Register a listener to handle redaction which can affect live and past timelines
|
||||
@@ -2693,32 +2611,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didMXSessionUpdatePublicisedGroupsForUsers:(NSNotification *)notif
|
||||
{
|
||||
// Retrieved the list of the concerned users
|
||||
NSArray<NSString*> *userIds = notif.userInfo[kMXSessionNotificationUserIdsArrayKey];
|
||||
if (userIds.count)
|
||||
{
|
||||
// Check whether at least one listed user is a room member.
|
||||
for (NSString* userId in userIds)
|
||||
{
|
||||
MXRoomMember * roomMember = [self.roomState.members memberWithUserId:userId];
|
||||
if (roomMember)
|
||||
{
|
||||
// Inform the delegate to refresh the bubble display
|
||||
// We dispatch here this action in order to let each bubble data update their sender flair.
|
||||
if (self.delegate)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)eventDidChangeSentState:(NSNotification *)notif
|
||||
{
|
||||
MXEvent *event = notif.object;
|
||||
@@ -2947,11 +2839,14 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
- (void)setState:(MXKDataSourceState)newState
|
||||
{
|
||||
self->state = newState;
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(dataSource:didStateChange:)])
|
||||
if (self->state != newState)
|
||||
{
|
||||
[self.delegate dataSource:self didStateChange:self->state];
|
||||
self->state = newState;
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(dataSource:didStateChange:)])
|
||||
{
|
||||
[self.delegate dataSource:self didStateChange:self->state];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3993,34 +3888,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Groups
|
||||
|
||||
- (MXGroup *)groupWithGroupId:(NSString*)groupId
|
||||
{
|
||||
MXGroup *group = [self.mxSession groupWithGroupId:groupId];
|
||||
if (!group)
|
||||
{
|
||||
// Check whether an instance has been already created.
|
||||
group = [externalRelatedGroups objectForKey:groupId];
|
||||
}
|
||||
|
||||
if (!group)
|
||||
{
|
||||
// Create a new group instance.
|
||||
group = [[MXGroup alloc] initWithGroupId:groupId];
|
||||
[externalRelatedGroups setObject:group forKey:groupId];
|
||||
|
||||
// Retrieve at least the group profile
|
||||
[self.mxSession updateGroupProfile:group success:nil failure:^(NSError *error) {
|
||||
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] groupWithGroupId: group profile update failed %@", self, groupId);
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
#pragma mark - MXScanManager notifications
|
||||
|
||||
- (void)registerScanManagerNotifications
|
||||
|
||||
@@ -78,6 +78,13 @@ typedef enum : NSUInteger {
|
||||
*/
|
||||
- (void)reset;
|
||||
|
||||
/**
|
||||
Flag indicating the manager has a room data source for a given room id.
|
||||
|
||||
@param roomId the room id to check.
|
||||
*/
|
||||
- (BOOL)hasRoomDataSourceForRoom:(NSString*)roomId;
|
||||
|
||||
/**
|
||||
Get a room data source corresponding to a room id.
|
||||
|
||||
|
||||
@@ -191,6 +191,11 @@ static Class _roomDataSourceClass;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasRoomDataSourceForRoom:(NSString *)roomId
|
||||
{
|
||||
return roomDataSources[roomId] != nil;
|
||||
}
|
||||
|
||||
- (void)roomDataSourceForRoom:(NSString *)roomId create:(BOOL)create onComplete:(void (^)(MXKRoomDataSource *roomDataSource))onComplete
|
||||
{
|
||||
NSParameterAssert(roomId);
|
||||
@@ -200,7 +205,7 @@ static Class _roomDataSourceClass;
|
||||
|
||||
if (!roomDataSource && create && roomId)
|
||||
{
|
||||
[_roomDataSourceClass loadRoomDataSourceWithRoomId:roomId andMatrixSession:mxSession onComplete:^(id roomDataSource) {
|
||||
[_roomDataSourceClass loadRoomDataSourceWithRoomId:roomId threadId:nil andMatrixSession:mxSession onComplete:^(id roomDataSource) {
|
||||
[self addRoomDataSource:roomDataSource];
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
|
||||
@@ -31,3 +31,4 @@ FOUNDATION_EXPORT NSString *const kMXKSlashCmdUnbanUser;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdSetUserPowerLevel;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdResetUserPowerLevel;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdChangeRoomTopic;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdDiscardSession;
|
||||
|
||||
@@ -27,3 +27,4 @@ NSString *const kMXKSlashCmdUnbanUser = @"/unban";
|
||||
NSString *const kMXKSlashCmdSetUserPowerLevel = @"/op";
|
||||
NSString *const kMXKSlashCmdResetUserPowerLevel = @"/deop";
|
||||
NSString *const kMXKSlashCmdChangeRoomTopic = @"/topic";
|
||||
NSString *const kMXKSlashCmdDiscardSession = @"/discardsession";
|
||||
|
||||
Reference in New Issue
Block a user