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
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2017-08-10 22:38:47 +00:00
# import "ShareExtensionManager.h"
2017-08-16 20:01:54 +00:00
# import "MXKPieChartHUD.h"
2017-08-10 22:38:47 +00:00
@ import MobileCoreServices ;
2017-08-22 15:52:32 +00:00
# import "objc/runtime.h"
2017-08-10 22:38:47 +00:00
2017-08-21 20:33:06 +00:00
NSString * const kShareExtensionManagerDidChangeMXSessionNotification = @ "kShareExtensionManagerDidChangeMXSessionNotification" ;
2017-08-16 20:01:54 +00:00
typedef NS_ENUM ( NSInteger , ImageCompressionMode )
{
ImageCompressionModeNone ,
ImageCompressionModeSmall ,
ImageCompressionModeMedium ,
ImageCompressionModeLarge
} ;
@ interface ShareExtensionManager ( )
2017-08-21 20:33:06 +00:00
// The current user account
@ property ( nonatomic ) MXKAccount * userAccount ;
2017-08-22 15:52:32 +00:00
@ property NSMutableArray < NSData * > * pendingImages ;
@ property NSMutableDictionary < NSString * , NSNumber * > * imageUploadProgresses ;
2017-08-16 20:01:54 +00:00
@ property ImageCompressionMode imageCompressionMode ;
@ property CGFloat actualLargeSize ;
@ end
2017-08-10 22:38:47 +00:00
@ implementation ShareExtensionManager
# pragma mark - Lifecycle
+ ( instancetype ) sharedManager
{
static ShareExtensionManager * sharedInstance = nil ;
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
2017-08-21 20:33:06 +00:00
2017-08-10 22:38:47 +00:00
sharedInstance = [ [ self alloc ] init ] ;
2017-08-21 20:33:06 +00:00
2017-08-22 15:52:32 +00:00
sharedInstance . pendingImages = [ NSMutableArray array ] ;
sharedInstance . imageUploadProgresses = [ NSMutableDictionary dictionary ] ;
2017-08-22 15:56:30 +00:00
2017-08-16 20:01:54 +00:00
[ [ NSNotificationCenter defaultCenter ] addObserver : sharedInstance selector : @ selector ( onMediaUploadProgress : ) name : kMXMediaUploadProgressNotification object : nil ] ;
2017-08-21 20:33:06 +00:00
// Add observer to handle logout
[ [ NSNotificationCenter defaultCenter ] addObserver : sharedInstance selector : @ selector ( checkUserAccount ) name : kMXKAccountManagerDidRemoveAccountNotification object : nil ] ;
// Add observer on the Extension host
[ [ NSNotificationCenter defaultCenter ] addObserver : sharedInstance selector : @ selector ( checkUserAccount ) name : NSExtensionHostWillEnterForegroundNotification object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : sharedInstance selector : @ selector ( suspendSession ) name : NSExtensionHostDidEnterBackgroundNotification object : nil ] ;
// Apply the application group
[ MXKAppSettings standardAppSettings ] . applicationGroup = @ "group.im.vector" ;
2017-08-10 22:38:47 +00:00
} ) ;
return sharedInstance ;
}
2017-08-21 20:33:06 +00:00
- ( void ) checkUserAccount
{
// Force account manager to reload account from the local storage .
[ [ MXKAccountManager sharedManager ] forceReloadAccounts ] ;
if ( self . userAccount )
{
// 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 closeSession : YES ] ;
self . userAccount = nil ;
_mxSession = nil ;
// Post notification
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kShareExtensionManagerDidChangeMXSessionNotification object : _mxSession userInfo : nil ] ;
}
}
if ( self . userAccount )
{
// Resume the matrix session
[ self . userAccount resume ] ;
}
else
{
// Prepare a new session if a new account is available .
[ self prepareSession ] ;
}
}
- ( void ) prepareSession
{
// We consider the first enabled account .
// TODO : Handle multiple accounts
self . userAccount = [ MXKAccountManager sharedManager ] . activeAccounts . firstObject ;
if ( self . userAccount )
{
NSLog ( @ "[ShareExtensionManager] openSession for %@ account" , self . userAccount . mxCredentials . userId ) ;
// Use MXFileStore as MXStore to permanently store events .
[ self . userAccount openSessionWithStore : [ [ MXFileStore alloc ] init ] ] ;
_mxSession = self . userAccount . mxSession ;
// Post notification
[ [ NSNotificationCenter defaultCenter ] postNotificationName : kShareExtensionManagerDidChangeMXSessionNotification object : _mxSession userInfo : nil ] ;
}
}
- ( void ) suspendSession
{
[ self . userAccount pauseInBackgroundTask ] ;
}
2017-08-14 11:25:02 +00:00
# pragma mark - Public
2017-08-21 20:33:06 +00:00
- ( void ) setShareExtensionContext : ( NSExtensionContext * ) shareExtensionContext
{
_shareExtensionContext = shareExtensionContext ;
// Prepare or resume the matrix session .
[ self checkUserAccount ] ;
}
2017-08-10 22:38:47 +00:00
- ( void ) sendContentToRoom : ( MXRoom * ) room failureBlock : ( void ( ^ ) ( ) ) failureBlock
{
NSString * UTTypeText = ( __bridge NSString * ) kUTTypeText ;
NSString * UTTypeURL = ( __bridge NSString * ) kUTTypeURL ;
NSString * UTTypeImage = ( __bridge NSString * ) kUTTypeImage ;
NSString * UTTypeVideo = ( __bridge NSString * ) kUTTypeVideo ;
2017-08-14 11:25:02 +00:00
NSString * UTTypeFileUrl = ( __bridge NSString * ) kUTTypeFileURL ;
NSString * UTTypeMovie = ( __bridge NSString * ) kUTTypeMovie ;
2017-08-10 22:38:47 +00:00
2017-08-17 15:28:08 +00:00
__weak typeof ( self ) weakSelf = self ;
2017-08-16 20:01:54 +00:00
2017-08-24 10:55:35 +00:00
[ self . pendingImages removeAllObjects ] ;
2017-08-10 22:38:47 +00:00
for ( NSExtensionItem * item in self . shareExtensionContext . inputItems )
{
for ( NSItemProvider * itemProvider in item . attachments )
{
2017-08-14 11:25:02 +00:00
if ( [ itemProvider hasItemConformingToTypeIdentifier : UTTypeFileUrl ] )
{
[ itemProvider loadItemForTypeIdentifier : UTTypeFileUrl options : nil completionHandler : ^ ( NSURL * fileUrl , NSError * _Null _unspecified error ) {
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
[ self sendFileWithUrl : fileUrl toRoom : room extensionItem : item failureBlock : failureBlock ] ;
}
2017-08-14 11:25:02 +00:00
} ] ;
}
else if ( [ itemProvider hasItemConformingToTypeIdentifier : UTTypeText ] )
2017-08-10 22:38:47 +00:00
{
[ itemProvider loadItemForTypeIdentifier : UTTypeText options : nil completionHandler : ^ ( NSString * text , NSError * _Null _unspecified error ) {
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
[ self sendText : text toRoom : room extensionItem : item failureBlock : failureBlock ] ;
}
2017-08-10 22:38:47 +00:00
} ] ;
}
else if ( [ itemProvider hasItemConformingToTypeIdentifier : UTTypeURL ] )
{
[ itemProvider loadItemForTypeIdentifier : UTTypeURL options : nil completionHandler : ^ ( NSURL * url , NSError * _Null _unspecified error ) {
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
[ self sendText : url . absoluteString toRoom : room extensionItem : item failureBlock : failureBlock ] ;
}
2017-08-10 22:38:47 +00:00
} ] ;
}
else if ( [ itemProvider hasItemConformingToTypeIdentifier : UTTypeImage ] )
{
2017-08-22 15:52:32 +00:00
itemProvider . isLoaded = NO ;
2017-08-10 22:38:47 +00:00
[ itemProvider loadItemForTypeIdentifier : UTTypeImage options : nil completionHandler : ^ ( NSData * imageData , NSError * _Null _unspecified error )
{
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
2017-08-22 15:52:32 +00:00
itemProvider . isLoaded = YES ;
[ self . pendingImages addObject : imageData ] ;
if ( [ self areAttachmentsFullyLoaded ] )
{
UIImage * firstImage = [ UIImage imageWithData : self . pendingImages . firstObject ] ;
UIAlertController * compressionPrompt = [ self compressionPromptForImage : firstImage shareBlock : ^ {
2017-08-24 22:26:53 +00:00
[ self sendImages : self . pendingImages withProviders : item . attachments toRoom : room extensionItem : item failureBlock : failureBlock ] ;
2017-08-22 15:52:32 +00:00
} ] ;
[ self . delegate shareExtensionManager : self showImageCompressionPrompt : compressionPrompt ] ;
}
2017-08-17 15:28:08 +00:00
}
2017-08-10 22:38:47 +00:00
} ] ;
}
else if ( [ itemProvider hasItemConformingToTypeIdentifier : UTTypeVideo ] )
{
[ itemProvider loadItemForTypeIdentifier : UTTypeVideo options : nil completionHandler : ^ ( NSURL * videoLocalUrl , NSError * _Null _unspecified error )
{
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
[ self sendVideo : videoLocalUrl toRoom : room extensionItem : item failureBlock : failureBlock ] ;
}
2017-08-14 11:25:02 +00:00
} ] ;
}
else if ( [ itemProvider hasItemConformingToTypeIdentifier : UTTypeMovie ] )
{
[ itemProvider loadItemForTypeIdentifier : UTTypeMovie options : nil completionHandler : ^ ( NSURL * videoLocalUrl , NSError * _Null _unspecified error )
{
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
[ self sendVideo : videoLocalUrl toRoom : room extensionItem : item failureBlock : failureBlock ] ;
}
2017-08-10 22:38:47 +00:00
} ] ;
}
}
}
}
2017-08-16 20:01:54 +00:00
- ( BOOL ) hasImageTypeContent
{
for ( NSExtensionItem * item in self . shareExtensionContext . inputItems )
{
for ( NSItemProvider * itemProvider in item . attachments )
{
if ( [ itemProvider hasItemConformingToTypeIdentifier : ( __bridge NSString * ) kUTTypeImage ] )
{
return YES ;
}
}
}
return NO ;
}
2017-08-17 22:27:56 +00:00
- ( void ) terminateExtensionCanceled : ( BOOL ) canceled
2017-08-10 22:38:47 +00:00
{
2017-08-21 20:33:06 +00:00
[ self suspendSession ] ;
2017-08-17 22:27:56 +00:00
if ( canceled )
{
[ self . shareExtensionContext cancelRequestWithError : [ NSError errorWithDomain : @ "MXUserCancelErrorDomain" code : 4201 userInfo : nil ] ] ;
}
else
{
[ self . shareExtensionContext cancelRequestWithError : [ NSError errorWithDomain : @ "MXFailureErrorDomain" code : 500 userInfo : nil ] ] ;
}
2017-08-10 22:38:47 +00:00
}
2017-08-20 21:39:08 +00:00
# pragma mark - Private
- ( UIAlertController * ) compressionPromptForImage : ( UIImage * ) image shareBlock : ( void ( ^ ) ( ) ) shareBlock
2017-08-16 20:01:54 +00:00
{
UIAlertController * compressionPrompt ;
// Get availabe sizes for this image
MXKImageCompressionSizes compressionSizes = [ MXKTools availableCompressionSizesForImage : image ] ;
// Apply the compression mode
if ( compressionSizes . small . fileSize || compressionSizes . medium . fileSize || compressionSizes . large . fileSize )
{
__weak typeof ( self ) weakSelf = self ;
compressionPrompt = [ UIAlertController alertControllerWithTitle : [ NSBundle mxk_localizedStringForKey : @ "attachment_size_prompt" ] message : nil preferredStyle : UIAlertControllerStyleActionSheet ] ;
if ( compressionSizes . small . fileSize )
{
NSString * resolution = [ NSString stringWithFormat : @ "%@ (%d x %d)" , [ MXTools fileSizeToString : compressionSizes . small . fileSize round : NO ] , ( int ) compressionSizes . small . imageSize . width , ( int ) compressionSizes . small . imageSize . height ] ;
NSString * title = [ NSString stringWithFormat : [ NSBundle mxk_localizedStringForKey : @ "attachment_small" ] , resolution ] ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
// Send the small image
self . imageCompressionMode = ImageCompressionModeSmall ;
if ( shareBlock )
{
shareBlock ( ) ;
}
[ compressionPrompt dismissViewControllerAnimated : YES completion : nil ] ;
}
} ] ] ;
}
if ( compressionSizes . medium . fileSize )
{
NSString * resolution = [ NSString stringWithFormat : @ "%@ (%d x %d)" , [ MXTools fileSizeToString : compressionSizes . medium . fileSize round : NO ] , ( int ) compressionSizes . medium . imageSize . width , ( int ) compressionSizes . medium . imageSize . height ] ;
NSString * title = [ NSString stringWithFormat : [ NSBundle mxk_localizedStringForKey : @ "attachment_medium" ] , resolution ] ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
// Send the medium image
self . imageCompressionMode = ImageCompressionModeMedium ;
if ( shareBlock )
{
shareBlock ( ) ;
}
[ compressionPrompt dismissViewControllerAnimated : YES completion : nil ] ;
}
} ] ] ;
}
if ( compressionSizes . large . fileSize )
{
NSString * resolution = [ NSString stringWithFormat : @ "%@ (%d x %d)" , [ MXTools fileSizeToString : compressionSizes . large . fileSize round : NO ] , ( int ) compressionSizes . large . imageSize . width , ( int ) compressionSizes . large . imageSize . height ] ;
NSString * title = [ NSString stringWithFormat : [ NSBundle mxk_localizedStringForKey : @ "attachment_large" ] , resolution ] ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
// Send the large image
self . imageCompressionMode = ImageCompressionModeLarge ;
self . actualLargeSize = compressionSizes . actualLargeSize ;
if ( shareBlock )
{
shareBlock ( ) ;
}
[ compressionPrompt dismissViewControllerAnimated : YES completion : nil ] ;
}
} ] ] ;
}
NSString * resolution = [ NSString stringWithFormat : @ "%@ (%d x %d)" , [ MXTools fileSizeToString : compressionSizes . original . fileSize round : NO ] , ( int ) compressionSizes . original . imageSize . width , ( int ) compressionSizes . original . imageSize . height ] ;
NSString * title = [ NSString stringWithFormat : [ NSBundle mxk_localizedStringForKey : @ "attachment_original" ] , resolution ] ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : title
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
self . imageCompressionMode = ImageCompressionModeNone ;
if ( shareBlock )
{
shareBlock ( ) ;
}
[ compressionPrompt dismissViewControllerAnimated : YES completion : nil ] ;
}
} ] ] ;
[ compressionPrompt addAction : [ UIAlertAction actionWithTitle : [ NSBundle mxk_localizedStringForKey : @ "cancel" ]
style : UIAlertActionStyleDefault
handler : ^ ( UIAlertAction * action ) {
if ( weakSelf )
{
[ compressionPrompt dismissViewControllerAnimated : YES completion : nil ] ;
}
} ] ] ;
}
return compressionPrompt ;
}
2017-08-20 21:39:08 +00:00
- ( void ) didStartSendingToRoom : ( MXRoom * ) room
{
if ( [ self . delegate respondsToSelector : @ selector ( shareExtensionManager : didStartSendingContentToRoom : ) ] )
{
[ self . delegate shareExtensionManager : self didStartSendingContentToRoom : room ] ;
}
}
2017-08-22 15:52:32 +00:00
- ( BOOL ) areAttachmentsFullyLoaded
{
for ( NSExtensionItem * item in self . shareExtensionContext . inputItems )
{
for ( NSItemProvider * itemProvider in item . attachments )
{
if ( itemProvider . isLoaded = = NO )
{
return NO ;
}
}
}
return YES ;
}
2017-08-16 20:01:54 +00:00
# pragma mark - Notifications
- ( void ) onMediaUploadProgress : ( NSNotification * ) notification
{
2017-08-22 15:52:32 +00:00
self . imageUploadProgresses [ notification . object ] = ( NSNumber * ) notification . userInfo [ kMXMediaLoaderProgressValueKey ] ;
2017-08-16 20:01:54 +00:00
if ( [ self . delegate respondsToSelector : @ selector ( shareExtensionManager : mediaUploadProgress : ) ] )
{
2017-08-22 15:52:32 +00:00
const NSInteger totalImagesCount = self . pendingImages . count ;
CGFloat totalProgress = 0.0 ;
for ( NSNumber * progress in self . imageUploadProgresses . allValues )
{
totalProgress + = progress . floatValue / totalImagesCount ;
}
[ self . delegate shareExtensionManager : self mediaUploadProgress : totalProgress ] ;
2017-08-16 20:01:54 +00:00
}
}
2017-08-14 11:25:02 +00:00
# pragma mark - Sharing
- ( void ) sendText : ( NSString * ) text toRoom : ( MXRoom * ) room extensionItem : ( NSExtensionItem * ) extensionItem failureBlock : ( void ( ^ ) ( ) ) failureBlock
{
2017-08-20 21:39:08 +00:00
[ self didStartSendingToRoom : room ] ;
2017-08-14 11:25:02 +00:00
if ( ! text )
{
NSLog ( @ "[ShareExtensionManager] loadItemForTypeIdentifier: failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
}
return ;
}
2017-08-17 15:28:08 +00:00
__weak typeof ( self ) weakSelf = self ;
2017-08-14 11:25:02 +00:00
[ room sendTextMessage : text success : ^ ( NSString * eventId ) {
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
2017-08-21 20:33:06 +00:00
[ self suspendSession ] ;
2017-08-17 15:28:08 +00:00
[ self . shareExtensionContext completeRequestReturningItems : @ [ extensionItem ] completionHandler : nil ] ;
}
2017-08-14 11:25:02 +00:00
} failure : ^ ( NSError * error ) {
NSLog ( @ "[ShareExtensionManager] sendTextMessage failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
}
} ] ;
}
- ( void ) sendFileWithUrl : ( NSURL * ) fileUrl toRoom : ( MXRoom * ) room extensionItem : ( NSExtensionItem * ) extensionItem failureBlock : ( void ( ^ ) ( ) ) failureBlock
{
2017-08-20 21:39:08 +00:00
[ self didStartSendingToRoom : room ] ;
2017-08-14 11:25:02 +00:00
if ( ! fileUrl )
{
NSLog ( @ "[ShareExtensionManager] loadItemForTypeIdentifier: failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
}
return ;
}
2017-08-21 22:31:43 +00:00
NSString * mimeType ;
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag ( kUTTagClassFilenameExtension , ( __bridge CFStringRef ) [ fileUrl pathExtension ] , NULL ) ;
mimeType = ( __bridge _transfer NSString * ) UTTypeCopyPreferredTagWithClass ( uti , kUTTagClassMIMEType ) ;
CFRelease ( uti ) ;
2017-08-17 15:28:08 +00:00
__weak typeof ( self ) weakSelf = self ;
2017-08-14 11:25:02 +00:00
[ room sendFile : fileUrl mimeType : mimeType localEcho : nil success : ^ ( NSString * eventId ) {
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
2017-08-21 20:33:06 +00:00
[ self suspendSession ] ;
2017-08-17 15:28:08 +00:00
[ self . shareExtensionContext completeRequestReturningItems : @ [ extensionItem ] completionHandler : nil ] ;
}
2017-08-14 11:25:02 +00:00
} failure : ^ ( NSError * error ) {
NSLog ( @ "[ShareExtensionManager] sendFile failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
}
2017-08-21 14:45:16 +00:00
} keepActualFilename : YES ] ;
2017-08-14 11:25:02 +00:00
}
2017-08-24 22:26:53 +00:00
- ( void ) sendImages : ( NSMutableArray * ) imageDatas withProviders : ( NSArray * ) itemProviders toRoom : ( MXRoom * ) room extensionItem : ( NSExtensionItem * ) extensionItem failureBlock : ( void ( ^ ) ( ) ) failureBlock
2017-08-14 11:25:02 +00:00
{
2017-08-20 21:39:08 +00:00
[ self didStartSendingToRoom : room ] ;
2017-08-22 15:52:32 +00:00
2017-08-24 22:26:53 +00:00
for ( NSInteger index = 0 ; index < imageDatas . count ; index + + )
2017-08-14 11:25:02 +00:00
{
2017-08-24 22:26:53 +00:00
NSData * imageData = imageDatas [ index ] ;
NSItemProvider * itemProvider = itemProviders [ index ] ;
2017-08-22 15:52:32 +00:00
if ( ! imageData )
2017-08-14 11:25:02 +00:00
{
2017-08-22 15:52:32 +00:00
NSLog ( @ "[ShareExtensionManager] loadItemForTypeIdentifier: failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
failureBlock = nil ;
}
return ;
2017-08-14 11:25:02 +00:00
}
2017-08-21 13:28:58 +00:00
2017-08-22 15:52:32 +00:00
// Prepare the image
BOOL rotated = NO ;
UIImage * image = [ [ UIImage alloc ] initWithData : imageData ] ;
// Make sure the uploaded image orientation is up
if ( image . imageOrientation ! = UIImageOrientationUp )
2017-08-21 13:28:58 +00:00
{
2017-08-22 15:52:32 +00:00
image = [ MXKTools forceImageOrientationUp : image ] ;
rotated = YES ;
2017-08-21 13:28:58 +00:00
}
2017-08-22 15:52:32 +00:00
if ( self . imageCompressionMode = = ImageCompressionModeSmall )
{
image = [ MXKTools reduceImage : image toFitInSize : CGSizeMake ( MXKTOOLS_SMALL _IMAGE _SIZE , MXKTOOLS_SMALL _IMAGE _SIZE ) ] ;
}
else if ( self . imageCompressionMode = = ImageCompressionModeMedium )
{
image = [ MXKTools reduceImage : image toFitInSize : CGSizeMake ( MXKTOOLS_MEDIUM _IMAGE _SIZE , MXKTOOLS_MEDIUM _IMAGE _SIZE ) ] ;
}
else if ( self . imageCompressionMode = = ImageCompressionModeLarge )
{
image = [ MXKTools reduceImage : image toFitInSize : CGSizeMake ( self . actualLargeSize , self . actualLargeSize ) ] ;
}
NSData * convertedImageData ;
NSString * mimeType ;
if ( [ itemProvider hasItemConformingToTypeIdentifier : ( __bridge NSString * ) kUTTypePNG ] )
2017-08-21 13:28:58 +00:00
{
2017-08-22 15:52:32 +00:00
mimeType = @ "image/png" ;
2017-08-21 13:28:58 +00:00
// Update imageData
2017-08-22 15:52:32 +00:00
convertedImageData = UIImagePNGRepresentation ( image ) ;
2017-08-21 13:28:58 +00:00
}
2017-08-22 15:52:32 +00:00
else if ( [ itemProvider hasItemConformingToTypeIdentifier : ( __bridge NSString * ) kUTTypeJPEG ] )
2017-08-14 11:25:02 +00:00
{
2017-08-22 15:52:32 +00:00
mimeType = @ "image/jpeg" ;
// Update imageData
convertedImageData = UIImageJPEGRepresentation ( image , 1.0 ) ;
2017-08-14 11:25:02 +00:00
}
2017-08-22 15:52:32 +00:00
else
2017-08-17 15:28:08 +00:00
{
2017-08-22 15:52:32 +00:00
convertedImageData = UIImageJPEGRepresentation ( image , 1.0 ) ;
image = [ [ UIImage alloc ] initWithData : imageData ] ;
mimeType = @ "image/jpeg" ;
2017-08-17 15:28:08 +00:00
}
2017-08-22 15:52:32 +00:00
UIImage * thumbnail = nil ;
// Thumbnail is useful only in case of encrypted room
if ( room . state . isEncrypted )
2017-08-14 11:25:02 +00:00
{
2017-08-22 15:52:32 +00:00
thumbnail = [ MXKTools reduceImage : image toFitInSize : CGSizeMake ( 800 , 600 ) ] ;
if ( thumbnail = = image )
{
thumbnail = nil ;
}
2017-08-14 11:25:02 +00:00
}
2017-08-22 15:52:32 +00:00
__weak typeof ( self ) weakSelf = self ;
[ room sendImage : convertedImageData withImageSize : image . size mimeType : mimeType andThumbnail : thumbnail localEcho : nil success : ^ ( NSString * eventId ) {
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
2017-08-24 10:55:35 +00:00
[ imageDatas removeObject : imageData ] ;
2017-08-22 15:52:32 +00:00
2017-08-24 10:55:35 +00:00
if ( ! imageDatas . count )
2017-08-22 15:52:32 +00:00
{
2017-08-22 15:56:30 +00:00
[ self suspendSession ] ;
2017-08-22 15:52:32 +00:00
[ self . shareExtensionContext completeRequestReturningItems : @ [ extensionItem ] completionHandler : nil ] ;
}
}
} failure : ^ ( NSError * error ) {
NSLog ( @ "[ShareExtensionManager] sendImage failed." ) ;
2017-08-24 10:55:35 +00:00
[ imageDatas removeObject : imageData ] ;
2017-08-22 15:52:32 +00:00
2017-08-24 10:55:35 +00:00
if ( ! imageDatas . count )
2017-08-22 15:52:32 +00:00
{
if ( failureBlock )
{
failureBlock ( ) ;
}
}
} ] ;
}
2017-08-14 11:25:02 +00:00
}
- ( void ) sendVideo : ( NSURL * ) videoLocalUrl toRoom : ( MXRoom * ) room extensionItem : ( NSExtensionItem * ) extensionItem failureBlock : ( void ( ^ ) ( ) ) failureBlock
{
2017-08-20 21:39:08 +00:00
[ self didStartSendingToRoom : room ] ;
2017-08-14 11:25:02 +00:00
if ( ! videoLocalUrl )
{
NSLog ( @ "[ShareExtensionManager] loadItemForTypeIdentifier: failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
}
return ;
}
// Retrieve the video frame at 1 sec to define the video thumbnail
AVURLAsset * urlAsset = [ [ AVURLAsset alloc ] initWithURL : videoLocalUrl options : nil ] ;
AVAssetImageGenerator * assetImageGenerator = [ AVAssetImageGenerator assetImageGeneratorWithAsset : urlAsset ] ;
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 ) ;
2017-08-17 15:28:08 +00:00
__weak typeof ( self ) weakSelf = self ;
2017-08-14 11:25:02 +00:00
[ room sendVideo : videoLocalUrl withThumbnail : videoThumbnail localEcho : nil success : ^ ( NSString * eventId ) {
2017-08-17 15:28:08 +00:00
if ( weakSelf )
{
typeof ( self ) self = weakSelf ;
2017-08-21 20:33:06 +00:00
[ self suspendSession ] ;
2017-08-17 15:28:08 +00:00
[ self . shareExtensionContext completeRequestReturningItems : @ [ extensionItem ] completionHandler : nil ] ;
}
2017-08-14 11:25:02 +00:00
} failure : ^ ( NSError * error ) {
NSLog ( @ "[ShareExtensionManager] sendVideo failed." ) ;
if ( failureBlock )
{
failureBlock ( ) ;
}
} ] ;
}
2017-08-10 22:38:47 +00:00
@ end
2017-08-22 15:52:32 +00:00
@ implementation NSItemProvider ( ShareExtensionManager )
- ( void ) setIsLoaded : ( BOOL ) isLoaded
{
NSNumber * number = [ NSNumber numberWithBool : isLoaded ] ;
objc_setAssociatedObject ( self , @ selector ( isLoaded ) , number , OBJC_ASSOCIATION _RETAIN _NONATOMIC ) ;
}
- ( BOOL ) isLoaded
{
NSNumber * number = objc_getAssociatedObject ( self , @ selector ( isLoaded ) ) ;
return number . boolValue ;
}
@ end