diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m index 60b94a184..92687819a 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m @@ -9,7 +9,6 @@ #import "OWSMessageHeaderView.h" #import "OWSSystemMessageCell.h" #import "Signal-Swift.h" -#import #import #import #import @@ -1020,41 +1019,59 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) break; } case OWSMessageCellType_MediaAlbum: { - // TODO: Use PHPhotoLibrary. - ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; - for (ConversationMediaAlbumItem *mediaAlbumItem in self.mediaAlbumItems) { - if (!mediaAlbumItem.attachmentStream) { - continue; - } - if (!mediaAlbumItem.attachmentStream.isValidVisualMedia) { - continue; - } - if (mediaAlbumItem.attachmentStream.isImage || mediaAlbumItem.attachmentStream.isAnimated) { - NSData *data = [NSData dataWithContentsOfURL:[mediaAlbumItem.attachmentStream originalMediaURL]]; - if (!data) { - OWSFailDebug(@"Could not load image data"); - continue; - } - [library writeImageDataToSavedPhotosAlbum:data - metadata:nil - completionBlock:^(NSURL *assetURL, NSError *error) { - if (error) { - OWSLogWarn(@"Error saving image to photo album: %@", error); - } - }]; - } - if (mediaAlbumItem.attachmentStream.isVideo) { - if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum( - mediaAlbumItem.attachmentStream.originalFilePath)) { - UISaveVideoAtPathToSavedPhotosAlbum( - mediaAlbumItem.attachmentStream.originalFilePath, self, nil, nil); - } - } - } + [self saveMediaAlbumItems]; + break; } } } +- (void)saveMediaAlbumItems +{ + // We need to do these writes serially to avoid "write busy" errors + // from too many concurrent asset saves. + [self saveMediaAlbumItems:[self.mediaAlbumItems mutableCopy]]; +} + +- (void)saveMediaAlbumItems:(NSMutableArray *)mediaAlbumItems +{ + if (mediaAlbumItems.count < 1) { + return; + } + ConversationMediaAlbumItem *mediaAlbumItem = mediaAlbumItems.firstObject; + [mediaAlbumItems removeObjectAtIndex:0]; + + if (!mediaAlbumItem.attachmentStream || !mediaAlbumItem.attachmentStream.isValidVisualMedia) { + // Skip this item. + } else if (mediaAlbumItem.attachmentStream.isImage || mediaAlbumItem.attachmentStream.isAnimated) { + [[PHPhotoLibrary sharedPhotoLibrary] + performChanges:^{ + [PHAssetChangeRequest + creationRequestForAssetFromImageAtFileURL:mediaAlbumItem.attachmentStream.originalMediaURL]; + } + completionHandler:^(BOOL success, NSError *error) { + if (error || !success) { + OWSFailDebug(@"Image save failed: %@", error); + } + [self saveMediaAlbumItems:mediaAlbumItems]; + }]; + return; + } else if (mediaAlbumItem.attachmentStream.isVideo) { + [[PHPhotoLibrary sharedPhotoLibrary] + performChanges:^{ + [PHAssetChangeRequest + creationRequestForAssetFromVideoAtFileURL:mediaAlbumItem.attachmentStream.originalMediaURL]; + } + completionHandler:^(BOOL success, NSError *error) { + if (error || !success) { + OWSFailDebug(@"Video save failed: %@", error); + } + [self saveMediaAlbumItems:mediaAlbumItems]; + }]; + return; + } + return [self saveMediaAlbumItems:mediaAlbumItems]; +} + - (void)deleteAction { [self.interaction remove];