mastodon-ios/MastodonSDK/Sources/MastodonCore/FetchedResultsController/StatusDataController.swift

157 lines
5.7 KiB
Swift

import UIKit
import Combine
import CoreData
import CoreDataStack
import MastodonSDK
import os.log
public final class StatusDataController {
private let logger = Logger(subsystem: "StatusDataController", category: "Data")
private static let entryNotFoundMessage = "Failed to find suitable record. Depending on the context this might result in errors (data not being updated) or can be discarded (e.g. when there are mixed data sources where an entry might or might not exist)."
@MainActor
@Published
public private(set) var records: [MastodonStatus] = []
@MainActor
public init(records: [MastodonStatus] = []) {
self.records = records
}
@MainActor
public func reset() {
records = []
}
@MainActor
public func setRecords(_ records: [MastodonStatus]) {
self.records = records
}
@MainActor
public func appendRecords(_ records: [MastodonStatus]) {
self.records += records
}
@MainActor
public func deleteRecord(_ record: MastodonStatus) {
self.records = self.records.filter { $0.id != record.id }
}
@MainActor
public func update(status: MastodonStatus, intent: MastodonStatus.UpdateIntent) {
switch intent {
case .delete:
deleteRecord(status)
case .edit:
updateEdited(status)
case let .bookmark(isBookmarked):
updateBookmarked(status, isBookmarked)
case let .favorite(isFavorited):
updateFavorited(status, isFavorited)
case let .reblog(isReblogged):
updateReblogged(status, isReblogged)
case let .toggleSensitive(isVisible):
updateSensitive(status, isVisible)
}
}
@MainActor
private func updateEdited(_ status: MastodonStatus) {
var newRecords = Array(records)
guard let index = newRecords.firstIndex(where: { $0.id == status.id }) else {
logger.warning("\(Self.entryNotFoundMessage)")
return
}
newRecords[index] = status.inheritSensitivityToggled(from: newRecords[index])
records = newRecords
}
@MainActor
private func updateBookmarked(_ status: MastodonStatus, _ isBookmarked: Bool) {
var newRecords = Array(records)
guard let index = newRecords.firstIndex(where: { $0.id == status.id }) else {
logger.warning("\(Self.entryNotFoundMessage)")
return
}
newRecords[index] = status.inheritSensitivityToggled(from: newRecords[index])
records = newRecords
}
@MainActor
private func updateFavorited(_ status: MastodonStatus, _ isFavorited: Bool) {
var newRecords = Array(records)
if let index = newRecords.firstIndex(where: { $0.id == status.id }) {
// Replace old status entity
let existingRecord = newRecords[index]
let newStatus = status.inheritSensitivityToggled(from: existingRecord)
.withOriginal(status: existingRecord)
newRecords[index] = newStatus
} else if let index = newRecords.firstIndex(where: { $0.reblog?.id == status.id }) {
// Replace reblogged entity of old "parent" status
let existingRecord = newRecords[index]
let newStatus = status.inheritSensitivityToggled(from: existingRecord)
.withOriginal(status: existingRecord)
newStatus.reblog = status
newRecords[index] = newStatus
} else {
logger.warning("\(Self.entryNotFoundMessage)")
}
records = newRecords
}
@MainActor
private func updateReblogged(_ status: MastodonStatus, _ isReblogged: Bool) {
var newRecords = Array(records)
switch isReblogged {
case true:
let index: Int
if let idx = newRecords.firstIndex(where: { $0.reblog?.id == status.reblog?.id }) {
index = idx
} else if let idx = newRecords.firstIndex(where: { $0.id == status.reblog?.id }) {
index = idx
} else {
logger.warning("\(Self.entryNotFoundMessage)")
return
}
let existingStatus = newRecords[index]
newRecords[index] = status.withOriginal(status: existingStatus)
case false:
let index: Int
if let idx = newRecords.firstIndex(where: { $0.reblog?.id == status.id }) {
index = idx
} else if let idx = newRecords.firstIndex(where: { $0.id == status.id }) {
index = idx
} else {
logger.warning("\(Self.entryNotFoundMessage)")
return
}
let existingRecord = newRecords[index]
let newStatus = existingRecord.originalStatus ?? status.inheritSensitivityToggled(from: existingRecord)
newRecords[index] = newStatus
}
records = newRecords
}
@MainActor
private func updateSensitive(_ status: MastodonStatus, _ isVisible: Bool) {
var newRecords = Array(records)
if let index = newRecords.firstIndex(where: { $0.reblog?.id == status.id }) {
let newStatus: MastodonStatus = .fromEntity(newRecords[index].entity)
newStatus.reblog = status
newRecords[index] = newStatus
} else if let index = newRecords.firstIndex(where: { $0.id == status.id }) {
let newStatus: MastodonStatus = .fromEntity(newRecords[index].entity)
.inheritSensitivityToggled(from: status)
newRecords[index] = newStatus
} else {
logger.warning("\(Self.entryNotFoundMessage)")
return
}
records = newRecords
}
}