mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 15:22:39 +00:00
vector-im/element-ios/issues/5009 - Implemented multi-room forwarding and added various tweaks following code review.
This commit is contained in:
parent
e3f1bd25a9
commit
12c167ba6c
25 changed files with 620 additions and 484 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/Contents.json
vendored
Normal file
23
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "radio-button-default.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "radio-button-default@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "radio-button-default@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/radio-button-default.png
vendored
Normal file
BIN
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/radio-button-default.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 615 B |
BIN
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/radio-button-default@2x.png
vendored
Normal file
BIN
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/radio-button-default@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/radio-button-default@3x.png
vendored
Normal file
BIN
Riot/Assets/SharedImages.xcassets/radio-button-default.imageset/radio-button-default@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
23
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/Contents.json
vendored
Normal file
23
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "radio-button-selected.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "radio-button-selected@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "radio-button-selected@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/radio-button-selected.png
vendored
Normal file
BIN
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/radio-button-selected.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 729 B |
BIN
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/radio-button-selected@2x.png
vendored
Normal file
BIN
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/radio-button-selected@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/radio-button-selected@3x.png
vendored
Normal file
BIN
Riot/Assets/SharedImages.xcassets/radio-button-selected.imageset/radio-button-selected@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
|
@ -210,6 +210,8 @@ internal enum Asset {
|
|||
internal static let cancel = ImageAsset(name: "cancel")
|
||||
internal static let e2eVerified = ImageAsset(name: "e2e_verified")
|
||||
internal static let horizontalLogo = ImageAsset(name: "horizontal_logo")
|
||||
internal static let radioButtonDefault = ImageAsset(name: "radio-button-default")
|
||||
internal static let radioButtonSelected = ImageAsset(name: "radio-button-selected")
|
||||
}
|
||||
}
|
||||
// swiftlint:enable identifier_name line_length nesting type_body_length type_name
|
||||
|
|
|
@ -2399,10 +2399,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
|||
|
||||
// Set a default title view class without handling tap gesture (Let [self refreshRoomTitle] refresh this view correctly).
|
||||
[self setRoomTitleViewClass:RoomTitleView.class];
|
||||
|
||||
// Remove details icon
|
||||
RoomTitleView *roomTitleView = (RoomTitleView*)self.titleView;
|
||||
|
||||
|
||||
// Remove the shadow image used to hide the bottom border of the navigation bar when the preview header is displayed
|
||||
[mainNavigationController.navigationBar setShadowImage:nil];
|
||||
[mainNavigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
|
||||
|
@ -3198,7 +3195,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
|||
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
self.shareManager = [[ShareManager alloc] initWithShareItemProvider:[[SimpleShareItemProvider alloc] initWithTextMessage:selectedComponent.textMessage]];
|
||||
self.shareManager = [[ShareManager alloc] initWithShareItemProvider:[[SimpleShareItemProvider alloc] initWithTextMessage:selectedComponent.textMessage]
|
||||
type:ShareManagerTypeForward];
|
||||
|
||||
MXWeakify(self);
|
||||
[self.shareManager setCompletionCallback:^(ShareManagerResult result) {
|
||||
|
@ -3264,6 +3262,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
|||
}
|
||||
else // Add action for attachment
|
||||
{
|
||||
if (attachment.type == MXKAttachmentTypeFile ||
|
||||
attachment.type == MXKAttachmentTypeImage ||
|
||||
attachment.type == MXKAttachmentTypeVideo ||
|
||||
attachment.type == MXKAttachmentTypeVoiceMessage) {
|
||||
|
||||
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
self.shareManager = [[ShareManager alloc] initWithShareItemProvider:[[SimpleShareItemProvider alloc] initWithAttachment:attachment]
|
||||
type:ShareManagerTypeForward];
|
||||
|
||||
MXWeakify(self);
|
||||
[self.shareManager setCompletionCallback:^(ShareManagerResult result) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[attachment onShareEnded];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
self.shareManager = nil;
|
||||
}];
|
||||
|
||||
[self presentViewController:self.shareManager.mainViewController animated:YES completion:nil];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (BuildSettings.messageDetailsAllowSave)
|
||||
{
|
||||
if (attachment.type == MXKAttachmentTypeImage || attachment.type == MXKAttachmentTypeVideo)
|
||||
|
@ -3390,37 +3411,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
|||
}]];
|
||||
}
|
||||
}
|
||||
|
||||
if (attachment.type == MXKAttachmentTypeFile ||
|
||||
attachment.type == MXKAttachmentTypeImage ||
|
||||
attachment.type == MXKAttachmentTypeVideo ||
|
||||
attachment.type == MXKAttachmentTypeVoiceMessage) {
|
||||
|
||||
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomEventActionForward]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
[self startActivityIndicator];
|
||||
|
||||
[attachment prepareShare:^(NSURL *fileURL) {
|
||||
[self stopActivityIndicator];
|
||||
|
||||
self.shareManager = [[ShareManager alloc] initWithShareItemProvider:[[SimpleShareItemProvider alloc] initWithAttachment:attachment]];
|
||||
|
||||
MXWeakify(self);
|
||||
[self.shareManager setCompletionCallback:^(ShareManagerResult result) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[attachment onShareEnded];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
self.shareManager = nil;
|
||||
}];
|
||||
|
||||
[self presentViewController:self.shareManager.mainViewController animated:YES completion:nil];
|
||||
} failure:^(NSError *error) {
|
||||
[self showError:error];
|
||||
[self stopActivityIndicator];
|
||||
}];
|
||||
}]];
|
||||
}
|
||||
}
|
||||
|
||||
// Check status of the selected event
|
||||
|
|
|
@ -16,25 +16,25 @@
|
|||
|
||||
#import <MatrixKit/MatrixKit.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, ShareDataSourceMode)
|
||||
{
|
||||
DataSourceModePeople,
|
||||
DataSourceModeRooms
|
||||
};
|
||||
@class ShareDataSource;
|
||||
|
||||
@protocol ShareDataSourceDelegate <NSObject>
|
||||
|
||||
- (void)shareDataSourceDidChangeSelectedRoomIdentifiers:(ShareDataSource *)shareDataSource;
|
||||
|
||||
@end
|
||||
|
||||
@interface ShareDataSource : MXKRecentsDataSource
|
||||
|
||||
- (instancetype)initWithMode:(ShareDataSourceMode)dataSourceMode
|
||||
fileStore:(MXFileStore *)fileStore
|
||||
credentials:(MXCredentials *)credentials;
|
||||
@property (nonatomic, weak) id<ShareDataSourceDelegate> shareDelegate;
|
||||
|
||||
/**
|
||||
Returns the cell data at the index path
|
||||
|
||||
@param indexPath the index of the cell
|
||||
@return the MXKRecentCellData instance if it exists
|
||||
*/
|
||||
- (MXKRecentCellData *)cellDataAtIndexPath:(NSIndexPath *)indexPath;
|
||||
@property (nonatomic, strong, readonly) NSSet<NSString *> *selectedRoomIdentifiers;
|
||||
|
||||
- (instancetype)initWithFileStore:(MXFileStore *)fileStore
|
||||
credentials:(MXCredentials *)credentials;
|
||||
|
||||
- (void)selectRoomWithIdentifier:(NSString *)roomIdentifier animated:(BOOL)animated;
|
||||
|
||||
- (void)deselectRoomWithIdentifier:(NSString *)roomIdentifier animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
|
|
@ -19,27 +19,28 @@
|
|||
|
||||
@interface ShareDataSource ()
|
||||
|
||||
@property (nonatomic, assign, readonly) ShareDataSourceMode dataSourceMode;
|
||||
@property (nonatomic, strong, readonly) MXFileStore *fileStore;
|
||||
@property (nonatomic, strong, readonly) MXCredentials *credentials;
|
||||
|
||||
@property NSArray <MXKRecentCellData *> *recentCellDatas;
|
||||
@property NSMutableArray <MXKRecentCellData *> *visibleRoomCellDatas;
|
||||
|
||||
@property (nonatomic, strong) NSMutableSet<NSString *> *internalSelectedRoomIdentifiers;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ShareDataSource
|
||||
|
||||
- (instancetype)initWithMode:(ShareDataSourceMode)dataSourceMode
|
||||
fileStore:(MXFileStore *)fileStore
|
||||
credentials:(MXCredentials *)credentials
|
||||
- (instancetype)initWithFileStore:(MXFileStore *)fileStore
|
||||
credentials:(MXCredentials *)credentials
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_dataSourceMode = dataSourceMode;
|
||||
_fileStore = fileStore;
|
||||
_credentials = credentials;
|
||||
|
||||
_internalSelectedRoomIdentifiers = [NSMutableSet set];
|
||||
|
||||
[self loadCellData];
|
||||
}
|
||||
return self;
|
||||
|
@ -53,6 +54,25 @@
|
|||
_visibleRoomCellDatas = nil;
|
||||
}
|
||||
|
||||
- (NSSet<NSString *> *)selectedRoomIdentifiers
|
||||
{
|
||||
return self.internalSelectedRoomIdentifiers.copy;
|
||||
}
|
||||
|
||||
- (void)selectRoomWithIdentifier:(NSString *)roomIdentifier animated:(BOOL)animated
|
||||
{
|
||||
[self.internalSelectedRoomIdentifiers addObject:roomIdentifier];
|
||||
|
||||
[self.shareDelegate shareDataSourceDidChangeSelectedRoomIdentifiers:self];
|
||||
}
|
||||
|
||||
- (void)deselectRoomWithIdentifier:(NSString *)roomIdentifier animated:(BOOL)animated
|
||||
{
|
||||
[self.internalSelectedRoomIdentifiers removeObject:roomIdentifier];
|
||||
|
||||
[self.shareDelegate shareDataSourceDidChangeSelectedRoomIdentifiers:self];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)loadCellData
|
||||
|
@ -66,7 +86,7 @@
|
|||
|
||||
for (MXRoomSummary *roomSummary in roomsSummaries)
|
||||
{
|
||||
if (!roomSummary.hiddenFromUser && ((self.dataSourceMode == DataSourceModeRooms) ^ roomSummary.isDirect))
|
||||
if (!roomSummary.hiddenFromUser)
|
||||
{
|
||||
[roomSummary setMatrixSession:session];
|
||||
|
||||
|
@ -137,6 +157,7 @@
|
|||
{
|
||||
self.visibleRoomCellDatas = nil;
|
||||
}
|
||||
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
|
@ -160,7 +181,11 @@
|
|||
{
|
||||
RecentRoomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[RecentRoomTableViewCell defaultReuseIdentifier]];
|
||||
|
||||
[cell render:[self cellDataAtIndexPath:indexPath]];
|
||||
MXKRecentCellData *data = [self cellDataAtIndexPath:indexPath];
|
||||
|
||||
[cell render:data];
|
||||
|
||||
[cell setCustomSelected:[self.selectedRoomIdentifiers containsObject:data.roomSummary.roomId] animated:NO];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,12 @@ private class SimpleShareItem: ShareItemProtocol {
|
|||
|
||||
let items: [ShareItemProtocol]
|
||||
|
||||
private override init() {
|
||||
attachment = nil
|
||||
textMessage = nil
|
||||
self.items = []
|
||||
}
|
||||
|
||||
@objc public init(withAttachment attachment: MXKAttachment) {
|
||||
self.attachment = attachment
|
||||
self.items = [SimpleShareItem(withAttachment: attachment)];
|
||||
|
@ -78,10 +84,18 @@ private class SimpleShareItem: ShareItemProtocol {
|
|||
return
|
||||
}
|
||||
|
||||
attachment?.prepareShare({ url in
|
||||
completion(url, nil)
|
||||
guard let attachment = attachment else {
|
||||
fatalError("[SimpleShareItemProvider] Invalid item provider state.")
|
||||
}
|
||||
|
||||
attachment.prepareShare({ url in
|
||||
DispatchQueue.main.async {
|
||||
completion(url, nil)
|
||||
}
|
||||
}, failure: { error in
|
||||
completion(nil, error)
|
||||
DispatchQueue.main.async {
|
||||
completion(nil, error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ShareManagerType) {
|
||||
ShareManagerTypeSend,
|
||||
ShareManagerTypeForward,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ShareManagerResult) {
|
||||
ShareManagerResultFinished,
|
||||
ShareManagerResultCancelled,
|
||||
|
@ -30,17 +35,12 @@ typedef NS_ENUM(NSUInteger, ShareManagerResult) {
|
|||
|
||||
@property (nonatomic, copy) void (^completionCallback)(ShareManagerResult);
|
||||
|
||||
- (instancetype)initWithShareItemProvider:(id<ShareItemProviderProtocol>)shareItemProvider;
|
||||
- (instancetype)initWithShareItemProvider:(id<ShareItemProviderProtocol>)shareItemProvider
|
||||
type:(ShareManagerType)type;
|
||||
|
||||
- (UIViewController *)mainViewController;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface NSItemProvider (ShareManager)
|
||||
|
||||
@property BOOL isLoaded;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#endif
|
||||
|
||||
static const CGFloat kLargeImageSizeMaxDimension = 2048.0;
|
||||
static const CGSize kThumbnailSize = {800.0, 600.0};
|
||||
|
||||
typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
||||
{
|
||||
|
@ -61,6 +62,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
@implementation ShareManager
|
||||
|
||||
- (instancetype)initWithShareItemProvider:(id<ShareItemProviderProtocol>)shareItemProvider
|
||||
type:(ShareManagerType)type
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
@ -91,7 +93,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
|
||||
[MXLog configure:configuration];
|
||||
|
||||
_shareViewController = [[ShareViewController alloc] initWithType:ShareViewControllerTypeSend
|
||||
_shareViewController = [[ShareViewController alloc] initWithType:(type == ShareManagerTypeForward ? ShareViewControllerTypeForward : ShareViewControllerTypeSend)
|
||||
currentState:ShareViewControllerAccountStateNotConfigured];
|
||||
[_shareViewController setDelegate:self];
|
||||
|
||||
|
@ -101,7 +103,6 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
[NSBundle mxk_setLanguage:language];
|
||||
[NSBundle mxk_setFallbackLanguage:@"en"];
|
||||
|
||||
// Check the current matrix user.
|
||||
[self checkUserAccount];
|
||||
}
|
||||
|
||||
|
@ -117,8 +118,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
|
||||
#pragma mark - ShareViewControllerDelegate
|
||||
|
||||
- (void)shareViewControllerDidRequestShare:(ShareViewController *)shareViewController
|
||||
forRoomIdentifier:(NSString *)roomIdentifier
|
||||
- (void)shareViewController:(ShareViewController *)shareViewController didRequestShareForRoomIdentifiers:(NSSet<NSString *> *)roomIdentifiers
|
||||
{
|
||||
MXSession *session = [[MXSession alloc] initWithMatrixRestClient:[[MXRestClient alloc] initWithCredentials:self.userAccount.mxCredentials andOnUnrecognizedCertificateBlock:nil]];
|
||||
[MXFileStore setPreloadOptions:0];
|
||||
|
@ -129,12 +129,22 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
|
||||
session.crypto.warnOnUnknowDevices = NO; // Do not warn for unknown devices. We have cross-signing now
|
||||
|
||||
MXRoom *selectedRoom = [MXRoom loadRoomFromStore:self.fileStore withRoomId:roomIdentifier matrixSession:session];
|
||||
[self sendContentToRoom:selectedRoom success:nil failure:^(NSError *error){
|
||||
NSMutableArray<MXRoom *> *rooms = [NSMutableArray array];
|
||||
for (NSString *roomIdentifier in roomIdentifiers) {
|
||||
MXRoom *room = [MXRoom loadRoomFromStore:self.fileStore withRoomId:roomIdentifier matrixSession:session];
|
||||
if (room) {
|
||||
[rooms addObject:room];
|
||||
}
|
||||
}
|
||||
|
||||
[self sendContentToRooms:rooms success:^{
|
||||
self.completionCallback(ShareManagerResultFinished);
|
||||
} failure:^(NSError *error){
|
||||
[self showFailureAlert:[VectorL10n roomEventFailedToSend]];
|
||||
}];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[ShareManager] Failed preparign matrix session");
|
||||
MXLogError(@"[ShareManager] Failed preparing matrix session");
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -145,16 +155,37 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)sendContentToRoom:(MXRoom *)room success:(void(^)(void))success failure:(void(^)(NSError *))failure
|
||||
- (void)showFailureAlert:(NSString *)title
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
MXWeakify(self);
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:[MatrixKitL10n ok] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (self.completionCallback)
|
||||
{
|
||||
self.completionCallback(ShareManagerResultFailed);
|
||||
}
|
||||
}];
|
||||
|
||||
[alertController addAction:okAction];
|
||||
|
||||
[self.mainViewController presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)sendContentToRooms:(NSArray<MXRoom *> *)rooms success:(void(^)(void))success failure:(void(^)(NSError *))failure
|
||||
{
|
||||
[self resetPendingData];
|
||||
|
||||
NSMutableArray <id<ShareItemProtocol>> *pendingImagesItemProviders = [NSMutableArray array]; // Used to keep the items associated to pending images (used only when all items are images).
|
||||
|
||||
__block NSError *firstRequestError = nil;
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
|
||||
void (^requestFailure)(NSError*) = ^(NSError *requestError) {
|
||||
void (^requestSuccess)(void) = ^() {
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
};
|
||||
|
||||
void (^requestFailure)(NSError *) = ^(NSError *requestError) {
|
||||
if (requestError && !firstRequestError)
|
||||
{
|
||||
firstRequestError = requestError;
|
||||
|
@ -166,68 +197,93 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
MXWeakify(self);
|
||||
for (id<ShareItemProtocol> item in self.shareItemProvider.items)
|
||||
{
|
||||
if (item.type == ShareItemTypeText || item.type == ShareItemTypeURL) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(id item, NSError *error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (error)
|
||||
{
|
||||
requestFailure(error);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *text = nil;
|
||||
if([item isKindOfClass:[NSString class]])
|
||||
{
|
||||
text = item;
|
||||
}
|
||||
else if([item isKindOfClass:[NSURL class]])
|
||||
{
|
||||
text = [(NSURL *)item absoluteString];
|
||||
}
|
||||
|
||||
if(text.length == 0)
|
||||
{
|
||||
requestFailure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[self sendText:text toRooms:rooms success:requestSuccess failure:requestFailure];
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeFileURL) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *url, NSError *error) {
|
||||
if (error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (error)
|
||||
{
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self sendFileWithUrl:url toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
});
|
||||
[self sendFileWithUrl:url toRooms:rooms success:requestSuccess failure:requestFailure];
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeText) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSString *text, NSError *error) {
|
||||
if (error) {
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self sendText:text toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeURL)
|
||||
if (item.type == ShareItemTypeVideo || item.type == ShareItemTypeMovie)
|
||||
{
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *url, NSError *error) {
|
||||
if (error) {
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *videoLocalUrl, NSError *error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (error)
|
||||
{
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self sendText:url.absoluteString toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
});
|
||||
[self sendVideo:videoLocalUrl toRooms:rooms success:requestSuccess failure:requestFailure];
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeVoiceMessage)
|
||||
{
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *fileURL, NSError *error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (error)
|
||||
{
|
||||
requestFailure(error);
|
||||
return;
|
||||
}
|
||||
|
||||
[self sendVoiceMessage:fileURL toRooms:rooms success:requestSuccess failure:requestFailure];
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeImage)
|
||||
{
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(id<NSSecureCoding> itemProviderItem, NSError *error) {
|
||||
if (error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (error)
|
||||
{
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -250,30 +306,23 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
imageData = UIImagePNGRepresentation(image);
|
||||
}
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (imageData)
|
||||
if (!imageData)
|
||||
{
|
||||
if ([self.shareItemProvider areAllItemsImages])
|
||||
{
|
||||
[self.pendingImages addObject:imageData];
|
||||
[pendingImagesItemProviders addObject:item];
|
||||
}
|
||||
else
|
||||
{
|
||||
CGSize imageSize = [self imageSizeFromImageData:imageData];
|
||||
self.imageCompressionMode = ImageCompressionModeNone;
|
||||
self.actualLargeSize = MAX(imageSize.width, imageSize.height);
|
||||
|
||||
[self sendImageData:imageData withItem:item toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
}
|
||||
requestFailure(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self.shareItemProvider areAllItemsImages])
|
||||
{
|
||||
[self.pendingImages addObject:imageData];
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogError(@"[ShareManager] sendContentToRoom: failed to loadItemForTypeIdentifier. Error: %@", error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
CGSize imageSize = [self imageSizeFromImageData:imageData];
|
||||
self.imageCompressionMode = ImageCompressionModeNone;
|
||||
self.actualLargeSize = MAX(imageSize.width, imageSize.height);
|
||||
|
||||
[self sendImageData:imageData toRooms:rooms success:requestSuccess failure:requestFailure];
|
||||
}
|
||||
|
||||
// Only prompt for image resize if all items are images
|
||||
|
@ -283,9 +332,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
if ([self.shareItemProvider areAllItemsLoaded])
|
||||
{
|
||||
UIAlertController *compressionPrompt = [self compressionPromptForPendingImagesWithShareBlock:^{
|
||||
[self sendImageDatas:self.pendingImages.copy withItems:pendingImagesItemProviders toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
[self sendImageDatas:self.pendingImages.copy toRooms:rooms success:requestSuccess failure:requestFailure];
|
||||
}];
|
||||
|
||||
if (compressionPrompt)
|
||||
|
@ -300,63 +347,6 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
}
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeVideo)
|
||||
{
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *videoLocalUrl, NSError *error) {
|
||||
if (error) {
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self sendVideo:videoLocalUrl toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeMovie)
|
||||
{
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *videoLocalUrl, NSError *error) {
|
||||
if (error) {
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self sendVideo:videoLocalUrl toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
if (item.type == ShareItemTypeVoiceMessage)
|
||||
{
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[self.shareItemProvider loadItem:item completion:^(NSURL *fileURL, NSError *error) {
|
||||
if (error) {
|
||||
requestFailure(error);
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self sendVoiceMessage:fileURL toRoom:room success:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:requestFailure];
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
|
@ -368,30 +358,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
}
|
||||
else
|
||||
{
|
||||
self.completionCallback(ShareManagerResultFinished);
|
||||
success();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)showFailureAlert:(NSString *)title
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
MXWeakify(self);
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:[MatrixKitL10n ok] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (self.completionCallback)
|
||||
{
|
||||
self.completionCallback(ShareManagerResultFailed);
|
||||
}
|
||||
}];
|
||||
|
||||
[alertController addAction:okAction];
|
||||
|
||||
[self.mainViewController presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)checkUserAccount
|
||||
{
|
||||
// Force account manager to reload account from the local storage.
|
||||
|
@ -428,21 +399,14 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
{
|
||||
_fileStore = [[MXFileStore alloc] initWithCredentials:self.userAccount.mxCredentials];
|
||||
|
||||
ShareDataSource *roomDataSource = [[ShareDataSource alloc] initWithMode:DataSourceModeRooms
|
||||
fileStore:_fileStore
|
||||
credentials:self.userAccount.mxCredentials];
|
||||
|
||||
ShareDataSource *peopleDataSource = [[ShareDataSource alloc] initWithMode:DataSourceModePeople
|
||||
fileStore:_fileStore
|
||||
credentials:self.userAccount.mxCredentials];
|
||||
ShareDataSource *roomDataSource = [[ShareDataSource alloc] initWithFileStore:_fileStore
|
||||
credentials:self.userAccount.mxCredentials];
|
||||
|
||||
[self.shareViewController configureWithState:ShareViewControllerAccountStateConfigured
|
||||
roomDataSource:roomDataSource
|
||||
peopleDataSource:peopleDataSource];
|
||||
roomDataSource:roomDataSource];
|
||||
} else {
|
||||
[self.shareViewController configureWithState:ShareViewControllerAccountStateNotConfigured
|
||||
roomDataSource:nil
|
||||
peopleDataSource:nil];
|
||||
roomDataSource:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,7 +545,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
return compressionPrompt;
|
||||
}
|
||||
|
||||
- (void)didStartSendingToRoom:(MXRoom *)room
|
||||
- (void)didStartSending
|
||||
{
|
||||
[self.shareViewController showProgressIndicator];
|
||||
}
|
||||
|
@ -738,11 +702,9 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
|
||||
- (void)presentCompressionPrompt:(UIAlertController *)compressionPrompt
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[compressionPrompt popoverPresentationController].sourceView = self.mainViewController.view;
|
||||
[compressionPrompt popoverPresentationController].sourceRect = self.mainViewController.view.frame;
|
||||
[self.mainViewController presentViewController:compressionPrompt animated:YES completion:nil];
|
||||
});
|
||||
[compressionPrompt popoverPresentationController].sourceView = self.mainViewController.view;
|
||||
[compressionPrompt popoverPresentationController].sourceRect = self.mainViewController.view.frame;
|
||||
[self.mainViewController presentViewController:compressionPrompt animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
@ -781,11 +743,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
#pragma mark - Sharing
|
||||
|
||||
- (void)sendText:(NSString *)text
|
||||
toRoom:(MXRoom *)room
|
||||
toRooms:(NSArray<MXRoom *> *)rooms
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
[self didStartSendingToRoom:room];
|
||||
[self didStartSending];
|
||||
if (!text)
|
||||
{
|
||||
MXLogError(@"[ShareManager] Invalid text.");
|
||||
|
@ -793,19 +755,34 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
return;
|
||||
}
|
||||
|
||||
[room sendTextMessage:text success:^(NSString *eventId) {
|
||||
success();
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[ShareManager] sendTextMessage failed with error %@", error);
|
||||
failure(error);
|
||||
}];
|
||||
__block NSError *error = nil;
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
for (MXRoom *room in rooms) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[room sendTextMessage:text success:^(NSString *eventId) {
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:^(NSError *innerError) {
|
||||
MXLogError(@"[ShareManager] sendTextMessage failed with error %@", error);
|
||||
error = innerError;
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
}];
|
||||
}
|
||||
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
if(error) {
|
||||
failure(error);
|
||||
} else {
|
||||
success();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendFileWithUrl:(NSURL *)fileUrl toRoom:(MXRoom *)room
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
- (void)sendFileWithUrl:(NSURL *)fileUrl
|
||||
toRooms:(NSArray<MXRoom *> *)rooms
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
[self didStartSendingToRoom:room];
|
||||
[self didStartSending];
|
||||
if (!fileUrl)
|
||||
{
|
||||
MXLogError(@"[ShareManager] Invalid file url.");
|
||||
|
@ -818,21 +795,185 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
mimeType = [self mimeTypeFromUTI:(__bridge NSString *)uti];
|
||||
CFRelease(uti);
|
||||
|
||||
[room sendFile:fileUrl mimeType:mimeType localEcho:nil success:^(NSString *eventId) {
|
||||
success();
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[ShareManager] sendFile failed with error %@", error);
|
||||
failure(error);
|
||||
} keepActualFilename:YES];
|
||||
__block NSError *error = nil;
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
for (MXRoom *room in rooms) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[room sendFile:fileUrl mimeType:mimeType localEcho:nil success:^(NSString *eventId) {
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:^(NSError *innerError) {
|
||||
MXLogError(@"[ShareManager] sendFile failed with error %@", innerError);
|
||||
error = innerError;
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} keepActualFilename:YES];
|
||||
}
|
||||
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
if(error) {
|
||||
failure(error);
|
||||
} else {
|
||||
success();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendVideo:(NSURL *)videoLocalUrl
|
||||
toRooms:(NSArray<MXRoom *> *)rooms
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoLocalUrl options:nil];
|
||||
|
||||
MXWeakify(self);
|
||||
|
||||
// Ignore showMediaCompressionPrompt setting due to memory constraints when encrypting large videos.
|
||||
UIAlertController *compressionPrompt = [MXKTools videoConversionPromptForVideoAsset:videoAsset withCompletion:^(NSString *presetName) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// If the preset name is nil, the user cancelled.
|
||||
if (!presetName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the chosen video conversion preset.
|
||||
[MXSDKOptions sharedInstance].videoConversionPresetName = presetName;
|
||||
|
||||
[self didStartSending];
|
||||
if (!videoLocalUrl)
|
||||
{
|
||||
MXLogError(@"[ShareManager] Invalid video file url.");
|
||||
failure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the video frame at 1 sec to define the video thumbnail
|
||||
AVAssetImageGenerator *assetImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:videoAsset];
|
||||
assetImageGenerator.appliesPreferredTrackTransform = YES;
|
||||
CMTime time = CMTimeMake(1, 1);
|
||||
CGImageRef imageRef = [assetImageGenerator copyCGImageAtTime:time actualTime:NULL error:nil];
|
||||
// Finalize video attachment
|
||||
UIImage *videoThumbnail = [[UIImage alloc] initWithCGImage:imageRef];
|
||||
CFRelease(imageRef);
|
||||
|
||||
__block NSError *error = nil;
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
for (MXRoom *room in rooms) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[room sendVideoAsset:videoAsset withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) {
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:^(NSError *innerError) {
|
||||
MXLogError(@"[ShareManager] Failed sending video with error %@", innerError);
|
||||
error = innerError;
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
}];
|
||||
}
|
||||
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
if(error) {
|
||||
failure(error);
|
||||
} else {
|
||||
success();
|
||||
}
|
||||
});
|
||||
}];
|
||||
|
||||
[self presentCompressionPrompt:compressionPrompt];
|
||||
}
|
||||
|
||||
- (void)sendVoiceMessage:(NSURL *)fileUrl
|
||||
toRooms:(NSArray<MXRoom *> *)rooms
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
[self didStartSending];
|
||||
if (!fileUrl)
|
||||
{
|
||||
MXLogError(@"[ShareManager] Invalid voice message file url.");
|
||||
failure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
__block NSError *error = nil;
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
for (MXRoom *room in rooms) {
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[room sendVoiceMessage:fileUrl mimeType:nil duration:0.0 samples:nil localEcho:nil success:^(NSString *eventId) {
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:^(NSError *innerError) {
|
||||
MXLogError(@"[ShareManager] sendVoiceMessage failed with error %@", error);
|
||||
error = innerError;
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} keepActualFilename:YES];
|
||||
}
|
||||
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
if(error) {
|
||||
failure(error);
|
||||
} else {
|
||||
success();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendImageDatas:(NSArray<id<ShareItemProtocol>> *)imageDatas
|
||||
toRooms:(NSArray<MXRoom *> *)rooms
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
if (imageDatas.count == 0)
|
||||
{
|
||||
MXLogError(@"[ShareManager] sendImages: no images to send.");
|
||||
failure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[self didStartSending];
|
||||
|
||||
dispatch_group_t requestsGroup = dispatch_group_create();
|
||||
__block NSError *firstRequestError;
|
||||
|
||||
NSUInteger index = 0;
|
||||
|
||||
for (NSData *imageData in imageDatas)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
dispatch_group_enter(requestsGroup);
|
||||
[self sendImageData:imageData toRooms:rooms success:^{
|
||||
dispatch_group_leave(requestsGroup);
|
||||
} failure:^(NSError *error) {
|
||||
if (error && !firstRequestError)
|
||||
{
|
||||
firstRequestError = error;
|
||||
}
|
||||
|
||||
dispatch_group_leave(requestsGroup);
|
||||
}];
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
dispatch_group_notify(requestsGroup, dispatch_get_main_queue(), ^{
|
||||
|
||||
if (firstRequestError)
|
||||
{
|
||||
failure(firstRequestError);
|
||||
}
|
||||
else
|
||||
{
|
||||
success();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendImageData:(NSData *)imageData
|
||||
withItem:(id<ShareItemProtocol>)item
|
||||
toRoom:(MXRoom *)room
|
||||
toRooms:(NSArray<MXRoom *> *)rooms
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
[self didStartSendingToRoom:room];
|
||||
[self didStartSending];
|
||||
|
||||
NSString *imageUTI;
|
||||
NSString *mimeType;
|
||||
|
@ -848,7 +989,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
|
||||
if (!mimeType)
|
||||
{
|
||||
MXLogError(@"[ShareManager] sendImage failed. Cannot determine MIME type of %@", item);
|
||||
MXLogError(@"[ShareManager] sendImage failed. Cannot determine MIME type .");
|
||||
if (failure)
|
||||
{
|
||||
failure(nil);
|
||||
|
@ -921,142 +1062,33 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode)
|
|||
imageSize = [self imageSizeFromImageData:imageData];
|
||||
}
|
||||
|
||||
UIImage *thumbnail = nil;
|
||||
// Thumbnail is useful only in case of encrypted room
|
||||
if (room.summary.isEncrypted)
|
||||
{
|
||||
thumbnail = [MXKTools resizeImageWithData:imageData toFitInSize:CGSizeMake(800, 600)];
|
||||
}
|
||||
|
||||
[room sendImage:finalImageData withImageSize:imageSize mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) {
|
||||
success();
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[ShareManager] sendImage failed with error %@", error);
|
||||
failure(error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)sendImageDatas:(NSArray<id<ShareItemProtocol>> *)imageDatas
|
||||
withItems:(NSArray<id<ShareItemProtocol>> *)items toRoom:(MXRoom *)room
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
if (imageDatas.count == 0 || imageDatas.count != items.count)
|
||||
{
|
||||
MXLogError(@"[ShareManager] sendImages: no images to send.");
|
||||
failure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[self didStartSendingToRoom:room];
|
||||
|
||||
dispatch_group_t requestsGroup = dispatch_group_create();
|
||||
__block NSError *firstRequestError;
|
||||
|
||||
NSUInteger index = 0;
|
||||
|
||||
for (NSData *imageData in imageDatas)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
dispatch_group_enter(requestsGroup);
|
||||
[self sendImageData:imageData withItem:items[index] toRoom:room success:^{
|
||||
dispatch_group_leave(requestsGroup);
|
||||
} failure:^(NSError *error) {
|
||||
if (error && !firstRequestError)
|
||||
{
|
||||
firstRequestError = error;
|
||||
}
|
||||
__block NSError *error = nil;
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
for (MXRoom *room in rooms) {
|
||||
|
||||
dispatch_group_leave(requestsGroup);
|
||||
}];
|
||||
UIImage *thumbnail = nil;
|
||||
if (room.summary.isEncrypted) // Thumbnail is useful only in case of encrypted room
|
||||
{
|
||||
thumbnail = [MXKTools resizeImageWithData:imageData toFitInSize:kThumbnailSize];
|
||||
}
|
||||
|
||||
index++;
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
[room sendImage:finalImageData withImageSize:imageSize mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) {
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
} failure:^(NSError *innerError) {
|
||||
MXLogError(@"[ShareManager] sendImage failed with error %@", error);
|
||||
error = innerError;
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
}];
|
||||
}
|
||||
|
||||
dispatch_group_notify(requestsGroup, dispatch_get_main_queue(), ^{
|
||||
|
||||
if (firstRequestError)
|
||||
{
|
||||
failure(firstRequestError);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
if(error) {
|
||||
failure(error);
|
||||
} else {
|
||||
success();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendVideo:(NSURL *)videoLocalUrl
|
||||
toRoom:(MXRoom *)room
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoLocalUrl options:nil];
|
||||
|
||||
MXWeakify(self);
|
||||
|
||||
// Ignore showMediaCompressionPrompt setting due to memory constraints when encrypting large videos.
|
||||
UIAlertController *compressionPrompt = [MXKTools videoConversionPromptForVideoAsset:videoAsset withCompletion:^(NSString *presetName) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// If the preset name is nil, the user cancelled.
|
||||
if (!presetName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the chosen video conversion preset.
|
||||
[MXSDKOptions sharedInstance].videoConversionPresetName = presetName;
|
||||
|
||||
[self didStartSendingToRoom:room];
|
||||
if (!videoLocalUrl)
|
||||
{
|
||||
MXLogError(@"[ShareManager] Invalid video file url.");
|
||||
failure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the video frame at 1 sec to define the video thumbnail
|
||||
AVAssetImageGenerator *assetImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:videoAsset];
|
||||
assetImageGenerator.appliesPreferredTrackTransform = YES;
|
||||
CMTime time = CMTimeMake(1, 1);
|
||||
CGImageRef imageRef = [assetImageGenerator copyCGImageAtTime:time actualTime:NULL error:nil];
|
||||
// Finalize video attachment
|
||||
UIImage *videoThumbnail = [[UIImage alloc] initWithCGImage:imageRef];
|
||||
CFRelease(imageRef);
|
||||
|
||||
[room sendVideoAsset:videoAsset withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) {
|
||||
success();
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[ShareManager] Failed sending video with error %@", error);
|
||||
failure(error);
|
||||
}];
|
||||
}];
|
||||
|
||||
[self presentCompressionPrompt:compressionPrompt];
|
||||
}
|
||||
|
||||
- (void)sendVoiceMessage:(NSURL *)fileUrl
|
||||
toRoom:(MXRoom *)room
|
||||
success:(dispatch_block_t)success
|
||||
failure:(void(^)(NSError *error))failure
|
||||
{
|
||||
[self didStartSendingToRoom:room];
|
||||
if (!fileUrl)
|
||||
{
|
||||
MXLogError(@"[ShareManager] Invalid voice message file url.");
|
||||
failure(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[room sendVoiceMessage:fileUrl mimeType:nil duration:0.0 samples:nil localEcho:nil success:^(NSString *eventId) {
|
||||
success();
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"[ShareManager] sendVoiceMessage failed with error %@", error);
|
||||
failure(error);
|
||||
} keepActualFilename:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -20,4 +20,6 @@
|
|||
|
||||
+ (CGFloat)cellHeight;
|
||||
|
||||
- (void)setCustomSelected:(BOOL)selected animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
@property (weak, nonatomic) IBOutlet MXKImageView *avatarImageView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *roomTitleLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *encryptedRoomIcon;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *selectionButton;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -56,6 +57,12 @@
|
|||
|
||||
self.roomTitleLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
|
||||
self.contentView.backgroundColor = ThemeService.shared.theme.backgroundColor;
|
||||
|
||||
[self.selectionButton setImage:[UIImage imageNamed:@"radio-button-default"] forState:UIControlStateNormal];
|
||||
[self.selectionButton setImage:[UIImage imageNamed:@"radio-button-selected"] forState:UIControlStateSelected];
|
||||
|
||||
[self.selectionButton setTitle:@"" forState:UIControlStateNormal];
|
||||
[self.selectionButton setTitle:@"" forState:UIControlStateSelected];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
|
@ -92,4 +99,11 @@
|
|||
return 74;
|
||||
}
|
||||
|
||||
- (void)setCustomSelected:(BOOL)selected animated:(BOOL)animated
|
||||
{
|
||||
[UIView animateWithDuration:(animated ? 0.25f : 0.0f) animations:^{
|
||||
[self.selectionButton setSelected:selected];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -25,12 +25,9 @@
|
|||
<constraint firstAttribute="width" constant="42" id="Xp0-5S-1wI"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vBS-iO-8H6">
|
||||
<rect key="frame" x="78" y="27" width="33" height="20"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Text" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vBS-iO-8H6">
|
||||
<rect key="frame" x="76" y="15" width="32" height="44"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="H21-1K-fGz"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -43,15 +40,27 @@
|
|||
<constraint firstAttribute="width" constant="11" id="Mai-xD-TqV"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="m0f-of-6xq">
|
||||
<rect key="frame" x="562" y="29" width="16" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="Wue-Ih-eVg"/>
|
||||
<constraint firstAttribute="width" constant="16" id="s5a-PW-58p"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Button"/>
|
||||
<buttonConfiguration key="configuration" style="plain" image="radio-button-selected"/>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="vBS-iO-8H6" firstAttribute="top" secondItem="b83-aU-AJ3" secondAttribute="topMargin" constant="4" id="0nI-h1-enE"/>
|
||||
<constraint firstItem="HJd-Am-cCx" firstAttribute="leading" secondItem="b83-aU-AJ3" secondAttribute="leadingMargin" constant="6" id="4df-2f-865"/>
|
||||
<constraint firstItem="m0f-of-6xq" firstAttribute="centerY" secondItem="b83-aU-AJ3" secondAttribute="centerY" id="B3g-N6-bh1"/>
|
||||
<constraint firstItem="hqD-YY-LWz" firstAttribute="top" secondItem="b83-aU-AJ3" secondAttribute="topMargin" constant="34" id="Cdm-v3-js8"/>
|
||||
<constraint firstItem="hqD-YY-LWz" firstAttribute="leading" secondItem="b83-aU-AJ3" secondAttribute="leadingMargin" constant="42" id="UIE-13-LGw"/>
|
||||
<constraint firstItem="m0f-of-6xq" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="vBS-iO-8H6" secondAttribute="trailing" constant="16" id="dyz-rB-vUR"/>
|
||||
<constraint firstItem="HJd-Am-cCx" firstAttribute="centerY" secondItem="b83-aU-AJ3" secondAttribute="centerY" id="flh-LO-k3n"/>
|
||||
<constraint firstItem="vBS-iO-8H6" firstAttribute="centerY" secondItem="b83-aU-AJ3" secondAttribute="centerY" id="ocY-mt-0n0"/>
|
||||
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="vBS-iO-8H6" secondAttribute="trailing" constant="15" id="qqy-zs-Ccy"/>
|
||||
<constraint firstItem="vBS-iO-8H6" firstAttribute="leading" secondItem="HJd-Am-cCx" secondAttribute="trailing" constant="14" id="quv-47-R9n"/>
|
||||
<constraint firstAttribute="trailing" secondItem="m0f-of-6xq" secondAttribute="trailing" constant="22" id="k1V-mv-zgW"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="vBS-iO-8H6" secondAttribute="bottom" constant="4" id="k1n-ZD-FS0"/>
|
||||
<constraint firstItem="vBS-iO-8H6" firstAttribute="leading" secondItem="HJd-Am-cCx" secondAttribute="trailing" constant="12" id="quv-47-R9n"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
@ -60,11 +69,13 @@
|
|||
<outlet property="avatarImageView" destination="HJd-Am-cCx" id="Mv2-Kb-aG4"/>
|
||||
<outlet property="encryptedRoomIcon" destination="hqD-YY-LWz" id="Ikp-Sf-Vlc"/>
|
||||
<outlet property="roomTitleLabel" destination="vBS-iO-8H6" id="0J9-p3-Lzx"/>
|
||||
<outlet property="selectionButton" destination="m0f-of-6xq" id="pzc-VN-t72"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-53" y="-43"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="e2e_verified" width="10" height="12"/>
|
||||
<image name="radio-button-selected" width="24" height="24"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#import "RoomsListViewController.h"
|
||||
#import "RecentRoomTableViewCell.h"
|
||||
#import "ShareDataSource.h"
|
||||
#import "RecentCellData.h"
|
||||
#import "ThemeService.h"
|
||||
|
||||
|
@ -140,6 +141,22 @@
|
|||
return [RecentRoomTableViewCell cellHeight];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
NSString *roomIdentifier = [self.dataSource cellDataAtIndexPath:indexPath].roomSummary.roomId;
|
||||
|
||||
ShareDataSource *dataSource = (ShareDataSource *)self.dataSource;
|
||||
if ([dataSource.selectedRoomIdentifiers containsObject:roomIdentifier]) {
|
||||
[dataSource deselectRoomWithIdentifier:roomIdentifier animated:YES];
|
||||
} else {
|
||||
[dataSource selectRoomWithIdentifier:roomIdentifier animated:YES];
|
||||
}
|
||||
|
||||
[self.recentsTableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - MXKDataSourceDelegate
|
||||
|
||||
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
|
||||
|
|
|
@ -33,9 +33,7 @@ typedef NS_ENUM(NSUInteger, ShareViewControllerAccountState) {
|
|||
|
||||
@protocol ShareViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)shareViewControllerDidRequestShare:(ShareViewController *)shareViewController
|
||||
forRoomIdentifier:(NSString *)roomIdentifier;
|
||||
|
||||
- (void)shareViewController:(ShareViewController *)shareViewController didRequestShareForRoomIdentifiers:(NSSet<NSString *> *)roomIdentifiers;
|
||||
- (void)shareViewControllerDidRequestDismissal:(ShareViewController *)shareViewController;
|
||||
|
||||
@end
|
||||
|
@ -48,8 +46,7 @@ typedef NS_ENUM(NSUInteger, ShareViewControllerAccountState) {
|
|||
currentState:(ShareViewControllerAccountState)state;
|
||||
|
||||
- (void)configureWithState:(ShareViewControllerAccountState)state
|
||||
roomDataSource:(nullable ShareDataSource *)roomDataSource
|
||||
peopleDataSource:(nullable ShareDataSource *)peopleDataSource;
|
||||
roomDataSource:(nullable ShareDataSource *)roomDataSource;
|
||||
|
||||
- (void)showProgressIndicator;
|
||||
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
*/
|
||||
|
||||
#import "ShareViewController.h"
|
||||
#import "SegmentedViewController.h"
|
||||
#import "ShareDataSource.h"
|
||||
#import "RoomsListViewController.h"
|
||||
#import "FallbackViewController.h"
|
||||
#import "ShareDataSource.h"
|
||||
|
||||
#import "ThemeService.h"
|
||||
|
||||
|
@ -28,13 +27,16 @@
|
|||
#import "Riot-Swift.h"
|
||||
#endif
|
||||
|
||||
@interface ShareViewController () <MXKRecentListViewControllerDelegate>
|
||||
@interface ShareViewController () <MXKRecentListViewControllerDelegate, ShareDataSourceDelegate>
|
||||
|
||||
@property (nonatomic, assign, readonly) ShareViewControllerType type;
|
||||
|
||||
@property (nonatomic, assign) ShareViewControllerAccountState state;
|
||||
|
||||
@property (nonatomic, strong) RoomsListViewController *roomListViewController;
|
||||
@property (nonatomic, strong) ShareDataSource *roomDataSource;
|
||||
@property (nonatomic, strong) ShareDataSource *peopleDataSource;
|
||||
|
||||
@property (nonatomic, strong) FallbackViewController *fallbackViewController;
|
||||
|
||||
@property (nonatomic, weak) IBOutlet UIView *masterContainerView;
|
||||
@property (nonatomic, weak) IBOutlet UIButton *cancelButton;
|
||||
|
@ -42,8 +44,6 @@
|
|||
@property (nonatomic, weak) IBOutlet UIButton *shareButton;
|
||||
@property (nonatomic, weak) IBOutlet UIView *contentView;
|
||||
|
||||
@property (nonatomic, strong) SegmentedViewController *segmentedViewController;
|
||||
|
||||
@property (nonatomic, strong) MXKPieChartHUD *hudView;
|
||||
|
||||
@end
|
||||
|
@ -76,17 +76,17 @@
|
|||
[self.cancelButton setTitle:[VectorL10n cancel] forState:UIControlStateNormal];
|
||||
|
||||
[self.shareButton setTintColor:ThemeService.shared.theme.tintColor];
|
||||
[self.shareButton setEnabled:NO];
|
||||
|
||||
[self configureWithState:self.state roomDataSource:self.roomDataSource peopleDataSource:self.peopleDataSource];
|
||||
[self configureWithState:self.state roomDataSource:self.roomDataSource];
|
||||
}
|
||||
|
||||
- (void)configureWithState:(ShareViewControllerAccountState)state
|
||||
roomDataSource:(ShareDataSource *)roomDataSource
|
||||
peopleDataSource:(ShareDataSource *)peopleDataSource
|
||||
{
|
||||
self.state = state;
|
||||
self.roomDataSource = roomDataSource;
|
||||
self.peopleDataSource = peopleDataSource;
|
||||
self.roomDataSource.shareDelegate = self;
|
||||
|
||||
if (!self.isViewLoaded) {
|
||||
return;
|
||||
|
@ -110,19 +110,11 @@
|
|||
[self.hudView setProgress:progress];
|
||||
}
|
||||
|
||||
#pragma mark - MXKRecentListViewControllerDelegate
|
||||
#pragma mark - ShareDataSourceDelegate
|
||||
|
||||
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController
|
||||
didSelectRoom:(NSString *)roomId
|
||||
inMatrixSession:(MXSession *)mxSession
|
||||
- (void)shareDataSourceDidChangeSelectedRoomIdentifiers:(ShareDataSource *)shareDataSource
|
||||
{
|
||||
[self.delegate shareViewControllerDidRequestShare:self forRoomIdentifier:roomId];
|
||||
}
|
||||
|
||||
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController
|
||||
didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo
|
||||
{
|
||||
[self.delegate shareViewControllerDidRequestShare:self forRoomIdentifier:childInfo.childRoomId];
|
||||
self.shareButton.enabled = (shareDataSource.selectedRoomIdentifiers.count > 0);
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
@ -133,60 +125,53 @@
|
|||
|
||||
if (self.state == ShareViewControllerAccountStateConfigured)
|
||||
{
|
||||
self.titleLabel.text = [VectorL10n sendTo:@""];
|
||||
[self.shareButton setTitle:[VectorL10n roomEventActionForward] forState:UIControlStateNormal];
|
||||
|
||||
[self configureSegmentedViewController];
|
||||
[self.shareButton setHidden:NO];
|
||||
|
||||
if (self.type == ShareViewControllerTypeSend) {
|
||||
[self.titleLabel setText:[VectorL10n sendTo:@""]];
|
||||
[self.shareButton setTitle:[VectorL10n sendTo:@""] forState:UIControlStateNormal];
|
||||
} else {
|
||||
[self.titleLabel setText:[VectorL10n roomEventActionForward]];
|
||||
[self.shareButton setTitle:[VectorL10n roomEventActionForward] forState:UIControlStateNormal];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.titleLabel.text = [AppInfo.current displayName];
|
||||
[self configureFallbackViewController];
|
||||
[self.shareButton setHidden:NO];
|
||||
|
||||
self.titleLabel.text = [AppInfo.current displayName];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)configureSegmentedViewController
|
||||
{
|
||||
RoomsListViewController *roomsViewController = [RoomsListViewController recentListViewController];
|
||||
[roomsViewController displayList:self.roomDataSource];
|
||||
[roomsViewController setDelegate:self];
|
||||
|
||||
RoomsListViewController *peopleViewController = [RoomsListViewController recentListViewController];
|
||||
[peopleViewController setDelegate:self];
|
||||
[peopleViewController displayList:self.peopleDataSource];
|
||||
|
||||
self.segmentedViewController = [SegmentedViewController segmentedViewController];
|
||||
[self.segmentedViewController initWithTitles:@[[VectorL10n titleRooms], [VectorL10n titlePeople]]
|
||||
viewControllers:@[roomsViewController, peopleViewController] defaultSelected:0];
|
||||
|
||||
[self addChildViewController:self.segmentedViewController];
|
||||
[self.contentView vc_addSubViewMatchingParent:self.segmentedViewController.view];
|
||||
[self.segmentedViewController didMoveToParentViewController:self];
|
||||
self.roomListViewController = [RoomsListViewController recentListViewController];
|
||||
[self.roomListViewController displayList:self.roomDataSource];
|
||||
|
||||
[self addChildViewController:self.roomListViewController];
|
||||
[self.contentView vc_addSubViewMatchingParent:self.roomListViewController.view];
|
||||
[self.roomListViewController didMoveToParentViewController:self];
|
||||
}
|
||||
|
||||
- (void)configureFallbackViewController
|
||||
{
|
||||
FallbackViewController *fallbackVC = [FallbackViewController new];
|
||||
[self addChildViewController:fallbackVC];
|
||||
[self.contentView vc_addSubViewMatchingParent:fallbackVC.view];
|
||||
[fallbackVC didMoveToParentViewController:self];
|
||||
self.fallbackViewController = [FallbackViewController new];
|
||||
[self addChildViewController:self.fallbackViewController];
|
||||
[self.contentView vc_addSubViewMatchingParent:self.fallbackViewController.view];
|
||||
[self.fallbackViewController didMoveToParentViewController:self];
|
||||
}
|
||||
|
||||
- (void)resetContentView
|
||||
{
|
||||
NSArray *subviews = self.contentView.subviews;
|
||||
for (UIView *subview in subviews)
|
||||
{
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
[self.roomListViewController willMoveToParentViewController:nil];
|
||||
[self.roomListViewController.view removeFromSuperview];
|
||||
[self.roomListViewController removeFromParentViewController];
|
||||
|
||||
if (self.segmentedViewController)
|
||||
{
|
||||
[self.segmentedViewController removeFromParentViewController];
|
||||
|
||||
[self.segmentedViewController destroy];
|
||||
self.segmentedViewController = nil;
|
||||
}
|
||||
[self.fallbackViewController willMoveToParentViewController:nil];
|
||||
[self.fallbackViewController.view removeFromSuperview];
|
||||
[self.fallbackViewController removeFromParentViewController];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
@ -198,7 +183,11 @@
|
|||
|
||||
- (IBAction)onShareButtonTap:(UIButton *)sender
|
||||
{
|
||||
if (self.roomDataSource.selectedRoomIdentifiers.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate shareViewController:self didRequestShareForRoomIdentifiers:self.roomDataSource.selectedRoomIdentifiers];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<action selector="onCancelButtonTap:" destination="-1" eventType="touchUpInside" id="47D-fR-8PQ"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="otu-Ag-Bwo">
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="otu-Ag-Bwo">
|
||||
<rect key="frame" x="315" y="12" width="44" height="33"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<state key="normal" title="Share"/>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
[ThemeService.shared setThemeId:RiotSettings.shared.userInterfaceTheme];
|
||||
|
||||
ShareExtensionShareItemProvider *provider = [[ShareExtensionShareItemProvider alloc] initWithExtensionContext:self.extensionContext];
|
||||
_shareManager = [[ShareManager alloc] initWithShareItemProvider:provider];
|
||||
_shareManager = [[ShareManager alloc] initWithShareItemProvider:provider type:ShareManagerTypeSend];
|
||||
|
||||
MXWeakify(self);
|
||||
[_shareManager setCompletionCallback:^(ShareManagerResult result) {
|
||||
|
@ -49,27 +49,28 @@
|
|||
{
|
||||
case ShareManagerResultFinished:
|
||||
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
|
||||
[self _dismiss];
|
||||
[self dismiss];
|
||||
break;
|
||||
case ShareManagerResultCancelled:
|
||||
[self.extensionContext cancelRequestWithError:[NSError errorWithDomain:@"MXUserCancelErrorDomain" code:4201 userInfo:nil]];
|
||||
[self _dismiss];
|
||||
[self dismiss];
|
||||
break;
|
||||
case ShareManagerResultFailed:
|
||||
[self.extensionContext cancelRequestWithError:[NSError errorWithDomain:@"MXFailureErrorDomain" code:500 userInfo:nil]];
|
||||
[self _dismiss];
|
||||
[self dismiss];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}];
|
||||
|
||||
[self.shareManager.mainViewController setModalInPopover:YES];
|
||||
[self presentViewController:self.shareManager.mainViewController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)_dismiss
|
||||
- (void)dismiss
|
||||
{
|
||||
[self dismissViewControllerAnimated:true completion:^{
|
||||
[self.presentingViewController dismissViewControllerAnimated:false completion:nil];
|
||||
|
|
|
@ -16,13 +16,7 @@
|
|||
|
||||
import Foundation
|
||||
import MobileCoreServices
|
||||
|
||||
let UTTypeText = kUTTypeText as String
|
||||
let UTTypeURL = kUTTypeURL as String
|
||||
let UTTypeFileUrl = kUTTypeFileURL as String
|
||||
let UTTypeImage = kUTTypeImage as String
|
||||
let UTTypeVideo = kUTTypeVideo as String
|
||||
let UTTypeMovie = kUTTypeMovie as String
|
||||
import MatrixKit
|
||||
|
||||
private class ShareExtensionItem: ShareItemProtocol {
|
||||
let itemProvider: NSItemProvider
|
||||
|
@ -34,17 +28,17 @@ private class ShareExtensionItem: ShareItemProtocol {
|
|||
}
|
||||
|
||||
var type: ShareItemType {
|
||||
if itemProvider.hasItemConformingToTypeIdentifier(UTTypeText) {
|
||||
if itemProvider.hasItemConformingToTypeIdentifier(MXKUTI.text.rawValue) {
|
||||
return .text
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTTypeURL) {
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(MXKUTI.url.rawValue) {
|
||||
return .URL
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTTypeFileUrl) {
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(MXKUTI.fileUrl.rawValue) {
|
||||
return .fileURL
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTTypeImage) {
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(MXKUTI.image.rawValue) {
|
||||
return .image
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTTypeVideo) {
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(MXKUTI.video.rawValue) {
|
||||
return .video
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(UTTypeMovie) {
|
||||
} else if itemProvider.hasItemConformingToTypeIdentifier(MXKUTI.movie.rawValue) {
|
||||
return .movie
|
||||
}
|
||||
|
||||
|
@ -105,7 +99,9 @@ class ShareExtensionShareItemProvider: NSObject, ShareItemProviderProtocol {
|
|||
shareExtensionItem.loaded = true
|
||||
}
|
||||
|
||||
completion(result, error)
|
||||
DispatchQueue.main.async {
|
||||
completion(result, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,19 +110,19 @@ class ShareExtensionShareItemProvider: NSObject, ShareItemProviderProtocol {
|
|||
private func typeIdentifierForType(_ type: ShareItemType) -> String {
|
||||
switch type {
|
||||
case .text:
|
||||
return UTTypeText
|
||||
return MXKUTI.text.rawValue
|
||||
case .URL:
|
||||
return UTTypeURL
|
||||
return MXKUTI.url.rawValue
|
||||
case .fileURL:
|
||||
return UTTypeFileUrl
|
||||
return MXKUTI.fileUrl.rawValue
|
||||
case .image:
|
||||
return UTTypeImage
|
||||
return MXKUTI.image.rawValue
|
||||
case .video:
|
||||
return UTTypeVideo
|
||||
return MXKUTI.video.rawValue
|
||||
case .movie:
|
||||
return UTTypeMovie
|
||||
return MXKUTI.movie.rawValue
|
||||
case .voiceMessage:
|
||||
return UTTypeFileUrl
|
||||
return MXKUTI.fileUrl.rawValue
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue