2017-08-17 15:28:08 +00:00
/ *
Copyright 2017 Aram Sargsyan
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : // www . apache . org / licenses / LICENSE -2.0
Unless required by applicable law or agreed to in writing , software
2017-09-08 15:02:45 +00:00
distributed under the License is distributed on an "AS IS" BASIS ,
2017-08-17 15:28:08 +00:00
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2017-08-10 22:38:47 +00:00
@ import MobileCoreServices ;
2021-10-14 09:57:32 +00:00
2019-04-02 12:42:43 +00:00
# import < mach / mach . h >
2017-08-10 22:38:47 +00:00
2021-10-14 09:57:32 +00:00
# import < MatrixKit / MatrixKit . h >
# import "ShareManager.h"
# import "ShareViewController.h"
# import "ShareDataSource.h"
2021-10-14 09:05:28 +00:00
# ifdef IS_SHARE _EXTENSION
# import "RiotShareExtension-Swift.h"
# else
# import "Riot-Swift.h"
# endif
2017-08-21 20:33:06 +00:00
2019-03-21 11:50:02 +00:00
static const CGFloat kLargeImageSizeMaxDimension = 2048.0 ;
2021-10-18 13:30:32 +00:00
static const CGSize kThumbnailSize = { 800.0 , 600.0 } ;
2019-03-21 11:50:02 +00:00
2017-08-16 20:01:54 +00:00
typedef NS_ENUM ( NSInteger , ImageCompressionMode )
{
ImageCompressionModeNone ,
ImageCompressionModeSmall ,
ImageCompressionModeMedium ,
ImageCompressionModeLarge
} ;
2021-10-14 09:57:32 +00:00
@ interface ShareManager ( ) < ShareViewControllerDelegate >
2021-10-14 09:05:28 +00:00
2021-10-15 10:09:11 +00:00
@ property ( nonatomic , strong , readonly ) id < ShareItemProviderProtocol > shareItemProvider ;
2021-10-14 11:35:36 +00:00
@ property ( nonatomic , strong , readonly ) ShareViewController * shareViewController ;
2017-09-08 15:02:45 +00:00
2021-10-15 10:09:11 +00:00
@ property ( nonatomic , strong , readonly ) NSMutableArray < NSData * > * pendingImages ;
@ property ( nonatomic , strong , readonly ) NSMutableDictionary < NSString * , NSNumber * > * imageUploadProgresses ;
2021-10-14 09:05:28 +00:00
@ property ( nonatomic , strong , readonly ) id < Configurable > configuration ;
2017-08-16 20:01:54 +00:00
2021-10-14 09:05:28 +00:00
@ property ( nonatomic , strong ) MXKAccount * userAccount ;
@ property ( nonatomic , strong ) MXFileStore * fileStore ;
2017-08-26 11:54:25 +00:00
2021-10-14 09:05:28 +00:00
@ property ( nonatomic , assign ) ImageCompressionMode imageCompressionMode ;
@ property ( nonatomic , assign ) CGFloat actualLargeSize ;
2017-08-16 20:01:54 +00:00
@ end
2017-08-10 22:38:47 +00:00
2021-10-14 09:57:32 +00:00
@ implementation ShareManager
2017-08-10 22:38:47 +00:00
2021-10-15 10:09:11 +00:00
- ( instancetype ) initWithShareItemProvider : ( id < ShareItemProviderProtocol > ) shareItemProvider
2021-10-18 13:30:32 +00:00
type : ( ShareManagerType ) type
2017-08-10 22:38:47 +00:00
{
2021-10-15 10:09:11 +00:00
if ( self = [ super init ] )
{
_shareItemProvider = shareItemProvider ;
2017-08-21 20:33:06 +00:00
2021-10-14 09:05:28 +00:00
_pendingImages = [ NSMutableArray array ] ;
_imageUploadProgresses = [ NSMutableDictionary dictionary ] ;
2017-08-22 15:56:30 +00:00
2021-10-14 09:05:28 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( onMediaLoaderStateDidChange : ) name : kMXMediaLoaderStateDidChangeNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( checkUserAccount ) name : kMXKAccountManagerDidRemoveAccountNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self selector : @ selector ( checkUserAccount ) name : NSExtensionHostWillEnterForegroundNotification object : nil ] ;
[ NSNotificationCenter . defaultCenter addObserver : self selector : @ selector ( didReceiveMemoryWarning : ) name : UIApplicationDidReceiveMemoryWarningNotification object : nil ] ;
2017-08-21 20:33:06 +00:00
2021-10-14 11:35:36 +00:00
_configuration = [ [ CommonConfiguration alloc ] init ] ;
2021-10-14 09:05:28 +00:00
[ _configuration setupSettings ] ;
2021-06-03 08:30:07 +00:00
2017-10-20 12:57:51 +00:00
// NSLog -> console . log file when not debugging the app
2021-06-03 08:30:07 +00:00
MXLogConfiguration * configuration = [ [ MXLogConfiguration alloc ] init ] ;
configuration . logLevel = MXLogLevelVerbose ;
configuration . logFilesSizeLimit = 0 ;
configuration . maxLogFilesCount = 10 ;
configuration . subLogName = @ "share" ;
// Redirect NSLogs to files only if we are not debugging
if ( ! isatty ( STDERR_FILENO ) ) {
configuration . redirectLogsToFiles = YES ;
2017-10-20 12:57:51 +00:00
}
2021-06-03 08:30:07 +00:00
[ MXLog configure : configuration ] ;
2017-09-08 15:02:45 +00:00
2021-10-18 13:30:32 +00:00
_shareViewController = [ [ ShareViewController alloc ] initWithType : ( type = = ShareManagerTypeForward ? ShareViewControllerTypeForward : ShareViewControllerTypeSend )
2021-10-14 09:05:28 +00:00
currentState : ShareViewControllerAccountStateNotConfigured ] ;
[ _shareViewController setDelegate : self ] ;
// Set up runtime language on each context update .
NSUserDefaults * sharedUserDefaults = [ MXKAppSettings standardAppSettings ] . sharedUserDefaults ;
NSString * language = [ sharedUserDefaults objectForKey : @ "appLanguage" ] ;
[ NSBundle mxk_setLanguage : language ] ;
[ NSBundle mxk_setFallbackLanguage : @ "en" ] ;
[ self checkUserAccount ] ;
2017-09-08 15:02:45 +00:00
}
2017-09-29 08:37:54 +00:00
2021-10-14 09:05:28 +00:00
return self ;
2017-09-08 15:02:45 +00:00
}
2017-08-14 11:25:02 +00:00
# pragma mark - Public
2021-10-14 09:05:28 +00:00
- ( UIViewController * ) mainViewController
2017-08-21 20:33:06 +00:00
{
2021-10-14 09:05:28 +00:00
return self . shareViewController ;
}
# pragma mark - ShareViewControllerDelegate
2021-10-18 13:30:32 +00:00
- ( void ) shareViewController : ( ShareViewController * ) shareViewController didRequestShareForRoomIdentifiers : ( NSSet < NSString * > * ) roomIdentifiers
2021-10-14 09:05:28 +00:00
{
MXSession * session = [ [ MXSession alloc ] initWithMatrixRestClient : [ [ MXRestClient alloc ] initWithCredentials : self . userAccount . mxCredentials andOnUnrecognizedCertificateBlock : nil ] ] ;
[ MXFileStore setPreloadOptions : 0 ] ;
2017-12-27 13:00:16 +00:00
2021-10-14 09:05:28 +00:00
MXWeakify ( session ) ;
[ session setStore : self . fileStore success : ^ {
MXStrongifyAndReturnIfNil ( session ) ;
2021-10-14 11:35:36 +00:00
session . crypto . warnOnUnknowDevices = NO ; // Do not warn for unknown devices . We have cross - signing now
2021-10-14 09:05:28 +00:00
2021-10-18 13:30:32 +00:00
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 ) {
2021-10-14 11:35:36 +00:00
[ self showFailureAlert : [ VectorL10n roomEventFailedToSend ] ] ;
2021-10-14 09:05:28 +00:00
} ] ;
2021-10-18 13:30:32 +00:00
2021-10-14 09:05:28 +00:00
} failure : ^ ( NSError * error ) {
2021-10-18 13:30:32 +00:00
MXLogError ( @ "[ShareManager] Failed preparing matrix session" ) ;
2021-10-14 09:05:28 +00:00
} ] ;
2017-08-21 20:33:06 +00:00
}
2021-10-14 09:05:28 +00:00
- ( void ) shareViewControllerDidRequestDismissal : ( ShareViewController * ) shareViewController
{
2021-10-14 11:35:36 +00:00
self . completionCallback ( ShareManagerResultCancelled ) ;
2021-10-14 09:05:28 +00:00
}
# pragma mark - Private
2021-10-18 13:30:32 +00:00
- ( void ) showFailureAlert : ( NSString * ) title
2017-08-10 22:38:47 +00:00
{
2021-10-18 13:30:32 +00:00
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 ) ;
}
} ] ;
2019-02-08 13:43:21 +00:00
2021-10-18 13:30:32 +00:00
[ 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 ] ;
2017-08-10 22:38:47 +00:00
2019-02-08 10:04:51 +00:00
__block NSError * firstRequestError = nil ;
2021-10-14 11:35:36 +00:00
dispatch_group _t dispatchGroup = dispatch_group _create ( ) ;
2019-02-08 10:04:51 +00:00
2021-10-18 13:30:32 +00:00
void ( ^ requestSuccess ) ( void ) = ^ ( ) {
dispatch_group _leave ( dispatchGroup ) ;
} ;
void ( ^ requestFailure ) ( NSError * ) = ^ ( NSError * requestError ) {
2019-02-08 10:04:51 +00:00
if ( requestError && ! firstRequestError )
{
firstRequestError = requestError ;
}
2021-10-14 11:35:36 +00:00
dispatch_group _leave ( dispatchGroup ) ;
2019-02-08 10:04:51 +00:00
} ;
2017-08-24 10:55:35 +00:00
2021-10-14 11:35:36 +00:00
MXWeakify ( self ) ;
2021-10-15 10:09:11 +00:00
for ( id < ShareItemProtocol > item in self . shareItemProvider . items )
2017-08-10 22:38:47 +00:00
{
2021-10-18 13:30:32 +00:00
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 ] ;
} ] ;
}
2021-10-15 10:09:11 +00:00
if ( item . type = = ShareItemTypeFileURL ) {
dispatch_group _enter ( dispatchGroup ) ;
[ self . shareItemProvider loadItem : item completion : ^ ( NSURL * url , NSError * error ) {
2021-10-18 13:30:32 +00:00
MXStrongifyAndReturnIfNil ( self ) ;
if ( error )
{
2021-10-15 10:09:11 +00:00
requestFailure ( error ) ;
return ;
}
2021-10-18 13:30:32 +00:00
[ self sendFileWithUrl : url toRooms : rooms success : requestSuccess failure : requestFailure ] ;
2021-10-15 10:09:11 +00:00
} ] ;
}
2021-10-18 13:30:32 +00:00
if ( item . type = = ShareItemTypeVideo || item . type = = ShareItemTypeMovie )
{
2021-10-15 10:09:11 +00:00
dispatch_group _enter ( dispatchGroup ) ;
2021-10-18 13:30:32 +00:00
[ self . shareItemProvider loadItem : item completion : ^ ( NSURL * videoLocalUrl , NSError * error ) {
MXStrongifyAndReturnIfNil ( self ) ;
if ( error )
{
2021-10-15 10:09:11 +00:00
requestFailure ( error ) ;
return ;
}
2021-10-18 13:30:32 +00:00
[ self sendVideo : videoLocalUrl toRooms : rooms success : requestSuccess failure : requestFailure ] ;
2021-10-15 10:09:11 +00:00
} ] ;
}
2021-10-18 13:30:32 +00:00
if ( item . type = = ShareItemTypeVoiceMessage )
2017-08-10 22:38:47 +00:00
{
2021-10-15 10:09:11 +00:00
dispatch_group _enter ( dispatchGroup ) ;
2021-10-18 13:30:32 +00:00
[ self . shareItemProvider loadItem : item completion : ^ ( NSURL * fileURL , NSError * error ) {
MXStrongifyAndReturnIfNil ( self ) ;
if ( error )
{
2021-10-15 10:09:11 +00:00
requestFailure ( error ) ;
return ;
}
2019-01-04 12:45:41 +00:00
2021-10-18 13:30:32 +00:00
[ self sendVoiceMessage : fileURL toRooms : rooms success : requestSuccess failure : requestFailure ] ;
2021-10-15 10:09:11 +00:00
} ] ;
}
2021-10-18 13:30:32 +00:00
2021-10-15 10:09:11 +00:00
if ( item . type = = ShareItemTypeImage )
{
dispatch_group _enter ( dispatchGroup ) ;
[ self . shareItemProvider loadItem : item completion : ^ ( id < NSSecureCoding > itemProviderItem , NSError * error ) {
2021-10-18 13:30:32 +00:00
MXStrongifyAndReturnIfNil ( self ) ;
if ( error )
{
2021-10-15 10:09:11 +00:00
requestFailure ( error ) ;
return ;
}
NSData * imageData ;
if ( [ ( NSObject * ) itemProviderItem isKindOfClass : [ NSData class ] ] )
{
imageData = ( NSData * ) itemProviderItem ;
}
else if ( [ ( NSObject * ) itemProviderItem isKindOfClass : [ NSURL class ] ] )
{
NSURL * imageURL = ( NSURL * ) itemProviderItem ;
imageData = [ NSData dataWithContentsOfURL : imageURL ] ;
}
else if ( [ ( NSObject * ) itemProviderItem isKindOfClass : [ UIImage class ] ] )
{
// An application can share directly an UIImage .
// The most common case is screenshot sharing without saving to file .
// As screenshot using PNG format when they are saved to file we also use PNG format when saving UIImage to NSData .
UIImage * image = ( UIImage * ) itemProviderItem ;
imageData = UIImagePNGRepresentation ( image ) ;
}
2021-10-18 13:30:32 +00:00
if ( ! imageData )
{
requestFailure ( error ) ;
return ;
}
2021-10-15 10:09:11 +00:00
2021-10-18 13:30:32 +00:00
if ( [ self . shareItemProvider areAllItemsImages ] )
2021-10-15 10:09:11 +00:00
{
2021-10-18 13:30:32 +00:00
[ self . pendingImages addObject : imageData ] ;
2021-10-15 10:09:11 +00:00
}
else
{
2021-10-18 13:30:32 +00:00
CGSize imageSize = [ self imageSizeFromImageData : imageData ] ;
self . imageCompressionMode = ImageCompressionModeNone ;
self . actualLargeSize = MAX ( imageSize . width , imageSize . height ) ;
[ self sendImageData : imageData toRooms : rooms success : requestSuccess failure : requestFailure ] ;
2021-10-15 10:09:11 +00:00
}
// Only prompt for image resize if all items are images
// Ignore showMediaCompressionPrompt setting due to memory constraints with full size images .
if ( [ self . shareItemProvider areAllItemsImages ] )
{
if ( [ self . shareItemProvider areAllItemsLoaded ] )
2021-10-14 11:35:36 +00:00
{
2021-10-15 10:09:11 +00:00
UIAlertController * compressionPrompt = [ self compressionPromptForPendingImagesWithShareBlock : ^ {
2021-10-18 13:30:32 +00:00
[ self sendImageDatas : self . pendingImages . copy toRooms : rooms success : requestSuccess failure : requestFailure ] ;
2021-10-15 10:09:11 +00:00
} ] ;
if ( compressionPrompt )
{
[ self presentCompressionPrompt : compressionPrompt ] ;
2021-10-14 09:05:28 +00:00
}
2021-10-14 11:35:36 +00:00
}
else
{
dispatch_group _leave ( dispatchGroup ) ;
}
2021-10-15 10:09:11 +00:00
}
} ] ;
}
2017-08-10 22:38:47 +00:00
}
2019-02-08 10:04:51 +00:00
2021-10-14 11:35:36 +00:00
dispatch_group _notify ( dispatchGroup , dispatch_get _main _queue ( ) , ^ {
2019-02-08 10:04:51 +00:00
[ self resetPendingData ] ;
if ( firstRequestError )
{
2021-10-14 11:35:36 +00:00
failure ( firstRequestError ) ;
2019-02-08 10:04:51 +00:00
}
else
{
2021-10-18 13:30:32 +00:00
success ( ) ;
2019-02-08 10:04:51 +00:00
}
} ) ;
2017-08-10 22:38:47 +00:00
}
2021-10-14 09:05:28 +00:00
- ( void ) checkUserAccount
2017-08-10 22:38:47 +00:00
{
2021-10-14 09:05:28 +00:00
// Force account manager to reload account from the local storage .
[ [ MXKAccountManager sharedManager ] forceReloadAccounts ] ;
if ( self . userAccount )
2017-08-17 22:27:56 +00:00
{
2021-10-14 09:05:28 +00:00
// Check whether the used account is still the first active one
MXKAccount * firstAccount = [ MXKAccountManager sharedManager ] . activeAccounts . firstObject ;
// Compare the access token
if ( ! firstAccount || ! [ self . userAccount . mxCredentials . accessToken isEqualToString : firstAccount . mxCredentials . accessToken ] )
{
// Remove this account
self . userAccount = nil ;
}
2017-08-17 22:27:56 +00:00
}
2021-10-14 09:05:28 +00:00
if ( ! self . userAccount )
2017-08-17 22:27:56 +00:00
{
2021-10-14 09:05:28 +00:00
// We consider the first enabled account .
// TODO : Handle multiple accounts
self . userAccount = [ MXKAccountManager sharedManager ] . activeAccounts . firstObject ;
2017-08-17 22:27:56 +00:00
}
2017-08-25 09:55:37 +00:00
2021-10-14 09:05:28 +00:00
// Reset the file store to reload the room data .
if ( _fileStore )
{
[ _fileStore close ] ;
_fileStore = nil ;
}
2019-01-04 12:57:35 +00:00
2021-10-14 09:05:28 +00:00
if ( self . userAccount )
{
_fileStore = [ [ MXFileStore alloc ] initWithCredentials : self . userAccount . mxCredentials ] ;
2021-10-18 13:30:32 +00:00
ShareDataSource * roomDataSource = [ [ ShareDataSource alloc ] initWithFileStore : _fileStore
credentials : self . userAccount . mxCredentials ] ;
2021-10-14 09:05:28 +00:00
[ self . shareViewController configureWithState : ShareViewControllerAccountStateConfigured
2021-10-18 13:30:32 +00:00
roomDataSource : roomDataSource ] ;
2021-10-14 09:05:28 +00:00
} else {
[ self . shareViewController configureWithState : ShareViewControllerAccountStateNotConfigured
2021-10-18 13:30:32 +00:00
roomDataSource : nil ] ;
2021-10-14 09:05:28 +00:00
}
2017-08-10 22:38:47 +00:00
}
2017-11-09 14:59:42 +00:00
- ( void ) resetPendingData
2017-09-15 15:17:03 +00:00
{
2017-11-09 14:59:42 +00:00
[ self . pendingImages removeAllObjects ] ;
[ self . imageUploadProgresses removeAllObjects ] ;
2017-09-15 15:17:03 +00:00
}
2019-01-04 12:52:26 +00:00
- ( BOOL ) isAPendingImageNotOrientedUp
{
BOOL isAPendingImageNotOrientedUp = NO ;
for ( NSData * imageData in self . pendingImages )
{
2019-02-06 15:05:36 +00:00
if ( [ self isImageOrientationNotUpOrUndeterminedForImageData : imageData ] )
2019-01-04 12:52:26 +00:00
{
2019-02-06 15:05:36 +00:00
isAPendingImageNotOrientedUp = YES ;
break ;
2019-01-04 12:52:26 +00:00
}
}
return isAPendingImageNotOrientedUp ;
2017-08-25 09:55:37 +00:00
}
2019-01-04 12:52:26 +00:00
// TODO : When select multiple images :
// - Enhance prompt to display sum of all file sizes for each compression .
// - Find a way to choose compression sizes for all images .
- ( UIAlertController * ) compressionPromptForPendingImagesWithShareBlock : ( void ( ^ ) ( void ) ) shareBlock
2017-08-16 20:01:54 +00:00
{
2019-01-04 12:52:26 +00:00
if ( ! self . pendingImages . count )
{
return nil ;
}
BOOL isAPendingImageNotOrientedUp = [ self isAPendingImageNotOrientedUp ] ;
NSData * firstImageData = self . pendingImages . firstObject ;
UIImage * firstImage = [ UIImage imageWithData : firstImageData ] ;
2017-08-16 20:01:54 +00:00
2019-01-04 12:52:26 +00:00
MXKImageCompressionSizes compressionSizes = [ MXKTools availableCompressionSizesForImage : firstImage originalFileSize : firstImageData . length ] ;
2017-08-16 20:01:54 +00:00
2021-10-14 11:35:36 +00:00
if ( compressionSizes . small . fileSize = = 0 && compressionSizes . medium . fileSize = = 0 && compressionSizes . large . fileSize = = 0 )
2017-08-16 20:01:54 +00:00
{
2021-10-14 11:35:36 +00:00
if ( isAPendingImageNotOrientedUp && self . pendingImages . count > 1 )
2017-08-16 20:01:54 +00:00
{
2021-10-14 11:35:36 +00:00
self . imageCompressionMode = ImageCompressionModeSmall ;
2017-08-16 20:01:54 +00:00
}
2021-10-14 11:35:36 +00:00
else
2017-08-16 20:01:54 +00:00
{
2021-10-14 11:35:36 +00:00
self . imageCompressionMode = ImageCompressionModeNone ;
2017-08-16 20:01:54 +00:00
}
2021-10-14 11:35:36 +00:00
MXLogDebug ( @ "[ShareManager] Send %lu image(s) without compression prompt using compression mode: %ld" , ( unsigned long ) self . pendingImages . count , ( long ) self . imageCompressionMode ) ;
shareBlock ( ) ;
return nil ;
}
UIAlertController * compressionPrompt = [ UIAlertController alertControllerWithTitle : [ MatrixKitL10n attachmentSizePromptTitle ]
message : [ MatrixKitL10n attachmentSizePromptMessage ]
preferredStyle : UIAlertControllerStyleActionSheet ] ;
if ( compressionSizes . small . fileSize )
{
NSString * title = [ MatrixKitL10n attachmentSmall : [ MXTools fileSizeToString : compressionSizes . small . fileSize ] ] ;
MXWeakify ( self ) ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * action ) {
MXStrongifyAndReturnIfNil ( self ) ;
2017-08-16 20:01:54 +00:00
2021-10-14 11:35:36 +00:00
self . imageCompressionMode = ImageCompressionModeSmall ;
[ self logCompressionSizeChoice : compressionSizes . large ] ;
2017-08-16 20:01:54 +00:00
2021-10-14 11:35:36 +00:00
shareBlock ( ) ;
} ] ] ;
}
if ( compressionSizes . medium . fileSize )
{
NSString * title = [ MatrixKitL10n attachmentMedium : [ MXTools fileSizeToString : compressionSizes . medium . fileSize ] ] ;
2017-08-16 20:01:54 +00:00
2021-10-14 11:35:36 +00:00
MXWeakify ( self ) ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * action ) {
MXStrongifyAndReturnIfNil ( self ) ;
2017-08-24 10:59:46 +00:00
2021-10-14 11:35:36 +00:00
self . imageCompressionMode = ImageCompressionModeMedium ;
[ self logCompressionSizeChoice : compressionSizes . large ] ;
2017-08-24 10:59:46 +00:00
2021-10-14 11:35:36 +00:00
shareBlock ( ) ;
} ] ] ;
}
// Do not offer the possibility to resize an image with a dimension above kLargeImageSizeMaxDimension , to prevent the risk of memory limit exception .
// TODO : Remove this condition when issue https : // github . com / vector - im / riot - ios / issues / 2341 will be fixed .
if ( compressionSizes . large . fileSize && ( MAX ( compressionSizes . large . imageSize . width , compressionSizes . large . imageSize . height ) <= kLargeImageSizeMaxDimension ) )
{
NSString * title = [ MatrixKitL10n attachmentLarge : [ MXTools fileSizeToString : compressionSizes . large . fileSize ] ] ;
2017-08-16 20:01:54 +00:00
2021-10-14 11:35:36 +00:00
MXWeakify ( self ) ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * action ) {
MXStrongifyAndReturnIfNil ( self ) ;
self . imageCompressionMode = ImageCompressionModeLarge ;
self . actualLargeSize = compressionSizes . actualLargeSize ;
[ self logCompressionSizeChoice : compressionSizes . large ] ;
shareBlock ( ) ;
} ] ] ;
2017-08-16 20:01:54 +00:00
}
2021-10-14 11:35:36 +00:00
// To limit memory consumption , we suggest the original resolution only if the image orientation is up , or if the image size is moderate
if ( ! isAPendingImageNotOrientedUp || ! compressionSizes . large . fileSize )
2017-08-24 10:59:46 +00:00
{
2021-10-14 11:35:36 +00:00
NSString * fileSizeString = [ MXTools fileSizeToString : compressionSizes . original . fileSize ] ;
2019-01-04 12:52:26 +00:00
2021-10-14 11:35:36 +00:00
NSString * title = [ MatrixKitL10n attachmentOriginal : fileSizeString ] ;
2019-04-02 13:01:50 +00:00
2021-10-14 11:35:36 +00:00
MXWeakify ( self ) ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * action ) {
MXStrongifyAndReturnIfNil ( self ) ;
self . imageCompressionMode = ImageCompressionModeNone ;
[ self logCompressionSizeChoice : compressionSizes . large ] ;
2017-08-24 10:59:46 +00:00
shareBlock ( ) ;
2021-10-14 11:35:36 +00:00
} ] ] ;
2017-08-24 10:59:46 +00:00
}
2017-08-16 20:01:54 +00:00
2021-10-14 11:35:36 +00:00
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : [ MatrixKitL10n cancel ]
style : UIAlertActionStyleCancel
handler : nil ] ] ;
2017-08-16 20:01:54 +00:00
return compressionPrompt ;
}
2021-10-18 13:30:32 +00:00
- ( void ) didStartSending
2017-08-20 21:39:08 +00:00
{
2021-10-14 09:05:28 +00:00
[ self . shareViewController showProgressIndicator ] ;
2017-08-20 21:39:08 +00:00
}
2019-02-06 15:05:36 +00:00
- ( NSString * ) utiFromImageData : ( NSData * ) imageData
{
CGImageSourceRef imageSource = CGImageSourceCreateWithData ( ( CFDataRef ) imageData , NULL ) ;
NSString * uti = ( NSString * ) CGImageSourceGetType ( imageSource ) ;
CFRelease ( imageSource ) ;
return uti ;
}
- ( NSString * ) mimeTypeFromUTI : ( NSString * ) uti
{
return ( __bridge _transfer NSString * ) UTTypeCopyPreferredTagWithClass ( ( __bridge CFStringRef ) uti , kUTTagClassMIMEType ) ;
}
- ( BOOL ) isResizingSupportedForImageData : ( NSData * ) imageData
{
NSString * imageUTI = [ self utiFromImageData : imageData ] ;
return [ self isResizingSupportedForUTI : imageUTI ] ;
}
- ( BOOL ) isResizingSupportedForUTI : ( NSString * ) imageUTI
{
if ( [ imageUTI isEqualToString : ( __bridge NSString * ) kUTTypePNG ] || [ imageUTI isEqualToString : ( __bridge NSString * ) kUTTypeJPEG ] )
{
return YES ;
}
return NO ;
}
- ( CGSize ) imageSizeFromImageData : ( NSData * ) imageData
{
CGFloat width = 0.0 f ;
CGFloat height = 0.0 f ;
CGImageSourceRef imageSource = CGImageSourceCreateWithData ( ( CFDataRef ) imageData , NULL ) ;
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex ( imageSource , 0 , NULL ) ;
CFRelease ( imageSource ) ;
if ( imageProperties ! = NULL )
{
CFNumberRef widthNumber = CFDictionaryGetValue ( imageProperties , kCGImagePropertyPixelWidth ) ;
CFNumberRef heightNumber = CFDictionaryGetValue ( imageProperties , kCGImagePropertyPixelHeight ) ;
CFNumberRef orientationNumber = CFDictionaryGetValue ( imageProperties , kCGImagePropertyOrientation ) ;
if ( widthNumber ! = NULL )
{
CFNumberGetValue ( widthNumber , kCFNumberCGFloatType , & width ) ;
}
if ( heightNumber ! = NULL )
{
CFNumberGetValue ( heightNumber , kCFNumberCGFloatType , & height ) ;
}
// Check orientation and flip size if required
if ( orientationNumber ! = NULL )
{
int orientation ;
CFNumberGetValue ( orientationNumber , kCFNumberIntType , & orientation ) ;
// For orientation from kCGImagePropertyOrientationLeftMirrored to kCGImagePropertyOrientationLeft flip size
if ( orientation >= 5 )
{
CGFloat tempWidth = width ;
width = height ;
height = tempWidth ;
}
}
CFRelease ( imageProperties ) ;
}
return CGSizeMake ( width , height ) ;
}
- ( NSNumber * ) cgImageimageOrientationNumberFromImageData : ( NSData * ) imageData
{
NSNumber * orientationNumber ;
CGImageSourceRef imageSource = CGImageSourceCreateWithData ( ( CFDataRef ) imageData , NULL ) ;
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex ( imageSource , 0 , NULL ) ;
CFRelease ( imageSource ) ;
if ( imageProperties ! = NULL )
{
CFNumberRef orientationNum = CFDictionaryGetValue ( imageProperties , kCGImagePropertyOrientation ) ;
// Check orientation and flip size if required
if ( orientationNum ! = NULL )
{
orientationNumber = ( __bridge NSNumber * ) orientationNum ;
}
CFRelease ( imageProperties ) ;
}
return orientationNumber ;
}
- ( BOOL ) isImageOrientationNotUpOrUndeterminedForImageData : ( NSData * ) imageData
{
BOOL isImageNotOrientedUp = YES ;
NSNumber * cgImageOrientationNumber = [ self cgImageimageOrientationNumberFromImageData : imageData ] ;
if ( cgImageOrientationNumber && cgImageOrientationNumber . unsignedIntegerValue = = ( NSUInteger ) kCGImagePropertyOrientationUp )
{
isImageNotOrientedUp = NO ;
}
return isImageNotOrientedUp ;
}
2019-04-02 13:01:50 +00:00
- ( void ) logCompressionSizeChoice : ( MXKImageCompressionSize ) compressionSize
{
NSString * fileSize = [ MXTools fileSizeToString : compressionSize . fileSize round : NO ] ;
NSUInteger imageWidth = compressionSize . imageSize . width ;
NSUInteger imageHeight = compressionSize . imageSize . height ;
2021-10-14 09:57:32 +00:00
MXLogDebug ( @ "[ShareManager] User choose image compression with output size %lu x %lu (output file size: %@)" , ( unsigned long ) imageWidth , ( unsigned long ) imageHeight , fileSize ) ;
MXLogDebug ( @ "[ShareManager] Number of images to send: %lu" , ( unsigned long ) self . pendingImages . count ) ;
2019-04-02 13:01:50 +00:00
}
2019-04-02 12:42:43 +00:00
// Log memory usage .
// NOTE : This result may not be reliable for all iOS versions ( see https : // forums . developer . apple . com / thread / 64665 for more information ) .
- ( void ) logMemoryUsage
{
struct task_basic _info basicInfo ;
mach_msg _type _number _t size = TASK_BASIC _INFO _COUNT ;
kern_return _t kerr = task_info ( mach_task _self ( ) ,
TASK_BASIC _INFO ,
( task_info _t ) & basicInfo ,
& size ) ;
vm_size _t memoryUsedInBytes = basicInfo . resident_size ;
CGFloat memoryUsedInMegabytes = memoryUsedInBytes / ( 1024 * 1024 ) ;
if ( kerr = = KERN_SUCCESS )
{
2021-10-14 09:57:32 +00:00
MXLogDebug ( @ "[ShareManager] Memory in use (in MB): %f" , memoryUsedInMegabytes ) ;
2019-04-02 12:42:43 +00:00
}
else
{
2021-10-14 09:57:32 +00:00
MXLogDebug ( @ "[ShareManager] Error with task_info(): %s" , mach_error _string ( kerr ) ) ;
2019-04-02 12:42:43 +00:00
}
}
2021-10-14 09:05:28 +00:00
- ( void ) presentCompressionPrompt : ( UIAlertController * ) compressionPrompt
{
2021-10-18 13:30:32 +00:00
[ compressionPrompt popoverPresentationController ] . sourceView = self . mainViewController . view ;
[ compressionPrompt popoverPresentationController ] . sourceRect = self . mainViewController . view . frame ;
[ self . mainViewController presentViewController : compressionPrompt animated : YES completion : nil ] ;
2021-10-14 09:05:28 +00:00
}
2019-04-02 12:42:43 +00:00
2017-08-16 20:01:54 +00:00
# pragma mark - Notifications
2018-11-10 13:28:08 +00:00
- ( void ) onMediaLoaderStateDidChange : ( NSNotification * ) notification
2017-08-16 20:01:54 +00:00
{
2018-11-10 13:28:08 +00:00
MXMediaLoader * loader = ( MXMediaLoader * ) notification . object ;
// Consider only upload progress
switch ( loader . state ) {
case MXMediaLoaderStateUploadInProgress :
2017-08-22 15:52:32 +00:00
{
2018-11-10 13:28:08 +00:00
self . imageUploadProgresses [ loader . uploadId ] = ( NSNumber * ) loader . statisticsDict [ kMXMediaLoaderProgressValueKey ] ;
2021-10-14 09:05:28 +00:00
const NSInteger totalImagesCount = self . pendingImages . count ;
CGFloat totalProgress = 0.0 ;
for ( NSNumber * progress in self . imageUploadProgresses . allValues )
2018-11-10 13:28:08 +00:00
{
2021-10-14 09:05:28 +00:00
totalProgress + = progress . floatValue / totalImagesCount ;
2018-11-10 13:28:08 +00:00
}
2021-10-14 09:05:28 +00:00
[ self . shareViewController setProgress : totalProgress ] ;
2018-11-10 13:28:08 +00:00
break ;
2017-08-22 15:52:32 +00:00
}
2018-11-10 13:28:08 +00:00
default :
break ;
2017-08-16 20:01:54 +00:00
}
}
2019-03-11 17:04:42 +00:00
- ( void ) didReceiveMemoryWarning : ( NSNotification * ) notification
{
2021-10-14 09:57:32 +00:00
MXLogDebug ( @ "[ShareManager] Did receive memory warning" ) ;
2019-04-02 12:42:43 +00:00
[ self logMemoryUsage ] ;
2019-03-11 17:04:42 +00:00
}
2017-08-14 11:25:02 +00:00
# pragma mark - Sharing
2021-10-15 10:09:11 +00:00
- ( void ) sendText : ( NSString * ) text
2021-10-18 13:30:32 +00:00
toRooms : ( NSArray < MXRoom * > * ) rooms
2021-10-15 10:09:11 +00:00
success : ( dispatch_block _t ) success
failure : ( void ( ^ ) ( NSError * error ) ) failure
2017-08-14 11:25:02 +00:00
{
2021-10-18 13:30:32 +00:00
[ self didStartSending ] ;
2017-08-14 11:25:02 +00:00
if ( ! text )
{
2021-10-15 10:09:11 +00:00
MXLogError ( @ "[ShareManager] Invalid text." ) ;
failure ( nil ) ;
2017-08-14 11:25:02 +00:00
return ;
}
2017-08-17 15:28:08 +00:00
2021-10-18 13:30:32 +00:00
__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 ( ) ;
}
} ) ;
2017-08-14 11:25:02 +00:00
}
2021-10-18 13:30:32 +00:00
- ( void ) sendFileWithUrl : ( NSURL * ) fileUrl
toRooms : ( NSArray < MXRoom * > * ) rooms
success : ( dispatch_block _t ) success
failure : ( void ( ^ ) ( NSError * error ) ) failure
2017-08-14 11:25:02 +00:00
{
2021-10-18 13:30:32 +00:00
[ self didStartSending ] ;
2017-08-14 11:25:02 +00:00
if ( ! fileUrl )
{
2021-10-15 10:09:11 +00:00
MXLogError ( @ "[ShareManager] Invalid file url." ) ;
failure ( nil ) ;
2017-08-14 11:25:02 +00:00
return ;
}
2017-08-21 22:31:43 +00:00
NSString * mimeType ;
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag ( kUTTagClassFilenameExtension , ( __bridge CFStringRef ) [ fileUrl pathExtension ] , NULL ) ;
2019-02-06 15:05:36 +00:00
mimeType = [ self mimeTypeFromUTI : ( __bridge NSString * ) uti ] ;
2017-08-21 22:31:43 +00:00
CFRelease ( uti ) ;
2017-08-17 15:28:08 +00:00
2021-10-18 13:30:32 +00:00
__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 ( ) ;
}
} ) ;
2017-08-14 11:25:02 +00:00
}
2021-10-15 10:09:11 +00:00
- ( void ) sendImageData : ( NSData * ) imageData
2021-10-18 13:30:32 +00:00
toRooms : ( NSArray < MXRoom * > * ) rooms
2021-10-15 10:09:11 +00:00
success : ( dispatch_block _t ) success
failure : ( void ( ^ ) ( NSError * error ) ) failure
2017-08-14 11:25:02 +00:00
{
2021-10-18 13:30:32 +00:00
[ self didStartSending ] ;
2019-02-08 13:43:21 +00:00
NSString * imageUTI ;
NSString * mimeType ;
if ( ! mimeType )
{
imageUTI = [ self utiFromImageData : imageData ] ;
if ( imageUTI )
{
mimeType = [ self mimeTypeFromUTI : imageUTI ] ;
}
}
if ( ! mimeType )
{
2021-10-18 13:30:32 +00:00
MXLogError ( @ "[ShareManager] sendImage failed. Cannot determine MIME type ." ) ;
2021-10-15 10:09:11 +00:00
if ( failure )
2019-01-04 12:55:46 +00:00
{
2021-10-15 10:09:11 +00:00
failure ( nil ) ;
2019-01-04 12:55:46 +00:00
}
return ;
}
2019-02-08 13:43:21 +00:00
CGSize imageSize ;
NSData * finalImageData ;
2017-11-09 14:59:42 +00:00
2019-02-08 13:43:21 +00:00
// Only resize JPEG or PNG files
if ( [ self isResizingSupportedForUTI : imageUTI ] )
2017-08-14 11:25:02 +00:00
{
2019-02-08 13:43:21 +00:00
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 ) )
2017-08-14 11:25:02 +00:00
{
2019-02-08 13:43:21 +00:00
// No resize to make
// Make sure the uploaded image orientation is up
if ( [ self isImageOrientationNotUpOrUndeterminedForImageData : imageData ] )
2017-11-09 14:59:42 +00:00
{
2019-02-08 13:43:21 +00:00
UIImage * image = [ UIImage imageWithData : imageData ] ;
convertedImage = [ MXKTools forceImageOrientationUp : image ] ;
2017-11-09 14:59:42 +00:00
}
2019-02-08 13:43:21 +00:00
}
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 ] )
2017-08-22 15:52:32 +00:00
{
2019-02-08 13:43:21 +00:00
finalImageData = UIImagePNGRepresentation ( convertedImage ) ;
2017-08-22 15:52:32 +00:00
}
2019-02-08 13:43:21 +00:00
else if ( [ imageUTI isEqualToString : ( __bridge NSString * ) kUTTypeJPEG ] )
2019-01-04 12:55:46 +00:00
{
2019-02-08 13:43:21 +00:00
finalImageData = UIImageJPEGRepresentation ( convertedImage , 0.9 ) ;
2019-01-04 12:55:46 +00:00
}
2017-08-22 15:52:32 +00:00
2019-02-08 13:43:21 +00:00
imageSize = convertedImage . size ;
}
else
{
finalImageData = imageData ;
imageSize = [ self imageSizeFromImageData : imageData ] ;
}
}
else
{
finalImageData = imageData ;
imageSize = [ self imageSizeFromImageData : imageData ] ;
}
2021-10-18 13:30:32 +00:00
__block NSError * error = nil ;
dispatch_group _t dispatchGroup = dispatch_group _create ( ) ;
for ( MXRoom * room in rooms ) {
2019-02-06 15:05:36 +00:00
2021-10-18 13:30:32 +00:00
UIImage * thumbnail = nil ;
if ( room . summary . isEncrypted ) // Thumbnail is useful only in case of encrypted room
{
thumbnail = [ MXKTools resizeImageWithData : imageData toFitInSize : kThumbnailSize ] ;
2019-02-08 13:43:21 +00:00
}
2021-10-18 13:30:32 +00:00
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 ) ;
} ] ;
2019-02-08 13:43:21 +00:00
}
2021-10-18 13:30:32 +00:00
dispatch_group _notify ( dispatchGroup , dispatch_get _main _queue ( ) , ^ {
if ( error ) {
failure ( error ) ;
} else {
2021-10-15 10:09:11 +00:00
success ( ) ;
2019-01-04 12:55:46 +00:00
}
2019-02-08 13:43:21 +00:00
} ) ;
2017-08-14 11:25:02 +00:00
}
2017-08-22 15:52:32 +00:00
@ end