From e68e18c1b5d18c7ed3f5fdbc1780beae998bdf91 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 8 Feb 2019 11:04:51 +0100 Subject: [PATCH 1/4] [Share extension] Support rich item sharing (e.g. URL + text + image). Fix issue #2224. --- .../Managers/ShareExtensionManager.m | 163 ++++++++++++++---- 1 file changed, 128 insertions(+), 35 deletions(-) diff --git a/RiotShareExtension/Managers/ShareExtensionManager.m b/RiotShareExtension/Managers/ShareExtensionManager.m index 2c5d05340..81ce90a5e 100644 --- a/RiotShareExtension/Managers/ShareExtensionManager.m +++ b/RiotShareExtension/Managers/ShareExtensionManager.m @@ -156,9 +156,33 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) NSString *UTTypeFileUrl = (__bridge NSString *)kUTTypeFileURL; NSString *UTTypeMovie = (__bridge NSString *)kUTTypeMovie; + BOOL areAllAttachmentsImages = [self areAllAttachmentsImages]; + __weak typeof(self) weakSelf = self; [self resetPendingData]; + + __block NSError *firstRequestError = nil; + __block NSMutableArray *returningExtensionItems = [NSMutableArray new]; + dispatch_group_t requestsGroup = dispatch_group_create(); + + void (^requestSuccess)(NSExtensionItem*) = ^(NSExtensionItem *extensionItem) { + if (extensionItem && ![returningExtensionItems containsObject:extensionItem]) + { + [returningExtensionItems addObject:extensionItem]; + } + + dispatch_group_leave(requestsGroup); + }; + + void (^requestFailure)(NSError*) = ^(NSError *requestError) { + if (requestError && !firstRequestError) + { + firstRequestError = requestError; + } + + dispatch_group_leave(requestsGroup); + }; for (NSExtensionItem *item in self.shareExtensionContext.inputItems) { @@ -166,6 +190,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) { if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeFileUrl]) { + dispatch_group_enter(requestsGroup); + [itemProvider loadItemForTypeIdentifier:UTTypeFileUrl options:nil completionHandler:^(NSURL *fileUrl, NSError * _Null_unspecified error) { // Switch back on the main thread to handle correctly the UI change @@ -174,7 +200,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (weakSelf) { typeof(self) self = weakSelf; - [self sendFileWithUrl:fileUrl toRoom:room extensionItem:item failureBlock:failureBlock]; + [self sendFileWithUrl:fileUrl + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; } }); @@ -183,6 +213,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeText]) { + dispatch_group_enter(requestsGroup); + [itemProvider loadItemForTypeIdentifier:UTTypeText options:nil completionHandler:^(NSString *text, NSError * _Null_unspecified error) { // Switch back on the main thread to handle correctly the UI change @@ -191,7 +223,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (weakSelf) { typeof(self) self = weakSelf; - [self sendText:text toRoom:room extensionItem:item failureBlock:failureBlock]; + [self sendText:text + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; } }); @@ -200,6 +236,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeURL]) { + dispatch_group_enter(requestsGroup); + [itemProvider loadItemForTypeIdentifier:UTTypeURL options:nil completionHandler:^(NSURL *url, NSError * _Null_unspecified error) { // Switch back on the main thread to handle correctly the UI change @@ -208,7 +246,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (weakSelf) { typeof(self) self = weakSelf; - [self sendText:url.absoluteString toRoom:room extensionItem:item failureBlock:failureBlock]; + [self sendText:url.absoluteString + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; } }); @@ -217,6 +259,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeImage]) { + dispatch_group_enter(requestsGroup); + itemProvider.isLoaded = NO; [itemProvider loadItemForTypeIdentifier:UTTypeImage options:nil completionHandler:^(id _Nullable itemProviderItem, NSError * _Null_unspecified error) @@ -249,16 +293,37 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (imageData) { [self.pendingImages addObject:imageData]; + + if (!areAllAttachmentsImages) + { + CGSize imageSize = [self imageSizeFromImageData:imageData]; + self.imageCompressionMode = ImageCompressionModeNone; + self.actualLargeSize = MAX(imageSize.width, imageSize.height); + + [self sendImages:self.pendingImages + withProviders:item.attachments + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; + } } else { NSLog(@"[ShareExtensionManager] sendContentToRoom: failed to loadItemForTypeIdentifier. Error: %@", error); + dispatch_group_leave(requestsGroup); } - if ([self areAttachmentsFullyLoaded]) + // Only prompt for image resize only if all items are images + if (areAllAttachmentsImages && [self areAttachmentsFullyLoaded]) { UIAlertController *compressionPrompt = [self compressionPromptForPendingImagesWithShareBlock:^{ - [self sendImages:self.pendingImages withProviders:item.attachments toRoom:room extensionItem:item failureBlock:failureBlock]; + [self sendImages:self.pendingImages + withProviders:item.attachments + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; }]; if (compressionPrompt) @@ -271,6 +336,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeVideo]) { + dispatch_group_enter(requestsGroup); + [itemProvider loadItemForTypeIdentifier:UTTypeVideo options:nil completionHandler:^(NSURL *videoLocalUrl, NSError * _Null_unspecified error) { // Switch back on the main thread to handle correctly the UI change @@ -279,7 +346,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (weakSelf) { typeof(self) self = weakSelf; - [self sendVideo:videoLocalUrl toRoom:room extensionItem:item failureBlock:failureBlock]; + [self sendVideo:videoLocalUrl + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; } }); @@ -288,6 +359,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } else if ([itemProvider hasItemConformingToTypeIdentifier:UTTypeMovie]) { + dispatch_group_enter(requestsGroup); + [itemProvider loadItemForTypeIdentifier:UTTypeMovie options:nil completionHandler:^(NSURL *videoLocalUrl, NSError * _Null_unspecified error) { // Switch back on the main thread to handle correctly the UI change @@ -296,7 +369,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (weakSelf) { typeof(self) self = weakSelf; - [self sendVideo:videoLocalUrl toRoom:room extensionItem:item failureBlock:failureBlock]; + [self sendVideo:videoLocalUrl + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; } }); @@ -305,6 +382,22 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } } } + + dispatch_group_notify(requestsGroup, dispatch_get_main_queue(), ^{ + [self resetPendingData]; + + if (firstRequestError) + { + if (failureBlock) + { + failureBlock(firstRequestError); + } + } + else + { + [self completeRequestReturningItems:returningExtensionItems completionHandler:nil]; + } + }); } - (BOOL)hasImageTypeContent @@ -553,6 +646,21 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) return YES; } +- (BOOL)areAllAttachmentsImages +{ + for (NSExtensionItem *item in self.shareExtensionContext.inputItems) + { + for (NSItemProvider *itemProvider in item.attachments) + { + if (![itemProvider hasItemConformingToTypeIdentifier:(__bridge NSString *)kUTTypeImage]) + { + return NO; + } + } + } + return YES; +} + - (NSString*)utiFromImageTypeItemProvider:(NSItemProvider*)itemProvider { NSString *uti; @@ -723,7 +831,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) #pragma mark - Sharing -- (void)sendText:(NSString *)text toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock +- (void)sendText:(NSString *)text toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock { [self didStartSendingToRoom:room]; if (!text) @@ -736,12 +844,10 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) return; } - __weak typeof(self) weakSelf = self; [room sendTextMessage:text success:^(NSString *eventId) { - if (weakSelf) + if (successBlock) { - typeof(self) self = weakSelf; - [self completeRequestReturningItems:@[extensionItem] completionHandler:nil]; + successBlock(); } } failure:^(NSError *error) { NSLog(@"[ShareExtensionManager] sendTextMessage failed."); @@ -752,7 +858,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) }]; } -- (void)sendFileWithUrl:(NSURL *)fileUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock +- (void)sendFileWithUrl:(NSURL *)fileUrl toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock { [self didStartSendingToRoom:room]; if (!fileUrl) @@ -770,13 +876,10 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) mimeType = [self mimeTypeFromUTI:(__bridge NSString *)uti]; CFRelease(uti); - __weak typeof(self) weakSelf = self; - [room sendFile:fileUrl mimeType:mimeType localEcho:nil success:^(NSString *eventId) { - if (weakSelf) + if (successBlock) { - typeof(self) self = weakSelf; - [self completeRequestReturningItems:@[extensionItem] completionHandler:nil]; + successBlock(); } } failure:^(NSError *error) { NSLog(@"[ShareExtensionManager] sendFile failed."); @@ -788,7 +891,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } -- (void)sendImages:(NSMutableArray *)imageDatas withProviders:(NSArray*)itemProviders toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock +- (void)sendImages:(NSMutableArray *)imageDatas withProviders:(NSArray*)itemProviders toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock { if (imageDatas.count == 0) { @@ -803,7 +906,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) [self didStartSendingToRoom:room]; - __block NSUInteger count = imageDatas.count; +// __block NSUInteger count = imageDatas.count; for (NSInteger index = 0; index < imageDatas.count; index++) { @@ -915,18 +1018,11 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) thumbnail = [MXKTools resizeImageWithData:imageData toFitInSize:CGSizeMake(800, 600)]; } - __weak typeof(self) weakSelf = self; - [room sendImage:imageData withImageSize:imageSize mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) { - - if (!--count && weakSelf) + if (successBlock) { - typeof(self) self = weakSelf; - - [self resetPendingData]; - [self completeRequestReturningItems:@[extensionItem] completionHandler:nil]; + successBlock(); } - } failure:^(NSError *error) { NSLog(@"[ShareExtensionManager] sendImage failed."); @@ -941,7 +1037,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } } -- (void)sendVideo:(NSURL *)videoLocalUrl toRoom:(MXRoom *)room extensionItem:(NSExtensionItem *)extensionItem failureBlock:(void(^)(NSError *error))failureBlock +- (void)sendVideo:(NSURL *)videoLocalUrl toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock { [self didStartSendingToRoom:room]; if (!videoLocalUrl) @@ -964,13 +1060,10 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) UIImage *videoThumbnail = [[UIImage alloc] initWithCGImage:imageRef]; CFRelease(imageRef); - __weak typeof(self) weakSelf = self; - [room sendVideo:videoLocalUrl withThumbnail:videoThumbnail localEcho:nil success:^(NSString *eventId) { - if (weakSelf) + if (successBlock) { - typeof(self) self = weakSelf; - [self completeRequestReturningItems:@[extensionItem] completionHandler:nil]; + successBlock(); } } failure:^(NSError *error) { NSLog(@"[ShareExtensionManager] sendVideo failed."); From 307ef4c788022e66df47de003febe6eea480ed0d Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 8 Feb 2019 11:06:47 +0100 Subject: [PATCH 2/4] [Share extension] Add NSExtensionActivationDictionaryVersion to plist. By the way enable sharing with Apple Notes application. --- RiotShareExtension/SupportingFiles/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RiotShareExtension/SupportingFiles/Info.plist b/RiotShareExtension/SupportingFiles/Info.plist index d3c06698d..a1557d323 100644 --- a/RiotShareExtension/SupportingFiles/Info.plist +++ b/RiotShareExtension/SupportingFiles/Info.plist @@ -26,6 +26,8 @@ NSExtensionActivationRule + NSExtensionActivationDictionaryVersion + 2 NSExtensionActivationSupportsImageWithMaxCount 5 NSExtensionActivationSupportsMovieWithMaxCount From 5b53a96134d026641ccf02089b2a957b5b1c00a1 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 8 Feb 2019 11:12:49 +0100 Subject: [PATCH 3/4] Update changes --- CHANGES.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 95e43e552..38b0fe745 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -22,6 +22,8 @@ Bug fix: * Ban and kick reasons are silently discarded (#2162). * Room Version Upgrade: Clicking the link in the room continuation event to go back to the old version of the room doesn't work (#2179). * Share extension: Fail to send screenshot (#2168). + * Share extension: Handle rich item sharing (image + text + URL) (#2224). + * Share extension: Sharing pages from Firefox only shares their title (#2163). Changes in 0.7.11 (2019-01-08) =============================================== From 149e399b846bdf81d03b8e0cc864584feaa168cb Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 8 Feb 2019 14:43:21 +0100 Subject: [PATCH 4/4] [Share extension] Improve dispatch_group usage when sending only images. --- .../Managers/ShareExtensionManager.m | 341 ++++++++++-------- 1 file changed, 197 insertions(+), 144 deletions(-) diff --git a/RiotShareExtension/Managers/ShareExtensionManager.m b/RiotShareExtension/Managers/ShareExtensionManager.m index 81ce90a5e..7816130e0 100644 --- a/RiotShareExtension/Managers/ShareExtensionManager.m +++ b/RiotShareExtension/Managers/ShareExtensionManager.m @@ -149,6 +149,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) - (void)sendContentToRoom:(MXRoom *)room failureBlock:(void(^)(NSError *error))failureBlock { + [self resetPendingData]; + NSString *UTTypeText = (__bridge NSString *)kUTTypeText; NSString *UTTypeURL = (__bridge NSString *)kUTTypeURL; NSString *UTTypeImage = (__bridge NSString *)kUTTypeImage; @@ -157,10 +159,7 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) NSString *UTTypeMovie = (__bridge NSString *)kUTTypeMovie; BOOL areAllAttachmentsImages = [self areAllAttachmentsImages]; - - __weak typeof(self) weakSelf = self; - - [self resetPendingData]; + NSMutableArray *pendingImagesItemProviders = [NSMutableArray new]; // Used to keep NSItemProvider associated to pending images (used only when all items are images). __block NSError *firstRequestError = nil; __block NSMutableArray *returningExtensionItems = [NSMutableArray new]; @@ -184,6 +183,8 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) dispatch_group_leave(requestsGroup); }; + __weak typeof(self) weakSelf = self; + for (NSExtensionItem *item in self.shareExtensionContext.inputItems) { for (NSItemProvider *itemProvider in item.attachments) @@ -292,20 +293,23 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) if (imageData) { - [self.pendingImages addObject:imageData]; - - if (!areAllAttachmentsImages) + if (areAllAttachmentsImages) + { + [self.pendingImages addObject:imageData]; + [pendingImagesItemProviders addObject:itemProvider]; + } + else { CGSize imageSize = [self imageSizeFromImageData:imageData]; self.imageCompressionMode = ImageCompressionModeNone; self.actualLargeSize = MAX(imageSize.width, imageSize.height); - [self sendImages:self.pendingImages - withProviders:item.attachments - toRoom:room - successBlock:^{ - requestSuccess(item); - } failureBlock:requestFailure]; + [self sendImageData:imageData + withProvider:itemProvider + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; } } else @@ -315,20 +319,27 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } // Only prompt for image resize only if all items are images - if (areAllAttachmentsImages && [self areAttachmentsFullyLoaded]) + if (areAllAttachmentsImages) { - UIAlertController *compressionPrompt = [self compressionPromptForPendingImagesWithShareBlock:^{ - [self sendImages:self.pendingImages - withProviders:item.attachments - toRoom:room - successBlock:^{ - requestSuccess(item); - } failureBlock:requestFailure]; - }]; - - if (compressionPrompt) + if ([self areAttachmentsFullyLoaded]) { - [self.delegate shareExtensionManager:self showImageCompressionPrompt:compressionPrompt]; + UIAlertController *compressionPrompt = [self compressionPromptForPendingImagesWithShareBlock:^{ + [self sendImageDatas:self.pendingImages + withProviders:pendingImagesItemProviders + toRoom:room + successBlock:^{ + requestSuccess(item); + } failureBlock:requestFailure]; + }]; + + if (compressionPrompt) + { + [self.delegate shareExtensionManager:self showImageCompressionPrompt:compressionPrompt]; + } + } + else + { + dispatch_group_leave(requestsGroup); } } } @@ -890,10 +901,135 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) } keepActualFilename:YES]; } - -- (void)sendImages:(NSMutableArray *)imageDatas withProviders:(NSArray*)itemProviders toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock +- (void)sendImageData:(NSData *)imageData withProvider:(NSItemProvider*)itemProvider toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock { - if (imageDatas.count == 0) + [self didStartSendingToRoom:room]; + + NSString *imageUTI; + NSString *mimeType; + + // Try to get UTI plus mime type from NSItemProvider + imageUTI = [self utiFromImageTypeItemProvider:itemProvider]; + + if (imageUTI) + { + mimeType = [self mimeTypeFromUTI:imageUTI]; + } + + if (!mimeType) + { + // Try to get UTI plus mime type from image data + + imageUTI = [self utiFromImageData:imageData]; + + if (imageUTI) + { + mimeType = [self mimeTypeFromUTI:imageUTI]; + } + } + + // Sanity check + if (!mimeType) + { + NSLog(@"[ShareExtensionManager] sendImage failed. Cannot determine MIME type of %@", itemProvider); + if (failureBlock) + { + failureBlock(nil); + } + return; + } + + CGSize imageSize; + NSData *finalImageData; + + // Only resize JPEG or PNG files + if ([self isResizingSupportedForUTI:imageUTI]) + { + UIImage *convertedImage; + CGSize newImageSize; + + switch (self.imageCompressionMode) { + case ImageCompressionModeSmall: + newImageSize = CGSizeMake(MXKTOOLS_SMALL_IMAGE_SIZE, MXKTOOLS_SMALL_IMAGE_SIZE); + break; + case ImageCompressionModeMedium: + newImageSize = CGSizeMake(MXKTOOLS_MEDIUM_IMAGE_SIZE, MXKTOOLS_MEDIUM_IMAGE_SIZE); + break; + case ImageCompressionModeLarge: + newImageSize = CGSizeMake(self.actualLargeSize, self.actualLargeSize); + break; + default: + newImageSize = CGSizeZero; + break; + } + + if (CGSizeEqualToSize(newImageSize, CGSizeZero)) + { + // No resize to make + // Make sure the uploaded image orientation is up + if ([self isImageOrientationNotUpOrUndeterminedForImageData:imageData]) + { + UIImage *image = [UIImage imageWithData:imageData]; + convertedImage = [MXKTools forceImageOrientationUp:image]; + } + } + else + { + // Resize the image and set image in right orientation too + convertedImage = [MXKTools resizeImageWithData:imageData toFitInSize:newImageSize]; + } + + if (convertedImage) + { + if ([imageUTI isEqualToString:(__bridge NSString *)kUTTypePNG]) + { + finalImageData = UIImagePNGRepresentation(convertedImage); + } + else if ([imageUTI isEqualToString:(__bridge NSString *)kUTTypeJPEG]) + { + finalImageData = UIImageJPEGRepresentation(convertedImage, 0.9); + } + + imageSize = convertedImage.size; + } + else + { + finalImageData = imageData; + imageSize = [self imageSizeFromImageData:imageData]; + } + } + else + { + finalImageData = imageData; + 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) { + if (successBlock) + { + successBlock(); + } + } failure:^(NSError *error) { + + NSLog(@"[ShareExtensionManager] sendImage failed."); + if (failureBlock) + { + failureBlock(error); + } + + }]; +} + +- (void)sendImageDatas:(NSMutableArray *)imageDatas withProviders:(NSArray*)itemProviders toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock +{ + if (imageDatas.count == 0 || imageDatas.count != itemProviders.count) { NSLog(@"[ShareExtensionManager] sendImages: no images to send."); @@ -906,135 +1042,52 @@ typedef NS_ENUM(NSInteger, ImageCompressionMode) [self didStartSendingToRoom:room]; -// __block NSUInteger count = imageDatas.count; + dispatch_group_t requestsGroup = dispatch_group_create(); + __block NSError *firstRequestError; - for (NSInteger index = 0; index < imageDatas.count; index++) + NSUInteger index = 0; + + for (NSData *imageData in imageDatas) { @autoreleasepool { + dispatch_group_enter(requestsGroup); + NSItemProvider *itemProvider = itemProviders[index]; - NSData *imageData = imageDatas[index]; - NSString *imageUTI; - NSString *mimeType; - - // Try to get UTI plus mime type from NSItemProvider - imageUTI = [self utiFromImageTypeItemProvider:itemProvider]; - - if (imageUTI) - { - mimeType = [self mimeTypeFromUTI:imageUTI]; - } - - if (!mimeType) - { - // Try to get UTI plus mime type from image data + [self sendImageData:imageData withProvider:itemProvider toRoom:room successBlock:^{ + dispatch_group_leave(requestsGroup); + } failureBlock:^(NSError *error) { - imageUTI = [self utiFromImageData:imageData]; - - if (imageUTI) + if (error && !firstRequestError) { - mimeType = [self mimeTypeFromUTI:imageUTI]; - } - } - - // Sanity check - if (!mimeType) - { - NSLog(@"[ShareExtensionManager] sendImage failed. Cannot determine MIME type of %@", itemProvider); - if (failureBlock) - { - failureBlock(nil); - } - return; - } - - CGSize imageSize; - - // Only resize JPEG or PNG files - if ([self isResizingSupportedForUTI:imageUTI]) - { - UIImage *convertedImage; - CGSize newImageSize; - - switch (self.imageCompressionMode) { - case ImageCompressionModeSmall: - newImageSize = CGSizeMake(MXKTOOLS_SMALL_IMAGE_SIZE, MXKTOOLS_SMALL_IMAGE_SIZE); - break; - case ImageCompressionModeMedium: - newImageSize = CGSizeMake(MXKTOOLS_MEDIUM_IMAGE_SIZE, MXKTOOLS_MEDIUM_IMAGE_SIZE); - break; - case ImageCompressionModeLarge: - newImageSize = CGSizeMake(self.actualLargeSize, self.actualLargeSize); - break; - default: - newImageSize = CGSizeZero; - break; - } - - if (CGSizeEqualToSize(newImageSize, CGSizeZero)) - { - // No resize to make - // Make sure the uploaded image orientation is up - if ([self isImageOrientationNotUpOrUndeterminedForImageData:imageData]) - { - UIImage *image = [UIImage imageWithData:imageData]; - convertedImage = [MXKTools forceImageOrientationUp:image]; - } - } - else - { - // Resize the image and set image in right orientation too - convertedImage = [MXKTools resizeImageWithData:imageData toFitInSize:newImageSize]; - } - - if (convertedImage) - { - if ([imageUTI isEqualToString:(__bridge NSString *)kUTTypePNG]) - { - imageData = UIImagePNGRepresentation(convertedImage); - } - else if ([imageUTI isEqualToString:(__bridge NSString *)kUTTypeJPEG]) - { - imageData = UIImageJPEGRepresentation(convertedImage, 0.9); - } - - imageSize = convertedImage.size; - } - else - { - imageSize = [self imageSizeFromImageData:imageData]; - } - } - else - { - 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:imageData withImageSize:imageSize mimeType:mimeType andThumbnail:thumbnail localEcho:nil success:^(NSString *eventId) { - if (successBlock) - { - successBlock(); - } - } failure:^(NSError *error) { - - NSLog(@"[ShareExtensionManager] sendImage failed."); - if (failureBlock) - { - failureBlock(error); + firstRequestError = error; } + dispatch_group_leave(requestsGroup); }]; - } + + index++; } + + dispatch_group_notify(requestsGroup, dispatch_get_main_queue(), ^{ + + if (firstRequestError) + { + if (failureBlock) + { + failureBlock(firstRequestError); + } + } + else + { + if (successBlock) + { + successBlock(); + } + } + }); } - (void)sendVideo:(NSURL *)videoLocalUrl toRoom:(MXRoom *)room successBlock:(dispatch_block_t)successBlock failureBlock:(void(^)(NSError *error))failureBlock