Start converting UI to use CoreData backed objects instead of API
objects directly
This commit is contained in:
parent
a0e95d4577
commit
2c8ba878b7
|
@ -58,7 +58,7 @@ extension AccountMO {
|
|||
}
|
||||
|
||||
self.acct = account.acct
|
||||
self.avatar = account.avatar
|
||||
self.avatar = account.avatarStatic // we don't animate avatars
|
||||
self.bot = account.bot ?? false
|
||||
self.createdAt = account.createdAt
|
||||
self.displayName = account.displayName
|
||||
|
@ -66,7 +66,7 @@ extension AccountMO {
|
|||
self.fields = account.fields ?? []
|
||||
self.followersCount = account.followersCount
|
||||
self.followingCount = account.followingCount
|
||||
self.header = account.header
|
||||
self.header = account.headerStatic // we don't animate headers
|
||||
self.id = account.id
|
||||
self.locked = account.locked
|
||||
self.moved = account.moved ?? false
|
||||
|
|
|
@ -37,19 +37,33 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
}
|
||||
}
|
||||
|
||||
private func upsert(status: Status) {
|
||||
if let statusMO = self.status(for: status.id, in: self.backgroundContext) {
|
||||
statusMO.updateFrom(apiStatus: status, container: self)
|
||||
} else {
|
||||
_ = StatusMO(apiStatus: status, container: self, context: self.backgroundContext)
|
||||
}
|
||||
}
|
||||
|
||||
func addOrUpdate(status: Status, save: Bool = true) {
|
||||
backgroundContext.perform {
|
||||
if let statusMO = self.status(for: status.id, in: self.backgroundContext) {
|
||||
statusMO.updateFrom(apiStatus: status, container: self)
|
||||
} else {
|
||||
_ = StatusMO(apiStatus: status, container: self, context: self.backgroundContext)
|
||||
}
|
||||
self.upsert(status: status)
|
||||
if save, self.backgroundContext.hasChanges {
|
||||
try! self.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addAll(statuses: [Status], completion: (() -> Void)? = nil) {
|
||||
backgroundContext.perform {
|
||||
statuses.forEach(self.upsert(status:))
|
||||
if self.backgroundContext.hasChanges {
|
||||
try! self.backgroundContext.save()
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
func account(for id: String, in context: NSManagedObjectContext? = nil) -> AccountMO? {
|
||||
let context = context ?? viewContext
|
||||
let request: NSFetchRequest<AccountMO> = AccountMO.fetchRequest()
|
||||
|
@ -62,17 +76,31 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
}
|
||||
}
|
||||
|
||||
private func upsert(account: Account) {
|
||||
if let accountMO = self.account(for: account.id, in: self.backgroundContext) {
|
||||
accountMO.updateFrom(apiAccount: account, container: self)
|
||||
} else {
|
||||
_ = AccountMO(apiAccount: account, container: self, context: self.backgroundContext)
|
||||
}
|
||||
}
|
||||
|
||||
func addOrUpdate(account: Account, save: Bool = true) {
|
||||
backgroundContext.perform {
|
||||
if let accountMO = self.account(for: account.id, in: self.backgroundContext) {
|
||||
accountMO.updateFrom(apiAccount: account, container: self)
|
||||
} else {
|
||||
_ = AccountMO(apiAccount: account, container: self, context: self.backgroundContext)
|
||||
}
|
||||
self.upsert(account: account)
|
||||
if save, self.backgroundContext.hasChanges {
|
||||
try! self.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addAll(accounts: [Account], completion: (() -> Void)? = nil) {
|
||||
backgroundContext.perform {
|
||||
accounts.forEach(self.upsert(account:))
|
||||
if self.backgroundContext.hasChanges {
|
||||
try! self.backgroundContext.save()
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ public final class StatusMO: NSManagedObject {
|
|||
@NSManaged public var reblogged: Bool
|
||||
@NSManaged public var reblogsCount: Int
|
||||
@NSManaged public var sensitive: Bool
|
||||
@NSManaged public var spoilerText: String
|
||||
@NSManaged public var uri: String // todo: are both uri and url necessary?
|
||||
@NSManaged public var url: URL?
|
||||
@NSManaged private var visibilityString: String
|
||||
|
@ -95,6 +96,7 @@ extension StatusMO {
|
|||
self.reblogged = status.reblogged ?? false
|
||||
self.reblogsCount = status.reblogsCount
|
||||
self.sensitive = status.sensitive
|
||||
self.spoilerText = status.spoilerText
|
||||
self.uri = status.uri
|
||||
self.visibility = status.visibility
|
||||
self.account = container.account(for: status.account.id, in: context) ?? AccountMO(apiAccount: status.account, container: container, context: context)
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<attribute name="reblogged" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="reblogsCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="sensitive" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="spoilerText" attributeType="String"/>
|
||||
<attribute name="uri" attributeType="String"/>
|
||||
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||
<attribute name="visibilityString" attributeType="String"/>
|
||||
|
@ -57,6 +58,6 @@
|
|||
</entity>
|
||||
<elements>
|
||||
<element name="Account" positionX="169.21875" positionY="78.9609375" width="128" height="313"/>
|
||||
<element name="Status" positionX="-63" positionY="-18" width="128" height="388"/>
|
||||
<element name="Status" positionX="-63" positionY="-18" width="128" height="403"/>
|
||||
</elements>
|
||||
</model>
|
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import Pachyderm
|
||||
|
||||
extension Account {
|
||||
extension AccountMO {
|
||||
|
||||
var displayOrUserName: String {
|
||||
if displayName.isEmpty {
|
||||
|
@ -31,7 +31,7 @@ extension Account {
|
|||
|
||||
private func stripCustomEmoji(from string: String) -> String {
|
||||
let range = NSRange(location: 0, length: string.utf16.count)
|
||||
return Account.customEmojiRegex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: "")
|
||||
return AccountMO.customEmojiRegex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: "")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import Foundation
|
|||
private let decoder = PropertyListDecoder()
|
||||
private let encoder = PropertyListEncoder()
|
||||
|
||||
// todo: invalidate cache on underlying data change using KVO?
|
||||
@propertyWrapper
|
||||
struct LazilyDecoding<Enclosing, Value: Codable> {
|
||||
|
||||
|
|
|
@ -64,12 +64,7 @@ class MastodonCache {
|
|||
|
||||
func addAll(statuses: [Status]) {
|
||||
statuses.forEach(add)
|
||||
if let container = mastodonController?.persistentContainer {
|
||||
statuses.forEach { container.addOrUpdate(status: $0, save: false) }
|
||||
container.backgroundContext.perform {
|
||||
try! container.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
mastodonController?.persistentContainer.addAll(statuses: statuses)
|
||||
}
|
||||
|
||||
// MARK: - Accounts
|
||||
|
@ -104,12 +99,7 @@ class MastodonCache {
|
|||
|
||||
func addAll(accounts: [Account]) {
|
||||
accounts.forEach(add)
|
||||
if let container = mastodonController?.persistentContainer {
|
||||
accounts.forEach { container.addOrUpdate(account: $0, save: false) }
|
||||
container.backgroundContext.perform {
|
||||
try! container.backgroundContext.save()
|
||||
}
|
||||
}
|
||||
mastodonController?.persistentContainer.addAll(accounts: accounts)
|
||||
}
|
||||
|
||||
// MARK: - Relationships
|
||||
|
|
|
@ -213,7 +213,8 @@ class ComposeViewController: UIViewController {
|
|||
replyAvatarImageViewTopConstraint!.isActive = true
|
||||
|
||||
inReplyToContainer.isHidden = false
|
||||
inReplyToLabel.text = "In reply to \(inReplyTo.account.displayOrUserName)"
|
||||
// todo: update to use managed objects
|
||||
inReplyToLabel.text = "In reply to \(inReplyTo.account.displayName)"
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
|
|
@ -128,7 +128,7 @@ class ProfileTableViewController: EnhancedTableViewController {
|
|||
}
|
||||
|
||||
@objc func updateUIForPreferences() {
|
||||
guard let accountID = accountID, let account = mastodonController.cache.account(for: accountID) else { return }
|
||||
guard let accountID = accountID, let account = mastodonController.persistentContainer.account(for: accountID) else { return }
|
||||
navigationItem.title = account.displayNameWithoutCustomEmoji
|
||||
}
|
||||
|
||||
|
|
|
@ -59,12 +59,15 @@ class TimelineTableViewController: EnhancedTableViewController {
|
|||
let request = Client.getStatuses(timeline: timeline)
|
||||
mastodonController.run(request) { response in
|
||||
guard case let .success(statuses, pagination) = response else { fatalError() }
|
||||
self.mastodonController.cache.addAll(statuses: statuses)
|
||||
// self.mastodonController.cache.addAll(statuses: statuses)
|
||||
// todo: possible race condition here? we update the underlying data before waiting to reload the table view
|
||||
self.timelineSegments.insert(statuses.map { ($0.id, .unknown) }, at: 0)
|
||||
self.newer = pagination?.newer
|
||||
self.older = pagination?.older
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
self.mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,13 +104,15 @@ class TimelineTableViewController: EnhancedTableViewController {
|
|||
mastodonController.run(request) { response in
|
||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||
self.older = pagination?.older
|
||||
self.mastodonController.cache.addAll(statuses: newStatuses)
|
||||
// self.mastodonController.cache.addAll(statuses: newStatuses)
|
||||
let newRows = self.timelineSegments.last!.count..<(self.timelineSegments.last!.count + newStatuses.count)
|
||||
let newIndexPaths = newRows.map { IndexPath(row: $0, section: self.timelineSegments.count - 1) }
|
||||
self.timelineSegments[self.timelineSegments.count - 1].append(contentsOf: newStatuses.map { ($0.id, .unknown) })
|
||||
DispatchQueue.main.async {
|
||||
UIView.performWithoutAnimation {
|
||||
self.tableView.insertRows(at: newIndexPaths, with: .none)
|
||||
self.mastodonController.persistentContainer.addAll(statuses: newStatuses) {
|
||||
DispatchQueue.main.async {
|
||||
UIView.performWithoutAnimation {
|
||||
self.tableView.insertRows(at: newIndexPaths, with: .none)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,25 +138,27 @@ class TimelineTableViewController: EnhancedTableViewController {
|
|||
mastodonController.run(request) { response in
|
||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||
self.newer = pagination?.newer
|
||||
self.mastodonController.cache.addAll(statuses: newStatuses)
|
||||
// self.mastodonController.cache.addAll(statuses: newStatuses)
|
||||
self.timelineSegments[0].insert(contentsOf: newStatuses.map { ($0.id, .unknown) }, at: 0)
|
||||
|
||||
if let newer = pagination?.newer {
|
||||
self.newer = newer
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
let newIndexPaths = (0..<newStatuses.count).map {
|
||||
IndexPath(row: $0, section: 0)
|
||||
}
|
||||
UIView.performWithoutAnimation {
|
||||
self.tableView.insertRows(at: newIndexPaths, with: .automatic)
|
||||
}
|
||||
self.mastodonController.persistentContainer.addAll(statuses: newStatuses) {
|
||||
DispatchQueue.main.async {
|
||||
let newIndexPaths = (0..<newStatuses.count).map {
|
||||
IndexPath(row: $0, section: 0)
|
||||
}
|
||||
UIView.performWithoutAnimation {
|
||||
self.tableView.insertRows(at: newIndexPaths, with: .automatic)
|
||||
}
|
||||
|
||||
self.refreshControl?.endRefreshing()
|
||||
self.refreshControl?.endRefreshing()
|
||||
|
||||
// maintain the current position in the list (don't scroll to the top)
|
||||
self.tableView.scrollToRow(at: IndexPath(row: newStatuses.count, section: 0), at: .top, animated: false)
|
||||
// maintain the current position in the list (don't scroll to the top)
|
||||
self.tableView.scrollToRow(at: IndexPath(row: newStatuses.count, section: 0), at: .top, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +182,7 @@ extension TimelineTableViewController: StatusTableViewCellDelegate {
|
|||
extension TimelineTableViewController: UITableViewDataSourcePrefetching {
|
||||
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
||||
for indexPath in indexPaths {
|
||||
guard let status = mastodonController.cache.status(for: statusID(for: indexPath)) else { continue }
|
||||
guard let status = mastodonController.persistentContainer.status(for: statusID(for: indexPath)) else { continue }
|
||||
_ = ImageCache.avatars.get(status.account.avatar, completion: nil)
|
||||
for attachment in status.attachments {
|
||||
_ = ImageCache.attachments.get(attachment.url, completion: nil)
|
||||
|
@ -185,7 +192,7 @@ extension TimelineTableViewController: UITableViewDataSourcePrefetching {
|
|||
|
||||
func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
|
||||
for indexPath in indexPaths {
|
||||
guard let status = mastodonController.cache.status(for: statusID(for: indexPath)) else { continue }
|
||||
guard let status = mastodonController.persistentContainer.status(for: statusID(for: indexPath)) else { continue }
|
||||
ImageCache.avatars.cancelWithoutCallback(status.account.avatar)
|
||||
for attachment in status.attachments {
|
||||
ImageCache.attachments.cancelWithoutCallback(attachment.url)
|
||||
|
|
|
@ -32,12 +32,13 @@ class UserActivityManager {
|
|||
|
||||
// MARK: - New Post
|
||||
static func newPostActivity(mentioning: Account? = nil) -> NSUserActivity {
|
||||
// todo: update to use managed objects
|
||||
let activity = NSUserActivity(type: .newPost)
|
||||
activity.isEligibleForPrediction = true
|
||||
if let mentioning = mentioning {
|
||||
activity.userInfo = ["mentioning": mentioning.acct]
|
||||
activity.title = "Send a message to \(mentioning.displayOrUserName)"
|
||||
activity.suggestedInvocationPhrase = "Send a message to \(mentioning.displayOrUserName)"
|
||||
activity.title = "Send a message to \(mentioning.displayName)"
|
||||
activity.suggestedInvocationPhrase = "Send a message to \(mentioning.displayName)"
|
||||
} else {
|
||||
activity.userInfo = [:]
|
||||
activity.title = "New Post"
|
||||
|
|
|
@ -48,7 +48,7 @@ class AttachmentsContainerView: UIView {
|
|||
|
||||
// MARK: - User Interaface
|
||||
|
||||
func updateUI(status: Status) {
|
||||
func updateUI(status: StatusMO) {
|
||||
self.statusID = status.id
|
||||
attachments = status.attachments.filter { AttachmentsContainerView.supportedAttachmentTypes.contains($0.kind) }
|
||||
|
||||
|
|
|
@ -83,6 +83,15 @@ class EmojiLabel: UILabel {
|
|||
|
||||
extension EmojiLabel {
|
||||
func updateForAccountDisplayName(account: Account) {
|
||||
if Preferences.shared.hideCustomEmojiInUsernames {
|
||||
self.text = account.displayName
|
||||
self.removeEmojis()
|
||||
} else {
|
||||
self.text = account.displayName
|
||||
self.setEmojis(account.emojis, identifier: account.id)
|
||||
}
|
||||
}
|
||||
func updateForAccountDisplayName(account: AccountMO) {
|
||||
if Preferences.shared.hideCustomEmojiInUsernames {
|
||||
self.text = account.displayNameWithoutCustomEmoji
|
||||
self.removeEmojis()
|
||||
|
|
|
@ -138,13 +138,14 @@ class ActionNotificationGroupTableViewCell: UITableViewCell {
|
|||
}
|
||||
let peopleStr: String
|
||||
// todo: figure out how to localize this
|
||||
// todo: update to use managed objects
|
||||
switch people.count {
|
||||
case 1:
|
||||
peopleStr = people.first!.displayOrUserName
|
||||
peopleStr = people.first!.displayName
|
||||
case 2:
|
||||
peopleStr = people.first!.displayOrUserName + " and " + people.last!.displayOrUserName
|
||||
peopleStr = people.first!.displayName + " and " + people.last!.displayName
|
||||
default:
|
||||
peopleStr = people.dropLast().map { $0.displayOrUserName }.joined(separator: ", ") + ", and " + people.last!.displayOrUserName
|
||||
peopleStr = people.dropLast().map { $0.displayName }.joined(separator: ", ") + ", and " + people.last!.displayName
|
||||
}
|
||||
actionLabel.text = "\(verb) by \(peopleStr)"
|
||||
}
|
||||
|
|
|
@ -72,15 +72,16 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
func updateActionLabel(people: [Account]) {
|
||||
// todo: update to use managed objects
|
||||
// todo: figure out how to localize this
|
||||
let peopleStr: String
|
||||
switch people.count {
|
||||
case 1:
|
||||
peopleStr = people.first!.displayOrUserName
|
||||
peopleStr = people.first!.displayName
|
||||
case 2:
|
||||
peopleStr = people.first!.displayOrUserName + " and " + people.last!.displayOrUserName
|
||||
peopleStr = people.first!.displayName + " and " + people.last!.displayName
|
||||
default:
|
||||
peopleStr = people.dropLast().map { $0.displayOrUserName }.joined(separator: ", ") + ", and " + people.last!.displayOrUserName
|
||||
peopleStr = people.dropLast().map { $0.displayName }.joined(separator: ", ") + ", and " + people.last!.displayName
|
||||
|
||||
}
|
||||
actionLabel.text = "Followed by \(peopleStr)"
|
||||
|
|
|
@ -52,12 +52,13 @@ class FollowRequestNotificationTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
func updateUI(account: Account) {
|
||||
// todo: update to use managed objects
|
||||
self.account = account
|
||||
if Preferences.shared.hideCustomEmojiInUsernames {
|
||||
actionLabel.text = "Request to follow from \(account.displayNameWithoutCustomEmoji)"
|
||||
actionLabel.text = "Request to follow from \(account.displayName)"
|
||||
actionLabel.removeEmojis()
|
||||
} else {
|
||||
actionLabel.text = "Request to follow from \(account.displayOrUserName)"
|
||||
actionLabel.text = "Request to follow from \(account.displayName)"
|
||||
actionLabel.setEmojis(account.emojis, identifier: account.id)
|
||||
}
|
||||
avatarRequest = ImageCache.avatars.get(account.avatar) { [weak self] (data) in
|
||||
|
|
|
@ -95,25 +95,26 @@ class BaseStatusTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
open func createObserversIfNecessary() {
|
||||
if statusUpdater == nil {
|
||||
statusUpdater = mastodonController.cache.statusSubject
|
||||
.filter { [unowned self] in $0.id == self.statusID }
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [unowned self] in self.updateStatusState(status: $0) }
|
||||
}
|
||||
|
||||
if accountUpdater == nil {
|
||||
accountUpdater = mastodonController.cache.accountSubject
|
||||
.filter { [unowned self] in $0.id == self.accountID }
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [unowned self] in self.updateUI(account: $0) }
|
||||
}
|
||||
// todo: KVO on StatusMO for this?
|
||||
// if statusUpdater == nil {
|
||||
// statusUpdater = mastodonController.cache.statusSubject
|
||||
// .filter { [unowned self] in $0.id == self.statusID }
|
||||
// .receive(on: DispatchQueue.main)
|
||||
// .sink { [unowned self] in self.updateStatusState(status: $0) }
|
||||
// }
|
||||
//
|
||||
// if accountUpdater == nil {
|
||||
// accountUpdater = mastodonController.cache.accountSubject
|
||||
// .filter { [unowned self] in $0.id == self.accountID }
|
||||
// .receive(on: DispatchQueue.main)
|
||||
// .sink { [unowned self] in self.updateUI(account: $0) }
|
||||
// }
|
||||
}
|
||||
|
||||
func updateUI(statusID: String, state: StatusState) {
|
||||
createObserversIfNecessary()
|
||||
|
||||
guard let status = mastodonController.cache.status(for: statusID) else {
|
||||
guard let status = mastodonController.persistentContainer.status(for: statusID) else {
|
||||
fatalError("Missing cached status")
|
||||
}
|
||||
self.statusID = statusID
|
||||
|
@ -161,9 +162,9 @@ class BaseStatusTableViewCell: UITableViewCell {
|
|||
}
|
||||
}
|
||||
|
||||
func updateStatusState(status: Status) {
|
||||
favorited = status.favourited ?? false
|
||||
reblogged = status.reblogged ?? false
|
||||
func updateStatusState(status: StatusMO) {
|
||||
favorited = status.favourited
|
||||
reblogged = status.reblogged
|
||||
|
||||
if favorited {
|
||||
favoriteButton.accessibilityLabel = NSLocalizedString("Undo Favorite", comment: "undo favorite button accessibility label")
|
||||
|
@ -177,22 +178,22 @@ class BaseStatusTableViewCell: UITableViewCell {
|
|||
}
|
||||
}
|
||||
|
||||
func updateUI(account: Account) {
|
||||
func updateUI(account: AccountMO) {
|
||||
usernameLabel.text = "@\(account.acct)"
|
||||
avatarImageView.image = nil
|
||||
avatarRequest = ImageCache.avatars.get(account.avatar) { [weak self] (data) in
|
||||
guard let self = self, let data = data, self.accountID == account.id else { return }
|
||||
DispatchQueue.main.async {
|
||||
guard let self = self, let data = data, self.accountID == account.id else { return }
|
||||
self.avatarImageView.image = UIImage(data: data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func updateUIForPreferences() {
|
||||
guard let mastodonController = mastodonController, let account = mastodonController.cache.account(for: accountID) else { return }
|
||||
guard let mastodonController = mastodonController, let account = mastodonController.persistentContainer.account(for: accountID) else { return }
|
||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
||||
displayNameLabel.updateForAccountDisplayName(account: account)
|
||||
attachmentsView.contentHidden = Preferences.shared.blurAllMedia || (mastodonController.cache.status(for: statusID)?.sensitive ?? false)
|
||||
attachmentsView.contentHidden = Preferences.shared.blurAllMedia || (mastodonController.persistentContainer.status(for: statusID)?.sensitive ?? false)
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
|
@ -311,7 +312,7 @@ class BaseStatusTableViewCell: UITableViewCell {
|
|||
|
||||
extension BaseStatusTableViewCell: AttachmentViewDelegate {
|
||||
func attachmentViewGallery(startingAt index: Int) -> UIViewController {
|
||||
guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||
guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||
let sourceViews = status.attachments.map(attachmentsView.getAttachmentView(for:))
|
||||
return delegate!.gallery(attachments: status.attachments, sourceViews: sourceViews, startIndex: index)
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class ConversationMainStatusTableViewCell: BaseStatusTableViewCell {
|
|||
timestampAndClientLabel.text = timestampAndClientText
|
||||
}
|
||||
|
||||
override func updateStatusState(status: Status) {
|
||||
override func updateStatusState(status: StatusMO) {
|
||||
super.updateStatusState(status: status)
|
||||
|
||||
// todo: localize me
|
||||
|
@ -57,7 +57,7 @@ class ConversationMainStatusTableViewCell: BaseStatusTableViewCell {
|
|||
totalReblogsButton.setTitle("\(status.reblogsCount) Reblog\(status.reblogsCount == 1 ? "" : "s")", for: .normal)
|
||||
}
|
||||
|
||||
override func updateUI(account: Account) {
|
||||
override func updateUI(account: AccountMO) {
|
||||
super.updateUI(account: account)
|
||||
|
||||
profileAccessibilityElement.accessibilityLabel = account.displayNameWithoutCustomEmoji
|
||||
|
|
|
@ -47,20 +47,20 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell {
|
|||
override func createObserversIfNecessary() {
|
||||
super.createObserversIfNecessary()
|
||||
|
||||
if rebloggerAccountUpdater == nil {
|
||||
rebloggerAccountUpdater = mastodonController.cache.accountSubject
|
||||
.filter { [unowned self] in $0.id == self.rebloggerID }
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [unowned self] in self.updateRebloggerLabel(reblogger: $0) }
|
||||
}
|
||||
// todo: use KVO on reblogger account?
|
||||
// if rebloggerAccountUpdater == nil {
|
||||
// rebloggerAccountUpdater = mastodonController.cache.accountSubject
|
||||
// .filter { [unowned self] in $0.id == self.rebloggerID }
|
||||
// .receive(on: DispatchQueue.main)
|
||||
// .sink { [unowned self] in self.updateRebloggerLabel(reblogger: $0) }
|
||||
// }
|
||||
}
|
||||
|
||||
override func updateUI(statusID: String, state: StatusState) {
|
||||
guard var status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") }
|
||||
guard var status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID)") }
|
||||
|
||||
let realStatusID: String
|
||||
if let rebloggedStatusID = status.reblog?.id,
|
||||
let rebloggedStatus = mastodonController.cache.status(for: rebloggedStatusID) {
|
||||
if let rebloggedStatus = status.reblog {
|
||||
reblogStatusID = statusID
|
||||
rebloggerID = status.account.id
|
||||
status = rebloggedStatus
|
||||
|
@ -77,7 +77,7 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell {
|
|||
|
||||
updateTimestamp()
|
||||
|
||||
let pinned = status.pinned ?? false
|
||||
let pinned = status.pinned
|
||||
pinImageView.isHidden = !(pinned && showPinned)
|
||||
timestampLabel.isHidden = !pinImageView.isHidden
|
||||
}
|
||||
|
@ -85,12 +85,12 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell {
|
|||
@objc override func updateUIForPreferences() {
|
||||
super.updateUIForPreferences()
|
||||
if let rebloggerID = rebloggerID,
|
||||
let reblogger = mastodonController.cache.account(for: rebloggerID) {
|
||||
let reblogger = mastodonController.persistentContainer.account(for: rebloggerID) {
|
||||
updateRebloggerLabel(reblogger: reblogger)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateRebloggerLabel(reblogger: Account) {
|
||||
private func updateRebloggerLabel(reblogger: AccountMO) {
|
||||
if Preferences.shared.hideCustomEmojiInUsernames {
|
||||
reblogLabel.text = "Reblogged by \(reblogger.displayNameWithoutCustomEmoji)"
|
||||
reblogLabel.removeEmojis()
|
||||
|
@ -104,7 +104,7 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell {
|
|||
// if the mastodonController is nil (i.e. the delegate is nil), then the screen this cell was a part of has been deallocated
|
||||
// so we bail out immediately, since there's nothing to update
|
||||
guard let mastodonController = mastodonController else { return }
|
||||
guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||
guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||
|
||||
timestampLabel.text = status.createdAt.timeAgoString()
|
||||
timestampLabel.accessibilityLabel = TimelineStatusTableViewCell.relativeDateFormatter.localizedString(for: status.createdAt, relativeTo: Date())
|
||||
|
|
|
@ -15,7 +15,7 @@ class StatusContentTextView: ContentTextView {
|
|||
didSet {
|
||||
guard let statusID = statusID else { return }
|
||||
guard let mastodonController = mastodonController,
|
||||
let status = mastodonController.cache.status(for: statusID) else {
|
||||
let status = mastodonController.persistentContainer.status(for: statusID) else {
|
||||
fatalError("Can't set StatusContentTextView text without cached status for \(statusID)")
|
||||
}
|
||||
setTextFromHtml(status.content)
|
||||
|
|
|
@ -314,7 +314,8 @@ struct XCBActions {
|
|||
DispatchQueue.main.async {
|
||||
show(vc)
|
||||
}
|
||||
let alertController = UIAlertController(title: "Follow \(account.displayNameWithoutCustomEmoji)?", message: nil, preferredStyle: .alert)
|
||||
// todo: update to use managed objects
|
||||
let alertController = UIAlertController(title: "Follow \(account.displayName)?", message: nil, preferredStyle: .alert)
|
||||
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
|
||||
performAction(account)
|
||||
}))
|
||||
|
|
Loading…
Reference in New Issue