From 8f8e2a2aea7267641544c7e71d35bf002b740de5 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 4 Jul 2023 09:56:35 -0700 Subject: [PATCH] Add unfollow hashtag action to Explore screen Closes #417 --- Tusker/API/ToggleFollowHashtagService.swift | 11 +++- .../Explore/ExploreViewController.swift | 54 ++++++++++--------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/Tusker/API/ToggleFollowHashtagService.swift b/Tusker/API/ToggleFollowHashtagService.swift index f554d373..e2ee0e53 100644 --- a/Tusker/API/ToggleFollowHashtagService.swift +++ b/Tusker/API/ToggleFollowHashtagService.swift @@ -22,7 +22,9 @@ class ToggleFollowHashtagService { self.presenter = presenter } - func toggleFollow() async { + @discardableResult + func toggleFollow() async -> Bool { + let success: Bool let context = mastodonController.persistentContainer.viewContext var config: ToastConfiguration if let existing = mastodonController.followedHashtags.first(where: { $0.name == hashtagName }) { @@ -36,11 +38,14 @@ class ToggleFollowHashtagService { config = ToastConfiguration(title: "Unfollowed Hashtag") config.systemImageName = "checkmark" config.dismissAutomaticallyAfter = 2 + + success = true } catch { config = ToastConfiguration(from: error, with: "Error Unfollowing Hashtag", in: presenter) { toast in toast.dismissToast(animated: true) await self.toggleFollow() } + success = false } } else { do { @@ -53,15 +58,19 @@ class ToggleFollowHashtagService { config = ToastConfiguration(title: "Followed Hashtag") config.systemImageName = "checkmark" config.dismissAutomaticallyAfter = 2 + + success = true } catch { config = ToastConfiguration(from: error, with: "Error Following Hashtag", in: presenter) { toast in toast.dismissToast(animated: true) await self.toggleFollow() } + success = false } } presenter.showToast(configuration: config, animated: true) mastodonController.persistentContainer.save(context: context) + return success } } diff --git a/Tusker/Screens/Explore/ExploreViewController.swift b/Tusker/Screens/Explore/ExploreViewController.swift index 1a3261a2..98069a31 100644 --- a/Tusker/Screens/Explore/ExploreViewController.swift +++ b/Tusker/Screens/Explore/ExploreViewController.swift @@ -288,15 +288,6 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate, Collect } } - func removeSavedHashtag(_ hashtag: Hashtag) { - let context = mastodonController.persistentContainer.viewContext - let req = SavedHashtag.fetchRequest(name: hashtag.name, account: mastodonController.accountInfo!) - if let hashtag = try? context.fetch(req).first { - context.delete(hashtag) - try! context.save() - } - } - func removeSavedInstance(_ instanceURL: URL) { let context = mastodonController.persistentContainer.viewContext let req = SavedInstance.fetchRequest(url: instanceURL, account: mastodonController.accountInfo!) @@ -307,36 +298,45 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate, Collect } private func trailingSwipeActionsForCell(at indexPath: IndexPath) -> UISwipeActionsConfiguration? { - let title: String - let handler: UIContextualAction.Handler + var actions = [UIContextualAction]() switch dataSource.itemIdentifier(for: indexPath) { case let .list(list): - title = NSLocalizedString("Delete", comment: "delete swipe action title") - handler = { (_, _, completion) in + actions.append(UIContextualAction(style: .destructive, title: "Delete", handler: { _, _, completion in self.deleteList(list, completion: completion) - } + })) case let .savedHashtag(hashtag): - title = NSLocalizedString("Unsave", comment: "unsave swipe action title") - handler = { (_, _, completion) in - self.removeSavedHashtag(hashtag) - completion(true) + let name = hashtag.name.lowercased() + let context = mastodonController.persistentContainer.viewContext + let existing = try? context.fetch(SavedHashtag.fetchRequest(name: name, account: mastodonController.accountInfo!)).first + if let existing { + actions.append(UIContextualAction(style: .destructive, title: "Unsave", handler: { _, _, completion in + context.delete(existing) + try! context.save() + })) + } + if mastodonController.instanceFeatures.canFollowHashtags, + mastodonController.followedHashtags.contains(where: { $0.name.lowercased() == name }) { + actions.append(UIContextualAction(style: .destructive, title: "Unfollow", handler: { _, _, completion in + Task { + let success = + await ToggleFollowHashtagService(hashtagName: hashtag.name, presenter: self) + .toggleFollow() + completion(success) + } + })) } case let .savedInstance(url): - title = NSLocalizedString("Unsave", comment: "unsave swipe action title") - handler = { (_, _, completion) in + actions.append(UIContextualAction(style: .destructive, title: "Unsave", handler: { _, _, completion in self.removeSavedInstance(url) completion(true) - } + })) default: return nil } - - return UISwipeActionsConfiguration(actions: [ - UIContextualAction(style: .destructive, title: title, handler: handler) - ]) + return UISwipeActionsConfiguration(actions: actions) } // MARK: - Collection View Delegate @@ -581,3 +581,7 @@ extension ExploreViewController: UICollectionViewDragDelegate { return [UIDragItem(itemProvider: provider)] } } + +extension ExploreViewController: TuskerNavigationDelegate { + var apiController: MastodonController! { mastodonController } +}