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:
Frank Rotermund
2022-09-19 14:42:25 +02:00
508 changed files with 12777 additions and 9549 deletions
@@ -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";