From f5b683e9d70d73f282ab1b9b2309ed00ac51a157 Mon Sep 17 00:00:00 2001 From: Danmei Chen Date: Thu, 25 Feb 2021 09:36:14 +0100 Subject: [PATCH] rework storage and display files --- Classes/ChatConversationTableView.h | 4 +- Classes/ChatConversationTableView.m | 6 +- Classes/ChatConversationView.h | 4 + Classes/ChatConversationView.m | 222 +++++----------- Classes/LinphoneUI/UIChatBubblePhotoCell.m | 289 +++++++++------------ Classes/LinphoneUI/UIChatBubbleTextCell.m | 194 +++++++------- Classes/Utils/FileTransferDelegate.h | 4 +- Classes/Utils/FileTransferDelegate.m | 270 +++++-------------- 8 files changed, 352 insertions(+), 641 deletions(-) diff --git a/Classes/ChatConversationTableView.h b/Classes/ChatConversationTableView.h index a87f35f14..017889f00 100644 --- a/Classes/ChatConversationTableView.h +++ b/Classes/ChatConversationTableView.h @@ -27,8 +27,8 @@ @protocol ChatConversationDelegate -- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality; -- (BOOL)startFileUpload:(NSData *)data assetId:(NSString *)phAssetId; +- (BOOL)resendFile:(NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message; +- (BOOL)startImageUpload:(UIImage *)image withQuality:(float)quality andMessage:(NSString *)message; - (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name; - (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url; - (void)tableViewIsScrolling; diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m index f72d9acc5..781fe0360 100644 --- a/Classes/ChatConversationTableView.m +++ b/Classes/ChatConversationTableView.m @@ -363,9 +363,9 @@ static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f; - (void)removeSelectionUsing:(void (^)(NSIndexPath *))remover { [super removeSelectionUsing:^(NSIndexPath *indexPath) { LinphoneEventLog *event = [[eventList objectAtIndex:indexPath.row] pointerValue]; - // TODO: fix workaround - //linphone_event_log_delete_from_database(event); - linphone_chat_room_delete_message(_chatRoom, linphone_event_log_get_chat_message(event)); + if (linphone_event_log_get_chat_message(event)) { + linphone_chat_room_delete_message(_chatRoom, linphone_event_log_get_chat_message(event)); + } NSInteger index = indexPath.row + _currentIndex + (totalEventList.count - eventList.count); if (index < totalEventList.count) [totalEventList removeObjectAtIndex:index]; diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h index 7f97ac7d1..0fc0a6a67 100644 --- a/Classes/ChatConversationView.h +++ b/Classes/ChatConversationView.h @@ -92,6 +92,10 @@ + (void)markAsRead:(LinphoneChatRoom *)chatRoom; + (void)autoDownload:(LinphoneChatMessage *)message; ++(NSString *)getKeyFromFileType:(NSString *)fileType fileName:(NSString *)name; ++ (NSURL *)getCacheFileUrl:(NSString *)name; ++ (void)writeFileInCache:(NSData *)data name:(NSString *)name; ++ (NSData *)getCacheFileData:(NSString *)name; - (void)configureForRoom:(BOOL)editing; - (IBAction)onBackClick:(id)event; diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index bf1d95b12..7afa6fcb0 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -337,33 +337,17 @@ static UICompositeViewDescription *compositeDescription = nil; //file shared from photo lib NSString *fileName = dict[@"url"]; [_messageField setText:dict[@"message"]]; - NSString *key = [[fileName componentsSeparatedByString:@"."] firstObject]; - NSMutableDictionary * assetDict = [LinphoneUtils photoAssetsDictionary]; - PHAsset *phasset = [assetDict objectForKey:key]; - if (!phasset) { - // for the images or videos not really in the photo album - [self confirmShare:[self nsDataRead] url:nil fileName:fileName assetId:nil]; - } else if ([fileName hasSuffix:@"JPG"] || [fileName hasSuffix:@"PNG"] || [fileName hasSuffix:@"jpg"] || [fileName hasSuffix:@"png"]) { - UIImage *image = [[UIImage alloc] initWithData:[self nsDataRead]]; - [self chooseImageQuality:image assetId:[phasset localIdentifier]]; - } else if ([fileName hasSuffix:@"MOV"] || [fileName hasSuffix:@"mov"]) { - [self confirmShare:[self nsDataRead] url:nil fileName:nil assetId:[phasset localIdentifier]]; - } else { - LOGE(@"Unable to parse file %@",fileName); - } - + [self confirmShare:[self nsDataRead] url:nil fileName:fileName]; [defaults removeObjectForKey:@"photoData"]; } else if (dictFile) { NSString *fileName = dictFile[@"url"]; [_messageField setText:dictFile[@"message"]]; - [self confirmShare:[self nsDataRead] url:nil fileName:fileName assetId:nil]; - + [self confirmShare:[self nsDataRead] url:nil fileName:fileName]; [defaults removeObjectForKey:@"icloudData"]; } else if (dictUrl) { NSString *url = dictUrl[@"url"]; [_messageField setText:dictUrl[@"message"]]; - [self confirmShare:nil url:url fileName:nil assetId:nil]; - + [self confirmShare:nil url:url fileName:nil]; [defaults removeObjectForKey:@"url"]; } } @@ -417,7 +401,7 @@ static UICompositeViewDescription *compositeDescription = nil; } } -- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl withInternalURL:(NSURL *)internalUrl { +- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl { if (_chatRoom == NULL) { LOGW(@"Cannot send message: No chatroom"); return FALSE; @@ -428,11 +412,6 @@ static UICompositeViewDescription *compositeDescription = nil; linphone_chat_message_set_external_body_url(msg, [[externalUrl absoluteString] UTF8String]); } - if (internalUrl) { - // 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 linphone_chat_message_send(msg); @@ -474,7 +453,7 @@ static UICompositeViewDescription *compositeDescription = nil; }); } -- (void)confirmShare:(NSData *)data url:(NSString *)url fileName:(NSString *)fileName assetId:(NSString *)phAssetId { +- (void)confirmShare:(NSData *)data url:(NSString *)url fileName:(NSString *)fileName { DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:@""]; dispatch_async(dispatch_get_main_queue(), ^{ [sheet addButtonWithTitle:NSLocalizedString(@"Send to this friend", nil) @@ -483,11 +462,10 @@ static UICompositeViewDescription *compositeDescription = nil; [self sendMessageInMessageField]; } if (url) - [self sendMessage:url withExterlBodyUrl:nil withInternalURL:nil]; - else if (fileName) - [self startFileUpload:data withName:fileName]; + [self sendMessage:url withExterlBodyUrl:nil]; else - [self startFileUpload:data assetId:phAssetId];}]; + [self startFileUpload:data withName:fileName]; + }]; [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; [sheet showInView:PhoneMainView.instance.view]; @@ -568,7 +546,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (void)sendMessageInMessageField { - if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil withInternalURL:nil]) { + if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil]) { scrollOnGrowingEnabled = FALSE; [_messageField setText:@""]; scrollOnGrowingEnabled = TRUE; @@ -651,15 +629,15 @@ static UICompositeViewDescription *compositeDescription = nil; if ([_imagesArray count] > 0) { int i = 0; for (i = 0; i < [_imagesArray count] - 1; ++i) { - [self startImageUpload:[_imagesArray objectAtIndex:i] assetId:[_assetIdsArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue]; + [self startImageUpload:[_imagesArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue andMessage:NULL]; } if (isOneToOne) { - [self startImageUpload:[_imagesArray objectAtIndex:i] assetId:[_assetIdsArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue]; + [self startImageUpload:[_imagesArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue andMessage:NULL]; if (![[self.messageField text] isEqualToString:@""]) { - [self sendMessage:[_messageField text] withExterlBodyUrl:nil withInternalURL:nil]; + [self sendMessage:[_messageField text] withExterlBodyUrl:nil]; } } else { - [self startImageUpload:[_imagesArray objectAtIndex:i] assetId:[_assetIdsArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue andMessage:[self.messageField text]]; + [self startImageUpload:[_imagesArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue andMessage:[self.messageField text]]; } [self clearMessageView]; @@ -761,28 +739,15 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark ChatRoomDelegate -- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality { +- (BOOL)startImageUpload:(UIImage *)image withQuality:(float)quality andMessage:(NSString *)message { FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init]; - [fileTransfer upload:image withassetId:phAssetId forChatRoom:_chatRoom withQuality:quality]; + if (message) + [fileTransfer setText:message]; + [fileTransfer uploadImage:image forChatRoom:_chatRoom withQuality:quality]; [_tableController scrollToBottom:true]; return TRUE; } -- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality andMessage:(NSString *)message { - FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init]; - [fileTransfer setText:message]; - [fileTransfer upload:image withassetId:phAssetId forChatRoom:_chatRoom withQuality:quality]; - [_tableController scrollToBottom:true]; - return TRUE; -} - -- (BOOL)startFileUpload:(NSData *)data assetId:(NSString *)phAssetId { - FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init]; - [fileTransfer uploadVideo:data withassetId:phAssetId forChatRoom:_chatRoom]; - [_tableController scrollToBottom:true]; - return TRUE; -} - - (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name { FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init]; [fileTransfer uploadFile:data forChatRoom:_chatRoom withName:name]; @@ -790,8 +755,17 @@ static UICompositeViewDescription *compositeDescription = nil; return TRUE; } +- (BOOL)resendFile: (NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message { + FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init]; + if (message) + [fileTransfer setText:message]; + [fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key]; + [_tableController scrollToBottom:true]; + return TRUE; +} + - (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url { - [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] withInternalURL:nil]; + [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url]]; } #pragma mark ImagePickerDelegate @@ -1179,6 +1153,23 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog [PhoneMainView.instance fullScreen:NO]; } ++ (NSData *)getCacheFileData: (NSString *)name { + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]; + return [NSData dataWithContentsOfFile:filePath]; +} + ++ (NSURL *)getCacheFileUrl: (NSString *)name { + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]; + return [NSURL fileURLWithPath:filePath]; +} + ++ (void)writeFileInCache:(NSData *)data name:(NSString *)name { + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]; + [[NSFileManager defaultManager] createFileAtPath:filePath + contents:data + attributes:nil]; +} + - (NSURL *)getICloudFileUrl:(NSString *)name { if (@available(iOS 11.0, *)) { return [NSURL fileURLWithPath:[LinphoneManager documentFile:name]]; @@ -1324,118 +1315,25 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; } ++ (NSString *)getKeyFromFileType:(NSString *)fileType fileName:(NSString *)name{ + if ([fileType isEqualToString:@"video"]) { + return @"localvideo"; + } else if ([fileType isEqualToString:@"image"] || [name hasSuffix:@"JPG"] || [name hasSuffix:@"PNG"] || [name hasSuffix:@"jpg"] || [name hasSuffix:@"png"]) { + return @"localimage"; + } + return @"localfile"; +} + + (void)autoDownload:(LinphoneChatMessage *)message { ChatConversationView *view = VIEW(ChatConversationView); - //TODO: migrate with "linphone_iphone_file_transfer_recv" - LinphoneContent *content = linphone_chat_message_get_file_transfer_information(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)]; + LinphoneContent *content = linphone_chat_message_get_file_transfer_information(message); + NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)]; + NSString *fileType = [NSString stringWithUTF8String:linphone_content_get_type(content)]; + NSString *key = [ChatConversationView getKeyFromFileType:fileType fileName:name]; - // 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 NSString *createdAssetId = nil; - [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ - createdAssetId = [PHAssetCreationRequest creationRequestForAssetFromImage:image].placeholderForCreatedAsset.localIdentifier; - } error:nil]; - if (createdAssetId != nil) { - LOGI(@"Image saved to [%@]", createdAssetId); - [LinphoneManager setValueInMessageAppData:createdAssetId - forKey:@"localimage" - inMessage:message]; - dispatch_async(dispatch_get_main_queue(), ^{ - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view]; - }); - } else { - LOGE(@"Cannot save image data downloaded"); - [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:message]; - dispatch_async(dispatch_get_main_queue(), ^{ - 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 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 NSString *createdAssetId = nil; - [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ - createdAssetId = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:filePath]].placeholderForCreatedAsset.localIdentifier; - } error:nil]; - if (createdAssetId != nil) { - LOGI(@"video saved to [%@]", createdAssetId); - [LinphoneManager setValueInMessageAppData:createdAssetId - forKey:@"localvideo" - inMessage:message]; - dispatch_async(dispatch_get_main_queue(), ^{ - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view]; - }); - } else { - LOGE(@"Cannot save video data downloaded"); - [LinphoneManager setValueInMessageAppData:nil forKey:@"localvideo" inMessage:message]; - dispatch_async(dispatch_get_main_queue(), ^{ - 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]; - }); - } - } - }; - - // 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 ([fileType isEqualToString:@"image"] || [fileType isEqualToString:@"video"]) { - 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]; - } - }); - }]; - } - } else { - NSString *key = @"localfile"; - //write file to path - if([view writeFileInICloud:data fileURL:[view getICloudFileUrl:name]]) { - [LinphoneManager setValueInMessageAppData:name forKey:key inMessage:message]; - dispatch_async(dispatch_get_main_queue(), ^{ - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view];}); - } else { - LOGE(@"[Auto download error] can not save the file %@", name); - } - } - } + [LinphoneManager setValueInMessageAppData:name forKey:key inMessage:message]; + dispatch_async(dispatch_get_main_queue(), ^{ + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:view];}); } -(void) documentMenu:(UIDocumentMenuViewController *)documentMenu didPickDocumentPicker:(UIDocumentPickerViewController *)documentPicker { diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 5e62338f4..11f23748f 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -154,172 +154,105 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; LOGW(@"Cannot update message room cell: NULL message"); return; } - [super update]; + [super update]; 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]; + NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:self.message]; + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; assert(is_external || localImage || localVideo || localFile); - - + + LinphoneContent *fileContent = linphone_chat_message_get_file_transfer_information(self.message); + NSString *type = fileContent ? [NSString stringWithUTF8String:linphone_content_get_type(fileContent)] : @""; if (!(localImage || localVideo || localFile)) { - // If the file has been downloaded in background, save it in the folders and display it. - ChatConversationView *view = VIEW(ChatConversationView); - //TODO: migrate with "linphone_iphone_file_transfer_recv" - 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]); - [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:self.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" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) {}]; - - [errView addAction:defaultAction]; - [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; - } else { - LOGI(@"Image saved to [%@]", [placeHolder localIdentifier]); - [LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier] - forKey:@"localimage" - inMessage:self.message]; - [self updateButtons:[LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:self.message] localVideo:localVideo localFile:localFile]; - } - }); - }]; - } 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]); - [LinphoneManager setValueInMessageAppData:nil forKey:@"localvideo" inMessage:self.message]; - 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]); - [LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier] - forKey:@"localvideo" - inMessage:self.message]; - [self updateButtons:localImage localVideo:[LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:self.message] localFile:localFile]; - } - }); - }]; - } - }; - - // 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 ([fileType isEqualToString:@"image"] || [fileType isEqualToString:@"video"]) { - 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]; - } - }); - }]; - } - } else { - NSString *key = @"localfile"; - //write file to path - if([view writeFileInICloud:data fileURL:[view getICloudFileUrl:name]]) { - dispatch_async(dispatch_get_main_queue(), ^{ - [LinphoneManager setValueInMessageAppData:name forKey:key inMessage:self.message]; - [self updateButtons:localImage localVideo:localVideo localFile:[LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]]; - }); - } else { - LOGE(@"[Auto download error] can not save the file %@", name); - } - } - } - } - - [self updateButtons:localImage localVideo:localVideo localFile:localFile]; -} - -- (void)updateButtons: (NSString *)localImage localVideo:(NSString *)localVideo localFile:(NSString *)localFile { - LinphoneContent *fileContent = linphone_chat_message_get_file_transfer_information(self.message); - NSString *type = fileContent ? [NSString stringWithUTF8String:linphone_content_get_type(fileContent)] : nil; - if (!(localImage || localVideo || localFile)) { - _playButton.hidden = YES; - _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES; - _messageImageView.hidden = _cancelButton.hidden = (_ftd.message == nil); - _downloadButton.hidden = !_cancelButton.hidden; - _fileTransferProgress.hidden = NO; - } else { - // file is being saved on device - just wait for it - if ([localImage isEqualToString:@"saving..."] || [localVideo isEqualToString:@"saving..."] || [localFile isEqualToString:@"saving..."]) { - _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES; + _playButton.hidden = YES; + _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES; + _messageImageView.hidden = _cancelButton.hidden = (_ftd.message == nil); + _downloadButton.hidden = !_cancelButton.hidden; + _fileTransferProgress.hidden = NO; + } else { + // file is being saved on device - just wait for it + if ([localImage isEqualToString:@"saving..."] || [localVideo isEqualToString:@"saving..."] || [localFile isEqualToString:@"saving..."]) { + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES; } else { if(!assetIsLoaded) { assetIsLoaded = TRUE; if (localImage) { // we did not load the image yet, so start doing so if (_messageImageView.image == nil) { - [self loadFirstImage:localImage type:PHAssetMediaTypeImage]; - _imageGestureRecognizer.enabled = YES; + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localImage]; + if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + NSData* data = [NSData dataWithContentsOfFile:filePath]; + UIImage *image = [[UIImage alloc] initWithData:data]; + [self loadImageAsset:nil image:image]; + _imageGestureRecognizer.enabled = YES; + } else { + // support previous versions + [self loadFirstImage:localImage type:PHAssetMediaTypeImage]; + _imageGestureRecognizer.enabled = YES; + + dispatch_async(dispatch_get_main_queue(), ^ { + UIImage *image = [chatTableView.imagesInChatroom objectForKey:localImage]; + NSString *name = [NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]]; + NSData *data = UIImageJPEGRepresentation(image, 1); + [ChatConversationView writeFileInCache:data name:name]; + [LinphoneManager setValueInMessageAppData:name forKey:@"localimage" inMessage:self.message]; + }); + } } - } - else if (localVideo) { + } else if (localVideo) { if (_messageImageView.image == nil) { - [self loadFirstImage:localVideo type:PHAssetMediaTypeVideo]; - _imageGestureRecognizer.enabled = NO; + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localVideo]; + if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + UIImage* image = [UIChatBubbleTextCell getImageFromVideoUrl:[ChatConversationView getCacheFileUrl:localVideo]]; + [self loadImageAsset:nil image:image]; + _imageGestureRecognizer.enabled = NO; + } else { + // support previous versions + [self loadFirstImage:localVideo type:PHAssetMediaTypeVideo]; + _imageGestureRecognizer.enabled = NO; + + dispatch_async(dispatch_get_main_queue(), ^ { + PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] options:nil]; + if (![assets firstObject]) + return; + PHAsset *asset = [assets firstObject]; + if (asset.mediaType != PHAssetMediaTypeVideo) + return; + PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; + options.version = PHImageRequestOptionsVersionCurrent; + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; + + [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { + AVURLAsset *urlAsset = (AVURLAsset *)asset; + NSData *data = [NSData dataWithContentsOfURL:urlAsset.URL]; + NSString *name = [NSString stringWithFormat:@"IMG-%f.MOV", [NSDate timeIntervalSinceReferenceDate]]; + [ChatConversationView writeFileInCache:data name:name]; + [LinphoneManager setValueInMessageAppData:name forKey:@"localvideo" inMessage:self.message]; + + }]; + + }); + } + } + } else if (localFile) { + BOOL newVersion = FALSE; + if(![[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localFile]]) { + dispatch_async(dispatch_get_main_queue(), ^ { + NSURL *url = [VIEW(ChatConversationView) getICloudFileUrl:localFile]; + NSData *data = [NSData dataWithContentsOfURL:url]; + [ChatConversationView writeFileInCache:data name:localFile]; + }); + } else { + newVersion = TRUE; } - } - else if (localFile) { if ([type isEqualToString:@"video"]) { - UIImage* image = [UIChatBubbleTextCell getImageFromVideoUrl:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; + UIImage* image = [UIChatBubbleTextCell getImageFromVideoUrl:newVersion? [ChatConversationView getCacheFileUrl:localFile] : [VIEW(ChatConversationView) getICloudFileUrl:localFile]]; [self loadImageAsset:nil image:image]; _imageGestureRecognizer.enabled = NO; } else if ([localFile hasSuffix:@"JPG"] || [localFile hasSuffix:@"PNG"] || [localFile hasSuffix:@"jpg"] || [localFile hasSuffix:@"png"]) { - NSData *data = [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; + NSData *data = newVersion? [ChatConversationView getCacheFileData:localFile] : [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; UIImage *image = [[UIImage alloc] initWithData:data]; [self loadImageAsset:nil image:image]; _imageGestureRecognizer.enabled = YES; @@ -342,7 +275,7 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; _playButton.hidden = ![type isEqualToString:@"video"]; _fileName.hidden = _fileView.hidden = _fileButton.hidden = localFile ? NO : YES; } - } + } } - (void)loadFirstImage:(NSString *)key type:(PHAssetMediaType)type { @@ -391,11 +324,29 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; } - (IBAction)onPlayClick:(id)sender { + NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:self.message]; + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; + if (localVideo && [[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localVideo]]) { + AVPlayer *player = [AVPlayer playerWithURL:[ChatConversationView getCacheFileUrl:localVideo]]; + [self playVideoByPlayer:player]; + return; + } else if (localFile && [[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localFile]]) { + AVPlayer *player = [AVPlayer playerWithURL:[ChatConversationView getCacheFileUrl:localFile]]; + [self playVideoByPlayer:player]; + return; + } + PHAsset *asset = [_messageImageView asset]; if (!asset) { NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; - AVPlayer *player = [AVPlayer playerWithURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; + NSURL *url = [VIEW(ChatConversationView) getICloudFileUrl:localFile]; + AVPlayer *player = [AVPlayer playerWithURL:url]; [self playVideoByPlayer:player]; + dispatch_async(dispatch_get_main_queue(), ^ { + NSData *data = [NSData dataWithContentsOfURL:url]; + [ChatConversationView writeFileInCache:data name:localFile]; + }); + return; } PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; @@ -413,7 +364,11 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; - (IBAction)onFileClick:(id)sender { ChatConversationView *view = VIEW(ChatConversationView); NSString *name = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; - [view openFileWithURL:[view getICloudFileUrl:name]]; + if([[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]]) { + [view openFileWithURL:[ChatConversationView getCacheFileUrl:name]]; + } else { + [view openFileWithURL:[view getICloudFileUrl:name]]; + } } @@ -441,22 +396,38 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; - (IBAction)onImageClick:(id)event { LinphoneChatMessageState state = linphone_chat_message_get_state(self.message); if (state == LinphoneChatMessageStateNotDelivered) { + FileTransferDelegate *thiz = [FileTransferDelegate messageDelegate:self.message]; + if (thiz) { + [thiz stopAndDestroy]; + } [self onResendClick:event]; } else { if (![_messageImageView isLoading]) { ImageView *view = VIEW(ImageView); [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; + NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:self.message]; + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; + NSString *imageName = NULL; + if (localImage && [[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localImage]]) { + imageName = localImage; + } else if (localFile && [[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localFile]]) { + if ([localFile hasSuffix:@"JPG"] || [localFile hasSuffix:@"PNG"] || [localFile hasSuffix:@"jpg"] || [localFile hasSuffix:@"png"]) { + imageName = localFile; + } + } + + if (imageName) { + NSData *data = [NSData dataWithContentsOfFile:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:imageName]]; + UIImage *image = [[UIImage alloc] initWithData:data]; + if (image) + [view setImage:image]; + else + LOGE(@"Can't read image"); + return; + } + PHAsset *asset = [_messageImageView asset]; if (!asset) { - NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message]; - if ([localFile hasSuffix:@"JPG"] || [localFile hasSuffix:@"PNG"] || [localFile hasSuffix:@"jpg"] || [localFile hasSuffix:@"png"]) { - NSData *data = [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; - UIImage *image = [[UIImage alloc] initWithData:data]; - if (image) - [view setImage:image]; - else - LOGE(@"Can't read image"); - } return; } PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index 7e20bc112..bcb30af36 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -276,74 +276,33 @@ 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]; + NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message]; + NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message]; + /*FileTransferDelegate *thiz = [FileTransferDelegate messageDelegate:_message]; + if (thiz) { + [thiz stop] + }*/ [self onDelete]; - if(localImage){ - ChatConversationTableView *tableView = VIEW(ChatConversationView).tableController; - UIImage *img = [tableView.imagesInChatroom objectForKey:localImage]; - if (img) { - dispatch_async(dispatch_get_main_queue(), ^ { - [_chatRoomDelegate startImageUpload:img assetId:localImage withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; - }); - } else { - PHFetchResult *assets = [LinphoneManager getPHAssets:localImage]; - - if (![assets firstObject]) - return; - PHAsset *asset = [assets firstObject]; - if (asset.mediaType != PHAssetMediaTypeImage) - return; - - PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; - options.synchronous = TRUE; - [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options - resultHandler:^(UIImage *image, NSDictionary * info) { - if (image) { - dispatch_async(dispatch_get_main_queue(), - ^(void) { - [_chatRoomDelegate startImageUpload:img assetId:localImage withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; - }); - } else { - LOGE(@"Can't read image"); - } - }]; - } - } else if (localVideo) { - PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] options:nil]; - if (![assets firstObject]) - return; - PHAsset *asset = [assets firstObject]; - if (asset.mediaType != PHAssetMediaTypeVideo) - return; - - PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; - options.version = PHImageRequestOptionsVersionCurrent; - options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; - - [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { - AVURLAsset *urlAsset = (AVURLAsset *)asset; - - NSURL *url = urlAsset.URL; - NSData *data = [NSData dataWithContentsOfURL:url]; - dispatch_async(dispatch_get_main_queue(), - ^(void) { - [_chatRoomDelegate startFileUpload:data assetId:localVideo]; - }); - }]; - - } else if (localFile) { - NSData *data = [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; - [_chatRoomDelegate startFileUpload:data withName:localFile]; - } + if(localImage){ + dispatch_async(dispatch_get_main_queue(), ^ { + [_chatRoomDelegate resendFile:[ChatConversationView getCacheFileData:localImage] withName:localImage type:@"image" key:@"localimage" message:self.textMessage]; + }); + } else if (localVideo) { + dispatch_async(dispatch_get_main_queue(), ^ { + [_chatRoomDelegate resendFile:[ChatConversationView getCacheFileData:localVideo] withName:localVideo type:@"video" key:@"localvideo" message:self.textMessage]; + }); + } else if (localFile) { + dispatch_async(dispatch_get_main_queue(), ^ { + [_chatRoomDelegate resendFile:[ChatConversationView getCacheFileData:localFile] withName:localFile type:@"image" key:@"localfile" message:self.textMessage]; + }); + } } else { - [self onDelete]; + [self onDelete]; double delayInSeconds = 0.4; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { - [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil]; + [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil]; }); } } @@ -443,53 +402,74 @@ static const CGFloat CELL_IMAGE_X_MARGIN = 100; font:messageFont]; size.height += textSize.height; } - - if(localFile) { - UIImage *image = nil; - NSString *type = [NSString stringWithUTF8String:linphone_content_get_type(fileContent)]; - if ([type isEqualToString:@"video"]) { - image = [self getImageFromVideoUrl:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; - } else if ([localFile hasSuffix:@"JPG"] || [localFile hasSuffix:@"PNG"] || [localFile hasSuffix:@"jpg"] || [localFile hasSuffix:@"png"]) { - NSData *data = [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; - image = [[UIImage alloc] initWithData:data]; - } - if (image) { - size = [self getMediaMessageSizefromOriginalSize:image.size withWidth:width]; - // add size for message text - size.height += textSize.height; - size.width = MAX(textSize.width, size.width); - } else { - CGSize fileSize = CGSizeMake(230, 50); - size = [self getMediaMessageSizefromOriginalSize:fileSize withWidth:width]; - } - } else { - if (!localImage && !localVideo) { - //We are loading the image - return CGSizeMake(CELL_MIN_WIDTH + CELL_MESSAGE_X_MARGIN, CELL_MIN_HEIGHT + CELL_MESSAGE_Y_MARGIN + textSize.height + 20); - } - PHFetchResult *assets; - if(localImage) - assets = [LinphoneManager getPHAssets:localImage]; - else - assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] options:nil]; - if (![assets firstObject]) { - return CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_WIDTH + CELL_MESSAGE_Y_MARGIN + textSize.height); - } else { - PHAsset *asset = [assets firstObject]; - CGSize originalImageSize = CGSizeMake([asset pixelWidth], [asset pixelHeight]); - size = [self getMediaMessageSizefromOriginalSize:originalImageSize withWidth:width]; - - // add size for message text - size.height += textSize.height; - size.width = MAX(textSize.width, size.width); - } - } - } + CGSize originalImageSize = CGSizeMake(230, 50); + if (localFile) { + UIImage *image = nil; + NSString *type = [NSString stringWithUTF8String:linphone_content_get_type(fileContent)]; + NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localFile]; + if ([type isEqualToString:@"video"]) { + if ([[NSFileManager defaultManager] fileExistsAtPath: filePath]) { + image = [self getImageFromVideoUrl:[ChatConversationView getCacheFileUrl:localFile]]; + } else { + image = [self getImageFromVideoUrl:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; + } + } else if ([localFile hasSuffix:@"JPG"] || [localFile hasSuffix:@"PNG"] || [localFile hasSuffix:@"jpg"] || [localFile hasSuffix:@"png"]) { + if ([[NSFileManager defaultManager] fileExistsAtPath: filePath]) { + NSData *data = [NSData dataWithContentsOfFile:filePath]; + image = [[UIImage alloc] initWithData:data]; + } else { + NSData *data = [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]]; + image = [[UIImage alloc] initWithData:data]; + } + } else { + // other files // todo for text + CGSize fileSize = CGSizeMake(230, 50); + size = [self getMediaMessageSizefromOriginalSize:fileSize withWidth:width]; + size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH); + size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT); + return size; + } - size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH); - size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT); - return size; + originalImageSize = image.size; + } else { + if (!localImage && !localVideo) { + //We are loading the image + return CGSizeMake(CELL_MIN_WIDTH + CELL_MESSAGE_X_MARGIN, CELL_MIN_HEIGHT + CELL_MESSAGE_Y_MARGIN + textSize.height + 20); + } + + if (localImage && [[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localImage]]) { + NSData* data = [ChatConversationView getCacheFileData:localImage]; + UIImage *image = [[UIImage alloc] initWithData:data]; + originalImageSize = image.size; + } else if (localVideo && [[NSFileManager defaultManager] fileExistsAtPath:[[LinphoneManager cacheDirectory] stringByAppendingPathComponent:localVideo]]) { + UIImage *image = [UIChatBubbleTextCell getImageFromVideoUrl:[ChatConversationView getCacheFileUrl:localVideo]]; + originalImageSize = image.size; + } else { + // support previous versions + PHFetchResult *assets; + if(localImage) + assets = [LinphoneManager getPHAssets:localImage]; + else + assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] options:nil]; + + if (![assets firstObject]) { + return CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_WIDTH + CELL_MESSAGE_Y_MARGIN + textSize.height); + } else { + PHAsset *asset = [assets firstObject]; + originalImageSize = CGSizeMake([asset pixelWidth], [asset pixelHeight]); + } + } + } + size = [self getMediaMessageSizefromOriginalSize:originalImageSize withWidth:width]; + // add size for message text + size.height += textSize.height; + size.width = MAX(textSize.width, size.width); + } + + size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH); + size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT); + return size; } + (CGSize)ViewSizeForMessage:(LinphoneChatMessage *)chat withWidth:(int)width { diff --git a/Classes/Utils/FileTransferDelegate.h b/Classes/Utils/FileTransferDelegate.h index 019474f9c..acf6429c3 100644 --- a/Classes/Utils/FileTransferDelegate.h +++ b/Classes/Utils/FileTransferDelegate.h @@ -23,12 +23,14 @@ @interface FileTransferDelegate : NSObject -- (void)upload:(UIImage *)image withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality; +- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key; +- (void)uploadImage:(UIImage *)image forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality; - (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name; - (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom; - (void)cancel; - (BOOL)download:(LinphoneChatMessage *)message; - (void)stopAndDestroy; ++ (FileTransferDelegate *)messageDelegate:(LinphoneChatMessage *)message; @property() LinphoneChatMessage *message; @property() NSString *text; diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index 4b1eaad53..0879271d6 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -53,160 +53,26 @@ 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); + NSString *name = [NSString stringWithUTF8String: linphone_content_get_name(content) ? : ""]; + LOGI(@"Transfer of %@ (%d bytes): download finished", name, size); assert([thiz.data length] == linphone_content_get_file_size(content)); - NSString *fileType = [NSString stringWithUTF8String:linphone_content_get_type(content)]; - ChatConversationView *view = VIEW(ChatConversationView); - void (^block)(void)= ^ { - if ([fileType isEqualToString:@"image"]) { - // we're finished, save the image and update the message - UIImage *image = [UIImage imageWithData:thiz.data]; - if (!image) { - [view showFileDownloadError]; - [thiz stopAndDestroy]; - return; - } - - 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]; - __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]); - [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" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) {}]; - - [errView addAction:defaultAction]; - [PhoneMainView.instance presentViewController:errView animated:YES completion:nil]; - } else { - LOGI(@"Image saved to [%@]", [placeHolder localIdentifier]); - [LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier] - forKey:@"localimage" - inMessage:message]; - } - [NSNotificationCenter.defaultCenter - postNotificationName:kLinphoneFileTransferRecvUpdate - object:thiz - userInfo:@{ - @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to - // trigger - // FileTransferDone here - @"image" : image, - @"progress" : @(1.f), - }]; - - [thiz stopAndDestroy]; - CFRelease((__bridge CFTypeRef)thiz); - }); - }]; - } else if([fileType isEqualToString:@"video"]) { - CFBridgingRetain(thiz); - [[LinphoneManager.instance fileTransferDelegates] removeObject:thiz]; - NSString *name =[NSString stringWithUTF8String:linphone_content_get_name(content)]; - NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name]; - [[NSFileManager defaultManager] createFileAtPath:filePath - contents:thiz.data - attributes:nil]; - // 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:@"localvideo" inMessage:message]; - - __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]); - [LinphoneManager setValueInMessageAppData:nil forKey:@"localvideo" inMessage:message]; - 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]); - [LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier] - forKey:@"localvideo" - inMessage:message]; - } - [NSNotificationCenter.defaultCenter - postNotificationName:kLinphoneFileTransferRecvUpdate - object:thiz - userInfo:@{ - @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to - // trigger - // FileTransferDone here - @"progress" : @(1.f), - }]; - - [thiz stopAndDestroy]; - CFRelease((__bridge CFTypeRef)thiz); - }); - }]; - } - }; - // 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 ([fileType isEqualToString:@"image"] || [fileType isEqualToString:@"video"]) { - 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]; - [thiz stopAndDestroy]; - } - }); - }]; - } - } else { - [[LinphoneManager.instance fileTransferDelegates] removeObject:thiz]; - NSString *key = @"localfile" ; - NSString *name =[NSString stringWithUTF8String:linphone_content_get_name(content)]; - [LinphoneManager setValueInMessageAppData:@"saving..." forKey:key inMessage:message]; - - //write file to path - dispatch_async(dispatch_get_main_queue(), ^{ - if([view writeFileInICloud:thiz.data fileURL:[view getICloudFileUrl:name]]) { - [LinphoneManager setValueInMessageAppData:name 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 { + NSString *fileType = [NSString stringWithUTF8String:linphone_content_get_type(content)]; + NSString *key = [ChatConversationView getKeyFromFileType:fileType fileName:name]; + [LinphoneManager setValueInMessageAppData:@"saving..." forKey:key inMessage:message]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [ChatConversationView writeFileInCache:thiz.data name:name]; + [LinphoneManager setValueInMessageAppData:name + forKey:key + inMessage:message]; + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneFileTransferRecvUpdate + object:thiz + userInfo:@{ + @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to trigger + @"progress" : @(1.f), // FileTransferDone here + }]; + }); + } 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]; @@ -218,7 +84,6 @@ 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, @@ -248,14 +113,18 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m // this is the last time we will be notified, so destroy ourselve if (remaining <= size) { LOGI(@"Upload ended"); + + linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(thiz.message), NULL); thiz.message = NULL; [thiz stopAndDestroy]; - //workaround fix : avoid chatconversationtableview scrolling - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneFileTransferSendUpdate - object:thiz - userInfo:@{@"state" : @(LinphoneChatMessageStateDelivered), - }]; + + //workaround fix : avoid chatconversationtableview scrolling + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneFileTransferSendUpdate + object:thiz + userInfo:@{@"state" : @(LinphoneChatMessageStateDelivered), + }]; + } return buffer; } else { @@ -266,65 +135,52 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m return NULL; } -- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key keyData:(NSString *)keyData qualityData:(NSNumber *)qualityData { - [LinphoneManager.instance.fileTransferDelegates addObject:self]; - - LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_core(chatRoom)); - _data = [NSMutableData dataWithData:data]; - linphone_content_set_type(content, [type UTF8String]); - linphone_content_set_subtype(content, [subtype UTF8String]); - linphone_content_set_name(content, [name UTF8String]); - linphone_content_set_size(content, _data.length); - _message = linphone_chat_room_create_file_transfer_message(chatRoom, content); - BOOL isOneToOneChat = linphone_chat_room_get_capabilities(chatRoom) & LinphoneChatRoomCapabilitiesOneToOne; - if (!isOneToOneChat && (_text!=nil && ![_text isEqualToString:@""])) - linphone_chat_message_add_text_content(_message, [_text UTF8String]); - linphone_content_unref(content); - - linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message), - linphone_iphone_file_transfer_send); +- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key{ + [LinphoneManager.instance.fileTransferDelegates addObject:self]; - // internal url is saved in the appdata for display and later save - [LinphoneManager setValueInMessageAppData:keyData forKey:key inMessage:_message]; - [LinphoneManager setValueInMessageAppData:qualityData forKey:@"uploadQuality" inMessage:_message]; - - LOGI(@"%p Uploading content from message %p", self, _message); - linphone_chat_message_send(_message); + LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_core(chatRoom)); + _data = [NSMutableData dataWithData:data]; + linphone_content_set_type(content, [type UTF8String]); + linphone_content_set_subtype(content, [subtype UTF8String]); + linphone_content_set_name(content, [name UTF8String]); + linphone_content_set_size(content, _data.length); + _message = linphone_chat_room_create_file_transfer_message(chatRoom, content); + BOOL isOneToOneChat = linphone_chat_room_get_capabilities(chatRoom) & LinphoneChatRoomCapabilitiesOneToOne; + if (!isOneToOneChat && (_text!=nil && ![_text isEqualToString:@""])) + linphone_chat_message_add_text_content(_message, [_text UTF8String]); + 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:name forKey:key inMessage:_message]; + + LOGI(@"%p Uploading content from message %p", self, _message); + linphone_chat_message_send(_message); } -- (void)upload:(UIImage *)image withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality { - NSString *name = [NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]]; - if (phAssetId) - [self uploadData:UIImageJPEGRepresentation(image, quality) forChatRoom:chatRoom type:@"image" subtype:@"jpeg" name:name key:@"localimage" keyData:phAssetId qualityData:[NSNumber numberWithFloat:quality]]; - else - [self uploadData:UIImageJPEGRepresentation(image, quality) forChatRoom:chatRoom type:@"image" subtype:@"jpeg" name:name key:@"localimage" keyData:nil qualityData:nil]; +- (void)uploadImage:(UIImage *)image forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality { + NSString *name = [NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]]; + NSData *data = UIImageJPEGRepresentation(image, quality); + [ChatConversationView writeFileInCache:data name:name]; + [self uploadData:data forChatRoom:chatRoom type:@"image" subtype:@"jpg" name:name key:@"localimage"]; } - (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom { - NSString *name = [NSString stringWithFormat:@"IMG-%f.MOV", [NSDate timeIntervalSinceReferenceDate]]; - if (phAssetId) - [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:nil name:name key:@"localvideo" keyData:phAssetId qualityData:nil]; - else - [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:nil name:name key:@"localvideo" keyData:@"ending..." qualityData:nil]; + NSString *name = [NSString stringWithFormat:@"IMG-%f.MOV", [NSDate timeIntervalSinceReferenceDate]]; + [ChatConversationView writeFileInCache:data name:name]; + [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:@"mov" name:name key:@"localvideo"]; } - (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name { - // we will write local files into ours folder of icloud - ChatConversationView *view = VIEW(ChatConversationView); - NSURL *url = [view getICloudFileUrl:name]; - if ([view writeFileInICloud:data fileURL:url]) { - AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; - if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] > 0) { - // if it's a video - [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:nil name:name key:@"localfile" keyData:name qualityData:nil]; - } else { - [self uploadData:data forChatRoom:chatRoom type:@"file" subtype:nil name:name key:@"localfile" keyData:name qualityData:nil]; - } - } + [ChatConversationView writeFileInCache:data name:name]; + NSURL *url = [ChatConversationView getCacheFileUrl:name]; + AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; + NSString *fileType = [[asset tracksWithMediaType:AVMediaTypeVideo] count] > 0 ? @"video" : @"file"; + NSString *key = [ChatConversationView getKeyFromFileType:fileType fileName:name]; + + [self uploadData:data forChatRoom:chatRoom type:fileType subtype:name.lastPathComponent name:name key:key]; } - - - (BOOL)download:(LinphoneChatMessage *)message { [[LinphoneManager.instance fileTransferDelegates] addObject:self];