Handle taps

This commit is contained in:
Kyle Bashour 2022-11-24 07:48:07 -08:00
parent f8d1afc7e4
commit ba7955bdb5
9 changed files with 184 additions and 16 deletions

View File

@ -48,18 +48,12 @@ extension DataSourceFacade {
assertionFailure()
return
}
let domain = provider.authContext.mastodonAuthenticationBox.domain
if url.host == domain,
url.pathComponents.count >= 4,
url.pathComponents[0] == "/",
url.pathComponents[1] == "web",
url.pathComponents[2] == "statuses" {
let statusID = url.pathComponents[3]
let threadViewModel = RemoteThreadViewModel(context: provider.context, authContext: provider.authContext, statusID: statusID)
_ = await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
} else {
_ = await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
}
await responseToURLAction(
provider: provider,
status: status,
url: url
)
case .hashtag(_, let hashtag, _):
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, authContext: provider.authContext, hashtag: hashtag)
_ = await provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show)

View File

@ -0,0 +1,32 @@
//
// DataSourceFacade+URL.swift
// Mastodon
//
// Created by Kyle Bashour on 11/24/22.
//
import Foundation
import CoreDataStack
import MetaTextKit
import MastodonCore
extension DataSourceFacade {
static func responseToURLAction(
provider: DataSourceProvider & AuthContextProvider,
status: ManagedObjectRecord<Status>,
url: URL
) async {
let domain = provider.authContext.mastodonAuthenticationBox.domain
if url.host == domain,
url.pathComponents.count >= 4,
url.pathComponents[0] == "/",
url.pathComponents[1] == "web",
url.pathComponents[2] == "statuses" {
let statusID = url.pathComponents[3]
let threadViewModel = RemoteThreadViewModel(context: provider.context, authContext: provider.authContext, statusID: statusID)
_ = await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
} else {
_ = await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
}
}
}

View File

@ -516,6 +516,61 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Aut
}
// MARK: - card
extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
statusView: StatusView,
didTapCardWithURL url: URL
) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
assertionFailure()
return
}
guard case let .status(status) = item else {
assertionFailure("only works for status data provider")
return
}
await DataSourceFacade.responseToURLAction(
provider: self,
status: status,
url: url
)
}
}
func tableViewCell(
_ cell: UITableViewCell,
notificationView: NotificationView,
quoteStatusView: StatusView,
didTapCardWithURL url: URL
) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
assertionFailure()
return
}
guard case let .status(status) = item else {
assertionFailure("only works for status data provider")
return
}
await DataSourceFacade.responseToURLAction(
provider: self,
status: status,
url: url
)
}
}
}
// MARK: a11y
extension NotificationTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, accessibilityActivate: Void) {

View File

@ -120,7 +120,36 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
)
}
}
}
// MARK: - card
extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider {
func tableViewCell(
_ cell: UITableViewCell,
statusView: StatusView,
didTapCardWithURL url: URL
) {
Task {
let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil)
guard let item = await item(from: source) else {
assertionFailure()
return
}
guard case let .status(status) = item else {
assertionFailure("only works for status data provider")
return
}
await DataSourceFacade.responseToURLAction(
provider: self,
status: status,
url: url
)
}
}
}
// MARK: - media

View File

@ -28,11 +28,13 @@ protocol NotificationTableViewCellDelegate: AnyObject, AutoGenerateProtocolDeleg
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, acceptFollowRequestButtonDidPressed button: UIButton)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, rejectFollowRequestButtonDidPressed button: UIButton)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, didTapCardWithURL url: URL)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, didTapCardWithURL url: URL)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, quoteStatusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
func tableViewCell(_ cell: UITableViewCell, notificationView: NotificationView, accessibilityActivate: Void)
@ -63,6 +65,10 @@ extension NotificationViewDelegate where Self: NotificationViewContainerTableVie
delegate?.tableViewCell(self, notificationView: notificationView, statusView: statusView, metaText: metaText, didSelectMeta: meta)
}
func notificationView(_ notificationView: NotificationView, statusView: StatusView, didTapCardWithURL url: URL) {
delegate?.tableViewCell(self, notificationView: notificationView, statusView: statusView, didTapCardWithURL: url)
}
func notificationView(_ notificationView: NotificationView, statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView) {
delegate?.tableViewCell(self, notificationView: notificationView, statusView: statusView, spoilerOverlayViewDidPressed: overlayView)
}
@ -83,6 +89,10 @@ extension NotificationViewDelegate where Self: NotificationViewContainerTableVie
delegate?.tableViewCell(self, notificationView: notificationView, quoteStatusView: quoteStatusView, metaText: metaText, didSelectMeta: meta)
}
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, didTapCardWithURL url: URL) {
delegate?.tableViewCell(self, notificationView: notificationView, quoteStatusView: quoteStatusView, didTapCardWithURL: url)
}
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView) {
delegate?.tableViewCell(self, notificationView: notificationView, quoteStatusView: quoteStatusView, spoilerOverlayViewDidPressed: overlayView)
}

View File

@ -27,6 +27,7 @@ protocol StatusTableViewCellDelegate: AnyObject, AutoGenerateProtocolDelegate {
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, didTapCardWithURL url: URL)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, pollTableView tableView: UITableView, didSelectRowAt indexPath: IndexPath)
func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton)
@ -61,6 +62,10 @@ extension StatusViewDelegate where Self: StatusViewContainerTableViewCell {
delegate?.tableViewCell(self, statusView: statusView, metaText: metaText, didSelectMeta: meta)
}
func statusView(_ statusView: StatusView, didTapCardWithURL url: URL) {
delegate?.tableViewCell(self, statusView: statusView, didTapCardWithURL: url)
}
func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int) {
delegate?.tableViewCell(self, statusView: statusView, mediaGridContainerView: mediaGridContainerView, mediaView: mediaView, didSelectMediaViewAt: index)
}

View File

@ -16,6 +16,7 @@ public final class LinkPreviewButton: UIControl {
private let containerStackView = UIStackView()
private let labelStackView = UIStackView()
private let highlightView = UIView()
private let imageView = UIImageView()
private let titleLabel = UILabel()
private let linkLabel = UILabel()
@ -30,6 +31,12 @@ public final class LinkPreviewButton: UIControl {
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 21 / 40),
]
public override var isHighlighted: Bool {
didSet {
highlightView.isHidden = !isHighlighted
}
}
public override init(frame: CGRect) {
super.init(frame: frame)
@ -38,6 +45,9 @@ public final class LinkPreviewButton: UIControl {
layer.cornerRadius = 10
layer.borderColor = ThemeService.shared.currentTheme.value.separator.cgColor
highlightView.backgroundColor = UIColor.black.withAlphaComponent(0.1)
highlightView.isHidden = true
titleLabel.numberOfLines = 2
titleLabel.setContentCompressionResistancePriority(.defaultLow - 1, for: .horizontal)
titleLabel.text = "This is where I'd put a title... if I had one"
@ -61,17 +71,23 @@ public final class LinkPreviewButton: UIControl {
containerStackView.addArrangedSubview(imageView)
containerStackView.addArrangedSubview(labelStackView)
containerStackView.distribution = .fill
addSubview(containerStackView)
addSubview(highlightView)
containerStackView.isUserInteractionEnabled = false
containerStackView.translatesAutoresizingMaskIntoConstraints = false
highlightView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
containerStackView.topAnchor.constraint(equalTo: topAnchor),
containerStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
containerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
containerStackView.trailingAnchor.constraint(equalTo: trailingAnchor),
highlightView.topAnchor.constraint(equalTo: topAnchor),
highlightView.bottomAnchor.constraint(equalTo: bottomAnchor),
highlightView.leadingAnchor.constraint(equalTo: leadingAnchor),
highlightView.trailingAnchor.constraint(equalTo: trailingAnchor),
])
}
@ -100,10 +116,12 @@ public final class LinkPreviewButton: UIControl {
if isCompact {
containerStackView.alignment = .center
containerStackView.axis = .horizontal
containerStackView.distribution = .fill
NSLayoutConstraint.activate(compactImageConstraints)
} else {
containerStackView.alignment = .fill
containerStackView.axis = .vertical
containerStackView.distribution = .equalSpacing
NSLayoutConstraint.activate(largeImageConstraints)
}
}

View File

@ -22,6 +22,7 @@ public protocol NotificationViewDelegate: AnyObject {
func notificationView(_ notificationView: NotificationView, rejectFollowRequestButtonDidPressed button: UIButton)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, didTapCardWithURL url: URL)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func notificationView(_ notificationView: NotificationView, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
@ -29,6 +30,7 @@ public protocol NotificationViewDelegate: AnyObject {
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, didTapCardWithURL url: URL)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
func notificationView(_ notificationView: NotificationView, quoteStatusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
@ -496,7 +498,17 @@ extension NotificationView {
// MARK: - StatusViewDelegate
extension NotificationView: StatusViewDelegate {
public func statusView(_ statusView: StatusView, didTapCardWithURL url: URL) {
switch statusView {
case self.statusView:
delegate?.notificationView(self, statusView: statusView, didTapCardWithURL: url)
case quoteStatusView:
delegate?.notificationView(self, quoteStatusView: statusView, didTapCardWithURL: url)
default:
assertionFailure()
}
}
public func statusView(_ statusView: StatusView, headerDidPressed header: UIView) {
// do nothing
}

View File

@ -23,6 +23,7 @@ public protocol StatusViewDelegate: AnyObject {
func statusView(_ statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)
func statusView(_ statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton)
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func statusView(_ statusView: StatusView, didTapCardWithURL url: URL)
func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int)
func statusView(_ statusView: StatusView, pollTableView tableView: UITableView, didSelectRowAt indexPath: IndexPath)
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton)
@ -263,7 +264,13 @@ extension StatusView {
// media
mediaGridContainerView.delegate = self
linkPreviewButton.addTarget(
self,
action: #selector(linkPreviewButtonPressed),
for: .touchUpInside
)
// poll
pollTableView.translatesAutoresizingMaskIntoConstraints = false
pollTableViewHeightLayoutConstraint = pollTableView.heightAnchor.constraint(equalToConstant: 44.0).priority(.required - 1)
@ -298,6 +305,12 @@ extension StatusView {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.statusView(self, spoilerOverlayViewDidPressed: spoilerOverlayView)
}
@objc private func linkPreviewButtonPressed(_ sender: LinkPreviewButton) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
guard let url = viewModel.card?.url else { return }
delegate?.statusView(self, didTapCardWithURL: url)
}
}