Merge MatrixKit develop with commit hash: b85b736313bec0592bd1cabc68035d97f5331137

This commit is contained in:
SBiOSoftWhare
2021-12-03 11:47:24 +01:00
parent 8d15fe55a2
commit e7d4cd7707
475 changed files with 87437 additions and 0 deletions
@@ -0,0 +1,25 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "MXKCellData.h"
#import "MXKSearchCellDataStoring.h"
/**
`MXKSearchCellData` modelised the data for a `MXKSearchCell` cell.
*/
@interface MXKSearchCellData : MXKCellData <MXKSearchCellDataStoring>
@end
@@ -0,0 +1,69 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "MXKSearchCellData.h"
#import "MXKSearchDataSource.h"
@implementation MXKSearchCellData
@synthesize roomId, senderDisplayName;
@synthesize searchResult, title, message, date, shouldShowRoomDisplayName, roomDisplayName, attachment, isAttachmentWithThumbnail, attachmentIcon;
- (instancetype)initWithSearchResult:(MXSearchResult *)searchResult2 andSearchDataSource:(MXKSearchDataSource *)searchDataSource
{
self = [super init];
if (self)
{
searchResult = searchResult2;
if (searchDataSource.roomEventFilter.rooms.count == 1)
{
// We are displaying a search within a room
// As title, display the user id
title = searchResult.result.sender;
roomId = searchDataSource.roomEventFilter.rooms[0];
}
else
{
// We are displaying a search over all user's rooms
// As title, display the room name of this search result
MXRoom *room = [searchDataSource.mxSession roomWithRoomId:searchResult.result.roomId];
if (room)
{
title = room.summary.displayname;
}
else
{
title = searchResult.result.roomId;
}
}
date = [searchDataSource.eventFormatter dateStringFromEvent:searchResult.result withTime:YES];
// Code from [MXEventFormatter stringFromEvent] for the particular case of a text message
message = [searchResult.result.content[@"body"] isKindOfClass:[NSString class]] ? searchResult.result.content[@"body"] : nil;
}
return self;
}
+ (void)cellDataWithSearchResult:(MXSearchResult *)searchResult andSearchDataSource:(MXKSearchDataSource *)searchDataSource onComplete:(void (^)(id<MXKSearchCellDataStoring>))onComplete
{
onComplete([[self alloc] initWithSearchResult:searchResult andSearchDataSource:searchDataSource]);
}
@end
@@ -0,0 +1,83 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
#import <MatrixSDK/MatrixSDK.h>
#import "MXKAttachment.h"
@class MXKSearchDataSource;
/**
`MXKSearchCellDataStoring` defines a protocol a class must conform in order to store
a search result in a cell data managed by `MXKSearchDataSource`.
*/
@protocol MXKSearchCellDataStoring <NSObject>
/**
The room id
*/
@property (nonatomic) NSString *roomId;
@property (nonatomic, readonly) NSString *title;
@property (nonatomic, readonly) NSString *message;
@property (nonatomic, readonly) NSString *date;
// Bulk result returned by MatrixSDK
@property (nonatomic, readonly) MXSearchResult *searchResult;
/**
Tell whether the room display name should be displayed in the cell. NO by default.
*/
@property (nonatomic) BOOL shouldShowRoomDisplayName;
/**
The room display name.
*/
@property (nonatomic) NSString *roomDisplayName;
/**
The sender display name.
*/
@property (nonatomic) NSString *senderDisplayName;
/**
The bubble attachment (if any).
*/
@property (nonatomic) MXKAttachment *attachment;
/**
YES when the bubble correspond to an attachment displayed with a thumbnail (see image, video).
*/
@property (nonatomic, readonly) BOOL isAttachmentWithThumbnail;
/**
The default icon relative to the attachment (if any).
*/
@property (nonatomic, readonly) UIImage* attachmentIcon;
#pragma mark - Public methods
/**
Create a new `MXKCellData` object for a new search result cell.
@param searchResult Bulk result returned by MatrixSDK.
@param searchDataSource the `MXKSearchDataSource` object that will use this instance.
@param onComplete a block providing the newly created instance.
*/
+ (void)cellDataWithSearchResult:(MXSearchResult*)searchResult andSearchDataSource:(MXKSearchDataSource*)searchDataSource onComplete:(void (^)(id<MXKSearchCellDataStoring> cellData))onComplete;
@end
@@ -0,0 +1,108 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "MXKDataSource.h"
#import "MXKSearchCellDataStoring.h"
#import "MXKEventFormatter.h"
/**
String identifying the object used to store and prepare the cell data of a result during a message search.
*/
extern NSString *const kMXKSearchCellDataIdentifier;
/**
The data source for `MXKSearchViewController` in case of message search.
Use the `initWithMatrixSession:` constructor to search in all user's rooms.
Use the `initWithRoomId:andMatrixSession: constructor to search in a specific room.
*/
@interface MXKSearchDataSource : MXKDataSource <UITableViewDataSource>
{
@protected
/**
List of results retrieved from the server.
The` MXKSearchDataSource` class stores MXKSearchCellDataStoring objects in it.
*/
NSMutableArray<MXKCellData*> *cellDataArray;
}
/**
The current search.
*/
@property (nonatomic, readonly) NSString *searchText;
/**
The room events filter which is applied during the messages search.
*/
@property (nonatomic) MXRoomEventFilter *roomEventFilter;
/**
Total number of results available on the server.
*/
@property (nonatomic, readonly) NSUInteger serverCount;
/**
The events to display texts formatter.
`MXKCellData` instances can use it to format text.
*/
@property (nonatomic) MXKEventFormatter *eventFormatter;
/**
Flag indicating if there are still results (in the past) to get with paginateBack.
*/
@property (nonatomic, readonly) BOOL canPaginate;
/**
Tell whether the room display name should be displayed in each result cell. NO by default.
*/
@property (nonatomic) BOOL shouldShowRoomDisplayName;
/**
Launch a message search homeserver side.
@discussion The result depends on the 'roomEventFilter' propertie.
@param textPattern the text to search in messages data.
@param force tell whether the search must be launched even if the text pattern is unchanged.
*/
- (void)searchMessages:(NSString*)textPattern force:(BOOL)force;
/**
Load more results from the past.
*/
- (void)paginateBack;
/**
Get the data for the cell at the given index.
@param index the index of the cell in the array
@return the cell data
*/
- (MXKCellData*)cellDataAtIndex:(NSInteger)index;
/**
Convert the results of a homeserver search requests into cells.
This methods is in charge of filling `cellDataArray`.
@param roomEventResults the homeserver response as provided by MatrixSDK.
@param onComplete the block called once complete.
*/
- (void)convertHomeserverResultsIntoCells:(MXSearchRoomEventResults*)roomEventResults onComplete:(dispatch_block_t)onComplete;
@end
@@ -0,0 +1,275 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "MXKSearchDataSource.h"
#import "MXKSearchCellData.h"
#pragma mark - Constant definitions
NSString *const kMXKSearchCellDataIdentifier = @"kMXKSearchCellDataIdentifier";
@interface MXKSearchDataSource ()
{
/**
The current search request.
*/
MXHTTPOperation *searchRequest;
/**
Token that can be used to get the next batch of results in the group, if exists.
*/
NSString *nextBatch;
}
@end
@implementation MXKSearchDataSource
- (instancetype)initWithMatrixSession:(MXSession *)mxSession
{
self = [super initWithMatrixSession:mxSession];
if (self)
{
// Set default data and view classes
// Cell data
[self registerCellDataClass:MXKSearchCellData.class forCellIdentifier:kMXKSearchCellDataIdentifier];
// Set default MXEvent -> NSString formatter
_eventFormatter = [[MXKEventFormatter alloc] initWithMatrixSession:mxSession];
_roomEventFilter = [[MXRoomEventFilter alloc] init];
cellDataArray = [NSMutableArray array];
}
return self;
}
- (void)destroy
{
cellDataArray = nil;
_eventFormatter = nil;
_roomEventFilter = nil;
[super destroy];
}
- (void)searchMessages:(NSString*)textPattern force:(BOOL)force
{
if (force || ![_searchText isEqualToString:textPattern])
{
// Reset data before making the new search
if (searchRequest)
{
[searchRequest cancel];
searchRequest = nil;
}
_searchText = textPattern;
_serverCount = 0;
_canPaginate = NO;
nextBatch = nil;
self.state = MXKDataSourceStatePreparing;
[cellDataArray removeAllObjects];
if (textPattern.length)
{
MXLogDebug(@"[MXKSearchDataSource] searchMessages: %@", textPattern);
[self doSearch];
}
else
{
// Refresh table display.
self.state = MXKDataSourceStateReady;
[self.delegate dataSource:self didCellChange:nil];
}
}
}
- (void)paginateBack
{
MXLogDebug(@"[MXKSearchDataSource] paginateBack");
self.state = MXKDataSourceStatePreparing;
[self doSearch];
}
- (MXKCellData*)cellDataAtIndex:(NSInteger)index
{
MXKCellData *cellData;
if (index < cellDataArray.count)
{
cellData = cellDataArray[index];
}
return cellData;
}
- (void)convertHomeserverResultsIntoCells:(MXSearchRoomEventResults*)roomEventResults onComplete:(dispatch_block_t)onComplete
{
// Retrieve the MXKCellData class to manage the data
// Note: MXKSearchDataSource only manages MXKCellData that conforms to MXKSearchCellDataStoring protocol
// see `[registerCellDataClass:forCellIdentifier:]`
Class class = [self cellDataClassForCellIdentifier:kMXKSearchCellDataIdentifier];
dispatch_group_t group = dispatch_group_create();
for (MXSearchResult *result in roomEventResults.results)
{
dispatch_group_enter(group);
[class cellDataWithSearchResult:result andSearchDataSource:self onComplete:^(__autoreleasing id<MXKSearchCellDataStoring> cellData) {
dispatch_group_leave(group);
if (cellData)
{
((id<MXKSearchCellDataStoring>)cellData).shouldShowRoomDisplayName = self.shouldShowRoomDisplayName;
// Use profile information as data to display
MXSearchUserProfile *userProfile = result.context.profileInfo[result.result.sender];
cellData.senderDisplayName = userProfile.displayName;
[self->cellDataArray insertObject:cellData atIndex:0];
}
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
onComplete();
});
}
#pragma mark - Private methods
// Update the MXKDataSource and notify the delegate
- (void)setState:(MXKDataSourceState)newState
{
state = newState;
if (self.delegate)
{
if ([self.delegate respondsToSelector:@selector(dataSource:didStateChange:)])
{
[self.delegate dataSource:self didStateChange:state];
}
}
}
- (void)doSearch
{
// Handle one request at a time
if (searchRequest)
{
return;
}
NSDate *startDate = [NSDate date];
MXWeakify(self);
searchRequest = [self.mxSession.matrixRestClient searchMessagesWithText:_searchText roomEventFilter:_roomEventFilter beforeLimit:0 afterLimit:0 nextBatch:nextBatch success:^(MXSearchRoomEventResults *roomEventResults) {
MXStrongifyAndReturnIfNil(self);
MXLogDebug(@"[MXKSearchDataSource] searchMessages: %@ (%d). Done in %.3fms - Got %tu / %tu messages", self.searchText, self.roomEventFilter.containsURL, [[NSDate date] timeIntervalSinceDate:startDate] * 1000, roomEventResults.results.count, roomEventResults.count);
self->searchRequest = nil;
self->_serverCount = roomEventResults.count;
self->nextBatch = roomEventResults.nextBatch;
self->_canPaginate = (nil != self->nextBatch);
// Process HS response to cells data
MXWeakify(self);
[self convertHomeserverResultsIntoCells:roomEventResults onComplete:^{
MXStrongifyAndReturnIfNil(self);
self.state = MXKDataSourceStateReady;
// Provide changes information to the delegate
NSIndexSet *insertedIndexes;
if (roomEventResults.results.count)
{
insertedIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, roomEventResults.results.count)];
}
[self.delegate dataSource:self didCellChange:insertedIndexes];
}];
} failure:^(NSError *error) {
MXStrongifyAndReturnIfNil(self);
self->searchRequest = nil;
self.state = MXKDataSourceStateFailed;
}];
}
#pragma mark - Override MXKDataSource
- (void)registerCellDataClass:(Class)cellDataClass forCellIdentifier:(NSString *)identifier
{
if ([identifier isEqualToString:kMXKSearchCellDataIdentifier])
{
// Sanity check
NSAssert([cellDataClass conformsToProtocol:@protocol(MXKSearchCellDataStoring)], @"MXKSearchDataSource only manages MXKCellData that conforms to MXKSearchCellDataStoring protocol");
}
[super registerCellDataClass:cellDataClass forCellIdentifier:identifier];
}
- (void)cancelAllRequests
{
if (searchRequest)
{
[searchRequest cancel];
searchRequest = nil;
}
[super cancelAllRequests];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return cellDataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MXKCellData* cellData = [self cellDataAtIndex:indexPath.row];
NSString *cellIdentifier = [self.delegate cellReuseIdentifierForCellData:cellData];
if (cellIdentifier)
{
UITableViewCell<MXKCellRendering> *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Make the bubble display the data
[cell render:cellData];
// Disable any interactions defined in the cell
// because we want [tableView didSelectRowAtIndexPath:] to be called
cell.contentView.userInteractionEnabled = NO;
// Force background color change on selection
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
return cell;
}
// Return a fake cell to prevent app from crashing.
return [[UITableViewCell alloc] init];
}
@end