From cdf2e454030c2b7dc1ae3a5bed28afe2acc080b1 Mon Sep 17 00:00:00 2001 From: Danmei Chen Date: Thu, 31 May 2018 13:09:55 +0200 Subject: [PATCH] enable share photo --- Classes/ChatConversationTableView.h | 1 + Classes/ChatConversationTableView.m | 4 +- Classes/ChatConversationView.h | 7 +- Classes/ChatConversationView.m | 90 +++++- Classes/ImageView.h | 2 +- Classes/LinphoneAppDelegate.m | 4 +- .../Base.lproj/UIChatBubbleFile.xib | 74 +++++ .../Base.lproj/UIChatBubblePhotoCell.xib | 32 ++ .../Base.lproj/UIChatBubbleTextCell.xib | 4 +- .../UIChatConversationImdnTableViewCell.xib | 2 +- Classes/LinphoneUI/UIChatBubblePhotoCell.h | 7 + Classes/LinphoneUI/UIChatBubblePhotoCell.m | 140 ++++++++- Classes/LinphoneUI/UIChatBubbleTextCell.m | 31 +- Classes/SettingsView.m | 2 + Classes/Utils/FileTransferDelegate.h | 1 + Classes/Utils/FileTransferDelegate.m | 163 +++++++--- linphone-Info.plist | 12 + linphone.entitlements | 4 + linphone.xcodeproj/project.pbxproj | 295 +++++++++++++++++- .../Base.lproj/MainInterface.storyboard | 24 ++ linphoneExtension/Info.plist | 36 +++ linphoneExtension/ShareViewController.h | 13 + linphoneExtension/ShareViewController.m | 86 +++++ .../linphoneExtension.entitlements | 10 + 24 files changed, 965 insertions(+), 79 deletions(-) create mode 100644 Classes/LinphoneUI/Base.lproj/UIChatBubbleFile.xib create mode 100644 linphoneExtension/Base.lproj/MainInterface.storyboard create mode 100644 linphoneExtension/Info.plist create mode 100644 linphoneExtension/ShareViewController.h create mode 100644 linphoneExtension/ShareViewController.m create mode 100644 linphoneExtension/linphoneExtension.entitlements diff --git a/Classes/ChatConversationTableView.h b/Classes/ChatConversationTableView.h index aae766894..0f6162f47 100644 --- a/Classes/ChatConversationTableView.h +++ b/Classes/ChatConversationTableView.h @@ -28,6 +28,7 @@ @protocol ChatConversationDelegate - (BOOL)startImageUpload:(UIImage *)image url:(NSURL *)url withQuality:(float)quality; +- (BOOL)startFileUpload:(NSData *)data withUrl:(NSURL *)url; - (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url; - (void)tableViewIsScrolling; diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m index 15939f5e0..b3f9de5ff 100644 --- a/Classes/ChatConversationTableView.m +++ b/Classes/ChatConversationTableView.m @@ -174,8 +174,8 @@ LinphoneEventLog *event = [[eventList objectAtIndex:indexPath.row] pointerValue]; if (linphone_event_log_get_type(event) == LinphoneEventLogTypeConferenceChatMessage) { LinphoneChatMessage *chat = linphone_event_log_get_chat_message(event); - if (linphone_chat_message_get_file_transfer_information(chat) || linphone_chat_message_get_external_body_url(chat)) - kCellId = NSStringFromClass(UIChatBubblePhotoCell.class); + if (linphone_chat_message_get_file_transfer_information(chat) || linphone_chat_message_get_external_body_url(chat)) + kCellId = NSStringFromClass(UIChatBubblePhotoCell.class); else kCellId = NSStringFromClass(UIChatBubbleTextCell.class); diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h index 71b50bd43..9e62f09c4 100644 --- a/Classes/ChatConversationView.h +++ b/Classes/ChatConversationView.h @@ -31,8 +31,8 @@ #include "linphone/linphonecore.h" @interface ChatConversationView - : TPMultiLayoutViewController { + : TPMultiLayoutViewController { OrderedDictionary *imageQualities; BOOL scrollOnGrowingEnabled; BOOL composingVisible; @@ -58,7 +58,7 @@ @property(weak, nonatomic) IBOutlet UIBackToCallButton *backToCallButton; @property (weak, nonatomic) IBOutlet UIIconButton *infoButton; @property (weak, nonatomic) IBOutlet UILabel *particpantsLabel; - +@property (nonatomic, strong) UIDocumentInteractionController *documentInteractionController; + (void)markAsRead:(LinphoneChatRoom *)chatRoom; - (void)configureForRoom:(BOOL)editing; @@ -72,5 +72,6 @@ - (IBAction)onDeleteClick:(id)sender; - (IBAction)onEditionChangeClick:(id)sender; - (void)update; +- (void)openResults:(NSString *) filePath; @end diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index 60fccdfd9..0eba6fa33 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -24,6 +24,7 @@ #import "UIChatBubbleTextCell.h" @implementation ChatConversationView +static NSString* groupName = @"group.belledonne-communications.linphone"; #pragma mark - Lifecycle Functions @@ -205,6 +206,53 @@ static UICompositeViewDescription *compositeDescription = nil; _chatView.hidden = NO; [self update]; + [self shareFile]; +} + +- (void)sendContentText:(NSString *)text { + if(![text isEqualToString:@""]) { + [self sendMessage:text withExterlBodyUrl:nil withInternalURL:nil]; + } +} + +- (void)shareFile { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName]; + + NSDictionary *dict = [defaults valueForKey:@"img"]; + NSDictionary *dictWeb = [defaults valueForKey:@"web"]; + NSDictionary *dictFile = [defaults valueForKey:@"file"]; + NSDictionary *dictText = [defaults valueForKey:@"text"]; + if (dict) { + //share photo + NSData *data = dict[@"nsData"]; + UIImage *image = [[UIImage alloc] initWithData:data]; + [self chooseImageQuality:image url:nil]; + [self sendContentText:dict[@"name"]]; + [defaults removeObjectForKey:@"img"]; + } else if(dictWeb) { + //share url, if local file, then upload file + NSString *url = dictWeb[@"url"]; + NSURL *fileUrl = [NSURL fileURLWithPath:url]; + if([[fileUrl scheme]isEqualToString:@"file"]) { + //local file + NSData *data = dictWeb[@"nsData"]; + [self confirmShare:data url:fileUrl]; + } else { + [self sendMessage:url withExterlBodyUrl:nil withInternalURL:nil]; + } + [self sendContentText:dictWeb[@"name"]]; + [defaults removeObjectForKey:@"web"]; + }else if(dictFile) { + //share file + NSData *data = dictFile[@"nsData"]; + [self confirmShare:data url:[NSURL fileURLWithPath:dictFile[@"url"]]]; + [self sendContentText:dictFile[@"name"]]; + [defaults removeObjectForKey:@"file"]; + }else if(dictText) { + //share text + [self sendContentText:dictText[@"name"]]; + [defaults removeObjectForKey:@"text"]; + } } - (void)applicationWillEnterForeground:(NSNotification *)notif { @@ -253,8 +301,8 @@ static UICompositeViewDescription *compositeDescription = nil; } if (internalUrl) { - // internal url is saved in the appdata for display and later save - [LinphoneManager setValueInMessageAppData:[internalUrl absoluteString] forKey:@"localimage" inMessage:msg]; + // internal url is saved in the appdata for display and later save + [LinphoneManager setValueInMessageAppData:[internalUrl absoluteString] forKey:@"localimage" inMessage:msg]; } // we must ref & unref message because in case of error, it will be destroy otherwise @@ -318,6 +366,22 @@ static UICompositeViewDescription *compositeDescription = nil; }); } +- (void)confirmShare:(NSData *)data url:(NSURL *)url { + DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"", nil)]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + [sheet addButtonWithTitle:@"send to him" + block:^() { + [self startFileUpload:data withUrl:url]; + }]; + + [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + [sheet showInView:PhoneMainView.instance.view]; + }); + }); +} + - (void)setComposingVisible:(BOOL)visible withDelay:(CGFloat)delay { Boolean shouldAnimate = composingVisible != visible; CGRect keyboardFrame = [_messageView frame]; @@ -547,6 +611,13 @@ static UICompositeViewDescription *compositeDescription = nil; return TRUE; } +- (BOOL)startFileUpload:(NSData *)data withUrl:(NSURL *)url { + FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init]; + [fileTransfer uploadFile:data forChatRoom:_chatRoom withUrl:url]; + [_tableController scrollToBottom:true]; + return TRUE; +} + - (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url { [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] withInternalURL:nil]; } @@ -783,4 +854,19 @@ void on_chat_room_conference_left(LinphoneChatRoom *cr, const LinphoneEventLog * [view.tableController scrollToBottom:true]; } +- (void)openResults:(NSString *) filePath +{ + //TODO: if file exist + // Open the controller. + _documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; + _documentInteractionController.delegate = self; + + BOOL canOpen = [_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES]; + //NO app can open the file + if (canOpen == NO) { + [[[UIAlertView alloc] initWithTitle:@"Info" message:@"There is no app found to open it" delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil] show]; + + } +} + @end diff --git a/Classes/ImageView.h b/Classes/ImageView.h index 6d960b81c..33aaf39eb 100644 --- a/Classes/ImageView.h +++ b/Classes/ImageView.h @@ -37,4 +37,4 @@ - (IBAction)onBackClick:(id)sender; -@end \ No newline at end of file +@end diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index ff39eb49d..083018950 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -348,7 +348,9 @@ [errView addAction:yesAction]; [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; - } else { + } else if([[url scheme] isEqualToString:@"message-linphone"]) { + [PhoneMainView.instance popToView:ChatsListView.compositeViewDescription]; + }else { if ([[url scheme] isEqualToString:@"sip"]) { // remove "sip://" from the URI, and do it correctly by taking resourceSpecifier and removing leading and // trailing "/" diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleFile.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubbleFile.xib new file mode 100644 index 000000000..6ed90765a --- /dev/null +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubbleFile.xib @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib index fb3a8990d..4da2cbc69 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib @@ -19,6 +19,7 @@ + @@ -26,6 +27,8 @@ + + @@ -69,6 +72,14 @@ + @@ -102,9 +113,25 @@ + + + + @@ -166,6 +193,11 @@ + + + + + diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib index f9eca9b79..d268ae5b5 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib @@ -1,11 +1,11 @@ - + - + diff --git a/Classes/LinphoneUI/Base.lproj/UIChatConversationImdnTableViewCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatConversationImdnTableViewCell.xib index 43c90b45f..90596f434 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatConversationImdnTableViewCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatConversationImdnTableViewCell.xib @@ -5,7 +5,7 @@ - + diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.h b/Classes/LinphoneUI/UIChatBubblePhotoCell.h index 1ae950e28..43e4deeb0 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.h +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.h @@ -29,9 +29,12 @@ @property(nonatomic, strong) IBOutlet UILoadingImageView *messageImageView; @property(nonatomic, strong) IBOutlet UIButton *downloadButton; +@property (weak, nonatomic) IBOutlet UILabel *fileName; +@property(nonatomic, strong) IBOutlet UIButton *playButton; @property(weak, nonatomic) IBOutlet UIProgressView *fileTransferProgress; @property(weak, nonatomic) IBOutlet UIButton *cancelButton; @property(weak, nonatomic) IBOutlet UIView *imageSubView; +@property (strong, nonatomic) IBOutlet UITapGestureRecognizer *openRecognizer; @property(weak, nonatomic) IBOutlet UIView *totalView; @property (weak, nonatomic) IBOutlet UIImageView *finalImage; @property(strong, nonatomic) IBOutlet UITapGestureRecognizer *imageGestureRecognizer; @@ -43,6 +46,10 @@ - (IBAction)onImageClick:(id)event; - (IBAction)onCancelClick:(id)sender; - (IBAction)onResendClick:(id)event; +- (IBAction)onPlayClick:(id)sender; +- (IBAction)onOpenClick:(id)event; @end + + diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 55ae42a0f..bb33db9a2 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -23,6 +23,9 @@ #import #import +#import +#import +#import @implementation UIChatBubblePhotoCell { FileTransferDelegate *_ftd; @@ -67,6 +70,7 @@ - (void)setChatMessage:(LinphoneChatMessage *)amessage { _imageGestureRecognizer.enabled = NO; + _openRecognizer.enabled = NO; _messageImageView.image = nil; _finalImage.image = nil; _finalImage.hidden = TRUE; @@ -112,22 +116,59 @@ }); } +- (void) loadVideoAsset: (AVAsset *) asset { + // Calculate a time for the snapshot - I'm using the half way mark. + CMTime duration = [asset duration]; + CMTime snapshot = CMTimeMake(duration.value / 2, duration.timescale); + + // Create a generator and copy image at the time. + // I'm not capturing the actual time or an error. + AVAssetImageGenerator *generator = + [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + CGImageRef imageRef = [generator copyCGImageAtTime:snapshot + actualTime:nil + error:nil]; + + // Make a UIImage and release the CGImage. + UIImage *image = [UIImage imageWithCGImage:imageRef]; + CGImageRelease(imageRef); + dispatch_async(dispatch_get_main_queue(), ^{ + [_messageImageView setImage:image]; + [_messageImageView stopLoading]; + _messageImageView.hidden = NO; + }); +} + +- (void) loadFileAsset { + dispatch_async(dispatch_get_main_queue(), ^{ + CGRect newFrame = _totalView.frame; + newFrame.origin.x = newFrame.origin.y = 0; + _fileName.frame = newFrame; + _fileName.hidden = NO; + }); +} + - (void)update { if (self.message == nil) { LOGW(@"Cannot update message room cell: NULL message"); return; } [super update]; + + LinphoneChatMessageState state = linphone_chat_message_get_state(self.message); const char *url = linphone_chat_message_get_external_body_url(self.message); BOOL is_external = (url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(self.message); NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:self.message]; + NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:self.message]; + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; BOOL fullScreenImage = NO; - assert(is_external || localImage); + assert(is_external || localImage || localVideo || localFile); + if (localImage) { // image is being saved on device - just wait for it if ([localImage isEqualToString:@"saving..."]) { - _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES; + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = YES; fullScreenImage = YES; } else { // we did not load the image yet, so start doing so @@ -172,17 +213,72 @@ _cancelButton.hidden = NO; _fileTransferProgress.hidden = NO; _downloadButton.hidden = YES; + _playButton.hidden = YES; + _fileName.hidden = YES; } else { - _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES; + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = YES; fullScreenImage = YES; } } // we must download the image: either it has already started (show cancel button) or not yet (show download // button) - } else { + } else if(localVideo) { + if ([localVideo isEqualToString:@"saving..."]) { + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = YES; + fullScreenImage = YES; + } else { + if (_messageImageView.image == nil) { + + [_messageImageView startLoading]; + NSURL *url = [NSURL fileURLWithPath:localVideo]; + AVAsset *asset = [AVAsset assetWithURL:url]; + if (asset) + [self loadVideoAsset:asset]; + //TODO fail + else return; + } + // we did not load the video yet, so start doing so + // we are uploading the video + if (_ftd.message != nil && state != LinphoneChatMessageStateNotDelivered && state != LinphoneChatMessageStateDisplayed) { + _cancelButton.hidden = NO; + _fileTransferProgress.hidden = NO; + _downloadButton.hidden = YES; + _playButton.hidden = YES; + _fileName.hidden = YES; + } else { + + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _fileName.hidden = YES; + _playButton.hidden = NO; + fullScreenImage = YES; + } + } + + } else if(localFile){ + if ([localFile isEqualToString:@"saving..."]) { + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = YES; + fullScreenImage = YES; + } else { + if (_ftd.message != nil && state != LinphoneChatMessageStateNotDelivered && state != LinphoneChatMessageStateDisplayed) { + _cancelButton.hidden = NO; + _fileTransferProgress.hidden = NO; + _downloadButton.hidden = YES; + _playButton.hidden = YES; + _fileName.hidden = YES; + } else { + NSString *text = [[NSURL fileURLWithPath:localFile] lastPathComponent]; + _fileName.text = text; + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = + _playButton.hidden = YES; + fullScreenImage = YES; + [self loadFileAsset]; + _openRecognizer.enabled = YES; + } + } + }else{ + _playButton.hidden = _fileName.hidden = YES; _messageImageView.hidden = _cancelButton.hidden = (_ftd.message == nil); - _downloadButton.hidden = !_cancelButton.hidden; - _fileTransferProgress.hidden = NO; + _downloadButton.hidden = !_cancelButton.hidden; + _fileTransferProgress.hidden = NO; } // resize image so that it take the full bubble space available @@ -194,6 +290,7 @@ _messageImageView.frame = newFrame; } + - (IBAction)onDownloadClick:(id)event { [_ftd cancel]; _ftd = [[FileTransferDelegate alloc] init]; @@ -201,8 +298,37 @@ [_ftd download:self.message]; _cancelButton.hidden = NO; _downloadButton.hidden = YES; + _playButton.hidden = YES; + _fileName.hidden = YES; } +- (IBAction)onPlayClick:(id)sender { + NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:self.message]; + + NSURL * fileURL= [[NSURL alloc] initFileURLWithPath:localVideo]; + + // create a player view controller + AVPlayer *player = [AVPlayer playerWithURL:fileURL]; + AVPlayerViewController *controller = [[AVPlayerViewController alloc] init]; + [PhoneMainView.instance presentViewController:controller animated:YES completion:nil]; + controller.player = player; + [player play]; + + _cancelButton.hidden = YES; + _downloadButton.hidden = YES; + _playButton.hidden = NO; + _fileTransferProgress.hidden = YES; +} + +- (IBAction)onOpenClick:(id)event { + + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; + + ChatConversationView *view = VIEW(ChatConversationView); + [view openResults:localFile]; +} + + - (IBAction)onCancelClick:(id)sender { FileTransferDelegate *tmp = _ftd; [self disconnectFromFileDelegate]; @@ -357,3 +483,5 @@ @end + + diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index ff8de9fc1..5f6fb2297 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -232,19 +232,28 @@ if (linphone_chat_message_get_file_transfer_information(_message) != NULL) { NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message]; NSNumber *uploadQuality =[LinphoneManager getMessageAppDataForKey:@"uploadQuality" inMessage:_message]; + NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message]; + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message]; NSURL *imageUrl = [NSURL URLWithString:localImage]; [self onDelete]; - [LinphoneManager.instance.photoLibrary assetForURL:imageUrl - resultBlock:^(ALAsset *asset) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), - ^(void) { - UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]]; - [_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; - }); - } - failureBlock:^(NSError *error) { - LOGE(@"Can't read image"); - }]; + if(localImage){ + [LinphoneManager.instance.photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]]; + [_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } else if(localVideo) { + [_chatRoomDelegate startFileUpload:[NSData dataWithContentsOfFile:localVideo] withUrl:[NSURL URLWithString:localVideo]]; + } else { + [_chatRoomDelegate startFileUpload:[NSData dataWithContentsOfFile:localFile] withUrl:[NSURL URLWithString:localFile]]; + } + } else { [self onDelete]; double delayInSeconds = 0.4; diff --git a/Classes/SettingsView.m b/Classes/SettingsView.m index f42986367..94d87f908 100644 --- a/Classes/SettingsView.m +++ b/Classes/SettingsView.m @@ -762,6 +762,8 @@ void update_hash_cbs(LinphoneAccountCreator *creator, LinphoneAccountCreatorStat if (!linphone_chat_message_is_outgoing(msg)) { [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:msg]; [LinphoneManager setValueInMessageAppData:nil forKey:@"uploadQuality" inMessage:msg]; + [LinphoneManager setValueInMessageAppData:nil forKey:@"localvideo" inMessage:msg]; + [LinphoneManager setValueInMessageAppData:nil forKey:@"localfile" inMessage:msg]; } events = events->next; } diff --git a/Classes/Utils/FileTransferDelegate.h b/Classes/Utils/FileTransferDelegate.h index 4b2f8de6c..10504b144 100644 --- a/Classes/Utils/FileTransferDelegate.h +++ b/Classes/Utils/FileTransferDelegate.h @@ -13,6 +13,7 @@ @interface FileTransferDelegate : NSObject - (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality; +- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withUrl:(NSURL *)url; - (void)cancel; - (BOOL)download:(LinphoneChatMessage *)message; - (void)stopAndDestroy; diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index c37782c24..272339ba1 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -44,62 +44,63 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con if (size == 0) { LOGI(@"Transfer of %s (%d bytes): download finished", linphone_content_get_name(content), size); assert([thiz.data length] == linphone_content_get_file_size(content)); + NSString *fileType = [NSString stringWithUTF8String:linphone_content_get_type(content)]; + if([fileType isEqualToString:@"image"]) { + // we're finished, save the image and update the message + UIImage *image = [UIImage imageWithData:thiz.data]; + if (!image) { + UIAlertController *errView = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"File download error", nil) + message:NSLocalizedString(@"Error while downloading the file.\n" + @"The file is probably encrypted.\n" + @"Please retry to download this file after activating LIME.", + nil) + preferredStyle:UIAlertControllerStyleAlert]; - // we're finished, save the image and update the message - UIImage *image = [UIImage imageWithData:thiz.data]; - if (!image) { - UIAlertController *errView = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"File download error", nil) - message:NSLocalizedString(@"Error while downloading the file.\n" - @"The file is probably encrypted.\n" - @"Please retry to download this file after activating LIME.", - nil) - preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action){ + }]; - UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action){ - }]; + [errView addAction:defaultAction]; + [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; + [thiz stopAndDestroy]; + return; + } - [errView addAction:defaultAction]; - [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; - [thiz stopAndDestroy]; - return; - } + CFBridgingRetain(thiz); + [[LinphoneManager.instance fileTransferDelegates] removeObject:thiz]; - CFBridgingRetain(thiz); - [[LinphoneManager.instance fileTransferDelegates] removeObject:thiz]; + // until image is properly saved, keep a reminder on it so that the + // chat bubble is aware of the fact that image is being saved to device + [LinphoneManager setValueInMessageAppData:@"saving..." forKey:@"localimage" inMessage:message]; - // until image is properly saved, keep a reminder on it so that the - // chat bubble is aware of the fact that image is being saved to device - [LinphoneManager setValueInMessageAppData:@"saving..." forKey:@"localimage" inMessage:message]; - - [LinphoneManager.instance.photoLibrary - writeImageToSavedPhotosAlbum:image.CGImage - orientation:(ALAssetOrientation)[image imageOrientation] - completionBlock:^(NSURL *assetURL, NSError *error) { - if (error) { - LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); - [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:message]; - UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil) + [LinphoneManager.instance.photoLibrary + writeImageToSavedPhotosAlbum:image.CGImage + orientation:(ALAssetOrientation)[image imageOrientation] + completionBlock:^(NSURL *assetURL, NSError *error) { + if (error) { + LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); + [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:message]; + UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil) message:NSLocalizedString(@"Cannot write image to photo library", nil) preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; - [errView addAction:defaultAction]; - [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; - } else { - LOGI(@"Image saved to [%@]", [assetURL absoluteString]); - [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] + [errView addAction:defaultAction]; + [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; + } else { + LOGI(@"Image saved to [%@]", [assetURL absoluteString]); + [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:message]; - } - [NSNotificationCenter.defaultCenter - postNotificationName:kLinphoneFileTransferRecvUpdate + } + [NSNotificationCenter.defaultCenter + postNotificationName:kLinphoneFileTransferRecvUpdate object:thiz userInfo:@{ @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to @@ -109,10 +110,41 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con @"progress" : @(1.f), }]; - [thiz stopAndDestroy]; - CFRelease((__bridge CFTypeRef)thiz); - }]; - } else { + [thiz stopAndDestroy]; + CFRelease((__bridge CFTypeRef)thiz); + }]; + } else{ + [[LinphoneManager.instance fileTransferDelegates] removeObject:thiz]; + + NSString *key = @"localvideo"; + NSString *name =[NSString stringWithUTF8String:linphone_content_get_name(content)]; + + if([fileType isEqualToString:@"file"]){ + key = @"localfile"; + } + [LinphoneManager setValueInMessageAppData:@"saving..." forKey:key inMessage:message]; + + //write file to path + dispatch_async(dispatch_get_main_queue(), ^{ + NSString *filePath = [LinphoneManager documentFile:name]; + [[NSFileManager defaultManager] createFileAtPath:filePath + contents:thiz.data + attributes:nil]; + + [LinphoneManager setValueInMessageAppData:filePath forKey:key inMessage:message]; + + [NSNotificationCenter.defaultCenter + postNotificationName:kLinphoneFileTransferRecvUpdate + object:thiz + userInfo:@{ + @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to trigger + @"progress" : @(1.f), // FileTransferDone here + }]; + + [thiz stopAndDestroy]; + }); + } + } else { LOGD(@"Transfer of %s (%d bytes): already %ld sent, adding %ld", linphone_content_get_name(content), linphone_content_get_file_size(content), [thiz.data length], size); [thiz.data appendBytes:linphone_buffer_get_string_content(buffer) length:size]; @@ -124,6 +156,7 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con @"progress" : @([thiz.data length] * 1.f / linphone_content_get_file_size(content)), }]; } + } static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent *content, @@ -198,6 +231,44 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m } } +- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withUrl:(NSURL *)url { + [LinphoneManager.instance.fileTransferDelegates addObject:self]; + + LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_core(chatRoom)); + _data = [NSMutableData dataWithData:data]; + + NSString *filePath = [LinphoneManager documentFile:[url lastPathComponent]]; + [[NSFileManager defaultManager] createFileAtPath:filePath + contents:_data + attributes:nil]; + + NSString *key = @"localvideo"; + if(![[url pathExtension]isEqualToString:@"MOV"]) { + linphone_content_set_type(content, "file"); + key = @"localfile"; + } + + linphone_content_set_name(content, [[url lastPathComponent] UTF8String]); + linphone_content_set_size(content, _data.length); + + _message = linphone_chat_room_create_file_transfer_message(chatRoom, content); + linphone_content_unref(content); + + linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message), + linphone_iphone_file_transfer_send); + + [LinphoneManager setValueInMessageAppData:filePath forKey:key inMessage:_message]; + + LOGI(@"%p Uploading content from message %p", self, _message); + linphone_chat_room_send_chat_message(chatRoom, _message); + + if (linphone_core_lime_enabled(LC) == LinphoneLimeMandatory && !linphone_chat_room_lime_available(chatRoom)) { + [LinphoneManager.instance alertLIME:chatRoom]; + } +} + + + - (BOOL)download:(LinphoneChatMessage *)message { [[LinphoneManager.instance fileTransferDelegates] addObject:self]; diff --git a/linphone-Info.plist b/linphone-Info.plist index 202f19195..59258204f 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -51,6 +51,18 @@ linphone-config + + CFBundleTypeRole + Editor + CFBundleURLIconFile + linphone_icon_72@2x + CFBundleURLName + org.linphone.phone + CFBundleURLSchemes + + message-linphone + + CFBundleVersion 0 diff --git a/linphone.entitlements b/linphone.entitlements index 903def2af..b579b2b0d 100644 --- a/linphone.entitlements +++ b/linphone.entitlements @@ -4,5 +4,9 @@ aps-environment development + com.apple.security.application-groups + + group.belledonne-communications.linphone + diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index ebfd5d388..f80fcbf4e 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -62,6 +62,10 @@ 570742581D5A0691004B9C84 /* ShopView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 570742561D5A0691004B9C84 /* ShopView.xib */; }; 570742611D5A09B8004B9C84 /* ShopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5707425F1D5A09B8004B9C84 /* ShopView.m */; }; 570742671D5A63DB004B9C84 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570742661D5A63DB004B9C84 /* StoreKit.framework */; }; + 61AE364F20C00B370089D9D3 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AE364E20C00B370089D9D3 /* ShareViewController.m */; }; + 61AE365220C00B370089D9D3 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61AE365020C00B370089D9D3 /* MainInterface.storyboard */; }; + 61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 61F1997520C6B1D5006B069A /* AVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61F1996E20C6B1D5006B069A /* AVKit.framework */; }; 630589E71B4E810900EFAE36 /* ChatTester.m in Sources */ = {isa = PBXBuildFile; fileRef = 630589DF1B4E810900EFAE36 /* ChatTester.m */; }; 630589E81B4E810900EFAE36 /* ContactsTester.m in Sources */ = {isa = PBXBuildFile; fileRef = 630589E11B4E810900EFAE36 /* ContactsTester.m */; }; 630589EA1B4E810900EFAE36 /* LinphoneTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 630589E41B4E810900EFAE36 /* LinphoneTestCase.m */; }; @@ -811,6 +815,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 61AE365420C00B370089D9D3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 61AE364A20C00B370089D9D3; + remoteInfo = linphoneExtension; + }; 630589FC1B4E816A00EFAE36 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; @@ -877,6 +888,17 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 61AE366220C00B370089D9D3 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; 8CDC89061EAF89A8006B5652 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1014,6 +1036,13 @@ 570742601D5A09B8004B9C84 /* ShopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShopView.h; sourceTree = ""; }; 570742631D5A1860004B9C84 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ShopView.strings; sourceTree = ""; }; 570742661D5A63DB004B9C84 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = linphoneExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 61AE364D20C00B370089D9D3 /* ShareViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareViewController.h; sourceTree = ""; }; + 61AE364E20C00B370089D9D3 /* ShareViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShareViewController.m; sourceTree = ""; }; + 61AE365120C00B370089D9D3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 61AE365320C00B370089D9D3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 61AE366320C00C810089D9D3 /* linphoneExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = linphoneExtension.entitlements; sourceTree = ""; }; + 61F1996E20C6B1D5006B069A /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; 630589DE1B4E810900EFAE36 /* ChatTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatTester.h; sourceTree = ""; }; 630589DF1B4E810900EFAE36 /* ChatTester.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatTester.m; sourceTree = ""; }; 630589E01B4E810900EFAE36 /* ContactsTester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsTester.h; sourceTree = ""; }; @@ -1932,6 +1961,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 61F1997520C6B1D5006B069A /* AVKit.framework in Frameworks */, 249660951FD6A35F001D55AA /* Photos.framework in Frameworks */, 24E1C7C01F9A235600D3F981 /* Contacts.framework in Frameworks */, 8C5BCED61EB3859300A9AAEF /* mediastreamer_voip.framework in Frameworks */, @@ -1979,6 +2009,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 61AE364820C00B370089D9D3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F08F118119C09C6A007D70C2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2176,6 +2213,7 @@ F0BB8BD51936208100974404 /* liblinphoneTester.app */, F08F118419C09C6A007D70C2 /* liblinphoneTesterTests.xctest */, F0F952001A6AEB1000254160 /* linphoneTests.xctest */, + 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */, ); name = Products; sourceTree = ""; @@ -2290,6 +2328,7 @@ children = ( 8C23BCB71D82AAC3005F19BB /* linphone.entitlements */, 080E96DDFE201D6D7F000001 /* Classes */, + 61AE364C20C00B370089D9D3 /* linphoneExtension */, 29B97323FDCFA39411CA2CEA /* Frameworks */, F0938158188E629800A55DFA /* iTunesArtwork */, 63058A0C1B4E821E00EFAE36 /* LiblinphoneTester */, @@ -2316,6 +2355,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 61F1996E20C6B1D5006B069A /* AVKit.framework */, 8C435FA520BC34DA004CCA25 /* belr.framework */, 8C435F8B20BBF862004CCA25 /* belcard.framework */, 8C601FD220B462B0004FF95C /* mediastreamer2.framework */, @@ -2383,6 +2423,18 @@ name = Frameworks; sourceTree = ""; }; + 61AE364C20C00B370089D9D3 /* linphoneExtension */ = { + isa = PBXGroup; + children = ( + 61AE366320C00C810089D9D3 /* linphoneExtension.entitlements */, + 61AE364D20C00B370089D9D3 /* ShareViewController.h */, + 61AE364E20C00B370089D9D3 /* ShareViewController.m */, + 61AE365020C00B370089D9D3 /* MainInterface.storyboard */, + 61AE365320C00B370089D9D3 /* Info.plist */, + ); + path = linphoneExtension; + sourceTree = ""; + }; 630589DD1B4E810900EFAE36 /* TestsLinphone */ = { isa = PBXGroup; children = ( @@ -3168,16 +3220,35 @@ 1D60588F0D05DD3D006BFB54 /* Frameworks */, 8CDC89061EAF89A8006B5652 /* Embed Frameworks */, 8CB438A61EE6A65D0006F944 /* ShellScript */, + 61AE366220C00B370089D9D3 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 61AE365520C00B370089D9D3 /* PBXTargetDependency */, ); name = linphone; productName = linphone; productReference = 1D6058910D05DD3D006BFB54 /* linphone.app */; productType = "com.apple.product-type.application"; }; + 61AE364A20C00B370089D9D3 /* linphoneExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 61AE366120C00B370089D9D3 /* Build configuration list for PBXNativeTarget "linphoneExtension" */; + buildPhases = ( + 61AE364720C00B370089D9D3 /* Sources */, + 61AE364820C00B370089D9D3 /* Frameworks */, + 61AE364920C00B370089D9D3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = linphoneExtension; + productName = linphoneExtension; + productReference = 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; F08F118319C09C6A007D70C2 /* liblinphoneTesterTests */ = { isa = PBXNativeTarget; buildConfigurationList = F08F119319C09C6B007D70C2 /* Build configuration list for PBXNativeTarget "liblinphoneTesterTests" */; @@ -3245,6 +3316,12 @@ 1D6058900D05DD3D006BFB54 = { DevelopmentTeam = Z2V957B3D6; SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + com.apple.BackgroundModes = { + enabled = 1; + }; com.apple.InAppPurchase = { enabled = 1; }; @@ -3253,6 +3330,16 @@ }; }; }; + 61AE364A20C00B370089D9D3 = { + CreatedOnToolsVersion = 9.2; + DevelopmentTeam = Z2V957B3D6; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; + }; F08F118319C09C6A007D70C2 = { DevelopmentTeam = Z2V957B3D6; TestTargetID = F0BB8BD41936208100974404; @@ -3304,6 +3391,7 @@ F0F951FF1A6AEB1000254160 /* linphoneTests */, F0BB8BD41936208100974404 /* liblinphoneTester */, F08F118319C09C6A007D70C2 /* liblinphoneTesterTests */, + 61AE364A20C00B370089D9D3 /* linphoneExtension */, ); }; /* End PBXProject section */ @@ -3892,6 +3980,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 61AE364920C00B370089D9D3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 61AE365220C00B370089D9D3 /* MainInterface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F08F118219C09C6A007D70C2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -4114,6 +4210,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 61AE364720C00B370089D9D3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 61AE364F20C00B370089D9D3 /* ShareViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F08F118019C09C6A007D70C2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -4152,6 +4256,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 61AE365520C00B370089D9D3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 61AE364A20C00B370089D9D3 /* linphoneExtension */; + targetProxy = 61AE365420C00B370089D9D3 /* PBXContainerItemProxy */; + }; 63058A4E1B4E832500EFAE36 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = KIF; @@ -4180,6 +4289,14 @@ name = ShopView.xib; sourceTree = ""; }; + 61AE365020C00B370089D9D3 /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 61AE365120C00B370089D9D3 /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; 63058A0F1B4E821E00EFAE36 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( @@ -4709,7 +4826,7 @@ "$(SRCROOT)/Classes/Utils/XMLRPC/", ); INFOPLIST_FILE = "linphone-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; @@ -4810,7 +4927,7 @@ "$(SRCROOT)/Classes/Utils/XMLRPC/", ); INFOPLIST_FILE = "linphone-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; @@ -4911,7 +5028,7 @@ "$(SRCROOT)/Classes/Utils/XMLRPC/", ); INFOPLIST_FILE = "linphone-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; @@ -5012,7 +5129,7 @@ "$(SRCROOT)/Classes/Utils/XMLRPC/", ); INFOPLIST_FILE = "linphone-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; @@ -5035,6 +5152,165 @@ }; name = Distribution; }; + 61AE365720C00B370089D9D3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = linphoneExtension/linphoneExtension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = Z2V957B3D6; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = linphoneExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.linphoneExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + 61AE365820C00B370089D9D3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = linphoneExtension/linphoneExtension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = linphoneExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.linphoneExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 1; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 61AE365920C00B370089D9D3 /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = linphoneExtension/linphoneExtension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = linphoneExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.linphoneExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 1; + VALIDATE_PRODUCT = YES; + }; + name = Distribution; + }; + 61AE365A20C00B370089D9D3 /* DistributionAdhoc */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = linphoneExtension/linphoneExtension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = linphoneExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.linphoneExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 1; + VALIDATE_PRODUCT = YES; + }; + name = DistributionAdhoc; + }; C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5677,6 +5953,17 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + 61AE366120C00B370089D9D3 /* Build configuration list for PBXNativeTarget "linphoneExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 61AE365720C00B370089D9D3 /* Debug */, + 61AE365820C00B370089D9D3 /* Release */, + 61AE365920C00B370089D9D3 /* Distribution */, + 61AE365A20C00B370089D9D3 /* DistributionAdhoc */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; C01FCF4E08A954540054247B /* Build configuration list for PBXProject "linphone" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/linphoneExtension/Base.lproj/MainInterface.storyboard b/linphoneExtension/Base.lproj/MainInterface.storyboard new file mode 100644 index 000000000..a14188503 --- /dev/null +++ b/linphoneExtension/Base.lproj/MainInterface.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linphoneExtension/Info.plist b/linphoneExtension/Info.plist new file mode 100644 index 000000000..53c1b33b9 --- /dev/null +++ b/linphoneExtension/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + linphone + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + TRUEPREDICATE + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.share-services + + + diff --git a/linphoneExtension/ShareViewController.h b/linphoneExtension/ShareViewController.h new file mode 100644 index 000000000..6f55e6d10 --- /dev/null +++ b/linphoneExtension/ShareViewController.h @@ -0,0 +1,13 @@ +// +// ShareViewController.h +// linphoneExtension +// +// Created by Danmei Chen on 31/05/2018. +// + +#import +#import + +@interface ShareViewController : SLComposeServiceViewController + +@end diff --git a/linphoneExtension/ShareViewController.m b/linphoneExtension/ShareViewController.m new file mode 100644 index 000000000..d36c4c8b0 --- /dev/null +++ b/linphoneExtension/ShareViewController.m @@ -0,0 +1,86 @@ +// +// ShareViewController.m +// linphoneExtension +// +// Created by Danmei Chen on 31/05/2018. +// + +#import "ShareViewController.h" + +@interface ShareViewController () + +@end +static NSString* groupName = @"group.belledonne-communications.linphone"; +@implementation ShareViewController + +- (BOOL)isContentValid { + // Do validation of contentText and/or NSExtensionContext attachments here + return YES; +} + +- (void)didSelectPost { + // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. + + // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context. + for (NSExtensionItem *item in self.extensionContext.inputItems) { + for (NSItemProvider *provider in item.attachments) { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName]; + + NSString *typeIdentifier; + if ([provider hasItemConformingToTypeIdentifier:@"public.jpeg"]) { + [self loadItem:provider typeIdentifier:@"public.jpeg" defaults:defaults key:@"img"]; + } else if ([provider hasItemConformingToTypeIdentifier:@"public.url"]) { + [self loadItem:provider typeIdentifier:@"public.url" defaults:defaults key:@"web"]; + } else if ([provider hasItemConformingToTypeIdentifier:@"public.movie"]) { + [self loadItem:provider typeIdentifier:@"public.movie" defaults:defaults key:@"file"]; + } else if ([provider hasItemConformingToTypeIdentifier:@"public.plain-text"]) { + [self loadItem:provider typeIdentifier:@"public.plain-text" defaults:defaults key:@"text"]; + } else if ([provider hasItemConformingToTypeIdentifier:@"com.adobe.pdf"]) { + [self loadItem:provider typeIdentifier:@"com.adobe.pdf" defaults:defaults key:@"file"]; + } else{ + NSLog(@"Unkown itemprovider = %@", provider); + typeIdentifier = nil; + } + } + } +} + +- (NSArray *)configurationItems { + // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. + return @[]; +} + +- (void)loadItem:(NSItemProvider *)provider typeIdentifier:(NSString *)typeIdentifier defaults:(NSUserDefaults *)defaults key:(NSString *)key { + [provider loadItemForTypeIdentifier:typeIdentifier options:nil completionHandler:^(id _Nullable item, NSError * _Null_unspecified error) { + if([(NSObject*)item isKindOfClass:[NSURL class]]) { + NSData *nsData = [NSData dataWithContentsOfURL:(NSURL*)item]; + if (nsData) { + NSDictionary *dict = @{@"nsData" : nsData, + @"url" : [(NSURL*)item absoluteString], + @"name" : self.contentText}; + [defaults setObject:dict forKey:key]; + } else { + NSLog(@"NSExtensionItem Error, provider = %@", provider); + [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil]; + return; + } + } else { + NSDictionary *dict = @{@"name" : self.contentText}; + [defaults setObject:dict forKey:key]; + } + + UIResponder *responder = self; + while (responder != nil) { + if ([responder respondsToSelector:@selector(openURL:)]) { + [responder performSelector:@selector(openURL:) + withObject:[NSURL URLWithString:@"message-linphone://" ]]; + [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil]; + break; + } + responder = [responder nextResponder]; + } + [defaults synchronize]; + }]; +} + +@end diff --git a/linphoneExtension/linphoneExtension.entitlements b/linphoneExtension/linphoneExtension.entitlements new file mode 100644 index 000000000..bfb9af2e1 --- /dev/null +++ b/linphoneExtension/linphoneExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.belledonne-communications.linphone + + +