From c30fb73922ea77b1f003b1feec47bbd239f0aabc Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Tue, 5 Dec 2023 12:28:36 +0100 Subject: [PATCH] Fix status deletion not updating data model (IOS-205) --- Mastodon/Protocol/Provider/DataSourceFacade+Status.swift | 8 +++++--- Mastodon/Protocol/Provider/DataSourceProvider.swift | 1 + ...coveryCommunityViewController+DataSourceProvider.swift | 8 +++++++- .../DiscoveryPostsViewController+DataSourceProvider.swift | 8 +++++++- ...HashtagTimelineViewController+DataSourceProvider.swift | 4 ++++ .../HomeTimelineViewController+DataSourceProvider.swift | 6 +++++- ...icationTimelineViewController+DataSourceProvider.swift | 6 +++++- .../BookmarkViewController+DataSourceProvider.swift | 8 +++++++- .../FamiliarFollowersViewController.swift | 6 +++++- .../FavoriteViewController+DataSourceProvider.swift | 8 +++++++- .../Profile/Follower/FollowerListViewController.swift | 8 ++++++-- .../Profile/Following/FollowingListViewController.swift | 6 +++++- Mastodon/Scene/Profile/ProfileViewController.swift | 8 ++++++-- .../UserTimelineViewController+DataSourceProvider.swift | 4 ++++ .../FavoritedByViewController+DataSourceProvider.swift | 6 +++++- .../RebloggedByViewController+DataSourceProvider.swift | 6 +++++- .../SearchHistoryViewController+DataSourceProvider.swift | 6 +++++- .../SearchResultViewController+DataSourceProvider.swift | 4 ++++ .../Thread/ThreadViewController+DataSourceProvider.swift | 4 ++++ .../FeedFetchedResultsController.swift | 4 ++++ .../StatusFetchedResultsController.swift | 5 +++++ MastodonSDK/Sources/MastodonSDK/MastodonStatus.swift | 5 ++++- 22 files changed, 110 insertions(+), 19 deletions(-) diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index 70fd66e7c..df8f634c6 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -20,13 +20,15 @@ import MastodonSDK extension DataSourceFacade { static func responseToDeleteStatus( - dependency: NeedsDependency & AuthContextProvider, + dependency: NeedsDependency & AuthContextProvider & DataSourceProvider, status: MastodonStatus ) async throws { - _ = try await dependency.context.apiService.deleteStatus( + let deletedStatus = try await dependency.context.apiService.deleteStatus( status: status, authenticationBox: dependency.authContext.mastodonAuthenticationBox - ) + ).value.asMastodonStatus + + dependency.delete(status: deletedStatus) } } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider.swift b/Mastodon/Protocol/Provider/DataSourceProvider.swift index c74a16356..d3b18240e 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider.swift @@ -40,4 +40,5 @@ extension DataSourceItem { protocol DataSourceProvider: ViewControllerWithDependencies { func item(from source: DataSourceItem.Source) async -> DataSourceItem? func update(status: MastodonStatus) + func delete(status: MastodonStatus) } diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift index 44db77f5b..a7f6af19d 100644 --- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift @@ -27,11 +27,17 @@ extension DiscoveryCommunityViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { viewModel.statusFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.statusFetchedResultsController.setRecords( + viewModel.statusFetchedResultsController.records.filter { $0.id != status.id } + ) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift index 300235ded..f160b0d5d 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift @@ -27,11 +27,17 @@ extension DiscoveryPostsViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { viewModel.statusFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.statusFetchedResultsController.setRecords( + viewModel.statusFetchedResultsController.records.filter { $0.id != status.id } + ) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController+DataSourceProvider.swift index 21bf2c79e..9f89d3058 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController+DataSourceProvider.swift @@ -32,6 +32,10 @@ extension HashtagTimelineViewController: DataSourceProvider { viewModel.fetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.fetchedResultsController.deleteRecord(status) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift index 9636ac6b4..28b6a4984 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift @@ -35,11 +35,15 @@ extension HomeTimelineViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { viewModel.fetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.fetchedResultsController.records = viewModel.fetchedResultsController.records.filter { $0.id != status.id } + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift index 4cda5e530..4a7d22229 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift @@ -36,11 +36,15 @@ extension NotificationTimelineViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { viewModel.feedFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.feedFetchedResultsController + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewController+DataSourceProvider.swift index 7b0252f62..0b3c1bc3a 100644 --- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewController+DataSourceProvider.swift @@ -27,11 +27,17 @@ extension BookmarkViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { viewModel.statusFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.statusFetchedResultsController.setRecords( + viewModel.statusFetchedResultsController.records.filter { $0.id != status.id } + ) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift index f477b0599..5db16d519 100644 --- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift +++ b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift @@ -104,7 +104,11 @@ extension FamiliarFollowersViewController: DataSourceProvider { } func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } @MainActor diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewController+DataSourceProvider.swift index 7fa1ced50..671a0d1e3 100644 --- a/Mastodon/Scene/Profile/Favorite/FavoriteViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewController+DataSourceProvider.swift @@ -27,11 +27,17 @@ extension FavoriteViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { viewModel.statusFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.statusFetchedResultsController.setRecords( + viewModel.statusFetchedResultsController.records.filter { $0.id != status.id } + ) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift index 48c66f36a..404eae6fa 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewController.swift @@ -153,9 +153,13 @@ extension FollowerListViewController: DataSourceProvider { return nil } } - + func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } @MainActor diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift index 5bb36a9fe..f1bd37ae7 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewController.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewController.swift @@ -151,7 +151,11 @@ extension FollowingListViewController: DataSourceProvider { } func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } @MainActor diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index a67da6167..8ece9ac2b 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -944,11 +944,15 @@ private extension ProfileViewController { extension ProfileViewController: DataSourceProvider { func item(from source: DataSourceItem.Source) async -> DataSourceItem? { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") return nil } func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } } diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController+DataSourceProvider.swift index 3c536888d..e569c4d69 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController+DataSourceProvider.swift @@ -32,6 +32,10 @@ extension UserTimelineViewController: DataSourceProvider { viewModel.statusFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.statusFetchedResultsController.deleteRecord(status) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift index 4fbde2165..4f9580fbd 100644 --- a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift @@ -29,7 +29,11 @@ extension FavoritedByViewController: DataSourceProvider { } func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } @MainActor diff --git a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift index c111d5491..61387c044 100644 --- a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift @@ -30,7 +30,11 @@ extension RebloggedByViewController: DataSourceProvider { } func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } @MainActor diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController+DataSourceProvider.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController+DataSourceProvider.swift index 61c31a678..1e1a03d5f 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewController+DataSourceProvider.swift @@ -30,7 +30,11 @@ extension SearchHistoryViewController: DataSourceProvider { } func update(status: MastodonStatus) { - assertionFailure("Implement not required in this class") + assertionFailure("Not required") + } + + func delete(status: MastodonStatus) { + assertionFailure("Not required") } @MainActor diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController+DataSourceProvider.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController+DataSourceProvider.swift index adb84b396..7a332ad62 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewController+DataSourceProvider.swift @@ -37,6 +37,10 @@ extension SearchResultViewController: DataSourceProvider { viewModel.statusFetchedResultsController.update(status: status) } + func delete(status: MastodonStatus) { + viewModel.statusFetchedResultsController.deleteRecord(status) + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/Mastodon/Scene/Thread/ThreadViewController+DataSourceProvider.swift b/Mastodon/Scene/Thread/ThreadViewController+DataSourceProvider.swift index 3ea91d0d5..187885175 100644 --- a/Mastodon/Scene/Thread/ThreadViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Thread/ThreadViewController+DataSourceProvider.swift @@ -33,6 +33,10 @@ extension ThreadViewController: DataSourceProvider { viewModel.root = .root(context: .init(status: status)) } + func delete(status: MastodonStatus) { + assertionFailure("Needs implementation") + } + @MainActor private func indexPath(for cell: UITableViewCell) async -> IndexPath? { return tableView.indexPath(for: cell) diff --git a/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FeedFetchedResultsController.swift b/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FeedFetchedResultsController.swift index 3961c5bae..77bf8098a 100644 --- a/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FeedFetchedResultsController.swift +++ b/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FeedFetchedResultsController.swift @@ -71,6 +71,10 @@ final public class FeedFetchedResultsController { } records = newRecords } + + public func delete(status: MastodonStatus) { + self.records.removeAll { $0.id == status.id } + } } private extension FeedFetchedResultsController { diff --git a/MastodonSDK/Sources/MastodonCore/FetchedResultsController/StatusFetchedResultsController.swift b/MastodonSDK/Sources/MastodonCore/FetchedResultsController/StatusFetchedResultsController.swift index 78bb50964..f0fbad458 100644 --- a/MastodonSDK/Sources/MastodonCore/FetchedResultsController/StatusFetchedResultsController.swift +++ b/MastodonSDK/Sources/MastodonCore/FetchedResultsController/StatusFetchedResultsController.swift @@ -36,6 +36,11 @@ public final class StatusFetchedResultsController { self.records += records } + @MainActor + public func deleteRecord(_ record: MastodonStatus) { + self.records = self.records.filter { $0.id != record.id } + } + @MainActor public func update(status: MastodonStatus) { var newRecords = Array(records) diff --git a/MastodonSDK/Sources/MastodonSDK/MastodonStatus.swift b/MastodonSDK/Sources/MastodonSDK/MastodonStatus.swift index 3257d900a..ab4103eaa 100644 --- a/MastodonSDK/Sources/MastodonSDK/MastodonStatus.swift +++ b/MastodonSDK/Sources/MastodonSDK/MastodonStatus.swift @@ -49,9 +49,12 @@ extension MastodonStatus: Hashable { } public extension Mastodon.Entity.Status { + var asMastodonStatus: MastodonStatus { + .fromEntity(self) + } + var mastodonVisibility: MastodonVisibility? { guard let visibility = visibility?.rawValue else { return nil } return MastodonVisibility(rawValue: visibility) } } -