Update cells when statuses/accounts change from other sources

This commit is contained in:
Shadowfacts 2019-08-01 21:01:15 -06:00
parent 44cfd44651
commit 199f95c465
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
7 changed files with 104 additions and 38 deletions

View File

@ -7,6 +7,7 @@
// //
import Foundation import Foundation
import Combine
import Pachyderm import Pachyderm
class MastodonCache { class MastodonCache {
@ -16,6 +17,9 @@ class MastodonCache {
private static var relationships = [String: Relationship]() private static var relationships = [String: Relationship]()
private static var notifications = [String: Pachyderm.Notification]() private static var notifications = [String: Pachyderm.Notification]()
static let statusSubject = PassthroughSubject<Status, Never>()
static let accountSubject = PassthroughSubject<Account, Never>()
// MARK: - Statuses // MARK: - Statuses
static func status(for id: String) -> Status? { static func status(for id: String) -> Status? {
return statuses[id] return statuses[id]
@ -28,6 +32,8 @@ class MastodonCache {
add(status: reblog) add(status: reblog)
add(account: reblog.account) add(account: reblog.account)
} }
statusSubject.send(status)
} }
static func status(for id: String, completion: @escaping (Status?) -> Void) { static func status(for id: String, completion: @escaping (Status?) -> Void) {
@ -57,6 +63,7 @@ class MastodonCache {
static func set(account: Account, for id: String) { static func set(account: Account, for id: String) {
accounts[id] = account accounts[id] = account
accountSubject.send(account)
} }
static func account(for id: String, completion: @escaping (Account?) -> Void) { static func account(for id: String, completion: @escaping (Account?) -> Void) {

View File

@ -116,12 +116,12 @@ class ConversationTableViewController: EnhancedTableViewController {
if statusID == mainStatusID { if statusID == mainStatusID {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "mainStatusCell", for: indexPath) as? ConversationMainStatusTableViewCell else { fatalError() } guard let cell = tableView.dequeueReusableCell(withIdentifier: "mainStatusCell", for: indexPath) as? ConversationMainStatusTableViewCell else { fatalError() }
cell.selectionStyle = .none cell.selectionStyle = .none
cell.updateUI(for: statusID) cell.updateUI(statusID: statusID)
cell.delegate = self cell.delegate = self
return cell return cell
} else { } else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() } guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
cell.updateUI(for: statusID) cell.updateUI(statusID: statusID)
cell.delegate = self cell.delegate = self
return cell return cell
} }

View File

@ -92,8 +92,7 @@ class NotificationsTableViewController: EnhancedTableViewController {
switch notification.kind { switch notification.kind {
case .mention: case .mention:
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() } guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
let status = notification.status! cell.updateUI(statusID: notification.status!.id)
cell.updateUI(for: status.id)
cell.delegate = self cell.delegate = self
return cell return cell
case .favourite, .reblog: case .favourite, .reblog:

View File

@ -183,8 +183,7 @@ class ProfileTableViewController: EnhancedTableViewController, PreferencesAdapti
return cell return cell
case 1: case 1:
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() } guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
let statusID = statusIDs[indexPath.row] cell.updateUI(statusID: statusIDs[indexPath.row])
cell.updateUI(for: statusID)
cell.delegate = self cell.delegate = self
return cell return cell
default: default:

View File

@ -101,8 +101,8 @@ class TimelineTableViewController: EnhancedTableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() } guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
cell.updateUI(for: statusID(for: indexPath)) cell.updateUI(statusID: statusID(for: indexPath))
cell.delegate = self cell.delegate = self
return cell return cell

View File

@ -7,6 +7,7 @@
// //
import UIKit import UIKit
import Combine
import Pachyderm import Pachyderm
class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive { class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive {
@ -47,6 +48,14 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
var avatarURL: URL? var avatarURL: URL?
var updateTimestampWorkItem: DispatchWorkItem? var updateTimestampWorkItem: DispatchWorkItem?
var statusUpdater: Cancellable?
var accountUpdater: Cancellable?
deinit {
statusUpdater?.cancel()
accountUpdater?.cancel()
}
override func awakeFromNib() { override func awakeFromNib() {
displayNameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed))) displayNameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
usernameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed))) usernameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
@ -55,6 +64,16 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
attachmentsView.delegate = self attachmentsView.delegate = self
attachmentsView.layer.cornerRadius = 5 attachmentsView.layer.cornerRadius = 5
attachmentsView.layer.masksToBounds = true attachmentsView.layer.masksToBounds = true
statusUpdater = MastodonCache.statusSubject
.filter { $0.id == self.statusID }
.receive(on: DispatchQueue.main)
.sink(receiveValue: updateStatusState(status:))
accountUpdater = MastodonCache.accountSubject
.filter { $0.id == self.accountID }
.receive(on: DispatchQueue.main)
.sink(receiveValue: updateUI(account:))
} }
func updateUIForPreferences() { func updateUIForPreferences() {
@ -64,11 +83,11 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
displayNameLabel.text = account.realDisplayName displayNameLabel.text = account.realDisplayName
} }
func updateUI(for statusID: String) { func updateUI(statusID: String) {
self.statusID = statusID
guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") }
self.statusID = status.id
let account: Account let account: Account
if let reblog = status.reblog { if let reblog = status.reblog {
account = reblog.account account = reblog.account
@ -76,9 +95,25 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
account = status.account account = status.account
} }
self.accountID = account.id self.accountID = account.id
updateUI(account: account)
updateUIForPreferences() updateUIForPreferences()
updateTimestamp()
attachmentsView.updateUI(status: status)
let realStatus = status.reblog ?? status
updateStatusState(status: realStatus)
contentLabel.statusID = statusID
}
private func updateStatusState(status: Status) {
favorited = status.favourited ?? false
reblogged = status.reblogged ?? false
}
private func updateUI(account: Account) {
usernameLabel.text = "@\(account.acct)" usernameLabel.text = "@\(account.acct)"
avatarImageView.image = nil avatarImageView.image = nil
avatarURL = account.avatar avatarURL = account.avatar
@ -89,15 +124,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
self.avatarURL = nil self.avatarURL = nil
} }
} }
updateTimestamp()
attachmentsView.updateUI(status: status)
let realStatus = status.reblog ?? status
favorited = realStatus.favourited ?? false
reblogged = realStatus.reblogged ?? false
contentLabel.statusID = statusID
} }
func updateTimestamp() { func updateTimestamp() {

View File

@ -7,6 +7,7 @@
// //
import UIKit import UIKit
import Combine
import Pachyderm import Pachyderm
protocol StatusTableViewCellDelegate: TuskerNavigationDelegate { protocol StatusTableViewCellDelegate: TuskerNavigationDelegate {
@ -50,6 +51,16 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
var updateTimestampWorkItem: DispatchWorkItem? var updateTimestampWorkItem: DispatchWorkItem?
var attachmentDataTasks: [URLSessionDataTask] = [] var attachmentDataTasks: [URLSessionDataTask] = []
var statusUpdater: Cancellable?
var accountUpdater: Cancellable?
var rebloggerAccountUpdater: Cancellable?
deinit {
statusUpdater?.cancel()
accountUpdater?.cancel()
rebloggerAccountUpdater?.cancel()
}
override func awakeFromNib() { override func awakeFromNib() {
displayNameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed))) displayNameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
usernameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed))) usernameLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
@ -59,8 +70,26 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
attachmentsView.delegate = self attachmentsView.delegate = self
attachmentsView.layer.cornerRadius = 5 attachmentsView.layer.cornerRadius = 5
attachmentsView.layer.masksToBounds = true attachmentsView.layer.masksToBounds = true
statusUpdater = MastodonCache.statusSubject
.filter { $0.id == self.statusID || $0.id == self.reblogStatusID }
.receive(on: DispatchQueue.main)
.sink(receiveValue: updateStatusState(status:))
accountUpdater = MastodonCache.accountSubject
.filter { $0.id == self.accountID }
.receive(on: DispatchQueue.main)
.sink(receiveValue: updateUI(account:))
rebloggerAccountUpdater = MastodonCache.accountSubject
.filter { $0.id == self.rebloggerID }
.receive(on: DispatchQueue.main)
.sink(receiveValue: { (_) in
// this method is responsible for setting the reblog label text
self.updateUIForPreferences()
})
} }
func updateUIForPreferences() { func updateUIForPreferences() {
guard let account = MastodonCache.account(for: accountID) else { fatalError("") } guard let account = MastodonCache.account(for: accountID) else { fatalError("") }
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView) avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
@ -70,9 +99,10 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
} }
displayNameLabel.text = account.realDisplayName displayNameLabel.text = account.realDisplayName
} }
func updateUI(for statusID: String) { func updateUI(statusID: String) {
guard var status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } guard var status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") }
self.statusID = statusID
if let reblogID = status.reblog?.id, if let reblogID = status.reblog?.id,
let reblog = MastodonCache.status(for: reblogID) { let reblog = MastodonCache.status(for: reblogID) {
@ -87,10 +117,26 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
} }
let account = status.account let account = status.account
self.accountID = account.id self.accountID = account.id
self.statusID = status.id updateUI(account: account)
updateUIForPreferences() updateUIForPreferences()
updateTimestamp()
attachmentsView.updateUI(status: status)
let realStatus = status.reblog ?? status
updateStatusState(status: realStatus)
contentLabel.statusID = status.id
}
private func updateStatusState(status: Status) {
favorited = status.favourited ?? false
reblogged = status.reblogged ?? false
}
private func updateUI(account: Account) {
usernameLabel.text = "@\(account.acct)" usernameLabel.text = "@\(account.acct)"
avatarImageView.image = nil avatarImageView.image = nil
avatarURL = account.avatar avatarURL = account.avatar
@ -101,15 +147,6 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
self.avatarURL = nil self.avatarURL = nil
} }
} }
updateTimestamp()
attachmentsView.updateUI(status: status)
let realStatus = status.reblog ?? status
favorited = realStatus.favourited ?? false
reblogged = realStatus.reblogged ?? false
contentLabel.statusID = status.id
} }
func updateTimestamp() { func updateTimestamp() {
@ -247,7 +284,6 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
} }
completion(true) completion(true)
MastodonCache.add(status: status) MastodonCache.add(status: status)
self.updateUI(for: self.reblogStatusID ?? self.statusID)
} }
}) })
} }
@ -275,7 +311,6 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
} }
completion(true) completion(true)
MastodonCache.add(status: status) MastodonCache.add(status: status)
self.updateUI(for: self.reblogStatusID ?? self.statusID)
} }
}) })
} }