From 6f64a809f341c2b1da420ea887d1467370619bed Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Fri, 9 Nov 2018 16:58:58 -0500
Subject: [PATCH] Tap on album item.

---
 .../Cells/ConversationMediaView.swift         |  5 ++-
 .../Cells/MediaAlbumCellView.swift            | 16 +++++++
 .../Cells/OWSMessageBubbleView.m              | 44 +++++++------------
 .../MediaGalleryViewController.swift          |  8 ++--
 SignalMessaging/categories/UIView+OWS.h       |  6 +++
 5 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift
index f6514cc8c..265b57c24 100644
--- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift
+++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift
@@ -4,7 +4,7 @@
 
 import Foundation
 
-@objc
+@objc(OWSConversationMediaView)
 public class ConversationMediaView: UIView {
 
     // MARK: - Dependencies
@@ -16,7 +16,8 @@ public class ConversationMediaView: UIView {
     // MARK: -
 
     private let mediaCache: NSCache<NSString, AnyObject>
-    private let attachment: TSAttachment
+    @objc
+    public let attachment: TSAttachment
     private let isOutgoing: Bool
     private let maxMessageWidth: CGFloat
     private var loadBlock : (() -> Void)?
diff --git a/Signal/src/ViewControllers/ConversationView/Cells/MediaAlbumCellView.swift b/Signal/src/ViewControllers/ConversationView/Cells/MediaAlbumCellView.swift
index 69e1d258b..9319a2938 100644
--- a/Signal/src/ViewControllers/ConversationView/Cells/MediaAlbumCellView.swift
+++ b/Signal/src/ViewControllers/ConversationView/Cells/MediaAlbumCellView.swift
@@ -261,4 +261,20 @@ public class MediaAlbumCellView: UIStackView {
             return CGSize(width: maxMessageWidth, height: bigImageSize + smallImageSize + kSpacingPts)
         }
     }
+
+    @objc
+    public func mediaView(forLocation location: CGPoint) -> ConversationMediaView? {
+        var bestMediaView: ConversationMediaView?
+        var bestDistance: CGFloat = 0
+        for itemView in itemViews {
+            let itemCenter = convert(itemView.center, from: itemView.superview)
+            let distance = CGPointDistance(location, itemCenter)
+            if bestMediaView != nil && distance > bestDistance {
+                continue
+            }
+            bestMediaView = itemView
+            bestDistance = distance
+        }
+        return bestMediaView
+    }
 }
diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m
index 7fdf6f72a..b323e39b4 100644
--- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m
+++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m
@@ -1307,7 +1307,7 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
             [self.delegate didTapTruncatedTextMessage:self.viewItem];
             return;
         case OWSMessageGestureLocation_Media:
-            [self handleMediaTapGesture];
+            [self handleMediaTapGesture:locationInMessageBubble];
             break;
         case OWSMessageGestureLocation_QuotedReply:
             if (self.viewItem.quotedReply) {
@@ -1319,7 +1319,7 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
     }
 }
 
-- (void)handleMediaTapGesture
+- (void)handleMediaTapGesture:(CGPoint)locationInMessageBubble
 {
     OWSAssertDebug(self.delegate);
 
@@ -1358,35 +1358,25 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes
                 [self.delegate didTapFailedIncomingAttachment:self.viewItem];
                 return;
             }
-
-            // TODO: We might be able to get rid of this.
-            if (self.viewItem.mediaAlbumItems.count == 1) {
-                ConversationMediaAlbumItem *mediaAlbumItem = self.viewItem.mediaAlbumItems.firstObject;
-                if (!mediaAlbumItem.attachmentStream.isValidVisualMedia) {
-                    // Do nothing.
-                } else if (mediaAlbumItem.attachmentStream.isAnimated || mediaAlbumItem.attachmentStream.isImage) {
-                    [self.delegate didTapImageViewItem:self.viewItem
-                                      attachmentStream:mediaAlbumItem.attachmentStream
-                                             imageView:self.bodyMediaView];
-                    return;
-                } else if (mediaAlbumItem.attachmentStream.isVideo) {
-                    [self.delegate didTapVideoViewItem:self.viewItem
-                                      attachmentStream:mediaAlbumItem.attachmentStream
-                                             imageView:self.bodyMediaView];
-                    return;
-                }
+            if (![self.bodyMediaView isKindOfClass:[OWSMediaAlbumCellView class]]) {
+                OWSFailDebug(@"Unexpected body media view: %@", self.bodyMediaView.class);
+                return;
             }
-
-            // For now, use first valid attachment.
-            TSAttachmentStream *_Nullable attachmentStream = self.viewItem.firstValidAlbumAttachment;
-            if (!attachmentStream) {
-                OWSLogInfo(@"Ignoring tap on album without any valid attachments.");
+            OWSMediaAlbumCellView *_Nullable mediaAlbumCellView = (OWSMediaAlbumCellView *)self.bodyMediaView;
+            CGPoint location = [self convertPoint:locationInMessageBubble toView:self.bodyMediaView];
+            OWSConversationMediaView *_Nullable mediaView = [mediaAlbumCellView mediaViewForLocation:location];
+            if (!mediaView) {
+                OWSFailDebug(@"Missing media view.");
                 return;
             }
 
-            [self.delegate didTapImageViewItem:self.viewItem
-                              attachmentStream:attachmentStream
-                                     imageView:self.bodyMediaView];
+            TSAttachment *attachment = mediaView.attachment;
+            if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
+                OWSLogWarn(@"Media attachment not yet downloaded.");
+                return;
+            }
+            TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment;
+            [self.delegate didTapImageViewItem:self.viewItem attachmentStream:attachmentStream imageView:mediaView];
             break;
         }
     }
diff --git a/Signal/src/ViewControllers/MediaGalleryViewController.swift b/Signal/src/ViewControllers/MediaGalleryViewController.swift
index ec0fe67c5..cdc2b15f5 100644
--- a/Signal/src/ViewControllers/MediaGalleryViewController.swift
+++ b/Signal/src/ViewControllers/MediaGalleryViewController.swift
@@ -264,10 +264,7 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
 
         self.options = options
         self.mediaGalleryFinder = OWSMediaGalleryFinder(thread: thread)
-        let navController = MediaGalleryNavigationController()
-        self.navigationController = navController
         super.init()
-        navController.retainUntilDismissed = self
     }
 
     // MARK: Present/Dismiss
@@ -307,6 +304,11 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
         self.addDataSourceDelegate(pageViewController)
 
         self.pageViewController = pageViewController
+
+        let navController = MediaGalleryNavigationController()
+        self.navigationController = navController
+        navController.retainUntilDismissed = self
+
         navigationController.setViewControllers([pageViewController], animated: false)
 
         self.replacingView = replacingView
diff --git a/SignalMessaging/categories/UIView+OWS.h b/SignalMessaging/categories/UIView+OWS.h
index 81bdde795..2597fe93d 100644
--- a/SignalMessaging/categories/UIView+OWS.h
+++ b/SignalMessaging/categories/UIView+OWS.h
@@ -188,6 +188,12 @@ CG_INLINE CGPoint CGPointScale(CGPoint point, CGFloat factor)
     return CGPointMake(point.x * factor, point.y * factor);
 }
 
+CG_INLINE CGFloat CGPointDistance(CGPoint left, CGPoint right)
+{
+    CGPoint delta = CGPointSubtract(left, right);
+    return sqrt(delta.x * delta.x + delta.y * delta.y);
+}
+
 CG_INLINE CGSize CGSizeScale(CGSize size, CGFloat factor)
 {
     return CGSizeMake(size.width * factor, size.height * factor);