Reimplement favorite/reblog state (IOS-176)
This commit is contained in:
parent
9809e69751
commit
e0671eb324
|
@ -18,9 +18,11 @@ extension DataSourceFacade {
|
|||
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
|
||||
await selectionFeedbackGenerator.selectionChanged()
|
||||
|
||||
_ = try await provider.context.apiService.favorite(
|
||||
let newStatus = try await provider.context.apiService.favorite(
|
||||
status: status,
|
||||
authenticationBox: provider.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
).value
|
||||
|
||||
provider.update(status: .fromEntity(newStatus))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ extension DataSourceFacade {
|
|||
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
|
||||
await selectionFeedbackGenerator.selectionChanged()
|
||||
|
||||
_ = try await provider.context.apiService.reblog(
|
||||
let newStatus = try await provider.context.apiService.reblog(
|
||||
status: status,
|
||||
authenticationBox: provider.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
} // end func
|
||||
).value
|
||||
|
||||
provider.update(status: .fromEntity(newStatus))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -439,7 +439,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
|
|||
assertionFailure("only works for status data provider")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
try await DataSourceFacade.responseToActionToolbar(
|
||||
provider: self,
|
||||
status: status,
|
||||
|
|
|
@ -46,4 +46,5 @@ extension DataSourceItem {
|
|||
|
||||
protocol DataSourceProvider: ViewControllerWithDependencies {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem?
|
||||
func update(status: MastodonStatus)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension DiscoveryCommunityViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension DiscoveryCommunityViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.statusFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension DiscoveryPostsViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension DiscoveryPostsViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.statusFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension HashtagTimelineViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension HashtagTimelineViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.fetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension HomeTimelineViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -35,6 +36,10 @@ extension HomeTimelineViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.fetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -37,6 +37,10 @@ extension NotificationTimelineViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.feedFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension BookmarkViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension BookmarkViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.statusFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension FamiliarFollowersViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension FamiliarFollowersViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
assertionFailure("Implement not required in this class")
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension FavoriteViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension FavoriteViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.statusFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -11,6 +11,7 @@ import Combine
|
|||
import MastodonCore
|
||||
import MastodonUI
|
||||
import MastodonLocalization
|
||||
import MastodonSDK
|
||||
|
||||
final class FollowerListViewController: UIViewController, NeedsDependency {
|
||||
|
||||
|
@ -152,6 +153,10 @@ extension FollowerListViewController: DataSourceProvider {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
assertionFailure("Implement not required in this class")
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
|
|
|
@ -12,6 +12,7 @@ import MastodonLocalization
|
|||
import MastodonCore
|
||||
import MastodonUI
|
||||
import CoreDataStack
|
||||
import MastodonSDK
|
||||
|
||||
final class FollowingListViewController: UIViewController, NeedsDependency {
|
||||
|
||||
|
@ -148,6 +149,10 @@ extension FollowingListViewController: DataSourceProvider {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
assertionFailure("Implement not required in this class")
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension UserTimelineViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension UserTimelineViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.statusFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension FavoritedByViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
|
@ -27,6 +28,10 @@ extension FavoritedByViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
assertionFailure("Implement not required in this class")
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension RebloggedByViewController: DataSourceProvider {
|
||||
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
var _indexPath = source.indexPath
|
||||
if _indexPath == nil, let cell = source.tableViewCell {
|
||||
|
@ -27,6 +29,10 @@ extension RebloggedByViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
assertionFailure("Implement not required in this class")
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
// MARK: - DataSourceProvider
|
||||
extension SearchHistoryViewController: DataSourceProvider {
|
||||
|
@ -28,6 +29,10 @@ extension SearchHistoryViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
assertionFailure("Implement not required in this class")
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UICollectionViewCell) async -> IndexPath? {
|
||||
return collectionView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
// MARK: - DataSourceProvider
|
||||
extension SearchResultViewController: DataSourceProvider {
|
||||
|
@ -32,6 +33,10 @@ extension SearchResultViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.statusFetchedResultsController.update(status: status)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
// MARK: - DataSourceProvider
|
||||
extension ThreadViewController: DataSourceProvider {
|
||||
|
@ -28,6 +29,10 @@ extension ThreadViewController: DataSourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus) {
|
||||
viewModel.root = .root(context: .init(status: status))
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
|
|
|
@ -38,6 +38,28 @@ final public class FeedFetchedResultsController {
|
|||
records = try await load(kind: kind, sinceId: lastId)
|
||||
}
|
||||
}
|
||||
|
||||
public func update(status: MastodonStatus) {
|
||||
var newRecords = Array(records)
|
||||
for (i, record) in newRecords.enumerated() {
|
||||
if record.status?.id == status.id {
|
||||
newRecords[i] = .fromStatus(status, kind: record.kind)
|
||||
} else if let reblog = status.reblog, reblog.id == record.status?.id {
|
||||
newRecords[i] = .fromStatus(status, kind: record.kind)
|
||||
} else if let reblog = record.status?.reblog, reblog.id == status.id {
|
||||
newRecords[i] = .fromStatus(status, kind: record.kind)
|
||||
switch status.entity.reblogged {
|
||||
case .some(true):
|
||||
newRecords[i].status?.reblog = status
|
||||
case .some(false):
|
||||
newRecords[i].status?.reblog = nil
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
records = newRecords
|
||||
}
|
||||
}
|
||||
|
||||
private extension FeedFetchedResultsController {
|
||||
|
|
|
@ -35,4 +35,17 @@ public final class StatusFetchedResultsController {
|
|||
public func appendRecords(_ records: [MastodonStatus]) {
|
||||
self.records += records
|
||||
}
|
||||
|
||||
@MainActor
|
||||
public func update(status: MastodonStatus) {
|
||||
var newRecords = Array(records)
|
||||
for (i, record) in newRecords.enumerated() {
|
||||
if record.id == status.id {
|
||||
newRecords[i] = status
|
||||
} else if let reblog = record.reblog, reblog.id == status.id {
|
||||
newRecords[i].reblog = status
|
||||
}
|
||||
}
|
||||
records = newRecords
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ extension APIService {
|
|||
|
||||
let reblogContext = MastodonReblogContext(
|
||||
statusID: _status.id,
|
||||
isReblogged: !isReblogged,
|
||||
isReblogged: isReblogged,
|
||||
rebloggedCount: rebloggedCount
|
||||
)
|
||||
return reblogContext
|
||||
|
|
|
@ -136,11 +136,22 @@ extension Mastodon.Entity.Status {
|
|||
|
||||
extension Mastodon.Entity.Status: Hashable {
|
||||
public static func == (lhs: Mastodon.Entity.Status, rhs: Mastodon.Entity.Status) -> Bool {
|
||||
lhs.uri == rhs.uri && lhs.id == rhs.id
|
||||
lhs.uri == rhs.uri &&
|
||||
lhs.id == rhs.id &&
|
||||
lhs.reblog == rhs.reblog &&
|
||||
lhs.favourited == rhs.favourited &&
|
||||
lhs.reblogged == rhs.reblogged &&
|
||||
lhs.bookmarked == rhs.bookmarked &&
|
||||
lhs.pinned == rhs.pinned
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(uri)
|
||||
hasher.combine(id)
|
||||
hasher.combine(reblog)
|
||||
hasher.combine(favourited)
|
||||
hasher.combine(reblogged)
|
||||
hasher.combine(bookmarked)
|
||||
hasher.combine(pinned)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,13 +54,15 @@ public extension MastodonFeed {
|
|||
|
||||
extension MastodonFeed: Hashable {
|
||||
public static func == (lhs: MastodonFeed, rhs: MastodonFeed) -> Bool {
|
||||
lhs.id == rhs.id && (lhs.status?.id == rhs.status?.id || lhs.notification?.id == rhs.notification?.id)
|
||||
lhs.id == rhs.id &&
|
||||
lhs.status?.entity == rhs.status?.entity &&
|
||||
lhs.status?.reblog?.entity == rhs.status?.reblog?.entity
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(id)
|
||||
hasher.combine(status)
|
||||
hasher.combine(notification)
|
||||
hasher.combine(status?.entity)
|
||||
hasher.combine(status?.reblog?.entity)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ public final class MastodonStatus: ObservableObject {
|
|||
public typealias ID = Mastodon.Entity.Status.ID
|
||||
|
||||
@Published public var entity: Mastodon.Entity.Status
|
||||
@Published public private(set) var reblog: MastodonStatus?
|
||||
@Published public var reblog: MastodonStatus?
|
||||
|
||||
@Published public var isSensitiveToggled: Bool = false
|
||||
|
||||
|
@ -36,12 +36,13 @@ extension MastodonStatus {
|
|||
|
||||
extension MastodonStatus: Hashable {
|
||||
public static func == (lhs: MastodonStatus, rhs: MastodonStatus) -> Bool {
|
||||
lhs.entity.id == rhs.entity.id
|
||||
lhs.entity == rhs.entity &&
|
||||
lhs.reblog?.entity == rhs.reblog?.entity
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(entity)
|
||||
hasher.combine(isSensitiveToggled)
|
||||
hasher.combine(reblog?.entity)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue