From a46eaafbcf537c74cc2c87be084bc9d395adf3f9 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Fri, 27 Oct 2023 17:00:53 -0500 Subject: [PATCH] Add reply policy and exclusive fields to lists --- .../Sources/Pachyderm/Model/List.swift | 25 ++++++++++++++--- .../Model/Protocols/ListProtocol.swift | 2 ++ Tusker/API/MastodonController.swift | 8 ++---- Tusker/API/RenameListService.swift | 2 +- Tusker/CoreData/ListMO.swift | 27 +++++++++++++++++++ .../Tusker.xcdatamodel/contents | 2 ++ Tusker/Scenes/AuxiliarySceneDelegate.swift | 2 +- 7 files changed, 57 insertions(+), 11 deletions(-) diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/List.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/List.swift index 491035ab..e8dfdde9 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/List.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/List.swift @@ -11,14 +11,18 @@ import Foundation public struct List: ListProtocol, Decodable, Equatable, Hashable, Sendable { public let id: String public let title: String + public let replyPolicy: ReplyPolicy? + public let exclusive: Bool? public var timeline: Timeline { return .list(id: id) } - public init(id: String, title: String) { + public init(id: String, title: String, replyPolicy: ReplyPolicy?, exclusive: Bool?) { self.id = id self.title = title + self.replyPolicy = replyPolicy + self.exclusive = exclusive } public static func ==(lhs: List, rhs: List) -> Bool { @@ -36,8 +40,15 @@ public struct List: ListProtocol, Decodable, Equatable, Hashable, Sendable { return request } - public static func update(_ listID: String, title: String) -> Request { - return Request(method: .put, path: "/api/v1/lists/\(listID)", body: ParametersBody(["title" => title])) + public static func update(_ listID: String, title: String, replyPolicy: ReplyPolicy?, exclusive: Bool?) -> Request { + var params = ["title" => title] + if let replyPolicy { + params.append("replies_policy" => replyPolicy.rawValue) + } + if let exclusive { + params.append("exclusive" => exclusive) + } + return Request(method: .put, path: "/api/v1/lists/\(listID)", body: ParametersBody(params)) } public static func delete(_ listID: String) -> Request { @@ -59,5 +70,13 @@ public struct List: ListProtocol, Decodable, Equatable, Hashable, Sendable { private enum CodingKeys: String, CodingKey { case id case title + case replyPolicy = "replies_policy" + case exclusive + } +} + +extension List { + public enum ReplyPolicy: String, Codable, Hashable, CaseIterable, Sendable { + case followed, list, none } } diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/ListProtocol.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/ListProtocol.swift index d9d5291d..efe3a76f 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/ListProtocol.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/ListProtocol.swift @@ -10,4 +10,6 @@ import Foundation public protocol ListProtocol { var id: String { get } var title: String { get } + var replyPolicy: List.ReplyPolicy? { get } + var exclusive: Bool? { get } } diff --git a/Tusker/API/MastodonController.swift b/Tusker/API/MastodonController.swift index e3bd73c8..5cb73fa1 100644 --- a/Tusker/API/MastodonController.swift +++ b/Tusker/API/MastodonController.swift @@ -449,16 +449,12 @@ class MastodonController: ObservableObject { guard let lists = try? persistentContainer.viewContext.fetch(req) else { return [] } - return lists.map { - List(id: $0.id, title: $0.title) - }.sorted(using: SemiCaseSensitiveComparator.keyPath(\.title)) + return lists.map(\.apiList).sorted(using: SemiCaseSensitiveComparator.keyPath(\.title)) } func getCachedList(id: String) -> List? { let req = ListMO.fetchRequest(id: id) - return (try? persistentContainer.viewContext.fetch(req).first).flatMap { - List(id: $0.id, title: $0.title) - } + return (try? persistentContainer.viewContext.fetch(req).first).map(\.apiList) } @MainActor diff --git a/Tusker/API/RenameListService.swift b/Tusker/API/RenameListService.swift index 9f3a9789..45931ceb 100644 --- a/Tusker/API/RenameListService.swift +++ b/Tusker/API/RenameListService.swift @@ -47,7 +47,7 @@ class RenameListService { private func updateList(with title: String) async { do { - let req = List.update(list.id, title: title) + let req = List.update(list.id, title: title, replyPolicy: nil, exclusive: nil) let (list, _) = try await mastodonController.run(req) mastodonController.renamedList(list) } catch { diff --git a/Tusker/CoreData/ListMO.swift b/Tusker/CoreData/ListMO.swift index b9cc59fb..d22a3942 100644 --- a/Tusker/CoreData/ListMO.swift +++ b/Tusker/CoreData/ListMO.swift @@ -25,6 +25,22 @@ public final class ListMO: NSManagedObject, ListProtocol { @NSManaged public var id: String @NSManaged public var title: String + @NSManaged private var replyPolicyString: String? + @NSManaged private var exclusiveInternal: Bool + + public var replyPolicy: List.ReplyPolicy? { + get { + replyPolicyString.flatMap(List.ReplyPolicy.init(rawValue:)) + } + set { + replyPolicyString = newValue?.rawValue + } + } + + public var exclusive: Bool? { + get { exclusiveInternal } + set { exclusiveInternal = newValue ?? false } + } } @@ -37,5 +53,16 @@ extension ListMO { func updateFrom(apiList list: List) { self.id = list.id self.title = list.title + self.replyPolicy = list.replyPolicy + self.exclusive = list.exclusive + } + + var apiList: List { + List( + id: id, + title: title, + replyPolicy: replyPolicy, + exclusive: exclusive + ) } } diff --git a/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents b/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents index efa6cd2a..ba52345a 100644 --- a/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents +++ b/Tusker/CoreData/Tusker.xcdatamodeld/Tusker.xcdatamodel/contents @@ -62,7 +62,9 @@ + + diff --git a/Tusker/Scenes/AuxiliarySceneDelegate.swift b/Tusker/Scenes/AuxiliarySceneDelegate.swift index 81b09431..284516a7 100644 --- a/Tusker/Scenes/AuxiliarySceneDelegate.swift +++ b/Tusker/Scenes/AuxiliarySceneDelegate.swift @@ -112,7 +112,7 @@ class AuxiliarySceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDel case .list(id: let id): let req = ListMO.fetchRequest(id: id) if let list = try? mastodonController.persistentContainer.viewContext.fetch(req).first { - return ListTimelineViewController(for: List(id: id, title: list.title), mastodonController: mastodonController) + return ListTimelineViewController(for: list.apiList, mastodonController: mastodonController) } else { return TimelineViewController(for: timeline, mastodonController: mastodonController) }