forked from shadowfacts/Tusker
Update cells when statuses/accounts change from other sources
This commit is contained in:
parent
44cfd44651
commit
199f95c465
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -102,7 +102,7 @@ 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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,6 +70,24 @@ 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() {
|
||||||
|
@ -71,8 +100,9 @@ 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)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue