From 5c834c7e096704452ca03ce002e572cb528e2549 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Fri, 10 Nov 2023 11:32:02 +0100 Subject: [PATCH] IOS-175: Remove CoreData status edit (#1148) --- Mastodon/Coordinator/SceneCoordinator.swift | 1 + ...Provider+StatusTableViewCellDelegate.swift | 21 +- .../PollOptionView+Configuration.swift | 3 +- .../StatusEditHistoryTableViewCell.swift | 2 +- .../StatusEditHistoryViewController.swift | 6 +- .../StatusEditHistoryViewModel.swift | 3 +- .../CoreData 9.xcdatamodel/contents | 14 +- .../Entity/Mastodon/Status.swift | 6 - .../Entity/Mastodon/StatusEdit.swift | 226 ------------------ .../CoreDataStack/StatusEdit+Property.swift | 24 -- .../MastodonCore/Model/Poll/PollItem.swift | 3 +- .../Persistence/Persistence+StatusEdit.swift | 48 ---- .../Persistence/Persistence.swift | 1 - .../API/APIService+Status+History.swift | 40 ---- .../Entity/Mastodon+Entity+StatusEdit.swift | 22 +- .../Protocol/StatusCompatible.swift | 14 -- .../Content/MediaView+Configuration.swift | 84 +++++++ .../Content/StatusView+Configuration.swift | 22 +- .../View/Content/StatusView+ViewModel.swift | 3 +- 19 files changed, 145 insertions(+), 398 deletions(-) delete mode 100644 MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/StatusEdit.swift delete mode 100644 MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/StatusEdit+Property.swift delete mode 100644 MastodonSDK/Sources/MastodonCore/Persistence/Persistence+StatusEdit.swift diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index d98e27b25..a7b32feb4 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -562,6 +562,7 @@ private extension SceneCoordinator { //MARK: - Loading public extension SceneCoordinator { + @MainActor func showLoading() { guard let rootViewController else { return } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index dafd65fdf..68be145e2 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -670,19 +670,30 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, statusMetricView: StatusMetricView, showEditHistory button: UIButton) { Task { - + + await coordinator.showLoading() + let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil) guard let item = await self.item(from: source), case let .status(status) = item else { assertionFailure("only works for status data provider") return } + + guard let status = status.object(in: context.managedObjectContext) else { + return await coordinator.hideLoading() + } + + do { + let edits = try await context.apiService.getHistory(forStatusID: status.id, authenticationBox: authContext.mastodonAuthenticationBox).value - guard let status = status.object(in: context.managedObjectContext), - let edits = status.editHistory?.sorted(by: { $0.createdAt > $1.createdAt }) else { return } + await coordinator.hideLoading() - let viewModel = StatusEditHistoryViewModel(status: status, edits: edits, appContext: context, authContext: authContext) - _ = await coordinator.present(scene: .editHistory(viewModel: viewModel), from: self, transition: .show) + let viewModel = StatusEditHistoryViewModel(status: status, edits: edits, appContext: context, authContext: authContext) + _ = await coordinator.present(scene: .editHistory(viewModel: viewModel), from: self, transition: .show) + } catch { + await coordinator.hideLoading() + } } } } diff --git a/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift b/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift index 0e3f07f66..631e5b337 100644 --- a/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift @@ -11,6 +11,7 @@ import CoreDataStack import MetaTextKit import MastodonCore import MastodonUI +import MastodonSDK extension PollOptionView { public func configure(pollOption option: PollOption) { @@ -103,7 +104,7 @@ extension PollOptionView { } extension PollOptionView { - public func configure(historyPollOption option: StatusEdit.Poll.Option) { + public func configure(historyPollOption option: Mastodon.Entity.StatusEdit.Poll.Option) { // background viewModel.roundedBackgroundViewColor = SystemTheme.systemElevatedBackgroundColor // metaContent diff --git a/Mastodon/Scene/Thread/Edit History/StatusEditHistoryTableViewCell.swift b/Mastodon/Scene/Thread/Edit History/StatusEditHistoryTableViewCell.swift index 06520462d..3485cfeab 100644 --- a/Mastodon/Scene/Thread/Edit History/StatusEditHistoryTableViewCell.swift +++ b/Mastodon/Scene/Thread/Edit History/StatusEditHistoryTableViewCell.swift @@ -72,7 +72,7 @@ class StatusEditHistoryTableViewCell: UITableViewCell { NSLayoutConstraint.activate(constraints) } - func configure(status: Status, statusEdit: StatusEdit, dateText: String) { + func configure(status: Status, statusEdit: Mastodon.Entity.StatusEdit, dateText: String) { dateLabel.text = dateText statusHistoryView.statusView.configure(status: status, statusEdit: statusEdit) } diff --git a/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewController.swift b/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewController.swift index 52dfd3cc2..a09242b4a 100644 --- a/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewController.swift +++ b/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewController.swift @@ -10,7 +10,7 @@ class StatusEditHistoryViewController: UIViewController { private let tableView: UITableView - var tableViewDataSource: UITableViewDiffableDataSource? + var tableViewDataSource: UITableViewDiffableDataSource? var viewModel: StatusEditHistoryViewModel private let dateFormatter: DateFormatter @@ -28,7 +28,7 @@ class StatusEditHistoryViewController: UIViewController { super.init(nibName: nil, bundle: nil) - let tableViewDataSource = UITableViewDiffableDataSource(tableView: tableView) {tableView, indexPath, itemIdentifier in + let tableViewDataSource = UITableViewDiffableDataSource(tableView: tableView) {tableView, indexPath, itemIdentifier in guard let cell = tableView.dequeueReusableCell(withIdentifier: StatusEditHistoryTableViewCell.identifier, for: indexPath) as? StatusEditHistoryTableViewCell else { fatalError("Wrong cell") } @@ -71,7 +71,7 @@ class StatusEditHistoryViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - var snapshot = NSDiffableDataSourceSnapshot() + var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([0]) snapshot.appendItems(viewModel.edits) diff --git a/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewModel.swift b/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewModel.swift index a5d778bec..525f7e72a 100644 --- a/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewModel.swift +++ b/Mastodon/Scene/Thread/Edit History/StatusEditHistoryViewModel.swift @@ -5,10 +5,11 @@ import CoreDataStack import MastodonCore import MastodonUI import UIKit +import MastodonSDK struct StatusEditHistoryViewModel { let status: Status - let edits: [StatusEdit] + let edits: [Mastodon.Entity.StatusEdit] let appContext: AppContext let authContext: AuthContext diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 9.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 9.xcdatamodel/contents index ee57231f2..c5bbd1485 100644 --- a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 9.xcdatamodel/contents +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 9.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -225,7 +225,6 @@ - @@ -239,17 +238,6 @@ - - - - - - - - - - - diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift index 736d4b7eb..1bdd9410a 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift @@ -99,8 +99,6 @@ public final class Status: NSManagedObject { @NSManaged public private(set) var replyFrom: Set @NSManaged public private(set) var notifications: Set @NSManaged public private(set) var searchHistories: Set - - @NSManaged public private(set) var editHistory: Set? // sourcery: autoUpdatableObject, autoGenerateProperty @NSManaged public private(set) var updatedAt: Date @@ -590,10 +588,6 @@ extension Status: AutoUpdatableObject { public func update(isReveal: Bool) { revealedAt = isReveal ? Date() : nil } - - public func update(editHistory: Set) { - self.editHistory = editHistory - } } extension Status { diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/StatusEdit.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/StatusEdit.swift deleted file mode 100644 index 1cb7aa1a4..000000000 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/StatusEdit.swift +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright © 2023 Mastodon gGmbH. All rights reserved. - -import Foundation -import CoreData - -public final class StatusEdit: NSManagedObject { - public final class Poll: NSObject, Codable { - public final class Option: NSObject, Codable { - public let title: String - - public init(title: String) { - self.title = title - } - } - public let options: [Option] - - public init(options: [Option]) { - self.options = options - } - } - - // sourcery: autoUpdatableObject, autoGenerateProperty - @NSManaged public var createdAt: Date - - // sourcery: autoUpdatableObject, autoGenerateProperty - @NSManaged public var content: String - - // sourcery: autoUpdatableObject, autoGenerateProperty - @NSManaged public var sensitive: Bool - - // sourcery: autoUpdatableObject, autoGenerateProperty - @NSManaged public var spoilerText: String? - - // MARK: - AutoGenerateProperty - // sourcery:inline:StatusEdit.AutoGenerateProperty - - // Generated using Sourcery - // DO NOT EDIT - public struct Property { - public let createdAt: Date - public let content: String - public let sensitive: Bool - public let spoilerText: String? - public let emojis: [MastodonEmoji] - public let attachments: [MastodonAttachment] - public let poll: Poll? - - public init( - createdAt: Date, - content: String, - sensitive: Bool, - spoilerText: String?, - emojis: [MastodonEmoji], - attachments: [MastodonAttachment], - poll: Poll? - ) { - self.createdAt = createdAt - self.content = content - self.sensitive = sensitive - self.spoilerText = spoilerText - self.emojis = emojis - self.attachments = attachments - self.poll = poll - } - } - - public func configure(property: Property) { - self.createdAt = property.createdAt - self.content = property.content - self.sensitive = property.sensitive - self.spoilerText = property.spoilerText - self.emojis = property.emojis - self.attachments = property.attachments - self.poll = property.poll - } - - public func update(property: Property) { - update(createdAt: property.createdAt) - update(content: property.content) - update(sensitive: property.sensitive) - update(spoilerText: property.spoilerText) - update(emojis: property.emojis) - update(attachments: property.attachments) - update(poll: property.poll) - } - // sourcery:end - - // sourcery: autoUpdatableObject, autoGenerateProperty - @objc public var emojis: [MastodonEmoji] { - get { - let keyPath = #keyPath(StatusEdit.emojis) - willAccessValue(forKey: keyPath) - let _data = primitiveValue(forKey: keyPath) as? Data - didAccessValue(forKey: keyPath) - do { - guard let data = _data else { return [] } - let emojis = try JSONDecoder().decode([MastodonEmoji].self, from: data) - return emojis - } catch { - assertionFailure(error.localizedDescription) - return [] - } - } - set { - let keyPath = #keyPath(StatusEdit.emojis) - let data = try? JSONEncoder().encode(newValue) - willChangeValue(forKey: keyPath) - setPrimitiveValue(data, forKey: keyPath) - didChangeValue(forKey: keyPath) - } - } -} - -extension StatusEdit { - // sourcery: autoUpdatableObject, autoGenerateProperty - @objc public var attachments: [MastodonAttachment] { - get { - let keyPath = #keyPath(StatusEdit.attachments) - willAccessValue(forKey: keyPath) - let _data = primitiveValue(forKey: keyPath) as? Data - didAccessValue(forKey: keyPath) - do { - guard let data = _data else { return [] } - let attachments = try JSONDecoder().decode([MastodonAttachment].self, from: data) - return attachments - } catch { - assertionFailure(error.localizedDescription) - return [] - } - } - set { - let keyPath = #keyPath(StatusEdit.attachments) - let data = try? JSONEncoder().encode(newValue) - willChangeValue(forKey: keyPath) - setPrimitiveValue(data, forKey: keyPath) - didChangeValue(forKey: keyPath) - } - } - -} - -extension StatusEdit { - // sourcery: autoUpdatableObject, autoGenerateProperty - @objc public var poll: Poll? { - get { - let keyPath = #keyPath(StatusEdit.poll) - willAccessValue(forKey: keyPath) - let _data = primitiveValue(forKey: keyPath) as? Data - didAccessValue(forKey: keyPath) - do { - guard let data = _data else { return nil } - let poll = try JSONDecoder().decode(Poll.self, from: data) - return poll - } catch { - return nil - } - } - set { - let keyPath = #keyPath(StatusEdit.poll) - let data = try? JSONEncoder().encode(newValue) - willChangeValue(forKey: keyPath) - setPrimitiveValue(data, forKey: keyPath) - didChangeValue(forKey: keyPath) - } - } - -} - -extension StatusEdit: Managed { - @discardableResult - public static func insert( - into context: NSManagedObjectContext, - property: Property - ) -> StatusEdit { - let object: StatusEdit = context.insertObject() - - object.configure(property: property) - - return object - } -} - -extension StatusEdit: AutoUpdatableObject { - // sourcery:inline:StatusEdit.AutoUpdatableObject - - // Generated using Sourcery - // DO NOT EDIT - public func update(createdAt: Date) { - if self.createdAt != createdAt { - self.createdAt = createdAt - } - } - public func update(content: String) { - if self.content != content { - self.content = content - } - } - public func update(sensitive: Bool) { - if self.sensitive != sensitive { - self.sensitive = sensitive - } - } - public func update(spoilerText: String?) { - if self.spoilerText != spoilerText { - self.spoilerText = spoilerText - } - } - public func update(emojis: [MastodonEmoji]) { - if self.emojis != emojis { - self.emojis = emojis - } - } - public func update(attachments: [MastodonAttachment]) { - if self.attachments != attachments { - self.attachments = attachments - } - } - public func update(poll: Poll?) { - if self.poll != poll { - self.poll = poll - } - } - // sourcery:end - -} - diff --git a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/StatusEdit+Property.swift b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/StatusEdit+Property.swift deleted file mode 100644 index e32d45795..000000000 --- a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/StatusEdit+Property.swift +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright © 2023 Mastodon gGmbH. All rights reserved. - -import Foundation -import CoreDataStack -import MastodonSDK - -extension StatusEdit.Property { - init(entity: Mastodon.Entity.StatusEdit) { - self.init( - createdAt: entity.createdAt, - content: entity.content, - sensitive: entity.sensitive, - spoilerText: entity.spoilerText, - emojis: entity.mastodonEmojis, - attachments: entity.mastodonAttachments, - poll: entity.poll.map { StatusEdit.Poll(options: $0.options.map { StatusEdit.Poll.Option(title: $0.title) } ) } ) - } -} - -extension Mastodon.Entity.StatusEdit { - public var mastodonAttachments: [MastodonAttachment] { - mediaAttachments.mastodonAttachments - } -} diff --git a/MastodonSDK/Sources/MastodonCore/Model/Poll/PollItem.swift b/MastodonSDK/Sources/MastodonCore/Model/Poll/PollItem.swift index 367422752..c0283cbd7 100644 --- a/MastodonSDK/Sources/MastodonCore/Model/Poll/PollItem.swift +++ b/MastodonSDK/Sources/MastodonCore/Model/Poll/PollItem.swift @@ -8,8 +8,9 @@ import Foundation import CoreData import CoreDataStack +import MastodonSDK public enum PollItem: Hashable { case option(record: ManagedObjectRecord) - case history(option: StatusEdit.Poll.Option) + case history(option: Mastodon.Entity.StatusEdit.Poll.Option) } diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+StatusEdit.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+StatusEdit.swift deleted file mode 100644 index be28ec63c..000000000 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+StatusEdit.swift +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright © 2023 Mastodon gGmbH. All rights reserved. - -import CoreData -import CoreDataStack -import MastodonSDK - -extension Persistence.StatusEdit { - - public static func createOrMerge( - in managedObjectContext: NSManagedObjectContext, - statusEdits: [Mastodon.Entity.StatusEdit], - forStatus status: Status - ) { - guard statusEdits.isEmpty == false else { return } - - // remove all edits for status - - if let editHistory = status.editHistory { - for statusEdit in Array(editHistory) { - managedObjectContext.delete(statusEdit) - } - } - status.update(editHistory: Set()) - let persistedEdits = create(in: managedObjectContext, statusEdits: statusEdits, forStatus: status) - status.update(editHistory: Set(persistedEdits)) - } - - public static func create( - in managedObjectContext: NSManagedObjectContext, - statusEdits: [Mastodon.Entity.StatusEdit], - forStatus status: Status - ) -> [StatusEdit] { - - var entries: [StatusEdit] = [] - - for statusEdit in statusEdits { - let property = StatusEdit.Property(createdAt: statusEdit.createdAt, content: statusEdit.content, sensitive: statusEdit.sensitive, spoilerText: statusEdit.spoilerText, emojis: statusEdit.mastodonEmojis, attachments: statusEdit.mastodonAttachments, poll: statusEdit.poll.map { StatusEdit.Poll(options: $0.options.map { StatusEdit.Poll.Option(title: $0.title) } ) }) - let statusEditEntry = StatusEdit.insert(into: managedObjectContext, property: property) - - entries.append(statusEditEntry) - } - - status.update(editHistory: Set(entries)) - - return entries - } -} - diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift index 9142e8b51..3a36dec41 100644 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift @@ -20,7 +20,6 @@ extension Persistence { public enum Tag { } public enum SearchHistory { } public enum Notification { } - public enum StatusEdit {} } extension Persistence { diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+History.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+History.swift index 482dd0019..523f95617 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+History.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+History.swift @@ -33,21 +33,6 @@ extension APIService { domain: domain, authorization: authorization).singleOutput() - guard response.value.isEmpty == false else { return response } - - let managedObjectContext = self.backgroundManagedObjectContext - - try await managedObjectContext.performChanges { - // get status - guard let status = Status.fetch(in: managedObjectContext, configurationBlock: { - $0.predicate = Status.predicate(domain: domain, id: statusID) - }).first else { return } - - Persistence.StatusEdit.createOrMerge(in: managedObjectContext, - statusEdits: response.value, - forStatus: status) - } - return response } @@ -71,32 +56,7 @@ extension APIService { domain: domain, authorization: authorization ).singleOutput() - - #if !APP_EXTENSION - let managedObjectContext = self.backgroundManagedObjectContext - try await managedObjectContext.performChanges { - let me = authenticationBox.authentication.user(in: managedObjectContext) - let status = Persistence.Status.createOrMerge( - in: managedObjectContext, - context: Persistence.Status.PersistContext( - domain: domain, - entity: response.value, - me: me, - statusCache: nil, - userCache: nil, - networkDate: response.networkDate - ) - ) - - Persistence.StatusEdit.createOrMerge( - in: managedObjectContext, - statusEdits: responseHistory.value, - forStatus: status.status - ) - } - #endif - return response } } diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift index eb092a4c6..fd61ff060 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift @@ -14,8 +14,16 @@ extension Mastodon.Entity { /// [Document](https://docs.joinmastodon.org/entities/statusedit/) public class StatusEdit: Codable { public class Poll: Codable { - public class Option: Codable { + public class Option: Codable, Hashable { public let title: String + + public func hash(into hasher: inout Hasher) { + hasher.combine(title) + } + + public static func == (lhs: Mastodon.Entity.StatusEdit.Poll.Option, rhs: Mastodon.Entity.StatusEdit.Poll.Option) -> Bool { + lhs.title == rhs.title + } } public let options: [Option] public let title: String? @@ -40,5 +48,17 @@ extension Mastodon.Entity { case mediaAttachments = "media_attachments" case emojis } + + } +} + +extension Mastodon.Entity.StatusEdit: Hashable, Equatable { + public func hash(into hasher: inout Hasher) { + hasher.combine(createdAt) + hasher.combine(content) + } + + public static func == (lhs: Mastodon.Entity.StatusEdit, rhs: Mastodon.Entity.StatusEdit) -> Bool { + lhs.createdAt == rhs.createdAt && lhs.content == rhs.content } } diff --git a/MastodonSDK/Sources/MastodonUI/Protocol/StatusCompatible.swift b/MastodonSDK/Sources/MastodonUI/Protocol/StatusCompatible.swift index 7ae2a932d..5977cba12 100644 --- a/MastodonSDK/Sources/MastodonUI/Protocol/StatusCompatible.swift +++ b/MastodonSDK/Sources/MastodonUI/Protocol/StatusCompatible.swift @@ -11,17 +11,3 @@ public protocol StatusCompatible { } extension Status: StatusCompatible {} - -extension StatusEdit: StatusCompatible { - public var reblog: Status? { - nil - } - - public var isMediaSensitive: Bool { - sensitive - } - - public var isSensitiveToggled: Bool { - true - } -} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift index 173f043f6..e3bed16ae 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift @@ -13,6 +13,7 @@ import CoreDataStack import Photos import AlamofireImage import MastodonCore +import MastodonSDK extension MediaView { public class Configuration: Hashable { @@ -243,3 +244,86 @@ extension MediaView { return configurations } } + +extension MediaView { + public static func configuration(status: Mastodon.Entity.StatusEdit) -> [MediaView.Configuration] { + func aspectRatio(from attachment: Mastodon.Entity.Attachment) -> CGSize? { + if let width = attachment.meta?.original?.width, let height = attachment.meta?.original?.height { + return CGSize(width: width, height: height) + } else if let width = attachment.meta?.width, let height = attachment.meta?.height { + return CGSize(width: width, height: height) + } + return nil + } + + func videoInfo(from attachment: Mastodon.Entity.Attachment) -> MediaView.Configuration.VideoInfo? { + guard let aspectRatio = aspectRatio(from: attachment) else { return nil } + return MediaView.Configuration.VideoInfo( + aspectRadio: aspectRatio, + assetURL: attachment.url, + previewURL: attachment.previewURL, + altDescription: attachment.description, + durationMS: { + guard let duration = attachment.meta?.duration else { + return 0 + } + return Int(duration) + }() + ) + } + + let attachments = status.mediaAttachments ?? [] + let configurations = attachments.enumerated().compactMap { (idx, attachment) -> MediaView.Configuration? in + let configuration: MediaView.Configuration? = { + switch attachment.attachmentKind { + case .image: + guard let aspectRatio = aspectRatio(from: attachment) else { return nil } + let info = MediaView.Configuration.ImageInfo( + aspectRadio: aspectRatio, + assetURL: attachment.url, + altDescription: attachment.description + ) + return .init( + info: .image(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .video: + guard let info = videoInfo(from: attachment) else { return nil } + return .init( + info: .video(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .gifv: + guard let info = videoInfo(from: attachment) else { return nil } + return .init( + info: .gif(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .audio: + guard let info = videoInfo(from: attachment) else { return nil } + return .init( + info: .video(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .none: + return nil + } // end switch + }() + + configuration?.load() + configuration?.isReveal = true + + return configuration + } + + return configurations + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift index fcb468d0d..5257fa483 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift @@ -40,7 +40,7 @@ extension StatusView { extension StatusView { - public func configure(status: Status, statusEdit: StatusEdit) { + public func configure(status: Status, statusEdit: Mastodon.Entity.StatusEdit) { viewModel.objects.insert(status) if let reblog = status.reblog { viewModel.objects.insert(reblog) @@ -313,7 +313,7 @@ extension StatusView { } } - private func configureContent(statusEdit: StatusEdit, status: Status) { + private func configureContent(statusEdit: Mastodon.Entity.StatusEdit, status: Status) { statusEdit.spoilerText.map { viewModel.spoilerContent = PlaintextMetaContent(string: $0) } @@ -322,7 +322,7 @@ extension StatusView { viewModel.language = (status.reblog ?? status).language // content do { - let content = MastodonContent(content: statusEdit.content, emojis: statusEdit.emojis.asDictionary) + let content = MastodonContent(content: statusEdit.content, emojis: statusEdit.emojis?.asDictionary ?? [:]) let metaContent = try MastodonMetaContent.convert(document: content) viewModel.content = metaContent viewModel.isCurrentlyTranslating = false @@ -385,7 +385,14 @@ extension StatusView { viewModel.mediaViewConfigurations = configurations } - private func configurePollHistory(statusEdit: StatusEdit) { + private func configureMedia(status: Mastodon.Entity.StatusEdit) { + viewModel.isMediaSensitive = status.sensitive + + let configurations = MediaView.configuration(status: status) + viewModel.mediaViewConfigurations = configurations + } + + private func configurePollHistory(statusEdit: Mastodon.Entity.StatusEdit) { guard let poll = statusEdit.poll else { return } let pollItems = poll.options.map { PollItem.history(option: $0) } @@ -499,13 +506,6 @@ extension StatusView { .assign(to: \.editedAt, on: viewModel) .store(in: &disposeBag) - status.publisher(for: \.editHistory) - .compactMap({ guard let edits = $0 else { return nil } - return Array(edits) - }) - .assign(to: \.statusEdits, on: viewModel) - .store(in: &disposeBag) - // relationship status.publisher(for: \.rebloggedBy) .map { [weak viewModel] rebloggedBy in diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index 86948b5b5..2ff5b6f85 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -99,8 +99,7 @@ extension StatusView { @Published public var replyCount: Int = 0 @Published public var reblogCount: Int = 0 @Published public var favoriteCount: Int = 0 - - @Published public var statusEdits: [StatusEdit] = [] + @Published public var editedAt: Date? = nil // Filter