forked from shadowfacts/Tusker
parent
dfc8234908
commit
6e5e0c3bb5
|
@ -81,6 +81,7 @@ public class DraftsPersistentContainer: NSPersistentContainer {
|
||||||
contentWarning: String,
|
contentWarning: String,
|
||||||
inReplyToID: String?,
|
inReplyToID: String?,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
|
language: String?,
|
||||||
localOnly: Bool
|
localOnly: Bool
|
||||||
) -> Draft {
|
) -> Draft {
|
||||||
let draft = Draft(context: viewContext)
|
let draft = Draft(context: viewContext)
|
||||||
|
@ -92,6 +93,7 @@ public class DraftsPersistentContainer: NSPersistentContainer {
|
||||||
draft.contentWarningEnabled = !contentWarning.isEmpty
|
draft.contentWarningEnabled = !contentWarning.isEmpty
|
||||||
draft.inReplyToID = inReplyToID
|
draft.inReplyToID = inReplyToID
|
||||||
draft.visibility = visibility
|
draft.visibility = visibility
|
||||||
|
draft.language = language
|
||||||
draft.localOnly = localOnly
|
draft.localOnly = localOnly
|
||||||
save()
|
save()
|
||||||
return draft
|
return draft
|
||||||
|
|
|
@ -171,6 +171,10 @@ public class InstanceFeatures: ObservableObject {
|
||||||
hasMastodonVersion(4, 2, 0)
|
hasMastodonVersion(4, 2, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var hasServerPreferences: Bool {
|
||||||
|
hasMastodonVersion(2, 8, 0)
|
||||||
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,20 @@ public class Client {
|
||||||
return task
|
return task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
public func run<Result: Sendable>(_ request: Request<Result>) async throws -> (Result, Pagination?) {
|
||||||
|
return try await withCheckedThrowingContinuation { continuation in
|
||||||
|
run(request) { response in
|
||||||
|
switch response {
|
||||||
|
case .failure(let error):
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
case .success(let result, let pagination):
|
||||||
|
continuation.resume(returning: (result, pagination))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createURLRequest<Result>(request: Request<Result>) -> URLRequest? {
|
func createURLRequest<Result>(request: Request<Result>) -> URLRequest? {
|
||||||
guard var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true) else { return nil }
|
guard var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true) else { return nil }
|
||||||
components.path = request.endpoint.path
|
components.path = request.endpoint.path
|
||||||
|
@ -225,6 +239,10 @@ public class Client {
|
||||||
return Request<[Emoji]>(method: .get, path: "/api/v1/custom_emojis")
|
return Request<[Emoji]>(method: .get, path: "/api/v1/custom_emojis")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func getPreferences() -> Request<Preferences> {
|
||||||
|
return Request(method: .get, path: "/api/v1/preferences")
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Accounts
|
// MARK: - Accounts
|
||||||
public static func getAccount(id: String) -> Request<Account> {
|
public static func getAccount(id: String) -> Request<Account> {
|
||||||
return Request<Account>(method: .get, path: "/api/v1/accounts/\(id)")
|
return Request<Account>(method: .get, path: "/api/v1/accounts/\(id)")
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// Preferences.swift
|
||||||
|
// Pachyderm
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 10/26/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct Preferences: Codable, Sendable {
|
||||||
|
public let postingDefaultVisibility: Visibility
|
||||||
|
public let postingDefaultSensitive: Bool
|
||||||
|
public let postingDefaultLanguage: String
|
||||||
|
public let readingExpandMedia: ExpandMedia
|
||||||
|
public let readingExpandSpoilers: Bool
|
||||||
|
public let readingAutoplayGifs: Bool
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case postingDefaultVisibility = "posting:default:visibility"
|
||||||
|
case postingDefaultSensitive = "posting:default:sensitive"
|
||||||
|
case postingDefaultLanguage = "posting:default:language"
|
||||||
|
case readingExpandMedia = "reading:expand:media"
|
||||||
|
case readingExpandSpoilers = "reading:expand:spoilers"
|
||||||
|
case readingAutoplayGifs = "reading:autoplay:gifs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Preferences {
|
||||||
|
public enum ExpandMedia: String, Codable, Sendable {
|
||||||
|
case `default`
|
||||||
|
case always = "show_all"
|
||||||
|
case never = "hide_all"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
//
|
||||||
|
// PostVisibility.swift
|
||||||
|
// TuskerPreferences
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 10/26/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
|
public enum PostVisibility: Codable, Hashable, CaseIterable {
|
||||||
|
case serverDefault
|
||||||
|
case visibility(Visibility)
|
||||||
|
|
||||||
|
public static var allCases: [PostVisibility] = [.serverDefault] + Visibility.allCases.map { .visibility($0) }
|
||||||
|
|
||||||
|
public func resolved(withServerDefault serverDefault: Visibility?) -> Visibility {
|
||||||
|
switch self {
|
||||||
|
case .serverDefault:
|
||||||
|
// If the server doesn't have a default visibility preference, we fallback to public.
|
||||||
|
// This isn't ideal, but I don't want to add a separate preference for "Default Post Visibility Fallback" :/
|
||||||
|
serverDefault ?? .public
|
||||||
|
case .visibility(let vis):
|
||||||
|
vis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func resolved(withServerDefault serverDefault: () async -> Visibility?) async -> Visibility {
|
||||||
|
switch self {
|
||||||
|
case .serverDefault:
|
||||||
|
await serverDefault() ?? .public
|
||||||
|
case .visibility(let vis):
|
||||||
|
vis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var displayName: String {
|
||||||
|
switch self {
|
||||||
|
case .serverDefault:
|
||||||
|
return "Account Default"
|
||||||
|
case .visibility(let vis):
|
||||||
|
return vis.displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var imageName: String? {
|
||||||
|
switch self {
|
||||||
|
case .serverDefault:
|
||||||
|
return nil
|
||||||
|
case .visibility(let vis):
|
||||||
|
return vis.imageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ReplyVisibility: Codable, Hashable, CaseIterable {
|
||||||
|
case sameAsPost
|
||||||
|
case visibility(Visibility)
|
||||||
|
|
||||||
|
public static var allCases: [ReplyVisibility] = [.sameAsPost] + Visibility.allCases.map { .visibility($0) }
|
||||||
|
|
||||||
|
public func resolved(withServerDefault serverDefault: Visibility?) -> Visibility {
|
||||||
|
switch self {
|
||||||
|
case .sameAsPost:
|
||||||
|
Preferences.shared.defaultPostVisibility.resolved(withServerDefault: serverDefault)
|
||||||
|
case .visibility(let vis):
|
||||||
|
vis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func resolved(withServerDefault serverDefault: () async -> Visibility?) async -> Visibility {
|
||||||
|
switch self {
|
||||||
|
case .sameAsPost:
|
||||||
|
await Preferences.shared.defaultPostVisibility.resolved(withServerDefault: serverDefault)
|
||||||
|
case .visibility(let vis):
|
||||||
|
vis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var displayName: String {
|
||||||
|
switch self {
|
||||||
|
case .sameAsPost:
|
||||||
|
return "Same as Default"
|
||||||
|
case .visibility(let vis):
|
||||||
|
return vis.displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var imageName: String? {
|
||||||
|
switch self {
|
||||||
|
case .sameAsPost:
|
||||||
|
return nil
|
||||||
|
case .visibility(let vis):
|
||||||
|
return vis.imageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,7 +63,11 @@ public final class Preferences: Codable, ObservableObject {
|
||||||
self.widescreenNavigationMode = try container.decodeIfPresent(WidescreenNavigationMode.self, forKey: .widescreenNavigationMode) ?? Self.defaultWidescreenNavigationMode
|
self.widescreenNavigationMode = try container.decodeIfPresent(WidescreenNavigationMode.self, forKey: .widescreenNavigationMode) ?? Self.defaultWidescreenNavigationMode
|
||||||
self.underlineTextLinks = try container.decodeIfPresent(Bool.self, forKey: .underlineTextLinks) ?? false
|
self.underlineTextLinks = try container.decodeIfPresent(Bool.self, forKey: .underlineTextLinks) ?? false
|
||||||
|
|
||||||
self.defaultPostVisibility = try container.decode(Visibility.self, forKey: .defaultPostVisibility)
|
if let existing = try? container.decode(Visibility.self, forKey: .defaultPostVisibility) {
|
||||||
|
self.defaultPostVisibility = .visibility(existing)
|
||||||
|
} else {
|
||||||
|
self.defaultPostVisibility = try container.decode(PostVisibility.self, forKey: .defaultPostVisibility)
|
||||||
|
}
|
||||||
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
|
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
|
||||||
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
||||||
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
||||||
|
@ -180,7 +184,7 @@ public final class Preferences: Codable, ObservableObject {
|
||||||
@Published public var underlineTextLinks = false
|
@Published public var underlineTextLinks = false
|
||||||
|
|
||||||
// MARK: Composing
|
// MARK: Composing
|
||||||
@Published public var defaultPostVisibility = Visibility.public
|
@Published public var defaultPostVisibility = PostVisibility.serverDefault
|
||||||
@Published public var defaultReplyVisibility = ReplyVisibility.sameAsPost
|
@Published public var defaultReplyVisibility = ReplyVisibility.sameAsPost
|
||||||
@Published public var requireAttachmentDescriptions = false
|
@Published public var requireAttachmentDescriptions = false
|
||||||
@Published public var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
@Published public var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
||||||
|
@ -292,42 +296,6 @@ public final class Preferences: Codable, ObservableObject {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Preferences {
|
|
||||||
public enum ReplyVisibility: Codable, Hashable, CaseIterable {
|
|
||||||
case sameAsPost
|
|
||||||
case visibility(Visibility)
|
|
||||||
|
|
||||||
public static var allCases: [Preferences.ReplyVisibility] = [.sameAsPost] + Visibility.allCases.map { .visibility($0) }
|
|
||||||
|
|
||||||
public var resolved: Visibility {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return Preferences.shared.defaultPostVisibility
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var displayName: String {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return "Same as Default"
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis.displayName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var imageName: String? {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return nil
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis.imageName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Preferences {
|
extension Preferences {
|
||||||
public enum AttachmentBlurMode: Codable, Hashable, CaseIterable {
|
public enum AttachmentBlurMode: Codable, Hashable, CaseIterable {
|
||||||
case useStatusSetting
|
case useStatusSetting
|
||||||
|
|
|
@ -12,6 +12,7 @@ import ComposeUI
|
||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
import TuskerPreferences
|
import TuskerPreferences
|
||||||
import Combine
|
import Combine
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
class ShareViewController: UIViewController {
|
class ShareViewController: UIViewController {
|
||||||
|
|
||||||
|
@ -50,21 +51,26 @@ class ShareViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createDraft(account: UserAccountInfo) async -> Draft {
|
private func createDraft(account: UserAccountInfo) async -> Draft {
|
||||||
let (text, attachments) = await getDraftConfigurationFromExtensionContext()
|
async let (text, attachments) = getDraftConfigurationFromExtensionContext()
|
||||||
|
|
||||||
|
// TODO: I really don't like that there's a network request in the hot path here, but we don't have easy access to AccountPreferences :/
|
||||||
|
let serverPrefs = try? await Client(baseURL: account.instanceURL, accessToken: account.accessToken).run(Client.getPreferences()).0
|
||||||
|
let visibility = Preferences.shared.defaultPostVisibility.resolved(withServerDefault: serverPrefs?.postingDefaultVisibility)
|
||||||
|
|
||||||
let draft = DraftsPersistentContainer.shared.createDraft(
|
let draft = DraftsPersistentContainer.shared.createDraft(
|
||||||
accountID: account.id,
|
accountID: account.id,
|
||||||
text: text,
|
text: await text,
|
||||||
contentWarning: "",
|
contentWarning: "",
|
||||||
inReplyToID: nil,
|
inReplyToID: nil,
|
||||||
visibility: Preferences.shared.defaultPostVisibility,
|
visibility: visibility,
|
||||||
|
language: serverPrefs?.postingDefaultLanguage,
|
||||||
localOnly: false
|
localOnly: false
|
||||||
)
|
)
|
||||||
|
|
||||||
for attachment in attachments {
|
for attachment in await attachments {
|
||||||
DraftsPersistentContainer.shared.viewContext.insert(attachment)
|
DraftsPersistentContainer.shared.viewContext.insert(attachment)
|
||||||
}
|
}
|
||||||
draft.draftAttachments = attachments
|
draft.draftAttachments = await attachments
|
||||||
|
|
||||||
return draft
|
return draft
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,6 +193,8 @@ class MastodonController: ObservableObject {
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func initialize() {
|
func initialize() {
|
||||||
|
precondition(!transient, "Cannot initialize transient MastodonController")
|
||||||
|
|
||||||
// we want this to happen immediately, and synchronously so that the filters (which don't change that often)
|
// we want this to happen immediately, and synchronously so that the filters (which don't change that often)
|
||||||
// are available when Filterers are constructed
|
// are available when Filterers are constructed
|
||||||
loadCachedFilters()
|
loadCachedFilters()
|
||||||
|
@ -217,6 +219,7 @@ class MastodonController: ObservableObject {
|
||||||
|
|
||||||
loadLists()
|
loadLists()
|
||||||
_ = await loadFilters()
|
_ = await loadFilters()
|
||||||
|
await loadServerPreferences()
|
||||||
} catch {
|
} catch {
|
||||||
Logging.general.error("MastodonController initialization failed: \(String(describing: error))")
|
Logging.general.error("MastodonController initialization failed: \(String(describing: error))")
|
||||||
}
|
}
|
||||||
|
@ -358,6 +361,17 @@ class MastodonController: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MainActor because the accountPreferences instance is bound to the view context
|
||||||
|
@MainActor
|
||||||
|
private func loadServerPreferences() async {
|
||||||
|
guard instanceFeatures.hasServerPreferences,
|
||||||
|
let (prefs, _) = try? await run(Client.getPreferences()) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
accountPreferences!.serverDefaultLanguage = prefs.postingDefaultLanguage
|
||||||
|
accountPreferences!.serverDefaultVisibility = prefs.postingDefaultVisibility
|
||||||
|
}
|
||||||
|
|
||||||
private func updateActiveInstance(from instance: Instance) {
|
private func updateActiveInstance(from instance: Instance) {
|
||||||
persistentContainer.performBackgroundTask { context in
|
persistentContainer.performBackgroundTask { context in
|
||||||
if let existing = try? context.fetch(ActiveInstance.fetchRequest()).first {
|
if let existing = try? context.fetch(ActiveInstance.fetchRequest()).first {
|
||||||
|
@ -519,7 +533,11 @@ class MastodonController: ObservableObject {
|
||||||
func createDraft(inReplyToID: String? = nil, mentioningAcct: String? = nil, text: String? = nil) -> Draft {
|
func createDraft(inReplyToID: String? = nil, mentioningAcct: String? = nil, text: String? = nil) -> Draft {
|
||||||
var acctsToMention = [String]()
|
var acctsToMention = [String]()
|
||||||
|
|
||||||
var visibility = inReplyToID != nil ? Preferences.shared.defaultReplyVisibility.resolved : Preferences.shared.defaultPostVisibility
|
var visibility = if inReplyToID != nil {
|
||||||
|
Preferences.shared.defaultReplyVisibility.resolved(withServerDefault: accountPreferences!.serverDefaultVisibility)
|
||||||
|
} else {
|
||||||
|
Preferences.shared.defaultPostVisibility.resolved(withServerDefault: accountPreferences!.serverDefaultVisibility)
|
||||||
|
}
|
||||||
var localOnly = false
|
var localOnly = false
|
||||||
var contentWarning = ""
|
var contentWarning = ""
|
||||||
|
|
||||||
|
@ -559,6 +577,7 @@ class MastodonController: ObservableObject {
|
||||||
contentWarning: contentWarning,
|
contentWarning: contentWarning,
|
||||||
inReplyToID: inReplyToID,
|
inReplyToID: inReplyToID,
|
||||||
visibility: visibility,
|
visibility: visibility,
|
||||||
|
language: accountPreferences!.serverDefaultLanguage,
|
||||||
localOnly: localOnly
|
localOnly: localOnly
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,21 @@ public final class AccountPreferences: NSManagedObject {
|
||||||
@NSManaged public var accountID: String
|
@NSManaged public var accountID: String
|
||||||
@NSManaged var createdAt: Date
|
@NSManaged var createdAt: Date
|
||||||
@NSManaged var pinnedTimelinesData: Data?
|
@NSManaged var pinnedTimelinesData: Data?
|
||||||
|
@NSManaged var serverDefaultLanguage: String?
|
||||||
|
@NSManaged private var serverDefaultVisibilityString: String?
|
||||||
|
|
||||||
@LazilyDecoding(from: \AccountPreferences.pinnedTimelinesData, fallback: AccountPreferences.defaultPinnedTimelines)
|
@LazilyDecoding(from: \AccountPreferences.pinnedTimelinesData, fallback: AccountPreferences.defaultPinnedTimelines)
|
||||||
var pinnedTimelines: [PinnedTimeline]
|
var pinnedTimelines: [PinnedTimeline]
|
||||||
|
|
||||||
|
var serverDefaultVisibility: Visibility? {
|
||||||
|
get {
|
||||||
|
serverDefaultVisibilityString.flatMap(Visibility.init(rawValue:))
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
serverDefaultVisibilityString = newValue?.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static func `default`(account: UserAccountInfo, context: NSManagedObjectContext) -> AccountPreferences {
|
static func `default`(account: UserAccountInfo, context: NSManagedObjectContext) -> AccountPreferences {
|
||||||
let prefs = AccountPreferences(context: context)
|
let prefs = AccountPreferences(context: context)
|
||||||
prefs.accountID = account.id
|
prefs.accountID = account.id
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21754" systemVersion="22D49" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22225" systemVersion="23A344" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Account" representedClassName="AccountMO" syncable="YES">
|
<entity name="Account" representedClassName="AccountMO" syncable="YES">
|
||||||
<attribute name="acct" attributeType="String"/>
|
<attribute name="acct" attributeType="String"/>
|
||||||
<attribute name="active" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
<attribute name="active" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
|
@ -33,6 +33,8 @@
|
||||||
<attribute name="accountID" optional="YES" attributeType="String"/>
|
<attribute name="accountID" optional="YES" attributeType="String"/>
|
||||||
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="pinnedTimelinesData" optional="YES" attributeType="Binary"/>
|
<attribute name="pinnedTimelinesData" optional="YES" attributeType="Binary"/>
|
||||||
|
<attribute name="serverDefaultLanguage" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="serverDefaultVisibilityString" optional="YES" attributeType="String"/>
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="ActiveInstance" representedClassName="ActiveInstance" syncable="YES">
|
<entity name="ActiveInstance" representedClassName="ActiveInstance" syncable="YES">
|
||||||
<attribute name="configurationData" optional="YES" attributeType="Binary"/>
|
<attribute name="configurationData" optional="YES" attributeType="Binary"/>
|
||||||
|
|
|
@ -28,9 +28,11 @@ struct ComposingPrefsView: View {
|
||||||
var visibilitySection: some View {
|
var visibilitySection: some View {
|
||||||
Section {
|
Section {
|
||||||
Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Visibility")) {
|
Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Visibility")) {
|
||||||
ForEach(Visibility.allCases, id: \.self) { visibility in
|
ForEach(PostVisibility.allCases, id: \.self) { visibility in
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: visibility.imageName)
|
if let imageName = visibility.imageName {
|
||||||
|
Image(systemName: imageName)
|
||||||
|
}
|
||||||
Text(visibility.displayName)
|
Text(visibility.displayName)
|
||||||
}
|
}
|
||||||
.tag(visibility)
|
.tag(visibility)
|
||||||
|
@ -38,7 +40,7 @@ struct ComposingPrefsView: View {
|
||||||
// navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291
|
// navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291
|
||||||
}
|
}
|
||||||
Picker(selection: $preferences.defaultReplyVisibility, label: Text("Reply Visibility")) {
|
Picker(selection: $preferences.defaultReplyVisibility, label: Text("Reply Visibility")) {
|
||||||
ForEach(Preferences.ReplyVisibility.allCases, id: \.self) { visibility in
|
ForEach(ReplyVisibility.allCases, id: \.self) { visibility in
|
||||||
HStack {
|
HStack {
|
||||||
if let imageName = visibility.imageName {
|
if let imageName = visibility.imageName {
|
||||||
Image(systemName: imageName)
|
Image(systemName: imageName)
|
||||||
|
|
Loading…
Reference in New Issue