From fb3bb852ca87674ae84d1d65da699391f64a6d33 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 24 Oct 2017 13:24:33 -0400 Subject: [PATCH] Tap image attachment preview to view full screen. // FREEBIE --- Signal/src/Signal-Bridging-Header.h | 2 + .../ConversationViewController.m | 5 +- .../ViewControllers/FullImageViewController.h | 10 ++- .../ViewControllers/FullImageViewController.m | 80 +++++++++++++++---- .../ViewControllers/MediaMessageView.swift | 43 +++++++++- 5 files changed, 116 insertions(+), 24 deletions(-) diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 206a1d4c2..1e2d2ecc1 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -5,10 +5,12 @@ #import "AppSettingsViewController.h" #import "AttachmentSharing.h" #import "ContactTableViewCell.h" +#import "ConversationViewItem.h" #import "DateUtil.h" #import "DebugUIPage.h" #import "Environment.h" #import "FingerprintViewController.h" +#import "FullImageViewController.h" #import "HomeViewController.h" #import "NSString+OWS.h" #import "NotificationsManager.h" diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 8024b1dd9..a39f619c3 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1946,8 +1946,9 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { UIWindow *window = [UIApplication sharedApplication].keyWindow; CGRect convertedRect = [imageView convertRect:imageView.bounds toView:window]; - FullImageViewController *vc = - [[FullImageViewController alloc] initWithAttachment:attachmentStream fromRect:convertedRect viewItem:viewItem]; + FullImageViewController *vc = [[FullImageViewController alloc] initWithAttachmentStream:attachmentStream + fromRect:convertedRect + viewItem:viewItem]; [vc presentFromViewController:self]; } diff --git a/Signal/src/ViewControllers/FullImageViewController.h b/Signal/src/ViewControllers/FullImageViewController.h index b6edff4eb..6ade09366 100644 --- a/Signal/src/ViewControllers/FullImageViewController.h +++ b/Signal/src/ViewControllers/FullImageViewController.h @@ -7,13 +7,17 @@ NS_ASSUME_NONNULL_BEGIN @class ConversationViewItem; +@class SignalAttachment; @class TSAttachmentStream; @interface FullImageViewController : OWSViewController -- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream - fromRect:(CGRect)rect - viewItem:(ConversationViewItem *)viewItem; +// If viewItem is non-null, long press will show a menu controller. +- (instancetype)initWithAttachmentStream:(TSAttachmentStream *)attachmentStream + fromRect:(CGRect)rect + viewItem:(ConversationViewItem *_Nullable)viewItem; + +- (instancetype)initWithAttachment:(SignalAttachment *)attachment fromRect:(CGRect)rect; - (void)presentFromViewController:(UIViewController *)viewController; diff --git a/Signal/src/ViewControllers/FullImageViewController.m b/Signal/src/ViewControllers/FullImageViewController.m index 7309bf204..c3a68d592 100644 --- a/Signal/src/ViewControllers/FullImageViewController.m +++ b/Signal/src/ViewControllers/FullImageViewController.m @@ -5,6 +5,7 @@ #import "FullImageViewController.h" #import "AttachmentSharing.h" #import "ConversationViewItem.h" +#import "Signal-Swift.h" #import "TSAttachmentStream.h" #import "TSInteraction.h" #import "UIColor+OWS.h" @@ -56,8 +57,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BOOL isPresenting; @property (nonatomic) NSData *fileData; -@property (nonatomic) TSAttachmentStream *attachmentStream; -@property (nonatomic) ConversationViewItem *viewItem; +@property (nonatomic, nullable) TSAttachmentStream *attachmentStream; +@property (nonatomic, nullable) SignalAttachment *attachment; +@property (nonatomic, nullable) ConversationViewItem *viewItem; @property (nonatomic) UIToolbar *footerBar; @@ -65,10 +67,9 @@ NS_ASSUME_NONNULL_BEGIN @implementation FullImageViewController - -- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream - fromRect:(CGRect)rect - viewItem:(ConversationViewItem *)viewItem +- (instancetype)initWithAttachmentStream:(TSAttachmentStream *)attachmentStream + fromRect:(CGRect)rect + viewItem:(ConversationViewItem *_Nullable)viewItem { self = [super initWithNibName:nil bundle:nil]; @@ -77,14 +78,65 @@ NS_ASSUME_NONNULL_BEGIN self.attachmentStream = attachmentStream; self.originRect = rect; self.viewItem = viewItem; - self.fileData = [NSData dataWithContentsOfURL:[attachmentStream mediaURL]]; } return self; } +- (instancetype)initWithAttachment:(SignalAttachment *)attachment fromRect:(CGRect)rect +{ + + self = [super initWithNibName:nil bundle:nil]; + + if (self) { + self.attachment = attachment; + self.originRect = rect; + } + + return self; +} + +- (NSURL *_Nullable)attachmentUrl +{ + if (self.attachmentStream) { + return self.attachmentStream.mediaURL; + } else if (self.attachment) { + return self.attachment.dataUrl; + } else { + return nil; + } +} + +- (NSData *)fileData +{ + if (_fileData) { + NSURL *_Nullable url = self.attachmentUrl; + if (url) { + _fileData = [NSData dataWithContentsOfURL:url]; + } + } + return _fileData; +} + - (UIImage *)image { - return self.attachmentStream.image; + if (self.attachmentStream) { + return self.attachmentStream.image; + } else if (self.attachment) { + return self.attachment.image; + } else { + return nil; + } +} + +- (BOOL)isAnimated +{ + if (self.attachmentStream) { + return self.attachmentStream.isAnimated; + } else if (self.attachment) { + return self.attachment.isAnimatedImage; + } else { + return NO; + } } - (void)loadView { @@ -150,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)shareWasPressed:(id)sender { DDLogInfo(@"%@: sharing image.", self.tag); - [AttachmentSharing showShareUIForURL:[self.attachmentStream mediaURL]]; + [AttachmentSharing showShareUIForURL:self.attachmentUrl]; } - (void)initializeScrollView { @@ -162,13 +214,6 @@ NS_ASSUME_NONNULL_BEGIN [self.contentView addSubview:self.scrollView]; } -- (BOOL)isAnimated -{ - OWSAssert(self.attachmentStream); - - return self.attachmentStream.isAnimated; -} - - (void)initializeImageView { if (self.isAnimated) { if ([self.fileData ows_isValidImage]) { @@ -249,6 +294,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)longPressGesture:(UIGestureRecognizer *)sender { // We "eagerly" respond when the long press begins, not when it ends. if (sender.state == UIGestureRecognizerStateBegan) { + if (!self.viewItem) { + return; + } [self.view becomeFirstResponder]; diff --git a/Signal/src/ViewControllers/MediaMessageView.swift b/Signal/src/ViewControllers/MediaMessageView.swift index 1cbf4edb3..0dd9110a1 100644 --- a/Signal/src/ViewControllers/MediaMessageView.swift +++ b/Signal/src/ViewControllers/MediaMessageView.swift @@ -181,6 +181,9 @@ class MediaMessageView: UIView, OWSAudioAttachmentPlayerDelegate { let aspectRatio = image.size.width / image.size.height addSubviewWithScaleAspectFitLayout(view:animatedImageView, aspectRatio:aspectRatio) contentView = animatedImageView + + animatedImageView.isUserInteractionEnabled = true + animatedImageView.addGestureRecognizer(UITapGestureRecognizer(target:self, action:#selector(imageTapped))) } private func addSubviewWithScaleAspectFitLayout(view: UIView, aspectRatio: CGFloat) { @@ -212,7 +215,10 @@ class MediaMessageView: UIView, OWSAudioAttachmentPlayerDelegate { let aspectRatio = image.size.width / image.size.height addSubviewWithScaleAspectFitLayout(view:imageView, aspectRatio:aspectRatio) contentView = imageView - } + + imageView.isUserInteractionEnabled = true + imageView.addGestureRecognizer(UITapGestureRecognizer(target:self, action:#selector(imageTapped))) +} private func createVideoPreview() { guard let image = attachment.videoPreview() else { @@ -391,13 +397,44 @@ class MediaMessageView: UIView, OWSAudioAttachmentPlayerDelegate { audioPlayButton?.imageView?.tintColor = UIColor.ows_materialBlue() } + // MARK: - Full Screen Image + + func imageTapped(sender: UIGestureRecognizer) { + guard sender.state == .recognized else { + return + } + guard let fromView = sender.view else { + return + } + guard let fromViewController = fromViewController() else { + return + } + let window = UIApplication.shared.keyWindow + let convertedRect = fromView.convert(fromView.bounds, to:window) + let viewController = FullImageViewController(attachment:attachment, from:convertedRect) + viewController.present(from:fromViewController) + } + + private func fromViewController() -> UIViewController? { + var responder: UIResponder? = self + while true { + if responder == nil { + return nil + } + if let viewController = responder as? UIViewController { + return viewController + } + responder = responder?.next + } + } + // MARK: - Video Playback func videoTapped(sender: UIGestureRecognizer) { - guard let dataUrl = attachment.dataUrl else { + guard sender.state == .recognized else { return } - guard sender.state == .recognized else { + guard let dataUrl = attachment.dataUrl else { return } guard let videoPlayer = MPMoviePlayerController(contentURL: dataUrl) else {