From bf1ed57180b10eb0afb893ffeb3235e3a8def4c7 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Mon, 25 Sep 2023 21:23:28 -0400 Subject: [PATCH] Allow authoring local-only posts on Akkoma Closes #332 --- .../Sources/ComposeUI/API/PostService.swift | 4 ++-- .../Controllers/ToolbarController.swift | 16 ++++++++++++++-- .../InstanceFeatures/InstanceFeatures.swift | 11 +++++++++++ .../Pachyderm/Sources/Pachyderm/Client.swift | 4 ++-- .../Sources/Pachyderm/Model/Status.swift | 5 ++++- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift b/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift index 5a202928..2097647e 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift @@ -72,12 +72,12 @@ class PostService: ObservableObject { mediaIDs: uploadedAttachments, sensitive: sensitive, spoilerText: contentWarning, - visibility: draft.visibility, + visibility: draft.localOnly && mastodonController.instanceFeatures.localOnlyPostsVisibility ? Status.localPostVisibility : draft.visibility.rawValue, language: mastodonController.instanceFeatures.createStatusWithLanguage ? draft.language : nil, pollOptions: draft.poll?.pollOptions.map(\.text), pollExpiresIn: draft.poll == nil ? nil : Int(draft.poll!.duration), pollMultiple: draft.poll?.multiple, - localOnly: mastodonController.instanceFeatures.localOnlyPosts ? draft.localOnly : nil, + localOnly: mastodonController.instanceFeatures.localOnlyPosts && !mastodonController.instanceFeatures.localOnlyPostsVisibility ? draft.localOnly : nil, idempotencyKey: draft.id.uuidString ) } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Controllers/ToolbarController.swift b/Packages/ComposeUI/Sources/ComposeUI/Controllers/ToolbarController.swift index b96d2c6f..7ebe6622 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Controllers/ToolbarController.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Controllers/ToolbarController.swift @@ -53,10 +53,11 @@ class ToolbarController: ViewController { HStack(spacing: 0) { cwButton - MenuPicker(selection: $draft.visibility, options: visibilityOptions, buttonStyle: .iconOnly) + MenuPicker(selection: visibilityBinding, options: visibilityOptions, buttonStyle: .iconOnly) // the button has a bunch of extra space by default, but combined with what we add it's too much .padding(.horizontal, -8) .disabled(draft.editedStatusID != nil) + .disabled(composeController.mastodonController.instanceFeatures.localOnlyPostsVisibility && draft.localOnly) if composeController.mastodonController.instanceFeatures.localOnlyPosts { localOnlyPicker @@ -118,9 +119,20 @@ class ToolbarController: ViewController { .hoverEffect() } + private var visibilityBinding: Binding { + // On instances that conflate visibliity and local only, we still show two separate controls but don't allow + // changing the visibility when local-only. + if draft.localOnly, + composeController.mastodonController.instanceFeatures.localOnlyPostsVisibility { + return .constant(.public) + } else { + return $draft.visibility + } + } + private var visibilityOptions: [MenuPicker.Option] { let visibilities: [Pachyderm.Visibility] - if !controller.parent.mastodonController.instanceFeatures.composeDirectStatuses { + if !composeController.mastodonController.instanceFeatures.composeDirectStatuses { visibilities = [.public, .unlisted, .private] } else { visibilities = Pachyderm.Visibility.allCases diff --git a/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift b/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift index 263a3287..69f977a8 100644 --- a/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift +++ b/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift @@ -27,11 +27,22 @@ public class InstanceFeatures: ObservableObject { switch instanceType { case .mastodon(.hometown(_), _), .mastodon(.glitch, _): return true + case .pleroma(.akkoma(_)): + return true default: return false } } + /// Instance types that use a separate visibility to indicate local-only posts. + public var localOnlyPostsVisibility: Bool { + if case .pleroma(.akkoma(_)) = instanceType { + return true + } else { + return false + } + } + public var mastodonAttachmentRestrictions: Bool { instanceType.isMastodon } diff --git a/Packages/Pachyderm/Sources/Pachyderm/Client.swift b/Packages/Pachyderm/Sources/Pachyderm/Client.swift index b5ad328b..c5a95407 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Client.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Client.swift @@ -396,7 +396,7 @@ public class Client { mediaIDs: [String]? = nil, sensitive: Bool? = nil, spoilerText: String? = nil, - visibility: Visibility? = nil, + visibility: String? = nil, language: String? = nil, // language supported by mastodon and akkoma pollOptions: [String]? = nil, pollExpiresIn: Int? = nil, @@ -409,7 +409,7 @@ public class Client { "in_reply_to_id" => inReplyTo, "sensitive" => sensitive, "spoiler_text" => spoilerText, - "visibility" => visibility?.rawValue, + "visibility" => visibility, "language" => language, "poll[expires_in]" => pollExpiresIn, "poll[multiple]" => pollMultiple, diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift index 8f07e2b0..3806dd22 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift @@ -10,6 +10,9 @@ import Foundation import WebURL public final class Status: StatusProtocol, Decodable, Sendable { + /// The pseudo-visibility used by instance types (Akkoma) that overload the visibility for local-only posts. + public static let localPostVisibility: String = "local" + public let id: String public let uri: String public let url: WebURL? @@ -77,7 +80,7 @@ public final class Status: StatusProtocol, Decodable, Sendable { self.visibility = visibility self.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) } else if let s = try? container.decode(String.self, forKey: .visibility), - s == "local" { + s == Status.localPostVisibility { // hacky workaround for #332, akkoma describes local posts with a separate visibility self.visibility = .public self.localOnly = true