From 1806f9a350b5d8b7d462a0c510a02cd988a74f9f Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Thu, 9 Nov 2023 13:01:02 +0100 Subject: [PATCH 1/4] Replace CoreData.StatusEdit by Mastodon.Entity.StatusEdit --- Mastodon/Coordinator/SceneCoordinator.swift | 1 + ...Provider+StatusTableViewCellDelegate.swift | 21 +++-- .../PollOptionView+Configuration.swift | 3 +- .../StatusEditHistoryTableViewCell.swift | 2 +- .../StatusEditHistoryViewController.swift | 6 +- .../StatusEditHistoryViewModel.swift | 3 +- .../Mastodon+Entity+StatusEdit.swift | 15 ++++ .../MastodonCore/Model/Poll/PollItem.swift | 3 +- .../Entity/Mastodon+Entity+StatusEdit.swift | 15 +++- .../Content/MediaView+Configuration.swift | 80 +++++++++++++++++++ .../Content/StatusView+Configuration.swift | 15 +++- 11 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index a12d3509f9..1ef1dcb65d 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -571,6 +571,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 dafd65fdf4..68be145e2d 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 0e3f07f66d..631e5b337f 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 06520462d9..3485cfeab5 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 52dfd3cc2d..a09242b4a4 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 a5d778bec0..525f7e72a7 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/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift b/MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift new file mode 100644 index 0000000000..ba43924859 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift @@ -0,0 +1,15 @@ +// Copyright © 2023 Mastodon gGmbH. All rights reserved. + +import Foundation +import MastodonSDK + +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/MastodonCore/Model/Poll/PollItem.swift b/MastodonSDK/Sources/MastodonCore/Model/Poll/PollItem.swift index 367422752e..c0283cbd7e 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/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift index eb092a4c69..b1697b00c8 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift @@ -14,11 +14,23 @@ 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? + +// public static func == (lhs: Mastodon.Entity.StatusEdit.Poll, rhs: Mastodon.Entity.StatusEdit.Poll) -> Bool { +// lhs.title == rhs.title && lhs.options == rhs.options +// } } public let content: String @@ -40,5 +52,6 @@ extension Mastodon.Entity { case mediaAttachments = "media_attachments" case emojis } + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift index 173f043f66..4ce5da9115 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,82 @@ extension MediaView { return configurations } } + +extension MediaView { + public static func configuration(status: Mastodon.Entity.StatusEdit) -> [MediaView.Configuration] { + func aspectRatio(from attachment: Mastodon.Entity.Attachment) -> CGSize { + guard let width = attachment.meta?.width, let height = attachment.meta?.height else { + return .zero + } + return CGSize(width: width, height: height) + } + + func videoInfo(from attachment: Mastodon.Entity.Attachment) -> MediaView.Configuration.VideoInfo { + MediaView.Configuration.VideoInfo( + aspectRadio: aspectRatio(from: attachment), + assetURL: attachment.remoteURL, + 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: + let info = MediaView.Configuration.ImageInfo( + aspectRadio: aspectRatio(from: attachment), + assetURL: attachment.remoteURL, + altDescription: attachment.description + ) + return .init( + info: .image(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .video: + let info = videoInfo(from: attachment) + return .init( + info: .video(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .gifv: + let info = videoInfo(from: attachment) + return .init( + info: .gif(info: info), + blurhash: attachment.blurhash, + index: idx, + total: attachments.count + ) + case .audio: + let info = videoInfo(from: attachment) + 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 fcb468d0da..4ed4c603e8 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) } From 79f978cee7ce33bd84a0c63c002e01bd7a358637 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Thu, 9 Nov 2023 13:27:10 +0100 Subject: [PATCH 2/4] Remove CoreData entities and references of StatusEdit --- .../CoreData 9.xcdatamodel/contents | 14 +- .../Entity/Mastodon/Status.swift | 6 - .../Entity/Mastodon/StatusEdit.swift | 226 ------------------ .../CoreDataStack/StatusEdit+Property.swift | 24 -- .../Persistence/Persistence+StatusEdit.swift | 48 ---- .../Persistence/Persistence.swift | 1 - .../API/APIService+Status+History.swift | 40 ---- .../Protocol/StatusCompatible.swift | 14 -- .../Content/StatusView+Configuration.swift | 7 - .../View/Content/StatusView+ViewModel.swift | 3 +- 10 files changed, 2 insertions(+), 381 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/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 9.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 9.xcdatamodel/contents index ee57231f28..c5bbd1485c 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 736d4b7ebd..1bdd9410a9 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 1cb7aa1a44..0000000000 --- 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 e32d45795b..0000000000 --- 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/Persistence/Persistence+StatusEdit.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+StatusEdit.swift deleted file mode 100644 index be28ec63c5..0000000000 --- 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 9142e8b51b..3a36dec418 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 482dd0019a..523f956173 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/MastodonUI/Protocol/StatusCompatible.swift b/MastodonSDK/Sources/MastodonUI/Protocol/StatusCompatible.swift index 7ae2a932d3..5977cba12a 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/StatusView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift index 4ed4c603e8..5257fa4839 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift @@ -506,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 86948b5b5a..2ff5b6f852 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 From 5fbecdab2d7a3759194cf8a15dc64cb6df5651dd Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Fri, 10 Nov 2023 10:50:18 +0100 Subject: [PATCH 3/4] Fix Crash when returning CGSize.zero for Media Attachment in Edit History (IOS-175) --- .../Content/MediaView+Configuration.swift | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift index 4ce5da9115..e3bed16ae9 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift @@ -247,17 +247,20 @@ extension MediaView { extension MediaView { public static func configuration(status: Mastodon.Entity.StatusEdit) -> [MediaView.Configuration] { - func aspectRatio(from attachment: Mastodon.Entity.Attachment) -> CGSize { - guard let width = attachment.meta?.width, let height = attachment.meta?.height else { - return .zero + 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 CGSize(width: width, height: height) + return nil } - func videoInfo(from attachment: Mastodon.Entity.Attachment) -> MediaView.Configuration.VideoInfo { - MediaView.Configuration.VideoInfo( - aspectRadio: aspectRatio(from: attachment), - assetURL: attachment.remoteURL, + 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: { @@ -274,9 +277,10 @@ extension MediaView { 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(from: attachment), - assetURL: attachment.remoteURL, + aspectRadio: aspectRatio, + assetURL: attachment.url, altDescription: attachment.description ) return .init( @@ -286,7 +290,7 @@ extension MediaView { total: attachments.count ) case .video: - let info = videoInfo(from: attachment) + guard let info = videoInfo(from: attachment) else { return nil } return .init( info: .video(info: info), blurhash: attachment.blurhash, @@ -294,7 +298,7 @@ extension MediaView { total: attachments.count ) case .gifv: - let info = videoInfo(from: attachment) + guard let info = videoInfo(from: attachment) else { return nil } return .init( info: .gif(info: info), blurhash: attachment.blurhash, @@ -302,7 +306,7 @@ extension MediaView { total: attachments.count ) case .audio: - let info = videoInfo(from: attachment) + guard let info = videoInfo(from: attachment) else { return nil } return .init( info: .video(info: info), blurhash: attachment.blurhash, From 7d4182001572ed29f3647e6e2d12352a5cf5327d Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Fri, 10 Nov 2023 10:53:29 +0100 Subject: [PATCH 4/4] Cleanup Mastodon+Entity+StatusEdit (IOS-175) --- .../MastodonSDK/Mastodon+Entity+StatusEdit.swift | 15 --------------- .../Entity/Mastodon+Entity+StatusEdit.swift | 15 +++++++++++---- 2 files changed, 11 insertions(+), 19 deletions(-) delete mode 100644 MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift diff --git a/MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift b/MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift deleted file mode 100644 index ba43924859..0000000000 --- a/MastodonSDK/Sources/MastodonCore/Extension/MastodonSDK/Mastodon+Entity+StatusEdit.swift +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2023 Mastodon gGmbH. All rights reserved. - -import Foundation -import MastodonSDK - -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/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift index b1697b00c8..fd61ff0601 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+StatusEdit.swift @@ -27,10 +27,6 @@ extension Mastodon.Entity { } public let options: [Option] public let title: String? - -// public static func == (lhs: Mastodon.Entity.StatusEdit.Poll, rhs: Mastodon.Entity.StatusEdit.Poll) -> Bool { -// lhs.title == rhs.title && lhs.options == rhs.options -// } } public let content: String @@ -55,3 +51,14 @@ extension Mastodon.Entity { } } + +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 + } +}