forked from shadowfacts/Tusker
parent
2e64500c35
commit
5e2b551045
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
import CoreData
|
||||||
|
|
||||||
class BookmarksViewController: UIViewController, CollectionViewController {
|
class BookmarksViewController: UIViewController, CollectionViewController {
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ class BookmarksViewController: UIViewController, CollectionViewController {
|
||||||
}
|
}
|
||||||
return UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
|
return UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
|
||||||
switch itemIdentifier {
|
switch itemIdentifier {
|
||||||
case .status(id: let id, state: let state):
|
case .status(id: let id, state: let state, addedLocally: _):
|
||||||
return collectionView.dequeueConfiguredReusableCell(using: statusCell, for: indexPath, item: (id, state))
|
return collectionView.dequeueConfiguredReusableCell(using: statusCell, for: indexPath, item: (id, state))
|
||||||
case .loadingIndicator:
|
case .loadingIndicator:
|
||||||
return collectionView.dequeueConfiguredReusableCell(using: loadingCell, for: indexPath, item: ())
|
return collectionView.dequeueConfiguredReusableCell(using: loadingCell, for: indexPath, item: ())
|
||||||
|
@ -93,6 +94,9 @@ class BookmarksViewController: UIViewController, CollectionViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: mastodonController.persistentContainer.viewContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
@ -132,7 +136,7 @@ class BookmarksViewController: UIViewController, CollectionViewController {
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
snapshot.appendSections([.bookmarks])
|
snapshot.appendSections([.bookmarks])
|
||||||
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown) })
|
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown, addedLocally: false) })
|
||||||
await apply(snapshot: snapshot, animatingDifferences: true)
|
await apply(snapshot: snapshot, animatingDifferences: true)
|
||||||
|
|
||||||
state = .loaded
|
state = .loaded
|
||||||
|
@ -170,7 +174,7 @@ class BookmarksViewController: UIViewController, CollectionViewController {
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
||||||
|
|
||||||
snapshot.deleteItems([.loadingIndicator])
|
snapshot.deleteItems([.loadingIndicator])
|
||||||
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown) })
|
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown, addedLocally: false) })
|
||||||
await apply(snapshot: snapshot, animatingDifferences: true)
|
await apply(snapshot: snapshot, animatingDifferences: true)
|
||||||
|
|
||||||
state = .loaded
|
state = .loaded
|
||||||
|
@ -188,6 +192,63 @@ class BookmarksViewController: UIViewController, CollectionViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||||
|
guard let userInfo = notification.userInfo,
|
||||||
|
let accountID = mastodonController.accountInfo?.id,
|
||||||
|
userInfo["accountID"] as? String == accountID,
|
||||||
|
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var snapshot = dataSource.snapshot()
|
||||||
|
let toDelete = statusIDs.map { id in
|
||||||
|
Item.status(id: id, state: .unknown, addedLocally: false)
|
||||||
|
}.filter { item in
|
||||||
|
snapshot.itemIdentifiers.contains(item)
|
||||||
|
}
|
||||||
|
if !toDelete.isEmpty {
|
||||||
|
snapshot.deleteItems(toDelete)
|
||||||
|
Task {
|
||||||
|
await apply(snapshot: snapshot, animatingDifferences: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func managedObjectsDidChange(_ notification: Foundation.Notification) {
|
||||||
|
var snapshot = dataSource.snapshot()
|
||||||
|
func prepend(item: Item) {
|
||||||
|
if let first = snapshot.itemIdentifiers.first {
|
||||||
|
snapshot.insertItems([item], beforeItem: first)
|
||||||
|
} else {
|
||||||
|
snapshot.appendItems([item])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var hasChanges = false
|
||||||
|
if let inserted = notification.userInfo?[NSInsertedObjectsKey] as? Set<NSManagedObject> {
|
||||||
|
for case let status as StatusMO in inserted where status.bookmarked == true {
|
||||||
|
prepend(item: .status(id: status.id, state: .unknown, addedLocally: true))
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let updated = notification.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject> {
|
||||||
|
for case let status as StatusMO in updated {
|
||||||
|
let item = Item.status(id: status.id, state: .unknown, addedLocally: true)
|
||||||
|
var exists = snapshot.itemIdentifiers.contains(item)
|
||||||
|
if status.bookmarked == true && !exists {
|
||||||
|
prepend(item: item)
|
||||||
|
hasChanges = true
|
||||||
|
} else if status.bookmarked == false && exists {
|
||||||
|
snapshot.deleteItems([item])
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasChanges {
|
||||||
|
Task {
|
||||||
|
await apply(snapshot: snapshot, animatingDifferences: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BookmarksViewController {
|
extension BookmarksViewController {
|
||||||
|
@ -195,7 +256,7 @@ extension BookmarksViewController {
|
||||||
case bookmarks
|
case bookmarks
|
||||||
}
|
}
|
||||||
enum Item: Equatable, Hashable {
|
enum Item: Equatable, Hashable {
|
||||||
case status(id: String, state: CollapseState)
|
case status(id: String, state: CollapseState, addedLocally: Bool)
|
||||||
case loadingIndicator
|
case loadingIndicator
|
||||||
|
|
||||||
var hideIndicators: Bool {
|
var hideIndicators: Bool {
|
||||||
|
@ -209,7 +270,7 @@ extension BookmarksViewController {
|
||||||
|
|
||||||
static func ==(lhs: Item, rhs: Item) -> Bool {
|
static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||||
switch (lhs, rhs) {
|
switch (lhs, rhs) {
|
||||||
case (.status(id: let a, state: _), .status(id: let b, state: _)):
|
case (.status(id: let a, _, _), .status(id: let b, _, _)):
|
||||||
return a == b
|
return a == b
|
||||||
case (.loadingIndicator, .loadingIndicator):
|
case (.loadingIndicator, .loadingIndicator):
|
||||||
return true
|
return true
|
||||||
|
@ -220,7 +281,7 @@ extension BookmarksViewController {
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
func hash(into hasher: inout Hasher) {
|
||||||
switch self {
|
switch self {
|
||||||
case .status(id: let id, state: _):
|
case .status(id: let id, _, _):
|
||||||
hasher.combine(0)
|
hasher.combine(0)
|
||||||
hasher.combine(id)
|
hasher.combine(id)
|
||||||
case .loadingIndicator:
|
case .loadingIndicator:
|
||||||
|
@ -250,7 +311,7 @@ extension BookmarksViewController: UICollectionViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||||
if case .status(id: _, state: _) = dataSource.itemIdentifier(for: indexPath) {
|
if case .status(_, _, _) = dataSource.itemIdentifier(for: indexPath) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -258,7 +319,7 @@ extension BookmarksViewController: UICollectionViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
if case .status(id: let id, state: let state) = dataSource.itemIdentifier(for: indexPath) {
|
if case .status(id: let id, state: let state, _) = dataSource.itemIdentifier(for: indexPath) {
|
||||||
selected(status: id, state: state.copy())
|
selected(status: id, state: state.copy())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue