From d0feece606eed10957df33ce8ce5fb5e02e7d217 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 11 Oct 2018 21:20:58 -0400 Subject: [PATCH] Add 3d touch peek/pop navigation --- Tusker.xcodeproj/project.pbxproj | 6 +- Tusker/ImageCache.swift | 4 + .../ConversationViewController.swift | 2 + .../LargeImageViewController.swift | 14 +++- .../NotificationsTableViewController.swift | 2 + .../TimelineTableViewController.swift | 2 + Tusker/Screens/Utilities/Previewing.swift | 84 +++++++++++++++++++ .../Utilities/PreviewingController.swift | 15 ++++ Tusker/TuskerNavigationDelegate.swift | 69 ++++++++++----- Tusker/Views/ContentLabel.swift | 47 ++++++----- .../ActionNotificationTableViewCell.swift | 28 ++++--- .../ActionNotificationTableViewCell.xib | 5 +- .../FollowNotificationTableViewCell.swift | 6 ++ .../ProfileHeaderTableViewCell.swift | 21 ++--- .../ConversationMainStatusTableViewCell.swift | 40 +++++---- Tusker/Views/Status/StatusTableViewCell.swift | 40 +++++---- 16 files changed, 280 insertions(+), 105 deletions(-) create mode 100644 Tusker/Screens/Utilities/Previewing.swift create mode 100644 Tusker/Screens/Utilities/PreviewingController.swift diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index b0c5e1d8..77967db9 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -125,6 +125,7 @@ D6D4DDDA212518A200E1C4BB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6D4DDD8212518A200E1C4BB /* LaunchScreen.storyboard */; }; D6D4DDE5212518A200E1C4BB /* TuskerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDE4212518A200E1C4BB /* TuskerTests.swift */; }; D6D4DDF0212518A200E1C4BB /* TuskerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */; }; + D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; }; D6E6F26321603F8B006A8599 /* CharacterCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26221603F8B006A8599 /* CharacterCounter.swift */; }; D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; }; D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; }; @@ -318,6 +319,7 @@ D6D4DDEB212518A200E1C4BB /* TuskerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TuskerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TuskerUITests.swift; sourceTree = ""; }; D6D4DDF1212518A200E1C4BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = ""; }; D6E6F26221603F8B006A8599 /* CharacterCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounter.swift; sourceTree = ""; }; D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = ""; }; D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = ""; }; @@ -672,7 +674,6 @@ D6BED1722126661300F02DA0 /* Views */ = { isa = PBXGroup; children = ( - D621544921682AC60003D87D /* Tab */, 04496BD621625361001F1B23 /* ContentLabel.swift */, D6C693F82162E4DB007D6A6D /* StatusContentLabel.swift */, D6C94D882139E6EC00CB5196 /* AttachmentView.swift */, @@ -683,6 +684,7 @@ D641C78A213DD926004B4513 /* Status */, D641C78B213DD92F004B4513 /* Profile Header */, D641C78C213DD937004B4513 /* Notifications */, + D621544921682AC60003D87D /* Tab */, D6C693CB2161256B007D6A6D /* Silent Action Permissions */, ); path = Views; @@ -702,6 +704,7 @@ children = ( D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */, D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */, + D6E0DC8D216EDF1E00369478 /* Previewing.swift */, ); path = Utilities; sourceTree = ""; @@ -1117,6 +1120,7 @@ D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */, D679C09F215850EF00DA27FE /* XCBActions.swift in Sources */, D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */, + D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */, D6BED174212667E900F02DA0 /* StatusTableViewCell.swift in Sources */, D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */, D6C94D892139E6EC00CB5196 /* AttachmentView.swift in Sources */, diff --git a/Tusker/ImageCache.swift b/Tusker/ImageCache.swift index fd8a386b..0d4afeb5 100644 --- a/Tusker/ImageCache.swift +++ b/Tusker/ImageCache.swift @@ -44,6 +44,10 @@ class ImageCache { } } + func get(_ url: URL) -> UIImage? { + return try? storage.object(forKey: url.absoluteString) + } + func cancel(_ url: URL) { requests[url]?.cancel() } diff --git a/Tusker/Screens/Conversation/ConversationViewController.swift b/Tusker/Screens/Conversation/ConversationViewController.swift index 5250599c..d841109c 100644 --- a/Tusker/Screens/Conversation/ConversationViewController.swift +++ b/Tusker/Screens/Conversation/ConversationViewController.swift @@ -52,6 +52,8 @@ class ConversationViewController: UITableViewController { self.tableView.scrollToRow(at: indexPath, at: .middle, animated: false) } } + + registerForPreviewing(with: self, sourceView: view) } override func viewWillAppear(_ animated: Bool) { diff --git a/Tusker/Screens/Large Image/LargeImageViewController.swift b/Tusker/Screens/Large Image/LargeImageViewController.swift index d06884be..01f762a1 100644 --- a/Tusker/Screens/Large Image/LargeImageViewController.swift +++ b/Tusker/Screens/Large Image/LargeImageViewController.swift @@ -15,10 +15,22 @@ protocol LargeImageViewControllerDelegate { class LargeImageViewController: UIViewController, UIScrollViewDelegate { - static func create(image: UIImage, description: String?) -> LargeImageViewController { + static func create(image: UIImage, description: String?, sourceView: UIView, sourceViewController: UIViewController) -> LargeImageViewController { guard let vc = UIStoryboard(name: "LargeImage", bundle: nil).instantiateInitialViewController() as? LargeImageViewController else { fatalError() } vc.image = image vc.imageDescription = description + var frame = sourceView.convert(sourceView.bounds, to: sourceViewController.view) + if let scrollView = sourceViewController.view as? UIScrollView { + let scale = scrollView.zoomScale + let width = frame.width * scale + let height = frame.height * scale + let x = frame.minX * scale - scrollView.contentOffset.x + scrollView.frame.minX + let y = frame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY + frame = CGRect(x: x, y: y, width: width, height: height) + } + vc.originFrame = frame + vc.originCornerRadius = sourceView.layer.cornerRadius + vc.transitioningDelegate = sourceViewController return vc } diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index 25592560..7772c766 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -52,6 +52,8 @@ class NotificationsTableViewController: UITableViewController { self.newer = pagination?.newer self.older = pagination?.older } + + registerForPreviewing(with: self, sourceView: view) } override func viewWillAppear(_ animated: Bool) { diff --git a/Tusker/Screens/Timeline/TimelineTableViewController.swift b/Tusker/Screens/Timeline/TimelineTableViewController.swift index fd1e9880..85efb7a0 100644 --- a/Tusker/Screens/Timeline/TimelineTableViewController.swift +++ b/Tusker/Screens/Timeline/TimelineTableViewController.swift @@ -76,6 +76,8 @@ class TimelineTableViewController: UITableViewController { self.newer = pagination?.newer self.older = pagination?.older } + + registerForPreviewing(with: self, sourceView: view) } override func viewWillAppear(_ animated: Bool) { diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift new file mode 100644 index 00000000..7564282d --- /dev/null +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -0,0 +1,84 @@ +// +// PreviewViewControllerProvider.swift +// Tusker +// +// Created by Shadowfacts on 10/10/18. +// Copyright © 2018 Shadowfacts. All rights reserved. +// + +import UIKit + +enum PreviewCommitType { + case nav + case modal +} + +protocol PreviewViewControllerProvider { + + func getPreviewViewController(forLocation location: CGPoint, sourceViewController: UIViewController) -> UIViewController? + + func getPreviewCommitType(forViewController viewController: UIViewController) -> PreviewCommitType + +} + +extension PreviewViewControllerProvider { + func getPreviewCommitType(forViewController viewController: UIViewController) -> PreviewCommitType { + return viewController is LargeImageViewController ? .modal : .nav + } +} + +@objc extension UITableViewController: UIViewControllerPreviewingDelegate { + public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { + if let indexPath = tableView.indexPathForRow(at: location), + let cell = tableView.cellForRow(at: indexPath) as? UITableViewCell & PreviewViewControllerProvider { + let cellLocation = cell.convert(location, from: tableView) + if let vc = cell.getPreviewViewController(forLocation: cellLocation, sourceViewController: self) { + previewingContext.sourceRect = tableView.rectForRow(at: indexPath) + return vc + } + } + return nil + } + + public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { + if viewControllerToCommit is LargeImageViewController { + present(viewControllerToCommit, animated: false) + } else { + navigationController!.pushViewController(viewControllerToCommit, animated: false) + } + } +} + +//class PreviewingController: NSObject, UIViewControllerPreviewingDelegate { +// +// var currentCommitType: PreviewCommitType? +// var owner: UIViewController? +// +// init(owner: UIViewController) { +// self.owner = owner +// } +// +// func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { +// if let owner = owner as? UITableViewController, +// let indexPath = owner.tableView.indexPathForRow(at: location), +// let cell = owner.tableView.cellForRow(at: indexPath) as? UITableViewCell & PreviewViewControllerProvider { +// let cellLocation = cell.convert(location, from: owner.tableView) +// if let vc = cell.getPreviewViewController(forLocation: cellLocation, sourceViewController: owner) { +// currentCommitType = cell.getPreviewCommitType(forViewController: vc) +// previewingContext.sourceRect = owner.tableView.rectForRow(at: indexPath) +// return vc +// } +// } +// return nil +// } +// +// func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { +// switch currentCommitType ?? .nav { +// case .modal: +// owner?.present(viewControllerToCommit, animated: false) +// case .nav: +// owner?.navigationController!.pushViewController(viewControllerToCommit, animated: false) +// } +// } +// +//} diff --git a/Tusker/Screens/Utilities/PreviewingController.swift b/Tusker/Screens/Utilities/PreviewingController.swift new file mode 100644 index 00000000..9a3f3364 --- /dev/null +++ b/Tusker/Screens/Utilities/PreviewingController.swift @@ -0,0 +1,15 @@ +// +// PreviewingController.swift +// Tusker +// +// Created by Shadowfacts on 10/11/18. +// Copyright © 2018 Shadowfacts. All rights reserved. +// + +import UIKit + +class PreviewingController { + + var currentCommitType: PreviewCommitType + +} diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index 53806a30..ff89d9d5 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -11,18 +11,30 @@ import SafariServices import Pachyderm protocol TuskerNavigationDelegate { + func viewController(forAccount accountID: String) -> UIViewController + func selected(account accountID: String) + func viewController(forMention mention: Mention) -> UIViewController + func selected(mention: Mention) + func viewController(forTag tag: Hashtag) -> UIViewController + func selected(tag: Hashtag) + func viewController(forURL url: URL) -> UIViewController + func selected(url: URL) + func viewController(forStatus statusID: String) -> UIViewController + func selected(status statusID: String) func reply(to statusID: String) + func viewController(forImage image: UIImage, description: String?, animatingFrom originView: UIView) -> UIViewController + func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView) func showMoreOptions(forStatus statusID: String) @@ -30,6 +42,10 @@ protocol TuskerNavigationDelegate { extension TuskerNavigationDelegate where Self: UIViewController { + func viewController(forAccount accountID: String) -> UIViewController { + return ProfileTableViewController.create(for: accountID) + } + func selected(account accountID: String) { // don't open if the account is the same as the current one if let profileController = self as? ProfileTableViewController, @@ -40,32 +56,48 @@ extension TuskerNavigationDelegate where Self: UIViewController { guard let navigationController = navigationController else { fatalError("Can't show profile VC when not in navigation controller") } - let vc = ProfileTableViewController.create(for: accountID) + let vc = viewController(forAccount: accountID) navigationController.pushViewController(vc, animated: true) } + func viewController(forMention mention: Mention) -> UIViewController { + return ProfileTableViewController.create(for: mention.id) + } + func selected(mention: Mention) { guard let navigationController = navigationController else { fatalError("Can't show profile VC from mention when not in navigation controller") } - let vc = ProfileTableViewController.create(for: mention.id) + let vc = viewController(forMention: mention) navigationController.pushViewController(vc, animated: true) } + func viewController(forTag tag: Hashtag) -> UIViewController { + let timeline = Timeline.tag(hashtag: tag.name) + return TimelineTableViewController.create(for: timeline) + } + func selected(tag: Hashtag) { guard let navigationController = navigationController else { fatalError("Can't show hashtag timeline when not in navigation controller") } - let timeline = Timeline.tag(hashtag: tag.name) - let vc = TimelineTableViewController.create(for: timeline) + let vc = viewController(forTag: tag) navigationController.pushViewController(vc, animated: true) } + func viewController(forURL url: URL) -> UIViewController { + return SFSafariViewController(url: url) + } + func selected(url: URL) { - let vc = SFSafariViewController(url: url) + let vc = viewController(forURL: url) present(vc, animated: true) } + func viewController(forStatus statusID: String) -> UIViewController { + return ConversationViewController.create(for: statusID) + } + func selected(status statusID: String) { // don't open if the conversation is the same as the current one if let conversationController = self as? ConversationViewController, @@ -76,7 +108,7 @@ extension TuskerNavigationDelegate where Self: UIViewController { guard let navigationController = navigationController else { fatalError("Can't show conversation VC when not in navigation controller") } - let vc = ConversationViewController.create(for: statusID) + let vc = viewController(forStatus: statusID) navigationController.pushViewController(vc, animated: true) } @@ -85,22 +117,17 @@ extension TuskerNavigationDelegate where Self: UIViewController { present(vc, animated: true) } - func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView) { - guard let self = self as? UIViewController & LargeImageViewControllerDelegate else { return } - let vc = LargeImageViewController.create(image: image, description: description) - vc.delegate = self - var frame = originView.convert(originView.bounds, to: view) - if let scrollView = view as? UIScrollView { - let scale = scrollView.zoomScale - let width = frame.width * scale - let height = frame.height * scale - let x = frame.minX * scale - scrollView.contentOffset.x + scrollView.frame.minX - let y = frame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY - frame = CGRect(x: x, y: y, width: width, height: height) + func viewController(forImage image: UIImage, description: String?, animatingFrom originView: UIView) -> UIViewController { + guard let self = self as? UIViewController & LargeImageViewControllerDelegate else { + fatalError("Can't create large image view controller unless self is LargeImageViewControllerDelegate") } - vc.originFrame = frame - vc.originCornerRadius = originView.layer.cornerRadius - vc.transitioningDelegate = self + let vc = LargeImageViewController.create(image: image, description: description, sourceView: originView, sourceViewController: self) + vc.delegate = self + return vc + } + + func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView) { + let vc = viewController(forImage: image, description: description, animatingFrom: originView) present(vc, animated: true) } diff --git a/Tusker/Views/ContentLabel.swift b/Tusker/Views/ContentLabel.swift index 404c5591..5b9a4392 100644 --- a/Tusker/Views/ContentLabel.swift +++ b/Tusker/Views/ContentLabel.swift @@ -11,17 +11,9 @@ import TTTAttributedLabel import Pachyderm import SwiftSoup -protocol ContentLabelNavigationDelegate { - func selected(mention: Mention) - - func selected(tag: Hashtag) - - func selected(url: URL) -} - class ContentLabel: TTTAttributedLabel { - var navigationDelegate: ContentLabelNavigationDelegate? + var navigationDelegate: TuskerNavigationDelegate? override func awakeFromNib() { super.awakeFromNib() @@ -92,18 +84,35 @@ class ContentLabel: TTTAttributedLabel { } } + func getViewController(forLinkAt point: CGPoint) -> UIViewController? { + guard let navigationDelegate = navigationDelegate, + let link = link(at: point), + let url = link.result.url else { + return nil + } + let text = (self.text as! NSString).substring(with: link.result.range) + if let mention = getMention(for: url, text: text) { + return navigationDelegate.viewController(forMention: mention) + } else if let tag = getHashtag(for: url, text: text) { + return navigationDelegate.viewController(forTag: tag) + } else { + return navigationDelegate.viewController(forURL: url) + } + } + // MARK: - Interaction func linkTapped(_ label: TTTAttributedLabel!, _ link: TTTAttributedLabelLink!) { - if let navigationDelegate = navigationDelegate, - let url = link.result.url { - let text = (self.text as! NSString).substring(with: link.result.range) - if let mention = getMention(for: url, text: text) { - navigationDelegate.selected(mention: mention) - } else if let tag = getHashtag(for: url, text: text) { - navigationDelegate.selected(tag: tag) - } else { - navigationDelegate.selected(url: url) - } + guard let navigationDelegate = navigationDelegate, + let url = link.result.url else { + return + } + let text = (self.text as! NSString).substring(with: link.result.range) + if let mention = getMention(for: url, text: text) { + navigationDelegate.selected(mention: mention) + } else if let tag = getHashtag(for: url, text: text) { + navigationDelegate.selected(tag: tag) + } else { + navigationDelegate.selected(url: url) } } diff --git a/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift index b00fdd2a..048c437b 100644 --- a/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationTableViewCell.swift @@ -11,11 +11,16 @@ import Pachyderm class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive { - var delegate: StatusTableViewCellDelegate? + var delegate: StatusTableViewCellDelegate? { + didSet { + contentLabel.navigationDelegate = delegate + } + } @IBOutlet weak var displayNameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel! @IBOutlet weak var contentLabel: StatusContentLabel! + @IBOutlet weak var avatarContainerView: UIView! @IBOutlet weak var opAvatarImageView: UIImageView! @IBOutlet weak var actionAvatarImageView: UIImageView! @IBOutlet weak var actionLabel: UILabel! @@ -40,7 +45,6 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive { actionAvatarImageView.layer.masksToBounds = true actionLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(actionPressed))) actionLabel.isUserInteractionEnabled = true - contentLabel.navigationDelegate = self } func updateUIForPreferences() { @@ -186,16 +190,14 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive { } -extension ActionNotificationTableViewCell: ContentLabelNavigationDelegate { - func selected(mention: Mention) { - delegate?.selected(mention: mention) - } - - func selected(tag: Hashtag) { - delegate?.selected(tag: tag) - } - - func selected(url: URL) { - delegate?.selected(url: url) +extension ActionNotificationTableViewCell: PreviewViewControllerProvider { + func getPreviewViewController(forLocation location: CGPoint, sourceViewController: UIViewController) -> UIViewController? { + if avatarContainerView.frame.contains(location) { + return delegate?.viewController(forAccount: notification.account.id) + } else if contentLabel.frame.contains(location), + let vc = contentLabel.getViewController(forLinkAt: contentLabel.convert(location, from: self)) { + return vc + } + return delegate?.viewController(forStatus: statusID) } } diff --git a/Tusker/Views/Notifications/ActionNotificationTableViewCell.xib b/Tusker/Views/Notifications/ActionNotificationTableViewCell.xib index 4a382a33..3eec22ce 100644 --- a/Tusker/Views/Notifications/ActionNotificationTableViewCell.xib +++ b/Tusker/Views/Notifications/ActionNotificationTableViewCell.xib @@ -1,10 +1,10 @@ - + - + @@ -124,6 +124,7 @@ + diff --git a/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift index 726f102b..4c66702a 100644 --- a/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationTableViewCell.swift @@ -96,3 +96,9 @@ class FollowNotificationTableViewCell: UITableViewCell, PreferencesAdaptive { } } + +extension FollowNotificationTableViewCell: PreviewViewControllerProvider { + func getPreviewViewController(forLocation location: CGPoint, sourceViewController: UIViewController) -> UIViewController? { + return delegate?.viewController(forAccount: accountID) + } +} diff --git a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift index 3a51673d..6ed628ee 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift @@ -15,7 +15,11 @@ protocol ProfileHeaderTableViewCellDelegate: TuskerNavigationDelegate { class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive { - var delegate: ProfileHeaderTableViewCellDelegate? + var delegate: ProfileHeaderTableViewCellDelegate? { + didSet { + noteLabel.navigationDelegate = delegate + } + } @IBOutlet weak var headerImageView: UIImageView! @IBOutlet weak var avatarContainerView: UIView! @@ -37,7 +41,6 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive { avatarImageView.isUserInteractionEnabled = true headerImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(headerPressed))) headerImageView.isUserInteractionEnabled = true - noteLabel.navigationDelegate = self } func updateUIForPreferences() { @@ -109,17 +112,3 @@ class ProfileHeaderTableViewCell: UITableViewCell, PreferencesAdaptive { } } - -extension ProfileHeaderTableViewCell: ContentLabelNavigationDelegate { - func selected(mention: Mention) { - delegate?.selected(mention: mention) - } - - func selected(tag: Hashtag) { - delegate?.selected(tag: tag) - } - - func selected(url: URL) { - delegate?.selected(url: url) - } -} diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift index e0c1fabe..056789d7 100644 --- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift @@ -11,7 +11,11 @@ import Pachyderm class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive { - var delegate: StatusTableViewCellDelegate? + var delegate: StatusTableViewCellDelegate? { + didSet { + contentLabel.navigationDelegate = delegate + } + } @IBOutlet weak var displayNameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel! @@ -49,7 +53,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive avatarImageView.layer.masksToBounds = true attachmentsView.layer.cornerRadius = 5 attachmentsView.layer.masksToBounds = true - contentLabel.navigationDelegate = self } func updateUIForPreferences() { @@ -216,22 +219,27 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive } -extension ConversationMainStatusTableViewCell: ContentLabelNavigationDelegate { - func selected(mention: Mention) { - delegate?.selected(mention: mention) - } - - func selected(tag: Hashtag) { - delegate?.selected(tag: tag) - } - - func selected(url: URL) { - delegate?.selected(url: url) - } -} - extension ConversationMainStatusTableViewCell: AttachmentViewDelegate { func showLargeAttachment(for attachmentView: AttachmentView) { delegate?.showLargeImage(attachmentView.image!, description: attachmentView.attachment.description, animatingFrom: attachmentView) } } + +extension ConversationMainStatusTableViewCell: PreviewViewControllerProvider { + func getPreviewViewController(forLocation location: CGPoint, sourceViewController: UIViewController) -> UIViewController? { + if avatarImageView.frame.contains(location) { + return delegate?.viewController(forAccount: accountID) + } else if attachmentsView.frame.contains(location) { + let attachmentsViewLocation = attachmentsView.convert(location, from: self) + if let attachmentView = attachmentsView.subviews.first(where: { $0.frame.contains(attachmentsViewLocation) }) as? AttachmentView { + let image = attachmentView.image! + let description = attachmentView.description + return delegate?.viewController(forImage: image, description: description, animatingFrom: attachmentView) + } + } else if contentLabel.frame.contains(location), + let vc = contentLabel.getViewController(forLinkAt: contentLabel.convert(location, from: self)) { + return vc + } + return nil + } +} diff --git a/Tusker/Views/Status/StatusTableViewCell.swift b/Tusker/Views/Status/StatusTableViewCell.swift index 3b4db6f1..24bc1c20 100644 --- a/Tusker/Views/Status/StatusTableViewCell.swift +++ b/Tusker/Views/Status/StatusTableViewCell.swift @@ -14,7 +14,11 @@ protocol StatusTableViewCellDelegate: TuskerNavigationDelegate { class StatusTableViewCell: UITableViewCell, PreferencesAdaptive { - var delegate: StatusTableViewCellDelegate? + var delegate: StatusTableViewCellDelegate? { + didSet { + contentLabel.navigationDelegate = delegate + } + } @IBOutlet weak var displayNameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel! @@ -57,7 +61,6 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive { avatarImageView.layer.masksToBounds = true attachmentsView.layer.cornerRadius = 5 attachmentsView.layer.masksToBounds = true - contentLabel.navigationDelegate = self } func updateUIForPreferences() { @@ -345,22 +348,27 @@ extension StatusTableViewCell: TableViewSwipeActionProvider { } -extension StatusTableViewCell: ContentLabelNavigationDelegate { - func selected(mention: Mention) { - delegate?.selected(mention: mention) - } - - func selected(tag: Hashtag) { - delegate?.selected(tag: tag) - } - - func selected(url: URL) { - delegate?.selected(url: url) - } -} - extension StatusTableViewCell: AttachmentViewDelegate { func showLargeAttachment(for attachmentView: AttachmentView) { delegate?.showLargeImage(attachmentView.image!, description: attachmentView.attachment.description, animatingFrom: attachmentView) } } + +extension StatusTableViewCell: PreviewViewControllerProvider { + func getPreviewViewController(forLocation location: CGPoint, sourceViewController: UIViewController) -> UIViewController? { + if avatarImageView.frame.contains(location) { + return delegate?.viewController(forAccount: accountID) + } else if attachmentsView.frame.contains(location) { + let attachmentsViewLocation = attachmentsView.convert(location, from: self) + if let attachmentView = attachmentsView.subviews.first(where: { $0.frame.contains(attachmentsViewLocation) }) as? AttachmentView { + let image = attachmentView.image! + let description = attachmentView.attachment.description + return delegate?.viewController(forImage: image, description: description, animatingFrom: attachmentView) + } + } else if contentLabel.frame.contains(location), + let vc = contentLabel.getViewController(forLinkAt: contentLabel.convert(location, from: self)) { + return vc + } + return delegate?.viewController(forStatus: statusID) + } +}