Move Visibility to top-level type and move extensions to Pachyderm

This commit is contained in:
Shadowfacts 2023-03-07 10:14:35 -05:00
parent 850a0e90ce
commit b2fe2fdf9a
14 changed files with 45 additions and 57 deletions

View File

@ -383,7 +383,7 @@ public class Client {
media: [Attachment]? = nil, media: [Attachment]? = nil,
sensitive: Bool? = nil, sensitive: Bool? = nil,
spoilerText: String? = nil, spoilerText: String? = nil,
visibility: Status.Visibility? = nil, visibility: Visibility? = nil,
language: String? = nil, language: String? = nil,
pollOptions: [String]? = nil, pollOptions: [String]? = nil,
pollExpiresIn: Int? = nil, pollExpiresIn: Int? = nil,

View File

@ -25,7 +25,7 @@ public protocol StatusProtocol {
// var favourited: Bool { get } // var favourited: Bool { get }
var sensitive: Bool { get } var sensitive: Bool { get }
var spoilerText: String { get } var spoilerText: String { get }
var visibility: Pachyderm.Status.Visibility { get } var visibility: Visibility { get }
var applicationName: String? { get } var applicationName: String? { get }
var pinned: Bool? { get } var pinned: Bool? { get }
var bookmarked: Bool? { get } var bookmarked: Bool? { get }

View File

@ -63,7 +63,7 @@ public final class Status: StatusProtocol, Decodable, Sendable {
self.muted = try container.decodeIfPresent(Bool.self, forKey: .muted) self.muted = try container.decodeIfPresent(Bool.self, forKey: .muted)
self.sensitive = try container.decode(Bool.self, forKey: .sensitive) self.sensitive = try container.decode(Bool.self, forKey: .sensitive)
self.spoilerText = try container.decode(String.self, forKey: .spoilerText) self.spoilerText = try container.decode(String.self, forKey: .spoilerText)
if let visibility = try? container.decode(Status.Visibility.self, forKey: .visibility) { if let visibility = try? container.decode(Visibility.self, forKey: .visibility) {
self.visibility = visibility self.visibility = visibility
self.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) self.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly)
} else if let s = try? container.decode(String.self, forKey: .visibility), } else if let s = try? container.decode(String.self, forKey: .visibility),
@ -187,13 +187,4 @@ public final class Status: StatusProtocol, Decodable, Sendable {
} }
} }
extension Status {
public enum Visibility: String, Codable, CaseIterable, Sendable {
case `public`
case unlisted
case `private`
case direct
}
}
extension Status: Identifiable {} extension Status: Identifiable {}

View File

@ -1,16 +1,33 @@
// //
// Visibility+String.swift // Visibility.swift
// Tusker // Pachyderm
// //
// Created by Shadowfacts on 8/29/18. // Created by Shadowfacts on 3/7/23.
// Copyright © 2018 Shadowfacts. All rights reserved.
// //
import Pachyderm import Foundation
import UIKit
extension Status.Visibility { public enum Visibility: String, Sendable, Codable, CaseIterable, Comparable {
case `public`
case unlisted
case `private`
case direct
public static func < (lhs: Visibility, rhs: Visibility) -> Bool {
switch (lhs, rhs) {
case (.direct, .public), (.private, .public), (.unlisted, .public):
return true
case (.direct, .unlisted), (.private, .unlisted):
return true
case (.direct, .private):
return true
default:
return false
}
}
}
public extension Visibility {
var displayName: String { var displayName: String {
switch self { switch self {
case .public: case .public:
@ -62,20 +79,4 @@ extension Status.Visibility {
return "envelope" return "envelope"
} }
} }
}
extension Status.Visibility: Comparable {
public static func < (lhs: Pachyderm.Status.Visibility, rhs: Pachyderm.Status.Visibility) -> Bool {
switch (lhs, rhs) {
case (.direct, .public), (.private, .public), (.unlisted, .public):
return true
case (.direct, .unlisted), (.private, .unlisted):
return true
case (.direct, .private):
return true
default:
return false
}
}
} }

View File

@ -173,7 +173,6 @@
D663626221360B1900C9CBA2 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626121360B1900C9CBA2 /* Preferences.swift */; }; D663626221360B1900C9CBA2 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626121360B1900C9CBA2 /* Preferences.swift */; };
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626321360D2300C9CBA2 /* AvatarStyle.swift */; }; D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626321360D2300C9CBA2 /* AvatarStyle.swift */; };
D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626B21361C6700C9CBA2 /* Account+Preferences.swift */; }; D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626B21361C6700C9CBA2 /* Account+Preferences.swift */; };
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */; };
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */; }; D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */; };
D6676CA527A8D0020052936B /* WebURLFoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = D6676CA427A8D0020052936B /* WebURLFoundationExtras */; }; D6676CA527A8D0020052936B /* WebURLFoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = D6676CA427A8D0020052936B /* WebURLFoundationExtras */; };
D667E5E12134937B0057A976 /* TimelineStatusTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */; }; D667E5E12134937B0057A976 /* TimelineStatusTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */; };
@ -591,7 +590,6 @@
D663626121360B1900C9CBA2 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; }; D663626121360B1900C9CBA2 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
D663626321360D2300C9CBA2 /* AvatarStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStyle.swift; sourceTree = "<group>"; }; D663626321360D2300C9CBA2 /* AvatarStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStyle.swift; sourceTree = "<group>"; };
D663626B21361C6700C9CBA2 /* Account+Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Preferences.swift"; sourceTree = "<group>"; }; D663626B21361C6700C9CBA2 /* Account+Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Preferences.swift"; sourceTree = "<group>"; };
D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Visibility+Helpers.swift"; sourceTree = "<group>"; };
D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutItems.swift; sourceTree = "<group>"; }; D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutItems.swift; sourceTree = "<group>"; };
D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TimelineStatusTableViewCell.xib; sourceTree = "<group>"; }; D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TimelineStatusTableViewCell.xib; sourceTree = "<group>"; };
D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Delegates.swift"; sourceTree = "<group>"; }; D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Delegates.swift"; sourceTree = "<group>"; };
@ -1310,7 +1308,6 @@
D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */, D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */,
D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */, D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */,
D663626B21361C6700C9CBA2 /* Account+Preferences.swift */, D663626B21361C6700C9CBA2 /* Account+Preferences.swift */,
D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */,
D6333B362137838300CE884A /* AttributedString+Helpers.swift */, D6333B362137838300CE884A /* AttributedString+Helpers.swift */,
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */, D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */,
D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */, D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */,
@ -2227,7 +2224,6 @@
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */, D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
D647D92824257BEB0005044F /* AttachmentPreviewViewController.swift in Sources */, D647D92824257BEB0005044F /* AttachmentPreviewViewController.swift in Sources */,
D61F75B5293BD97400C0B37F /* DeleteFilterService.swift in Sources */, D61F75B5293BD97400C0B37F /* DeleteFilterService.swift in Sources */,
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */,
D6DFC6A0242C4CCC00ACC392 /* Weak.swift in Sources */, D6DFC6A0242C4CCC00ACC392 /* Weak.swift in Sources */,
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */, D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */,
D61ABEF828EFC3F900B29151 /* ProfileStatusesViewController.swift in Sources */, D61ABEF828EFC3F900B29151 /* ProfileStatusesViewController.swift in Sources */,

View File

@ -17,7 +17,7 @@ class ReblogService {
private let status: StatusMO private let status: StatusMO
var hapticFeedback = true var hapticFeedback = true
var visibility: Status.Visibility? = nil var visibility: Visibility? = nil
var requireConfirmation = Preferences.shared.confirmBeforeReblog var requireConfirmation = Preferences.shared.confirmBeforeReblog
init(status: StatusMO, mastodonController: MastodonController, presenter: any TuskerNavigationDelegate) { init(status: StatusMO, mastodonController: MastodonController, presenter: any TuskerNavigationDelegate) {
@ -39,8 +39,8 @@ class ReblogService {
let image: UIImage? let image: UIImage?
let reblogVisibilityActions: [CustomAlertController.MenuAction]? let reblogVisibilityActions: [CustomAlertController.MenuAction]?
if mastodonController.instanceFeatures.reblogVisibility { if mastodonController.instanceFeatures.reblogVisibility {
image = UIImage(systemName: Status.Visibility.public.unfilledImageName) image = UIImage(systemName: Visibility.public.unfilledImageName)
reblogVisibilityActions = [Status.Visibility.unlisted, .private].map { visibility in reblogVisibilityActions = [Visibility.unlisted, .private].map { visibility in
CustomAlertController.MenuAction(title: "Reblog as \(visibility.displayName)", subtitle: visibility.subtitle, image: UIImage(systemName: visibility.unfilledImageName)) { CustomAlertController.MenuAction(title: "Reblog as \(visibility.displayName)", subtitle: visibility.subtitle, image: UIImage(systemName: visibility.unfilledImageName)) {
// deliberately retain a strong reference to self // deliberately retain a strong reference to self
Task { Task {

View File

@ -75,9 +75,9 @@ public final class StatusMO: NSManagedObject, StatusProtocol {
public var pinned: Bool? { pinnedInternal } public var pinned: Bool? { pinnedInternal }
public var bookmarked: Bool? { bookmarkedInternal } public var bookmarked: Bool? { bookmarkedInternal }
public var visibility: Pachyderm.Status.Visibility { public var visibility: Pachyderm.Visibility {
get { get {
Pachyderm.Status.Visibility(rawValue: visibilityString) ?? .public Pachyderm.Visibility(rawValue: visibilityString) ?? .public
} }
set { set {
visibilityString = newValue.rawValue visibilityString = newValue.rawValue

View File

@ -19,7 +19,7 @@ class Draft: Codable, ObservableObject {
@Published var contentWarning: String @Published var contentWarning: String
@Published var attachments: [CompositionAttachment] @Published var attachments: [CompositionAttachment]
@Published var inReplyToID: String? @Published var inReplyToID: String?
@Published var visibility: Status.Visibility @Published var visibility: Visibility
@Published var poll: Poll? @Published var poll: Poll?
@Published var localOnly: Bool @Published var localOnly: Bool
@ -61,7 +61,7 @@ class Draft: Codable, ObservableObject {
self.contentWarning = try container.decode(String.self, forKey: .contentWarning) self.contentWarning = try container.decode(String.self, forKey: .contentWarning)
self.attachments = try container.decode([CompositionAttachment].self, forKey: .attachments) self.attachments = try container.decode([CompositionAttachment].self, forKey: .attachments)
self.inReplyToID = try container.decode(String?.self, forKey: .inReplyToID) self.inReplyToID = try container.decode(String?.self, forKey: .inReplyToID)
self.visibility = try container.decode(Status.Visibility.self, forKey: .visibility) self.visibility = try container.decode(Visibility.self, forKey: .visibility)
self.poll = try container.decode(Poll?.self, forKey: .poll) self.poll = try container.decode(Poll?.self, forKey: .poll)
self.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) ?? false self.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) ?? false

View File

@ -49,7 +49,7 @@ class Preferences: Codable, ObservableObject {
self.leadingStatusSwipeActions = try container.decodeIfPresent([StatusSwipeAction].self, forKey: .leadingStatusSwipeActions) ?? leadingStatusSwipeActions self.leadingStatusSwipeActions = try container.decodeIfPresent([StatusSwipeAction].self, forKey: .leadingStatusSwipeActions) ?? leadingStatusSwipeActions
self.trailingStatusSwipeActions = try container.decodeIfPresent([StatusSwipeAction].self, forKey: .trailingStatusSwipeActions) ?? trailingStatusSwipeActions self.trailingStatusSwipeActions = try container.decodeIfPresent([StatusSwipeAction].self, forKey: .trailingStatusSwipeActions) ?? trailingStatusSwipeActions
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility) self.defaultPostVisibility = try container.decode(Visibility.self, forKey: .defaultPostVisibility)
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts) self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions) self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
@ -158,7 +158,7 @@ class Preferences: Codable, ObservableObject {
@Published var trailingStatusSwipeActions: [StatusSwipeAction] = [.reply, .share] @Published var trailingStatusSwipeActions: [StatusSwipeAction] = [.reply, .share]
// MARK: Composing // MARK: Composing
@Published var defaultPostVisibility = Status.Visibility.public @Published var defaultPostVisibility = Visibility.public
@Published var defaultReplyVisibility = ReplyVisibility.sameAsPost @Published var defaultReplyVisibility = ReplyVisibility.sameAsPost
@Published var automaticallySaveDrafts = true @Published var automaticallySaveDrafts = true
@Published var requireAttachmentDescriptions = false @Published var requireAttachmentDescriptions = false
@ -266,11 +266,11 @@ class Preferences: Codable, ObservableObject {
extension Preferences { extension Preferences {
enum ReplyVisibility: Codable, Hashable, CaseIterable { enum ReplyVisibility: Codable, Hashable, CaseIterable {
case sameAsPost case sameAsPost
case visibility(Status.Visibility) case visibility(Visibility)
static var allCases: [Preferences.ReplyVisibility] = [.sameAsPost] + Status.Visibility.allCases.map { .visibility($0) } static var allCases: [Preferences.ReplyVisibility] = [.sameAsPost] + Visibility.allCases.map { .visibility($0) }
var resolved: Status.Visibility { var resolved: Visibility {
switch self { switch self {
case .sameAsPost: case .sameAsPost:
return Preferences.shared.defaultPostVisibility return Preferences.shared.defaultPostVisibility

View File

@ -12,7 +12,7 @@ import TuskerComponents
struct ComposeToolbar: View { struct ComposeToolbar: View {
static let height: CGFloat = 44 static let height: CGFloat = 44
private static let visibilityOptions: [MenuPicker.Option] = Status.Visibility.allCases.map { vis in private static let visibilityOptions: [MenuPicker.Option] = Visibility.allCases.map { vis in
.init(value: vis, title: vis.displayName, subtitle: vis.subtitle, image: UIImage(systemName: vis.unfilledImageName), accessibilityLabel: "Visibility: \(vis.displayName)") .init(value: vis, title: vis.displayName, subtitle: vis.subtitle, image: UIImage(systemName: vis.unfilledImageName), accessibilityLabel: "Visibility: \(vis.displayName)")
} }

View File

@ -86,7 +86,7 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
typealias UIViewType = UITextView typealias UIViewType = UITextView
@Binding var text: String @Binding var text: String
let visibility: Status.Visibility let visibility: Pachyderm.Visibility
@Binding var becomeFirstResponder: Bool @Binding var becomeFirstResponder: Bool
var textDidChange: (UITextView) -> Void var textDidChange: (UITextView) -> Void

View File

@ -27,7 +27,7 @@ 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(Status.Visibility.allCases, id: \.self) { visibility in ForEach(Visibility.allCases, id: \.self) { visibility in
HStack { HStack {
Image(systemName: visibility.imageName) Image(systemName: visibility.imageName)
Text(visibility.displayName) Text(visibility.displayName)

View File

@ -78,7 +78,7 @@ class ProfileViewController: UIViewController, StateRestorableViewController {
let composeButton = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(composeMentioning)) let composeButton = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(composeMentioning))
composeButton.menu = UIMenu(children: [ composeButton.menu = UIMenu(children: [
UIAction(title: "Direct Message", image: UIImage(systemName: Status.Visibility.direct.unfilledImageName), handler: { [unowned self] _ in UIAction(title: "Direct Message", image: UIImage(systemName: Visibility.direct.unfilledImageName), handler: { [unowned self] _ in
self.composeDirectMentioning() self.composeDirectMentioning()
}) })
]) ])

View File

@ -11,10 +11,10 @@ import Pachyderm
extension UIAlertController { extension UIAlertController {
convenience init(currentVisibility: Status.Visibility?, completion: @escaping (Status.Visibility?) -> Void) { convenience init(currentVisibility: Visibility?, completion: @escaping (Visibility?) -> Void) {
self.init(title: "Post Visibility", message: nil, preferredStyle: .actionSheet) self.init(title: "Post Visibility", message: nil, preferredStyle: .actionSheet)
for visibility in Status.Visibility.allCases { for visibility in Visibility.allCases {
let action = UIAlertAction(title: visibility.displayName, style: .default) { (_) in let action = UIAlertAction(title: visibility.displayName, style: .default) { (_) in
completion(visibility) completion(visibility)
} }