Gallery supports album messages

pull/1/head
Michael Kirk 7 years ago
parent 27cb91e9c8
commit 57681bd6f3

@ -2048,18 +2048,12 @@ typedef enum : NSUInteger {
[self becomeFirstResponder]; [self becomeFirstResponder];
} }
if (![viewItem.interaction isKindOfClass:[TSMessage class]]) {
OWSFailDebug(@"Unexpected viewItem.interaction");
return;
}
TSMessage *mediaMessage = (TSMessage *)viewItem.interaction;
MediaGallery *mediaGallery = MediaGallery *mediaGallery =
[[MediaGallery alloc] initWithThread:self.thread [[MediaGallery alloc] initWithThread:self.thread
uiDatabaseConnection:self.uiDatabaseConnection uiDatabaseConnection:self.uiDatabaseConnection
options:MediaGalleryOptionSliderEnabled | MediaGalleryOptionShowAllMediaButton]; options:MediaGalleryOptionSliderEnabled | MediaGalleryOptionShowAllMediaButton];
[mediaGallery presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView]; [mediaGallery presentDetailViewFromViewController:self mediaAttachment:attachmentStream replacingView:imageView];
} }
- (void)didTapVideoViewItem:(id<ConversationViewItem>)viewItem - (void)didTapVideoViewItem:(id<ConversationViewItem>)viewItem
@ -2077,18 +2071,12 @@ typedef enum : NSUInteger {
[self becomeFirstResponder]; [self becomeFirstResponder];
} }
if (![viewItem.interaction isKindOfClass:[TSMessage class]]) {
OWSFailDebug(@"Unexpected viewItem.interaction");
return;
}
TSMessage *mediaMessage = (TSMessage *)viewItem.interaction;
MediaGallery *mediaGallery = MediaGallery *mediaGallery =
[[MediaGallery alloc] initWithThread:self.thread [[MediaGallery alloc] initWithThread:self.thread
uiDatabaseConnection:self.uiDatabaseConnection uiDatabaseConnection:self.uiDatabaseConnection
options:MediaGalleryOptionSliderEnabled | MediaGalleryOptionShowAllMediaButton]; options:MediaGalleryOptionSliderEnabled | MediaGalleryOptionShowAllMediaButton];
[mediaGallery presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView]; [mediaGallery presentDetailViewFromViewController:self mediaAttachment:attachmentStream replacingView:imageView];
} }
- (void)didTapAudioViewItem:(id<ConversationViewItem>)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream - (void)didTapAudioViewItem:(id<ConversationViewItem>)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream

@ -350,6 +350,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)didPressShare:(id)sender - (void)didPressShare:(id)sender
{ {
OWSFailDebug(@"TODO: support sharing individual attachment, not viewItem");
OWSLogInfo(@"didPressShare"); OWSLogInfo(@"didPressShare");
if (!self.viewItem) { if (!self.viewItem) {
OWSFailDebug(@"share should only be available when a viewItem is present"); OWSFailDebug(@"share should only be available when a viewItem is present");
@ -361,6 +363,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)didPressDelete:(id)sender - (void)didPressDelete:(id)sender
{ {
OWSFailDebug(@"TODO: support sharing individual attachment, not viewItem");
OWSLogInfo(@"didPressDelete"); OWSLogInfo(@"didPressDelete");
if (!self.viewItem) { if (!self.viewItem) {
OWSFailDebug(@"delete should only be available when a viewItem is present"); OWSFailDebug(@"delete should only be available when a viewItem is present");

@ -39,13 +39,13 @@ public class MediaGalleryItem: Equatable, Hashable {
// MARK: Equatable // MARK: Equatable
public static func == (lhs: MediaGalleryItem, rhs: MediaGalleryItem) -> Bool { public static func == (lhs: MediaGalleryItem, rhs: MediaGalleryItem) -> Bool {
return lhs.message.uniqueId == rhs.message.uniqueId return lhs.attachmentStream.uniqueId == rhs.attachmentStream.uniqueId
} }
// MARK: Hashable // MARK: Hashable
public var hashValue: Int { public var hashValue: Int {
return message.hashValue return attachmentStream.hashValue
} }
} }
@ -281,10 +281,10 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
private var originRect: CGRect? private var originRect: CGRect?
@objc @objc
public func presentDetailView(fromViewController: UIViewController, mediaMessage: TSMessage, replacingView: UIView) { public func presentDetailView(fromViewController: UIViewController, mediaAttachment: TSAttachment, replacingView: UIView) {
var galleryItem: MediaGalleryItem? var galleryItem: MediaGalleryItem?
uiDatabaseConnection.read { transaction in uiDatabaseConnection.read { transaction in
galleryItem = self.buildGalleryItem(message: mediaMessage, transaction: transaction)! galleryItem = self.buildGalleryItem(attachment: mediaAttachment, transaction: transaction)!
} }
guard let initialDetailItem = galleryItem else { guard let initialDetailItem = galleryItem else {
@ -414,8 +414,8 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
func pushTileView(fromNavController: OWSNavigationController) { func pushTileView(fromNavController: OWSNavigationController) {
var mostRecentItem: MediaGalleryItem? var mostRecentItem: MediaGalleryItem?
self.uiDatabaseConnection.read { transaction in self.uiDatabaseConnection.read { transaction in
if let message = self.mediaGalleryFinder.mostRecentMediaMessage(transaction: transaction) { if let attachment = self.mediaGalleryFinder.mostRecentMediaAttachment(transaction: transaction) {
mostRecentItem = self.buildGalleryItem(message: message, transaction: transaction) mostRecentItem = self.buildGalleryItem(attachment: attachment, transaction: transaction)
} }
} }
@ -633,9 +633,13 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
var hasFetchedOldest = false var hasFetchedOldest = false
var hasFetchedMostRecent = false var hasFetchedMostRecent = false
func buildGalleryItem(message: TSMessage, transaction: YapDatabaseReadTransaction) -> MediaGalleryItem? { func buildGalleryItem(attachment: TSAttachment, transaction: YapDatabaseReadTransaction) -> MediaGalleryItem? {
// TODO: Support multi-image messages. guard let attachmentStream = attachment as? TSAttachmentStream else {
guard let attachmentStream = message.attachments(with: transaction).first as? TSAttachmentStream else { owsFailDebug("gallery doesn't yet support showing undownloaded attachments")
return nil
}
guard let message = attachmentStream.fetchAlbumMessage(with: transaction) else {
owsFailDebug("attachment was unexpectedly empty") owsFailDebug("attachment was unexpectedly empty")
return nil return nil
} }
@ -662,7 +666,7 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
Bench(title: "fetching gallery items") { Bench(title: "fetching gallery items") {
self.uiDatabaseConnection.read { transaction in self.uiDatabaseConnection.read { transaction in
let initialIndex: Int = Int(self.mediaGalleryFinder.mediaIndex(message: item.message, transaction: transaction)) let initialIndex: Int = Int(self.mediaGalleryFinder.mediaIndex(attachment: item.attachmentStream, transaction: transaction))
let mediaCount: Int = Int(self.mediaGalleryFinder.mediaCount(transaction: transaction)) let mediaCount: Int = Int(self.mediaGalleryFinder.mediaCount(transaction: transaction))
let requestRange: Range<Int> = { () -> Range<Int> in let requestRange: Range<Int> = { () -> Range<Int> in
@ -711,14 +715,14 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
Logger.debug("fetching set: \(unfetchedSet)") Logger.debug("fetching set: \(unfetchedSet)")
let nsRange: NSRange = NSRange(location: unfetchedSet.min()!, length: unfetchedSet.count) let nsRange: NSRange = NSRange(location: unfetchedSet.min()!, length: unfetchedSet.count)
self.mediaGalleryFinder.enumerateMediaMessages(range: nsRange, transaction: transaction) { (message: TSMessage) in self.mediaGalleryFinder.enumerateMediaAttachments(range: nsRange, transaction: transaction) { (attachment: TSAttachment) in
guard !self.deletedMessages.contains(message) else { guard !self.deletedAttachments.contains(attachment) else {
Logger.debug("skipping \(message) which has been deleted.") Logger.debug("skipping \(attachment) which has been deleted.")
return return
} }
guard let item: MediaGalleryItem = self.buildGalleryItem(message: message, transaction: transaction) else { guard let item: MediaGalleryItem = self.buildGalleryItem(attachment: attachment, transaction: transaction) else {
owsFailDebug("unexpectedly failed to buildGalleryItem") owsFailDebug("unexpectedly failed to buildGalleryItem")
return return
} }
@ -792,7 +796,7 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
dataSourceDelegates.append(Weak(value: dataSourceDelegate)) dataSourceDelegates.append(Weak(value: dataSourceDelegate))
} }
var deletedMessages: Set<TSMessage> = Set() var deletedAttachments: Set<TSAttachment> = Set()
var deletedGalleryItems: Set<MediaGalleryItem> = Set() var deletedGalleryItems: Set<MediaGalleryItem> = Set()
func delete(items: [MediaGalleryItem], initiatedBy: MediaGalleryDataSourceDelegate) { func delete(items: [MediaGalleryItem], initiatedBy: MediaGalleryDataSourceDelegate) {
@ -806,8 +810,9 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
self.editingDatabaseConnection.asyncReadWrite { transaction in self.editingDatabaseConnection.asyncReadWrite { transaction in
for item in items { for item in items {
let message = item.message let message = item.message
message.remove(with: transaction) let attachment = item.attachmentStream
self.deletedMessages.insert(message) message.removeAttachment(attachment, transaction: transaction)
self.deletedAttachments.insert(attachment)
} }
} }
@ -928,6 +933,6 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
self.uiDatabaseConnection.read { (transaction: YapDatabaseReadTransaction) in self.uiDatabaseConnection.read { (transaction: YapDatabaseReadTransaction) in
count = self.mediaGalleryFinder.mediaCount(transaction: transaction) count = self.mediaGalleryFinder.mediaCount(transaction: transaction)
} }
return Int(count) - deletedMessages.count return Int(count) - deletedAttachments.count
} }
} }

@ -619,14 +619,14 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
let mediaGallery = MediaGallery(thread: self.thread, uiDatabaseConnection: self.uiDatabaseConnection) let mediaGallery = MediaGallery(thread: self.thread, uiDatabaseConnection: self.uiDatabaseConnection)
mediaGallery.addDataSourceDelegate(self) mediaGallery.addDataSourceDelegate(self)
mediaGallery.presentDetailView(fromViewController: self, mediaMessage: self.message, replacingView: imageView) mediaGallery.presentDetailView(fromViewController: self, mediaAttachment: attachmentStream, replacingView: imageView)
} }
func didTapVideoViewItem(_ viewItem: ConversationViewItem, attachmentStream: TSAttachmentStream, imageView: UIView) { func didTapVideoViewItem(_ viewItem: ConversationViewItem, attachmentStream: TSAttachmentStream, imageView: UIView) {
let mediaGallery = MediaGallery(thread: self.thread, uiDatabaseConnection: self.uiDatabaseConnection) let mediaGallery = MediaGallery(thread: self.thread, uiDatabaseConnection: self.uiDatabaseConnection)
mediaGallery.addDataSourceDelegate(self) mediaGallery.addDataSourceDelegate(self)
mediaGallery.presentDetailView(fromViewController: self, mediaMessage: self.message, replacingView: imageView) mediaGallery.presentDetailView(fromViewController: self, mediaAttachment: attachmentStream, replacingView: imageView)
} }
func didTapContactShare(_ viewItem: ConversationViewItem) { func didTapContactShare(_ viewItem: ConversationViewItem) {

@ -6,6 +6,8 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class TSMessage;
typedef NS_ENUM(NSUInteger, TSAttachmentType) { typedef NS_ENUM(NSUInteger, TSAttachmentType) {
TSAttachmentTypeDefault = 0, TSAttachmentTypeDefault = 0,
TSAttachmentTypeVoiceMessage = 1, TSAttachmentTypeVoiceMessage = 1,
@ -41,6 +43,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) {
@property (nonatomic, readonly, nullable) NSString *caption; @property (nonatomic, readonly, nullable) NSString *caption;
@property (nonatomic, readonly, nullable) NSString *albumMessageId; @property (nonatomic, readonly, nullable) NSString *albumMessageId;
- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction;
#pragma mark - #pragma mark -

@ -4,6 +4,7 @@
#import "TSAttachment.h" #import "TSAttachment.h"
#import "MIMETypeUtil.h" #import "MIMETypeUtil.h"
#import "TSMessage.h"
#import <SignalCoreKit/NSString+SSK.h> #import <SignalCoreKit/NSString+SSK.h>
#import <SignalCoreKit/iOSVersions.h> #import <SignalCoreKit/iOSVersions.h>
@ -243,6 +244,16 @@ NSUInteger const TSAttachmentSchemaVersion = 4;
return _contentType.filterFilename; return _contentType.filterFilename;
} }
#pragma mark - Relationships
- (nullable TSMessage *)fetchAlbumMessageWithTransaction:(YapDatabaseReadTransaction *)transaction
{
if (self.albumMessageId == nil) {
return nil;
}
return [TSMessage fetchObjectWithUniqueID:self.albumMessageId transaction:transaction];
}
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -98,7 +98,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
{ {
OWSAssertDebug(timestamp > 0); OWSAssertDebug(timestamp > 0);
self = [super initWithUniqueId:nil]; self = [super initWithUniqueId:[[NSUUID UUID] UUIDString]];
if (!self) { if (!self) {
return self; return self;
@ -172,6 +172,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
} }
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
OWSAssertDebug(self.uniqueId);
if (!self.uniqueId) { if (!self.uniqueId) {
self.uniqueId = [OWSPrimaryStorage getAndIncrementMessageIdWithTransaction:transaction]; self.uniqueId = [OWSPrimaryStorage getAndIncrementMessageIdWithTransaction:transaction];
} }

@ -42,6 +42,8 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)hasAttachments; - (BOOL)hasAttachments;
- (NSArray<TSAttachment *> *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction; - (NSArray<TSAttachment *> *)attachmentsWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (void)removeAttachment:(TSAttachment *)attachment
transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(removeAttachment(_:transaction:));
- (BOOL)isMediaAlbumWithTransaction:(YapDatabaseReadTransaction *)transaction; - (BOOL)isMediaAlbumWithTransaction:(YapDatabaseReadTransaction *)transaction;

@ -214,6 +214,19 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
return [attachments copy]; return [attachments copy];
} }
- (void)removeAttachment:(TSAttachment *)attachment transaction:(YapDatabaseReadWriteTransaction *)transaction;
{
OWSAssertDebug([self.attachmentIds containsObject:attachment.uniqueId]);
[attachment removeWithTransaction:transaction];
[self.attachmentIds removeObject:attachment.uniqueId];
// TODO - Should we delete self if we delete the last attachment?
// Or should that depend on whether message.body == nil
[self saveWithTransaction:transaction];
}
- (BOOL)isMediaAlbumWithTransaction:(YapDatabaseReadTransaction *)transaction - (BOOL)isMediaAlbumWithTransaction:(YapDatabaseReadTransaction *)transaction
{ {
NSArray<TSAttachment *> *attachments = [self attachmentsWithTransaction:transaction]; NSArray<TSAttachment *> *attachments = [self attachmentsWithTransaction:transaction];

@ -87,6 +87,7 @@ void AssertIsOnSendingQueue()
contentType:(NSString *)contentType contentType:(NSString *)contentType
sourceFilename:(nullable NSString *)sourceFilename sourceFilename:(nullable NSString *)sourceFilename
caption:(nullable NSString *)caption caption:(nullable NSString *)caption
albumMessageId:(nullable NSString *)albumMessageId
{ {
self = [super init]; self = [super init];
if (!self) { if (!self) {
@ -97,6 +98,7 @@ void AssertIsOnSendingQueue()
_contentType = contentType; _contentType = contentType;
_sourceFilename = sourceFilename; _sourceFilename = sourceFilename;
_caption = caption; _caption = caption;
_albumMessageId = albumMessageId;
return self; return self;
} }
@ -455,10 +457,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:(void (^)(NSError *error))failureHandler failure:(void (^)(NSError *error))failureHandler
{ {
OWSAssertDebug(dataSource); OWSAssertDebug(dataSource);
NSString *albumMessageId = message.uniqueId;
OWSOutgoingAttachmentInfo *attachmentInfo = [[OWSOutgoingAttachmentInfo alloc] initWithDataSource:dataSource OWSOutgoingAttachmentInfo *attachmentInfo = [[OWSOutgoingAttachmentInfo alloc] initWithDataSource:dataSource
contentType:contentType contentType:contentType
sourceFilename:sourceFilename sourceFilename:sourceFilename
caption:nil]; caption:nil
albumMessageId:albumMessageId];
[OutgoingMessagePreparer prepareAttachments:@[ attachmentInfo ] [OutgoingMessagePreparer prepareAttachments:@[ attachmentInfo ]
inMessage:message inMessage:message
completionHandler:^(NSError *_Nullable error) { completionHandler:^(NSError *_Nullable error) {
@ -1826,14 +1831,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
for (TSAttachmentStream *attachmentStream in attachmentStreams) { for (TSAttachmentStream *attachmentStream in attachmentStreams) {
[attachmentStream saveWithTransaction:transaction];
[outgoingMessage.attachmentIds addObject:attachmentStream.uniqueId]; [outgoingMessage.attachmentIds addObject:attachmentStream.uniqueId];
if (attachmentStream.sourceFilename) { if (attachmentStream.sourceFilename) {
outgoingMessage.attachmentFilenameMap[attachmentStream.uniqueId] = attachmentStream.sourceFilename; outgoingMessage.attachmentFilenameMap[attachmentStream.uniqueId] = attachmentStream.sourceFilename;
} }
} }
[outgoingMessage saveWithTransaction:transaction]; [outgoingMessage saveWithTransaction:transaction];
for (TSAttachmentStream *attachmentStream in attachmentStreams) {
[attachmentStream saveWithTransaction:transaction];
}
}]; }];
completionHandler(nil); completionHandler(nil);

@ -5,7 +5,7 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class OWSStorage; @class OWSStorage;
@class TSMessage; @class TSAttachment;
@class TSThread; @class TSThread;
@class YapDatabaseReadTransaction; @class YapDatabaseReadTransaction;
@ -18,15 +18,20 @@ NS_ASSUME_NONNULL_BEGIN
// How many media items a thread has // How many media items a thread has
- (NSUInteger)mediaCountWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(mediaCount(transaction:)); - (NSUInteger)mediaCountWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(mediaCount(transaction:));
// The ordinal position of a message within a thread's media gallery // The ordinal position of an attachment within a thread's media gallery
- (NSUInteger)mediaIndexForMessage:(TSMessage *)message transaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(mediaIndex(message:transaction:)); - (NSUInteger)mediaIndexForAttachment:(TSAttachment *)attachment
transaction:(YapDatabaseReadTransaction *)transaction
NS_SWIFT_NAME(mediaIndex(attachment:transaction:));
- (nullable TSMessage *)oldestMediaMessageWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(oldestMediaMessage(transaction:)); - (nullable TSAttachment *)oldestMediaAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
- (nullable TSMessage *)mostRecentMediaMessageWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(mostRecentMediaMessage(transaction:)); NS_SWIFT_NAME(oldestMediaAttachment(transaction:));
- (nullable TSAttachment *)mostRecentMediaAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
NS_SWIFT_NAME(mostRecentMediaAttachment(transaction:));
- (void)enumerateMediaMessagesWithRange:(NSRange)range - (void)enumerateMediaAttachmentsWithRange:(NSRange)range
transaction:(YapDatabaseReadTransaction *)transaction transaction:(YapDatabaseReadTransaction *)transaction
block:(void (^)(TSMessage *))messageBlock NS_SWIFT_NAME(enumerateMediaMessages(range:transaction:block:)); block:(void (^)(TSAttachment *))attachmentBlock
NS_SWIFT_NAME(enumerateMediaAttachments(range:transaction:block:));
#pragma mark - Extension registration #pragma mark - Extension registration

@ -43,15 +43,15 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
return [[self galleryExtensionWithTransaction:transaction] numberOfItemsInGroup:self.mediaGroup]; return [[self galleryExtensionWithTransaction:transaction] numberOfItemsInGroup:self.mediaGroup];
} }
- (NSUInteger)mediaIndexForMessage:(TSMessage *)message transaction:(YapDatabaseReadTransaction *)transaction - (NSUInteger)mediaIndexForAttachment:(TSAttachment *)attachment transaction:(YapDatabaseReadTransaction *)transaction
{ {
NSString *groupId; NSString *groupId;
NSUInteger index; NSUInteger index;
BOOL wasFound = [[self galleryExtensionWithTransaction:transaction] getGroup:&groupId BOOL wasFound = [[self galleryExtensionWithTransaction:transaction] getGroup:&groupId
index:&index index:&index
forKey:message.uniqueId forKey:attachment.uniqueId
inCollection:[TSMessage collection]]; inCollection:[TSAttachment collection]];
OWSAssertDebug(wasFound); OWSAssertDebug(wasFound);
OWSAssertDebug([self.mediaGroup isEqual:groupId]); OWSAssertDebug([self.mediaGroup isEqual:groupId]);
@ -59,19 +59,19 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
return index; return index;
} }
- (nullable TSMessage *)oldestMediaMessageWithTransaction:(YapDatabaseReadTransaction *)transaction - (nullable TSAttachment *)oldestMediaAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
{ {
return [[self galleryExtensionWithTransaction:transaction] firstObjectInGroup:self.mediaGroup]; return [[self galleryExtensionWithTransaction:transaction] firstObjectInGroup:self.mediaGroup];
} }
- (nullable TSMessage *)mostRecentMediaMessageWithTransaction:(YapDatabaseReadTransaction *)transaction - (nullable TSAttachment *)mostRecentMediaAttachmentWithTransaction:(YapDatabaseReadTransaction *)transaction
{ {
return [[self galleryExtensionWithTransaction:transaction] lastObjectInGroup:self.mediaGroup]; return [[self galleryExtensionWithTransaction:transaction] lastObjectInGroup:self.mediaGroup];
} }
- (void)enumerateMediaMessagesWithRange:(NSRange)range - (void)enumerateMediaAttachmentsWithRange:(NSRange)range
transaction:(YapDatabaseReadTransaction *)transaction transaction:(YapDatabaseReadTransaction *)transaction
block:(void (^)(TSMessage *))messageBlock block:(void (^)(TSAttachment *))attachmentBlock
{ {
[[self galleryExtensionWithTransaction:transaction] [[self galleryExtensionWithTransaction:transaction]
@ -83,9 +83,8 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
id _Nonnull object, id _Nonnull object,
NSUInteger index, NSUInteger index,
BOOL *_Nonnull stop) { BOOL *_Nonnull stop) {
OWSAssertDebug([object isKindOfClass:[TSAttachment class]]);
OWSAssertDebug([object isKindOfClass:[TSMessage class]]); attachmentBlock((TSAttachment *)object);
messageBlock((TSMessage *)object);
}]; }];
} }
@ -124,63 +123,81 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
+ (YapDatabaseAutoView *)mediaGalleryDatabaseExtension + (YapDatabaseAutoView *)mediaGalleryDatabaseExtension
{ {
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction * _Nonnull transaction, NSString * _Nonnull group, NSString * _Nonnull collection1, NSString * _Nonnull key1, id _Nonnull object1, NSString * _Nonnull collection2, NSString * _Nonnull key2, id _Nonnull object2) { YapDatabaseViewSorting *sorting =
[YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *_Nonnull transaction,
if (![object1 isKindOfClass:[TSMessage class]]) { NSString *_Nonnull group,
OWSFailDebug(@"Unexpected object while sorting: %@", [object1 class]); NSString *_Nonnull collection1,
return NSOrderedSame; NSString *_Nonnull key1,
} id _Nonnull object1,
TSMessage *message1 = (TSMessage *)object1; NSString *_Nonnull collection2,
NSString *_Nonnull key2,
if (![object2 isKindOfClass:[TSMessage class]]) { id _Nonnull object2) {
OWSFailDebug(@"Unexpected object while sorting: %@", [object2 class]); if (![object1 isKindOfClass:[TSAttachment class]]) {
return NSOrderedSame; OWSFailDebug(@"Unexpected object while sorting: %@", [object1 class]);
} return NSOrderedSame;
TSMessage *message2 = (TSMessage *)object2;
return [@(message1.timestampForSorting) compare:@(message2.timestampForSorting)];
}];
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withObjectBlock:^NSString * _Nullable(YapDatabaseReadTransaction * _Nonnull transaction, NSString * _Nonnull collection, NSString * _Nonnull key, id _Nonnull object) {
if (![object isKindOfClass:[TSMessage class]]) {
return nil;
}
TSMessage *message = (TSMessage *)object;
BOOL allAttachmentsAreMedia = message.attachmentIds.count > 0;
for (NSString *attachmentId in message.attachmentIds) {
OWSAssertDebug(attachmentId.length > 0);
if (![self attachmentIdShouldAppearInMediaGallery:attachmentId transaction:transaction]) {
allAttachmentsAreMedia = NO;
break;
} }
} TSAttachment *attachment1 = (TSAttachment *)object1;
if (allAttachmentsAreMedia) { if (![object2 isKindOfClass:[TSAttachment class]]) {
return [self mediaGroupWithThreadId:message.uniqueThreadId]; OWSFailDebug(@"Unexpected object while sorting: %@", [object2 class]);
} return NSOrderedSame;
}
TSAttachment *attachment2 = (TSAttachment *)object2;
return nil; TSMessage *_Nullable message1 = [attachment1 fetchAlbumMessageWithTransaction:transaction];
}]; TSMessage *_Nullable message2 = [attachment2 fetchAlbumMessageWithTransaction:transaction];
if (message1 == nil || message2 == nil) {
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; OWSFailDebug(@"couldn't find albumMessage");
options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:TSMessage.collection]]; return NSOrderedSame;
}
return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"3" options:options]; if ([message1.uniqueId isEqualToString:message2.uniqueId]) {
} NSUInteger index1 = [message1.attachmentIds indexOfObject:attachment1.uniqueId];
NSUInteger index2 = [message1.attachmentIds indexOfObject:attachment2.uniqueId];
if (index1 == NSNotFound || index2 == NSNotFound) {
OWSFailDebug(@"couldn't find attachmentId in it's albumMessage");
return NSOrderedSame;
}
return [@(index1) compare:@(index2)];
} else {
return [@(message1.timestampForSorting) compare:@(message2.timestampForSorting)];
}
}];
YapDatabaseViewGrouping *grouping =
[YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(YapDatabaseReadTransaction *_Nonnull transaction,
NSString *_Nonnull collection,
NSString *_Nonnull key,
id _Nonnull object) {
// Don't include nil or not yet downloaded attachments.
if (![object isKindOfClass:[TSAttachmentStream class]]) {
return nil;
}
+ (BOOL)attachmentIdShouldAppearInMediaGallery:(NSString *)attachmentId transaction:(YapDatabaseReadTransaction *)transaction TSAttachmentStream *attachment = (TSAttachmentStream *)object;
{ if (attachment.albumMessageId == nil) {
TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId return nil;
transaction:transaction]; }
// Don't include nil or not yet downloaded attachments. if (!attachment.isValidVisualMedia) {
if (![attachment isKindOfClass:[TSAttachmentStream class]]) { return nil;
return NO; }
}
TSMessage *message = [attachment fetchAlbumMessageWithTransaction:transaction];
if (message == nil) {
OWSFailDebug(@"message was unexpectedly nil");
return nil;
}
return [self mediaGroupWithThreadId:message.uniqueThreadId];
}];
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:TSAttachment.collection]];
return attachment.isValidVisualMedia; return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"4" options:options];
} }
@end @end

Loading…
Cancel
Save