diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h index 0fc0a6a67..3e4532df0 100644 --- a/Classes/ChatConversationView.h +++ b/Classes/ChatConversationView.h @@ -96,6 +96,7 @@ + (NSURL *)getCacheFileUrl:(NSString *)name; + (void)writeFileInCache:(NSData *)data name:(NSString *)name; + (NSData *)getCacheFileData:(NSString *)name; ++ (void)writeMediaToGallery:(NSString *)name fileType:(NSString *)fileType; - (void)configureForRoom:(BOOL)editing; - (IBAction)onBackClick:(id)event; diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index 7afa6fcb0..51b0ab6af 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -814,6 +814,88 @@ static UICompositeViewDescription *compositeDescription = nil; } } ++ (void)writeMediaToGallery:(NSString *)name fileType:(NSString *)fileType { + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:filePath]) { + NSData* data = [NSData dataWithContentsOfFile:filePath]; + + // define a block , not called immediately. To avoid crash when saving photo before PHAuthorizationStatusNotDetermined. + void (^block)(void)= ^ { + if ([fileType isEqualToString:@"image"] ) { + // we're finished, save the image and update the message + UIImage *image = [UIImage imageWithData:data]; + if (!image) { + ChatConversationView *view = VIEW(ChatConversationView); + [view showFileDownloadError]; + return; + } + __block PHObjectPlaceholder *placeHolder; + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ + PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromImage:image]; + placeHolder = [request placeholderForCreatedAsset]; + } completionHandler:^(BOOL success, NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (error) { + LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); + UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil) + message:NSLocalizedString(@"Cannot write image to photo library",nil) + preferredStyle:UIAlertControllerStyleAlert]; + + 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 [%@]", [placeHolder localIdentifier]); + } + }); + }]; + } else if([fileType isEqualToString:@"video"]) { + __block PHObjectPlaceholder *placeHolder; + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ + PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:filePath]]; + placeHolder = [request placeholderForCreatedAsset]; + } completionHandler:^(BOOL success, NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (error) { + LOGE(@"Cannot save video data downloaded [%@]", [error localizedDescription]); + UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil) + message:NSLocalizedString(@"Cannot write video to photo library", nil) + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) {}]; + + [errView addAction:defaultAction]; + [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; + } else { + LOGI(@"video saved to [%@]", [placeHolder localIdentifier]); + } + }); + }]; + } + }; + + // When you save an image or video to a photo library, make sure that it is allowed. Otherwise, there will be a backup error. + if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { + block(); + } else { + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + dispatch_async(dispatch_get_main_queue(), ^{ + if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { + block(); + } else { + [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show]; + } + }); + }]; + } + } +} -(void) writeVideoToGallery:(NSURL *)url { NSString *localIdentifier; @@ -1324,6 +1406,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog return @"localfile"; } +/* There are three cases: auto download in foreground, auto download in background, on click download*/ + (void)autoDownload:(LinphoneChatMessage *)message { ChatConversationView *view = VIEW(ChatConversationView); LinphoneContent *content = linphone_chat_message_get_file_transfer_information(message); @@ -1333,7 +1416,11 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog [LinphoneManager setValueInMessageAppData:name forKey:key inMessage:message]; dispatch_async(dispatch_get_main_queue(), ^{ - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view];}); + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view]; + if ([ConfigManager.instance lpConfigBoolForKeyWithKey:@"auto_write_to_gallery_preference"]) { + [ChatConversationView writeMediaToGallery:name fileType:fileType]; + } + }); } -(void) documentMenu:(UIDocumentMenuViewController *)documentMenu didPickDocumentPicker:(UIDocumentPickerViewController *)documentPicker { diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 1b4118483..2c3578c0d 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -338,7 +338,8 @@ [self setCString:linphone_core_get_file_transfer_server(LC) forKey:@"file_transfer_server_url_preference"]; int maxSize = linphone_core_get_max_size_for_auto_download_incoming_files(LC); [self setObject:maxSize==0 ? @"Always" : (maxSize==-1 ? @"Nerver" : @"Customize") forKey:@"auto_download_mode"]; - [self setInteger:maxSize forKey:@"auto_download_incoming_files_max_size"]; + [self setInteger:maxSize forKey:@"auto_download_incoming_files_max_size"]; + [self setBool:[lm lpConfigBoolForKey:@"auto_write_to_gallery_preference" withDefault:YES] forKey:@"auto_write_to_gallery_mode"]; } // network section @@ -779,6 +780,7 @@ } linphone_core_set_max_size_for_auto_download_incoming_files(LC, maxSize); [lm lpConfigSetString:[self stringForKey:@"auto_download_mode"] forKey:@"auto_download_mode"]; + [lm lpConfigSetBool:[self boolForKey:@"auto_write_to_gallery_mode"] forKey:@"auto_write_to_gallery_preference"]; // network section BOOL edgeOpt = [self boolForKey:@"edge_opt_preference"]; diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 032170706..de665dd05 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -199,6 +199,11 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; if (!(localImage || localVideo || localFile)) { // If the file has been downloaded in background, save it in the folders and display it. [LinphoneManager setValueInMessageAppData:fileName forKey:key inMessage:self.message]; + dispatch_async(dispatch_get_main_queue(), ^ { + if ([ConfigManager.instance lpConfigBoolForKeyWithKey:@"auto_write_to_gallery_preference"]) { + [ChatConversationView writeMediaToGallery:fileName fileType:fileType]; + } + }); } } [self uploadingImage:fileType localFile:localFile]; @@ -391,95 +396,11 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; } DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:@""]; dispatch_async(dispatch_get_main_queue(), ^{ - [sheet addButtonWithTitle:NSLocalizedString(@"Save to Photos", nil) + [sheet addButtonWithTitle:NSLocalizedString(@"Save to Gallery", nil) block:^() { - ChatConversationView *view = VIEW(ChatConversationView); LinphoneContent *content = linphone_chat_message_get_file_transfer_information(self.message); NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)]; - // get download path - NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - if ([fileManager fileExistsAtPath:filePath]) { - NSData* data = [NSData dataWithContentsOfFile:filePath]; - NSString *fileType = [NSString stringWithUTF8String:linphone_content_get_type(content)]; - - // define a block , not called immediately. To avoid crash when saving photo before PHAuthorizationStatusNotDetermined. - void (^block)(void)= ^ { - if ([fileType isEqualToString:@"image"] ) { - // we're finished, save the image and update the message - UIImage *image = [UIImage imageWithData:data]; - if (!image) { - [view showFileDownloadError]; - return; - } - __block PHObjectPlaceholder *placeHolder; - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ - PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromImage:image]; - placeHolder = [request placeholderForCreatedAsset]; - } completionHandler:^(BOOL success, NSError *error) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (error) { - LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); - UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot write image to photo library",nil) - preferredStyle:UIAlertControllerStyleAlert]; - - 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 [%@]", [placeHolder localIdentifier]); - } - }); - }]; - } else if([fileType isEqualToString:@"video"]) { - // 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 - - __block PHObjectPlaceholder *placeHolder; - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ - PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:filePath]]; - placeHolder = [request placeholderForCreatedAsset]; - } completionHandler:^(BOOL success, NSError * _Nullable error) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (error) { - LOGE(@"Cannot save video data downloaded [%@]", [error localizedDescription]); - UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot write video to photo library", nil) - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) {}]; - - [errView addAction:defaultAction]; - [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; - } else { - LOGI(@"video saved to [%@]", [placeHolder localIdentifier]); - } - }); - }]; - } - }; - - // When you save an image or video to a photo library, make sure that it is allowed. Otherwise, there will be a backup error. - if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { - block(); - } else { - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { - dispatch_async(dispatch_get_main_queue(), ^{ - if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { - block(); - } else { - [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show]; - } - }); - }]; - } - } + [ChatConversationView writeMediaToGallery:name fileType:[NSString stringWithUTF8String:linphone_content_get_type(content)?:""]]; }]; [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index 0879271d6..542ff5bc5 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -71,6 +71,9 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to trigger @"progress" : @(1.f), // FileTransferDone here }]; + if ([ConfigManager.instance lpConfigBoolForKeyWithKey:@"auto_write_to_gallery_preference"]) { + [ChatConversationView writeMediaToGallery:name fileType:fileType]; + } }); } else { LOGD(@"Transfer of %s (%d bytes): already %ld sent, adding %ld", linphone_content_get_name(content),