From b2fe2fdf9a59676932312a87284d3166a55b6935 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 7 Mar 2023 10:14:35 -0500 Subject: [PATCH] Move Visibility to top-level type and move extensions to Pachyderm --- .../Pachyderm/Sources/Pachyderm/Client.swift | 2 +- .../Model/Protocols/StatusProtocol.swift | 2 +- .../Sources/Pachyderm/Model/Status.swift | 11 +---- .../Sources/Pachyderm/Model/Visibility.swift | 47 ++++++++++--------- Tusker.xcodeproj/project.pbxproj | 4 -- Tusker/API/ReblogService.swift | 6 +-- Tusker/CoreData/StatusMO.swift | 4 +- Tusker/Models/Draft.swift | 4 +- Tusker/Preferences/Preferences.swift | 10 ++-- Tusker/Screens/Compose/ComposeToolbar.swift | 2 +- .../Screens/Compose/MainComposeTextView.swift | 2 +- .../Preferences/ComposingPrefsView.swift | 2 +- .../Profile/ProfileViewController.swift | 2 +- .../UIAlertController+Visibility.swift | 4 +- 14 files changed, 45 insertions(+), 57 deletions(-) rename Tusker/Extensions/Visibility+Helpers.swift => Packages/Pachyderm/Sources/Pachyderm/Model/Visibility.swift (81%) diff --git a/Packages/Pachyderm/Sources/Pachyderm/Client.swift b/Packages/Pachyderm/Sources/Pachyderm/Client.swift index 02bd0955..ba171feb 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Client.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Client.swift @@ -383,7 +383,7 @@ public class Client { media: [Attachment]? = nil, sensitive: Bool? = nil, spoilerText: String? = nil, - visibility: Status.Visibility? = nil, + visibility: Visibility? = nil, language: String? = nil, pollOptions: [String]? = nil, pollExpiresIn: Int? = nil, diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/StatusProtocol.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/StatusProtocol.swift index afd49fde..e0a41264 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/StatusProtocol.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Protocols/StatusProtocol.swift @@ -25,7 +25,7 @@ public protocol StatusProtocol { // var favourited: Bool { get } var sensitive: Bool { get } var spoilerText: String { get } - var visibility: Pachyderm.Status.Visibility { get } + var visibility: Visibility { get } var applicationName: String? { get } var pinned: Bool? { get } var bookmarked: Bool? { get } diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift index 6941e09a..133a5d47 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Status.swift @@ -63,7 +63,7 @@ public final class Status: StatusProtocol, Decodable, Sendable { self.muted = try container.decodeIfPresent(Bool.self, forKey: .muted) self.sensitive = try container.decode(Bool.self, forKey: .sensitive) 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.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) } 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 {} diff --git a/Tusker/Extensions/Visibility+Helpers.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Visibility.swift similarity index 81% rename from Tusker/Extensions/Visibility+Helpers.swift rename to Packages/Pachyderm/Sources/Pachyderm/Model/Visibility.swift index 0c8d5b94..489b1f2e 100644 --- a/Tusker/Extensions/Visibility+Helpers.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Visibility.swift @@ -1,16 +1,33 @@ // -// Visibility+String.swift -// Tusker +// Visibility.swift +// Pachyderm // -// Created by Shadowfacts on 8/29/18. -// Copyright © 2018 Shadowfacts. All rights reserved. +// Created by Shadowfacts on 3/7/23. // -import Pachyderm -import UIKit +import Foundation -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 { switch self { case .public: @@ -62,20 +79,4 @@ extension Status.Visibility { 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 - } - } } diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index a967bb6e..aa6674c7 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -173,7 +173,6 @@ D663626221360B1900C9CBA2 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626121360B1900C9CBA2 /* Preferences.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 */; }; - D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */; }; D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */; }; D6676CA527A8D0020052936B /* WebURLFoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = D6676CA427A8D0020052936B /* WebURLFoundationExtras */; }; 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 = ""; }; D663626321360D2300C9CBA2 /* AvatarStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStyle.swift; sourceTree = ""; }; D663626B21361C6700C9CBA2 /* Account+Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Preferences.swift"; sourceTree = ""; }; - D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Visibility+Helpers.swift"; sourceTree = ""; }; D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutItems.swift; sourceTree = ""; }; D667E5E02134937B0057A976 /* TimelineStatusTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TimelineStatusTableViewCell.xib; sourceTree = ""; }; D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Delegates.swift"; sourceTree = ""; }; @@ -1310,7 +1308,6 @@ D667E5F02134D5050057A976 /* UIViewController+Delegates.swift */, D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */, D663626B21361C6700C9CBA2 /* Account+Preferences.swift */, - D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */, D6333B362137838300CE884A /* AttributedString+Helpers.swift */, D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */, D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */, @@ -2227,7 +2224,6 @@ D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */, D647D92824257BEB0005044F /* AttachmentPreviewViewController.swift in Sources */, D61F75B5293BD97400C0B37F /* DeleteFilterService.swift in Sources */, - D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */, D6DFC6A0242C4CCC00ACC392 /* Weak.swift in Sources */, D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */, D61ABEF828EFC3F900B29151 /* ProfileStatusesViewController.swift in Sources */, diff --git a/Tusker/API/ReblogService.swift b/Tusker/API/ReblogService.swift index ca331aed..3b928979 100644 --- a/Tusker/API/ReblogService.swift +++ b/Tusker/API/ReblogService.swift @@ -17,7 +17,7 @@ class ReblogService { private let status: StatusMO var hapticFeedback = true - var visibility: Status.Visibility? = nil + var visibility: Visibility? = nil var requireConfirmation = Preferences.shared.confirmBeforeReblog init(status: StatusMO, mastodonController: MastodonController, presenter: any TuskerNavigationDelegate) { @@ -39,8 +39,8 @@ class ReblogService { let image: UIImage? let reblogVisibilityActions: [CustomAlertController.MenuAction]? if mastodonController.instanceFeatures.reblogVisibility { - image = UIImage(systemName: Status.Visibility.public.unfilledImageName) - reblogVisibilityActions = [Status.Visibility.unlisted, .private].map { visibility in + image = UIImage(systemName: Visibility.public.unfilledImageName) + reblogVisibilityActions = [Visibility.unlisted, .private].map { visibility in CustomAlertController.MenuAction(title: "Reblog as \(visibility.displayName)", subtitle: visibility.subtitle, image: UIImage(systemName: visibility.unfilledImageName)) { // deliberately retain a strong reference to self Task { diff --git a/Tusker/CoreData/StatusMO.swift b/Tusker/CoreData/StatusMO.swift index 6d910991..cdb14745 100644 --- a/Tusker/CoreData/StatusMO.swift +++ b/Tusker/CoreData/StatusMO.swift @@ -75,9 +75,9 @@ public final class StatusMO: NSManagedObject, StatusProtocol { public var pinned: Bool? { pinnedInternal } public var bookmarked: Bool? { bookmarkedInternal } - public var visibility: Pachyderm.Status.Visibility { + public var visibility: Pachyderm.Visibility { get { - Pachyderm.Status.Visibility(rawValue: visibilityString) ?? .public + Pachyderm.Visibility(rawValue: visibilityString) ?? .public } set { visibilityString = newValue.rawValue diff --git a/Tusker/Models/Draft.swift b/Tusker/Models/Draft.swift index 909d109c..6cfab936 100644 --- a/Tusker/Models/Draft.swift +++ b/Tusker/Models/Draft.swift @@ -19,7 +19,7 @@ class Draft: Codable, ObservableObject { @Published var contentWarning: String @Published var attachments: [CompositionAttachment] @Published var inReplyToID: String? - @Published var visibility: Status.Visibility + @Published var visibility: Visibility @Published var poll: Poll? @Published var localOnly: Bool @@ -61,7 +61,7 @@ class Draft: Codable, ObservableObject { self.contentWarning = try container.decode(String.self, forKey: .contentWarning) self.attachments = try container.decode([CompositionAttachment].self, forKey: .attachments) 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.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) ?? false diff --git a/Tusker/Preferences/Preferences.swift b/Tusker/Preferences/Preferences.swift index 1cf03c4e..b5e8654e 100644 --- a/Tusker/Preferences/Preferences.swift +++ b/Tusker/Preferences/Preferences.swift @@ -49,7 +49,7 @@ class Preferences: Codable, ObservableObject { self.leadingStatusSwipeActions = try container.decodeIfPresent([StatusSwipeAction].self, forKey: .leadingStatusSwipeActions) ?? leadingStatusSwipeActions 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.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts) self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions) @@ -158,7 +158,7 @@ class Preferences: Codable, ObservableObject { @Published var trailingStatusSwipeActions: [StatusSwipeAction] = [.reply, .share] // MARK: Composing - @Published var defaultPostVisibility = Status.Visibility.public + @Published var defaultPostVisibility = Visibility.public @Published var defaultReplyVisibility = ReplyVisibility.sameAsPost @Published var automaticallySaveDrafts = true @Published var requireAttachmentDescriptions = false @@ -266,11 +266,11 @@ class Preferences: Codable, ObservableObject { extension Preferences { enum ReplyVisibility: Codable, Hashable, CaseIterable { 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 { case .sameAsPost: return Preferences.shared.defaultPostVisibility diff --git a/Tusker/Screens/Compose/ComposeToolbar.swift b/Tusker/Screens/Compose/ComposeToolbar.swift index d16bd943..f5574053 100644 --- a/Tusker/Screens/Compose/ComposeToolbar.swift +++ b/Tusker/Screens/Compose/ComposeToolbar.swift @@ -12,7 +12,7 @@ import TuskerComponents struct ComposeToolbar: View { 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)") } diff --git a/Tusker/Screens/Compose/MainComposeTextView.swift b/Tusker/Screens/Compose/MainComposeTextView.swift index 2ba9dae4..1ef34ea1 100644 --- a/Tusker/Screens/Compose/MainComposeTextView.swift +++ b/Tusker/Screens/Compose/MainComposeTextView.swift @@ -86,7 +86,7 @@ struct MainComposeWrappedTextView: UIViewRepresentable { typealias UIViewType = UITextView @Binding var text: String - let visibility: Status.Visibility + let visibility: Pachyderm.Visibility @Binding var becomeFirstResponder: Bool var textDidChange: (UITextView) -> Void diff --git a/Tusker/Screens/Preferences/ComposingPrefsView.swift b/Tusker/Screens/Preferences/ComposingPrefsView.swift index d1e91fda..59635f5d 100644 --- a/Tusker/Screens/Preferences/ComposingPrefsView.swift +++ b/Tusker/Screens/Preferences/ComposingPrefsView.swift @@ -27,7 +27,7 @@ struct ComposingPrefsView: View { var visibilitySection: some View { Section { Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Visibility")) { - ForEach(Status.Visibility.allCases, id: \.self) { visibility in + ForEach(Visibility.allCases, id: \.self) { visibility in HStack { Image(systemName: visibility.imageName) Text(visibility.displayName) diff --git a/Tusker/Screens/Profile/ProfileViewController.swift b/Tusker/Screens/Profile/ProfileViewController.swift index bdfd765b..2579372a 100644 --- a/Tusker/Screens/Profile/ProfileViewController.swift +++ b/Tusker/Screens/Profile/ProfileViewController.swift @@ -78,7 +78,7 @@ class ProfileViewController: UIViewController, StateRestorableViewController { let composeButton = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(composeMentioning)) 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() }) ]) diff --git a/Tusker/Screens/Utilities/UIAlertController+Visibility.swift b/Tusker/Screens/Utilities/UIAlertController+Visibility.swift index 6f4d8040..ad5c27aa 100644 --- a/Tusker/Screens/Utilities/UIAlertController+Visibility.swift +++ b/Tusker/Screens/Utilities/UIAlertController+Visibility.swift @@ -11,10 +11,10 @@ import Pachyderm 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) - for visibility in Status.Visibility.allCases { + for visibility in Visibility.allCases { let action = UIAlertAction(title: visibility.displayName, style: .default) { (_) in completion(visibility) }