forked from shadowfacts/Tusker
Shadowfacts
23a4999196
Fixes crash when the user things the action has failed and taps it again, which results in an invalid completion handler later being called
176 lines
6.7 KiB
Swift
176 lines
6.7 KiB
Swift
//
|
|
// StatusSwipeAction.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 11/26/22.
|
|
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import Pachyderm
|
|
|
|
enum StatusSwipeAction: String, Codable, Hashable, CaseIterable {
|
|
case reply
|
|
case favorite
|
|
case reblog
|
|
case share
|
|
case bookmark
|
|
case openInSafari
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .reply:
|
|
return "Reply"
|
|
case .favorite:
|
|
return "Favorite"
|
|
case .reblog:
|
|
return "Reblog"
|
|
case .share:
|
|
return "Share"
|
|
case .bookmark:
|
|
return "Bookmark"
|
|
case .openInSafari:
|
|
return "Open in Safari"
|
|
}
|
|
}
|
|
|
|
var systemImageName: String {
|
|
switch self {
|
|
case .reply:
|
|
return "arrowshape.turn.up.left.fill"
|
|
case .favorite:
|
|
return "star.fill"
|
|
case .reblog:
|
|
return "repeat"
|
|
case .share:
|
|
return "square.and.arrow.up"
|
|
case .bookmark:
|
|
return "bookmark.fill"
|
|
case .openInSafari:
|
|
return "safari"
|
|
}
|
|
}
|
|
|
|
func createAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction? {
|
|
switch self {
|
|
case .reply:
|
|
return createReplyAction(status: status, container: container)
|
|
case .favorite:
|
|
return createFavoriteAction(status: status, container: container)
|
|
case .reblog:
|
|
return createReblogAction(status: status, container: container)
|
|
case .share:
|
|
return createShareAction(status: status, container: container)
|
|
case .bookmark:
|
|
return createBookmarkAction(status: status, container: container)
|
|
case .openInSafari:
|
|
return createOpenInSafariAction(status: status, container: container)
|
|
}
|
|
}
|
|
}
|
|
|
|
protocol StatusSwipeActionContainer: UIView {
|
|
var mastodonController: MastodonController! { get }
|
|
var navigationDelegate: any TuskerNavigationDelegate { get }
|
|
var toastableViewController: ToastableViewController? { get }
|
|
|
|
var canReblog: Bool { get }
|
|
|
|
// necessary b/c the reblog-handling logic only exists in the cells
|
|
func performReplyAction()
|
|
}
|
|
|
|
private func createReplyAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction? {
|
|
guard container.mastodonController.loggedIn else {
|
|
return nil
|
|
}
|
|
let action = UIContextualAction(style: .normal, title: "Reply") { [unowned container] _, _, completion in
|
|
container.performReplyAction()
|
|
completion(true)
|
|
}
|
|
action.image = UIImage(systemName: "arrowshape.turn.up.left.fill")
|
|
action.backgroundColor = container.tintColor
|
|
return action
|
|
}
|
|
|
|
private func createFavoriteAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction? {
|
|
guard container.mastodonController.loggedIn else {
|
|
return nil
|
|
}
|
|
let title = status.favourited ? "Unfavorite" : "Favorite"
|
|
let action = UIContextualAction(style: .normal, title: title) { [unowned container] _, _, completion in
|
|
completion(true)
|
|
Task { @MainActor in
|
|
await FavoriteService(status: status, mastodonController: container.mastodonController, presenter: container.navigationDelegate).toggleFavorite()
|
|
}
|
|
}
|
|
action.image = UIImage(systemName: "star.fill")
|
|
action.backgroundColor = status.favourited ? UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1) : UIColor(displayP3Red: 1, green: 204/255, blue: 0, alpha: 1)
|
|
return action
|
|
}
|
|
|
|
private func createReblogAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction? {
|
|
guard container.mastodonController.loggedIn,
|
|
container.canReblog else {
|
|
return nil
|
|
}
|
|
let title = status.reblogged ? "Unreblog" : "Reblog"
|
|
let action = UIContextualAction(style: .normal, title: title) { [unowned container] _, _, completion in
|
|
completion(true)
|
|
Task { @MainActor in
|
|
await ReblogService(status: status, mastodonController: container.mastodonController, presenter: container.navigationDelegate).toggleReblog()
|
|
}
|
|
}
|
|
action.image = UIImage(systemName: "repeat")
|
|
action.backgroundColor = status.reblogged ? UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1) : container.tintColor
|
|
return action
|
|
}
|
|
|
|
private func createShareAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction {
|
|
let action = UIContextualAction(style: .normal, title: "Share") { [unowned container] _, _, completion in
|
|
container.navigationDelegate.showMoreOptions(forStatus: status.id, source: .view(container))
|
|
completion(true)
|
|
}
|
|
// bold to more closesly match other action symbols
|
|
let config = UIImage.SymbolConfiguration(weight: .bold)
|
|
action.image = UIImage(systemName: "square.and.arrow.up")!.applyingSymbolConfiguration(config)!
|
|
action.backgroundColor = .lightGray
|
|
return action
|
|
}
|
|
|
|
private func createBookmarkAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction? {
|
|
guard container.mastodonController.loggedIn else {
|
|
return nil
|
|
}
|
|
let bookmarked = status.bookmarked ?? false
|
|
let title = bookmarked ? "Unbookmark" : "Bookmark"
|
|
let action = UIContextualAction(style: .normal, title: title) { [unowned container] _, _, completion in
|
|
completion(true)
|
|
Task { @MainActor in
|
|
let request = (bookmarked ? Status.unbookmark : Status.bookmark)(status.id)
|
|
do {
|
|
let (status, _) = try await container.mastodonController.run(request)
|
|
container.mastodonController.persistentContainer.addOrUpdate(status: status)
|
|
} catch {
|
|
if let toastable = container.toastableViewController {
|
|
let config = ToastConfiguration(from: error, with: "Error \(bookmarked ? "Unb" : "B")ookmarking", in: toastable, retryAction: nil)
|
|
toastable.showToast(configuration: config, animated: true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
action.image = UIImage(systemName: "bookmark.fill")
|
|
action.backgroundColor = .systemRed
|
|
return action
|
|
}
|
|
|
|
private func createOpenInSafariAction(status: StatusMO, container: StatusSwipeActionContainer) -> UIContextualAction {
|
|
let action = UIContextualAction(style: .normal, title: "Open in Safari") { [unowned container] _, _, completion in
|
|
container.navigationDelegate.selected(url: status.url!, allowUniversalLinks: false)
|
|
completion(true)
|
|
}
|
|
action.image = UIImage(systemName: "safari")
|
|
action.backgroundColor = container.tintColor
|
|
return action
|
|
}
|