From f2e3870850080576b795bb8404dae56af78498e3 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 13 Jun 2019 17:53:17 -0700 Subject: [PATCH 1/8] Start rewriting preferences in SwiftUI --- Tusker.xcodeproj/project.pbxproj | 24 ++++++ Tusker/Extensions/Visibility+Helpers.swift | 12 ++- Tusker/Preferences/Preference.swift | 60 +++++++++++++++ Tusker/Preferences/Preferences.swift | 34 ++++++--- .../Compose/ComposeViewController.swift | 4 +- .../Preferences/AdvancedPrefsView.swift | 41 ++++++++++ .../Preferences/AppearancePrefsView.swift | 40 ++++++++++ .../Preferences/BehaviorPrefsView.swift | 49 ++++++++++++ .../Screens/Preferences/PreferencesView.swift | 37 ++++++++++ .../Preferences/SilentActionPrefs.swift | 74 +++++++++++++++++++ .../MyProfileTableViewController.swift | 11 ++- .../UIAlertController+Visibility.swift | 2 +- 12 files changed, 367 insertions(+), 21 deletions(-) create mode 100644 Tusker/Preferences/Preference.swift create mode 100644 Tusker/Screens/Preferences/AdvancedPrefsView.swift create mode 100644 Tusker/Screens/Preferences/AppearancePrefsView.swift create mode 100644 Tusker/Screens/Preferences/BehaviorPrefsView.swift create mode 100644 Tusker/Screens/Preferences/PreferencesView.swift create mode 100644 Tusker/Screens/Preferences/SilentActionPrefs.swift diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index c6ccbfb6ce..d69581a62d 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -7,8 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 0427033622B30B3D000D31B6 /* Preference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033522B30B3D000D31B6 /* Preference.swift */; }; + 0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */; }; + 0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */; }; + 0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */; }; 04496BD721625361001F1B23 /* ContentLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04496BD621625361001F1B23 /* ContentLabel.swift */; }; 0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450531E22B0097E00100BA2 /* Timline+UI.swift */; }; + 04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4022B2FFB10021BD04 /* PreferencesView.swift */; }; + 04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4222B301470021BD04 /* AppearancePrefsView.swift */; }; 0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; }; 0461A3912163CBAE00C0A807 /* Cache.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; }; @@ -235,8 +241,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0427033522B30B3D000D31B6 /* Preference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preference.swift; sourceTree = ""; }; + 0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BehaviorPrefsView.swift; sourceTree = ""; }; + 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsView.swift; sourceTree = ""; }; + 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPrefs.swift; sourceTree = ""; }; 04496BD621625361001F1B23 /* ContentLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLabel.swift; sourceTree = ""; }; 0450531E22B0097E00100BA2 /* Timline+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timline+UI.swift"; sourceTree = ""; }; + 04586B4022B2FFB10021BD04 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = ""; }; + 04586B4222B301470021BD04 /* AppearancePrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePrefsView.swift; sourceTree = ""; }; 0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = ""; }; 04DACE8D212CC7CC009840C4 /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = ""; }; @@ -702,6 +714,11 @@ D67E0512216438A7000E0927 /* AppearanceTableViewController.swift */, D627FF80217FE8F400CC0648 /* BehaviorTableViewController.swift */, D6C693C92161253F007D6A6D /* SilentActionPermissionsTableViewController.swift */, + 04586B4022B2FFB10021BD04 /* PreferencesView.swift */, + 04586B4222B301470021BD04 /* AppearancePrefsView.swift */, + 0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */, + 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */, + 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */, ); path = Preferences; sourceTree = ""; @@ -760,6 +777,7 @@ D663626121360B1900C9CBA2 /* Preferences.swift */, D663626321360D2300C9CBA2 /* AvatarStyle.swift */, D66362692136163000C9CBA2 /* PreferencesAdaptive.swift */, + 0427033522B30B3D000D31B6 /* Preference.swift */, ); path = Preferences; sourceTree = ""; @@ -1353,6 +1371,7 @@ buildActionMask = 2147483647; files = ( D6285B5321EA708700FE4B39 /* StatusFormat.swift in Sources */, + 0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */, D6757A822157E8FA00721E32 /* XCBSession.swift in Sources */, 04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */, D6C693F92162E4DB007D6A6D /* StatusContentLabel.swift in Sources */, @@ -1381,11 +1400,13 @@ D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */, D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */, D6BED174212667E900F02DA0 /* StatusTableViewCell.swift in Sources */, + 0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */, D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */, D6C94D892139E6EC00CB5196 /* AttachmentView.swift in Sources */, D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */, D6C94D872139E62700CB5196 /* LargeImageViewController.swift in Sources */, D6434EB3215B1856001A919A /* XCBRequest.swift in Sources */, + 0427033622B30B3D000D31B6 /* Preference.swift in Sources */, D663626221360B1900C9CBA2 /* Preferences.swift in Sources */, D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */, D641C77F213DC78A004B4513 /* InlineTextAttachment.swift in Sources */, @@ -1401,12 +1422,14 @@ D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */, D663626821360E2C00C9CBA2 /* PreferencesTableViewController.swift in Sources */, D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */, + 04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */, D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */, D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */, D67E0513216438A7000E0927 /* AppearanceTableViewController.swift in Sources */, D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */, D646C95A213B5D0500269FB5 /* LargeImageInteractionController.swift in Sources */, D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */, + 04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */, D663626A2136163000C9CBA2 /* PreferencesAdaptive.swift in Sources */, D667E5EB21349EF80057A976 /* ProfileHeaderTableViewCell.swift in Sources */, D641C77D213CB024004B4513 /* FollowNotificationTableViewCell.swift in Sources */, @@ -1414,6 +1437,7 @@ D6757A7C2157E01900721E32 /* XCBManager.swift in Sources */, D6C693CF216125FC007D6A6D /* SilentActionPermissionTableViewCell.swift in Sources */, D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */, + 0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */, D6757A7E2157E02600721E32 /* XCBRequestSpec.swift in Sources */, D667E5F12134D5050057A976 /* UIViewController+Delegates.swift in Sources */, D6BC8748219738E1006163F1 /* EnhancedTableViewController.swift in Sources */, diff --git a/Tusker/Extensions/Visibility+Helpers.swift b/Tusker/Extensions/Visibility+Helpers.swift index b69dbad38e..2d2f24952f 100644 --- a/Tusker/Extensions/Visibility+Helpers.swift +++ b/Tusker/Extensions/Visibility+Helpers.swift @@ -24,19 +24,17 @@ extension Status.Visibility { } } - var image: UIImage { - let name: String + var imageName: String { switch self { case .public: - name = "globe" + return "globe" case .unlisted: - name = "lock.open.fill" + return "lock.open.fill" case .private: - name = "lock.fill" + return "lock.fill" case .direct: - name = "envelope.fill" + return "envelope.fill" } - return UIImage(systemName: name)! } } diff --git a/Tusker/Preferences/Preference.swift b/Tusker/Preferences/Preference.swift new file mode 100644 index 0000000000..ac05294f27 --- /dev/null +++ b/Tusker/Preferences/Preference.swift @@ -0,0 +1,60 @@ +// Preference.swift +// Tusker +// +// Created by Shadowfacts on 6/13/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import SwiftUI + +@propertyWrapper +struct Preference: BindingConvertible { + let path: WritableKeyPath + let binding: Binding + + init(_ path: WritableKeyPath) { + self.path = path + self.binding = Binding(getValue: { + return Preferences.shared[keyPath: path] + }, setValue: { (newValue) in + Preferences.shared[keyPath: path] = newValue + }) + } + + var value: Value { + get { + return Preferences.shared[keyPath: path] + } + set { + Preferences.shared[keyPath: path] = newValue + } + } +} + +@propertyWrapper +struct MappedPreference: BindingConvertible { + let path: WritableKeyPath + let fromPref: (PrefValue) -> Value + let toPref: (Value) -> PrefValue + let binding: Binding + + init(_ path: WritableKeyPath, fromPref: @escaping (PrefValue) -> Value, toPref: @escaping (Value) -> PrefValue) { + self.path = path + self.fromPref = fromPref + self.toPref = toPref + self.binding = Binding(getValue: { + return fromPref(Preferences.shared[keyPath: path]) + }, setValue: { (newValue) in + Preferences.shared[keyPath: path] = toPref(newValue) + }) + } + + var value: Value { + get { + return fromPref(Preferences.shared[keyPath: path]) + } + set { + Preferences.shared[keyPath: path] = toPref(newValue) + } + } +} diff --git a/Tusker/Preferences/Preferences.swift b/Tusker/Preferences/Preferences.swift index f29bcc91c6..35408677d6 100644 --- a/Tusker/Preferences/Preferences.swift +++ b/Tusker/Preferences/Preferences.swift @@ -8,10 +8,12 @@ import Foundation import Pachyderm +import SwiftUI +import Combine -class Preferences: Codable { +class Preferences: Codable, BindableObject { - private(set) static var shared: Preferences = load() + static var shared: Preferences = load() private static var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! private static var archiveURL = Preferences.documentsDirectory.appendingPathComponent("preferences").appendingPathExtension("plist") @@ -33,22 +35,34 @@ class Preferences: Codable { private init() {} + let didChange = PassthroughSubject() + // MARK: - Appearance - var showRepliesInProfiles = false - var avatarStyle = AvatarStyle.roundRect - var hideCustomEmojiInUsernames = false + var showRepliesInProfiles = false { didSet { didChange.send(self) } } + var avatarStyle = AvatarStyle.roundRect { didSet { didChange.send(self) } } + var hideCustomEmojiInUsernames = false { didSet { didChange.send(self) } } // MARK: - Behavior - var defaultPostVisibility = Status.Visibility.public - var automaticallySaveDrafts = true - var openLinksInApps = true + var defaultPostVisibility = Status.Visibility.public { didSet { didChange.send(self) } } + var automaticallySaveDrafts = true { didSet { didChange.send(self) } } + var openLinksInApps = true { didSet { didChange.send(self) } } // MARK: - Advanced - var silentActions: [String: Permission] = [:] - var statusContentType: StatusContentType = .plain + var silentActions: [String: Permission] = [:] { didSet { didChange.send(self) } } + var statusContentType: StatusContentType = .plain { didSet { didChange.send(self) } } } +extension PassthroughSubject: Codable { + public convenience init(from decoder: Decoder) throws { + self.init() + } + + public func encode(to encoder: Encoder) throws { + + } +} + extension Preferences { enum Permission: String, Codable { case undecided, accepted, rejected diff --git a/Tusker/Screens/Compose/ComposeViewController.swift b/Tusker/Screens/Compose/ComposeViewController.swift index 96b645ec6b..1e277833ab 100644 --- a/Tusker/Screens/Compose/ComposeViewController.swift +++ b/Tusker/Screens/Compose/ComposeViewController.swift @@ -103,7 +103,7 @@ class ComposeViewController: UIViewController { let toolbar = UIToolbar() contentWarningBarButtonItem = UIBarButtonItem(title: "CW", style: .plain, target: self, action: #selector(contentWarningButtonPressed)) - visibilityBarButtonItem = UIBarButtonItem(image: Preferences.shared.defaultPostVisibility.image, style: .plain, target: self, action: #selector(visibilityButtonPressed)) + visibilityBarButtonItem = UIBarButtonItem(image: UIImage(systemName: Preferences.shared.defaultPostVisibility.imageName), style: .plain, target: self, action: #selector(visibilityButtonPressed)) toolbar.items = [ contentWarningBarButtonItem, visibilityBarButtonItem, @@ -297,7 +297,7 @@ class ComposeViewController: UIViewController { } func visibilityChanged() { - visibilityBarButtonItem.image = visibility.image + visibilityBarButtonItem.image = UIImage(systemName: visibility.imageName) } func saveDraft() { diff --git a/Tusker/Screens/Preferences/AdvancedPrefsView.swift b/Tusker/Screens/Preferences/AdvancedPrefsView.swift new file mode 100644 index 0000000000..913649029d --- /dev/null +++ b/Tusker/Screens/Preferences/AdvancedPrefsView.swift @@ -0,0 +1,41 @@ +// AdvancedPrefsView.swift +// Tusker +// +// Created by Shadowfacts on 6/13/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import SwiftUI +import Pachyderm + +struct AdvancedPrefsView : View { + @Preference(\.statusContentType) var statusContentType: StatusContentType + + var body: some View { + List { + Section(footer: Text("This option is only supported for Pleroma and Mastodon instances with formatting enabled. On all other instances, formatting symbols will remain in the unformatted plain text.").lineLimit(nil)) { + Picker(selection: $statusContentType.binding, label: Text("Post Content Type")) { + ForEach(StatusContentType.allCases.identified(by: \.self)) { type in + Text(type.displayName).tag(type) + } + } + } + + Section(header: Text("AUTOMATION")) { + NavigationButton(destination: SilentActionPrefs()) { + Text("Silent Action Permissions") + } + } + } + .listStyle(.grouped) + .navigationBarTitle(Text("Advanced")) + } +} + +#if DEBUG +struct AdvancedPrefsView_Previews : PreviewProvider { + static var previews: some View { + AdvancedPrefsView() + } +} +#endif diff --git a/Tusker/Screens/Preferences/AppearancePrefsView.swift b/Tusker/Screens/Preferences/AppearancePrefsView.swift new file mode 100644 index 0000000000..c115d1fc18 --- /dev/null +++ b/Tusker/Screens/Preferences/AppearancePrefsView.swift @@ -0,0 +1,40 @@ +// AppearancePrefsView.swift +// Tusker +// +// Created by Shadowfacts on 6/13/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import SwiftUI + +struct AppearancePrefsView : View { + @Preference(\.showRepliesInProfiles) var showRepliesInProfiles: Bool + @Preference(\.hideCustomEmojiInUsernames) var hideCustomEmojiInUsernames: Bool + + @MappedPreference(\.avatarStyle, fromPref: { $0 == .circle }, toPref: { $0 ? .circle : .roundRect }) + var useCircularAvatars: Bool + + var body: some View { + List { + Toggle(isOn: $showRepliesInProfiles.binding) { + Text("Show Replies in Profiles") + } + Toggle(isOn: $useCircularAvatars.binding) { + Text("Use Circular Avatars") + } + Toggle(isOn: $hideCustomEmojiInUsernames.binding) { + Text("Hide Custom Emoji in Usernames") + } + } + .listStyle(.grouped) + .navigationBarTitle(Text("Appearance")) + } +} + +#if DEBUG +struct AppearancePrefsView_Previews : PreviewProvider { + static var previews: some View { + AppearancePrefsView() + } +} +#endif diff --git a/Tusker/Screens/Preferences/BehaviorPrefsView.swift b/Tusker/Screens/Preferences/BehaviorPrefsView.swift new file mode 100644 index 0000000000..6404fb2592 --- /dev/null +++ b/Tusker/Screens/Preferences/BehaviorPrefsView.swift @@ -0,0 +1,49 @@ +// BehaviorPrefsView.swift +// Tusker +// +// Created by Shadowfacts on 6/13/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import SwiftUI +import Pachyderm + +struct BehaviorPrefsView : View { + @Preference(\.defaultPostVisibility) var defaultPostVisibility: Status.Visibility + @Preference(\.automaticallySaveDrafts) var automaticallySaveDrafts: Bool + @Preference(\.openLinksInApps) var openLinksInApps: Bool + + var body: some View { + List { + Section { + Picker(selection: $defaultPostVisibility.binding, label: Text("Default Post Visibility")) { + ForEach(Status.Visibility.allCases.identified(by: \.self)) { visibility in + HStack { + Image(systemName: visibility.imageName) + Text(visibility.displayName) + } + .tag(visibility) + } + } + Toggle(isOn: $automaticallySaveDrafts.binding) { + Text("Automatically Save Drafts") + } + } + Section { + Toggle(isOn: $openLinksInApps.binding) { + Text("Open Links in Apps") + } + } + } + .listStyle(.grouped) + .navigationBarTitle(Text("Behavior")) + } +} + +#if DEBUG +struct BehaviorPrefsView_Previews : PreviewProvider { + static var previews: some View { + BehaviorPrefsView() + } +} +#endif diff --git a/Tusker/Screens/Preferences/PreferencesView.swift b/Tusker/Screens/Preferences/PreferencesView.swift new file mode 100644 index 0000000000..4cbfea4fa7 --- /dev/null +++ b/Tusker/Screens/Preferences/PreferencesView.swift @@ -0,0 +1,37 @@ +// PreferencesView.swift +// Tusker +// +// Created by Shadowfacts on 6/13/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import SwiftUI + +struct PreferencesView : View { + var body: some View { + // workaround: the navigation view is provided by MyProfileTableViewController so that it can inject the Done button +// NavigationView { + List { + NavigationButton(destination: AppearancePrefsView()) { + Text("Appearance") + } + NavigationButton(destination: BehaviorPrefsView()) { + Text("Behavior") + } + NavigationButton(destination: AdvancedPrefsView()) { + Text("Advanced") + } + } + .listStyle(.grouped) + .navigationBarTitle(Text("Preferences"), displayMode: .inline) +// } + } +} + +#if DEBUG +struct PreferencesView_Previews : PreviewProvider { + static var previews: some View { + PreferencesView() + } +} +#endif diff --git a/Tusker/Screens/Preferences/SilentActionPrefs.swift b/Tusker/Screens/Preferences/SilentActionPrefs.swift new file mode 100644 index 0000000000..b45cb4a01f --- /dev/null +++ b/Tusker/Screens/Preferences/SilentActionPrefs.swift @@ -0,0 +1,74 @@ +// SilentActionPrefs.swift +// Tusker +// +// Created by Shadowfacts on 6/13/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import SwiftUI + +//struct SilentActionPermission: Identifiable { +// let application: String +// let permission: Preferences.Permission +// +// var id: String { +// return application +// } +// +// init(_ application: String, _ permission: Preferences.Permission) { +// self.application = application +// self.permission = permission +// } +//} + +struct SilentActionPrefs : View { +// @MappedPreference(\.silentActions, fromPref: { +// var array = [SilentActionPermission]() +// for (application, permission) in $0 { +// array.append(SilentActionPermission(application, permission)) +// } +// return array +// }) +// var silentActionPermissions: [SilentActionPermission] +// @Preference(\.silentActions) var silentActions: [String: Preferences.Permission] + @EnvironmentObject var preferences: Preferences + + var body: some View { + List(Array(preferences.silentActions.keys).identified(by: \.self)) { source in + SilentActionPermissionCell(source: source) + }.listStyle(.grouped) +// List(Array(silentActions.keys).identified(by: \.self)) { application in +// Text(application) +//// Toggle(isOn: Binding(getValue: { self.silentActions[application] == .accepted }, setValue: { self.silentActions[application] = $0 ? .accepted : .rejected }), label: Text(application)) +// }.listStyle(.grouped) + } +} + +struct SilentActionPermissionCell: View { + @EnvironmentObject var preferences: Preferences + let source: String +// var binding: Binding + + init(source: String) { + self.source = source +// self.binding = Binding(getValue: { self.preferences.silentActions[source] == .accepted }, setValue: { self.preferences.silentActions[source] = $0 ? .accepted : .rejected }) + } + + var body: some View { + Toggle(isOn: Binding(getValue: { + self.preferences.silentActions[self.source] == .accepted + }, setValue: { + self.preferences.silentActions[self.source] = $0 ? .accepted : .rejected + })) { + Text(verbatim: source) + } + } +} + +#if DEBUG +struct SilentActionPrefs_Previews : PreviewProvider { + static var previews: some View { + SilentActionPrefs().environmentObject(Preferences.shared) + } +} +#endif diff --git a/Tusker/Screens/Profile/MyProfileTableViewController.swift b/Tusker/Screens/Profile/MyProfileTableViewController.swift index 170a6d618c..4f284de898 100644 --- a/Tusker/Screens/Profile/MyProfileTableViewController.swift +++ b/Tusker/Screens/Profile/MyProfileTableViewController.swift @@ -7,6 +7,7 @@ // import UIKit +import SwiftUI class MyProfileTableViewController: ProfileTableViewController { @@ -50,7 +51,15 @@ class MyProfileTableViewController: ProfileTableViewController { } @objc func preferencesPressed() { - present(PreferencesTableViewController.create(), animated: true) + let view = PreferencesView().environmentObject(Preferences.shared) + let hostingController = UIHostingController(rootView: view) + let navigationController = UINavigationController(rootViewController: hostingController) + hostingController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(closePreferences)) + present(navigationController, animated: true) + } + + @objc func closePreferences() { + dismiss(animated: true) } } diff --git a/Tusker/Screens/Utilities/UIAlertController+Visibility.swift b/Tusker/Screens/Utilities/UIAlertController+Visibility.swift index 41f5bc920e..6f4d80402b 100644 --- a/Tusker/Screens/Utilities/UIAlertController+Visibility.swift +++ b/Tusker/Screens/Utilities/UIAlertController+Visibility.swift @@ -21,7 +21,7 @@ extension UIAlertController { if visibility == currentVisibility { action.setValue(true, forKey: "checked") } - action.setValue(visibility.image, forKey: "image") + action.setValue(UIImage(systemName: visibility.imageName), forKey: "image") addAction(action) } From 319c76f60afe18c897e817ac6e144ec75b00bf6f Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 18 Jul 2019 18:44:35 -0400 Subject: [PATCH 2/8] Updates for beta 4 --- Tusker/Preferences/Preference.swift | 4 ++-- Tusker/Preferences/Preferences.swift | 21 ++++++++++--------- .../Preferences/AdvancedPrefsView.swift | 6 +++--- .../Preferences/AppearancePrefsView.swift | 6 +++--- .../Preferences/BehaviorPrefsView.swift | 8 +++---- .../Screens/Preferences/PreferencesView.swift | 6 +++--- .../Preferences/SilentActionPrefs.swift | 2 +- .../EnhancedTableViewController.swift | 2 +- 8 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Tusker/Preferences/Preference.swift b/Tusker/Preferences/Preference.swift index ac05294f27..b08fe5d5fa 100644 --- a/Tusker/Preferences/Preference.swift +++ b/Tusker/Preferences/Preference.swift @@ -21,7 +21,7 @@ struct Preference: BindingConvertible { }) } - var value: Value { + var wrappedValue: Value { get { return Preferences.shared[keyPath: path] } @@ -49,7 +49,7 @@ struct MappedPreference: BindingConvertible { }) } - var value: Value { + var wrappedValue: Value { get { return fromPref(Preferences.shared[keyPath: path]) } diff --git a/Tusker/Preferences/Preferences.swift b/Tusker/Preferences/Preferences.swift index 35408677d6..877a5c966c 100644 --- a/Tusker/Preferences/Preferences.swift +++ b/Tusker/Preferences/Preferences.swift @@ -12,7 +12,7 @@ import SwiftUI import Combine class Preferences: Codable, BindableObject { - + static var shared: Preferences = load() private static var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! @@ -35,21 +35,22 @@ class Preferences: Codable, BindableObject { private init() {} - let didChange = PassthroughSubject() + typealias PublisherType = PassthroughSubject + let willChange = PassthroughSubject() // MARK: - Appearance - var showRepliesInProfiles = false { didSet { didChange.send(self) } } - var avatarStyle = AvatarStyle.roundRect { didSet { didChange.send(self) } } - var hideCustomEmojiInUsernames = false { didSet { didChange.send(self) } } + var showRepliesInProfiles = false { willSet { willChange.send(self) } } + var avatarStyle = AvatarStyle.roundRect { willSet { willChange.send(self) } } + var hideCustomEmojiInUsernames = false { willSet { willChange.send(self) } } // MARK: - Behavior - var defaultPostVisibility = Status.Visibility.public { didSet { didChange.send(self) } } - var automaticallySaveDrafts = true { didSet { didChange.send(self) } } - var openLinksInApps = true { didSet { didChange.send(self) } } + var defaultPostVisibility = Status.Visibility.public { willSet { willChange.send(self) } } + var automaticallySaveDrafts = true { willSet { willChange.send(self) } } + var openLinksInApps = true { willSet { willChange.send(self) } } // MARK: - Advanced - var silentActions: [String: Permission] = [:] { didSet { didChange.send(self) } } - var statusContentType: StatusContentType = .plain { didSet { didChange.send(self) } } + var silentActions: [String: Permission] = [:] { willSet { willChange.send(self) } } + var statusContentType: StatusContentType = .plain { willSet { willChange.send(self) } } } diff --git a/Tusker/Screens/Preferences/AdvancedPrefsView.swift b/Tusker/Screens/Preferences/AdvancedPrefsView.swift index 913649029d..9cbf3dff18 100644 --- a/Tusker/Screens/Preferences/AdvancedPrefsView.swift +++ b/Tusker/Screens/Preferences/AdvancedPrefsView.swift @@ -14,15 +14,15 @@ struct AdvancedPrefsView : View { var body: some View { List { Section(footer: Text("This option is only supported for Pleroma and Mastodon instances with formatting enabled. On all other instances, formatting symbols will remain in the unformatted plain text.").lineLimit(nil)) { - Picker(selection: $statusContentType.binding, label: Text("Post Content Type")) { - ForEach(StatusContentType.allCases.identified(by: \.self)) { type in + Picker(selection: _statusContentType.binding, label: Text("Post Content Type")) { + ForEach(StatusContentType.allCases, id: \.self) { type in Text(type.displayName).tag(type) } } } Section(header: Text("AUTOMATION")) { - NavigationButton(destination: SilentActionPrefs()) { + NavigationLink(destination: SilentActionPrefs()) { Text("Silent Action Permissions") } } diff --git a/Tusker/Screens/Preferences/AppearancePrefsView.swift b/Tusker/Screens/Preferences/AppearancePrefsView.swift index c115d1fc18..48eb8060cf 100644 --- a/Tusker/Screens/Preferences/AppearancePrefsView.swift +++ b/Tusker/Screens/Preferences/AppearancePrefsView.swift @@ -16,13 +16,13 @@ struct AppearancePrefsView : View { var body: some View { List { - Toggle(isOn: $showRepliesInProfiles.binding) { + Toggle(isOn: _showRepliesInProfiles.binding) { Text("Show Replies in Profiles") } - Toggle(isOn: $useCircularAvatars.binding) { + Toggle(isOn: _useCircularAvatars.binding) { Text("Use Circular Avatars") } - Toggle(isOn: $hideCustomEmojiInUsernames.binding) { + Toggle(isOn: _hideCustomEmojiInUsernames.binding) { Text("Hide Custom Emoji in Usernames") } } diff --git a/Tusker/Screens/Preferences/BehaviorPrefsView.swift b/Tusker/Screens/Preferences/BehaviorPrefsView.swift index 6404fb2592..02b090353b 100644 --- a/Tusker/Screens/Preferences/BehaviorPrefsView.swift +++ b/Tusker/Screens/Preferences/BehaviorPrefsView.swift @@ -16,8 +16,8 @@ struct BehaviorPrefsView : View { var body: some View { List { Section { - Picker(selection: $defaultPostVisibility.binding, label: Text("Default Post Visibility")) { - ForEach(Status.Visibility.allCases.identified(by: \.self)) { visibility in + Picker(selection: _defaultPostVisibility.binding, label: Text("Default Post Visibility")) { + ForEach(Status.Visibility.allCases, id: \.self) { visibility in HStack { Image(systemName: visibility.imageName) Text(visibility.displayName) @@ -25,12 +25,12 @@ struct BehaviorPrefsView : View { .tag(visibility) } } - Toggle(isOn: $automaticallySaveDrafts.binding) { + Toggle(isOn: _automaticallySaveDrafts.binding) { Text("Automatically Save Drafts") } } Section { - Toggle(isOn: $openLinksInApps.binding) { + Toggle(isOn: _openLinksInApps.binding) { Text("Open Links in Apps") } } diff --git a/Tusker/Screens/Preferences/PreferencesView.swift b/Tusker/Screens/Preferences/PreferencesView.swift index 4cbfea4fa7..3b69e7ead3 100644 --- a/Tusker/Screens/Preferences/PreferencesView.swift +++ b/Tusker/Screens/Preferences/PreferencesView.swift @@ -12,13 +12,13 @@ struct PreferencesView : View { // workaround: the navigation view is provided by MyProfileTableViewController so that it can inject the Done button // NavigationView { List { - NavigationButton(destination: AppearancePrefsView()) { + NavigationLink(destination: AppearancePrefsView()) { Text("Appearance") } - NavigationButton(destination: BehaviorPrefsView()) { + NavigationLink(destination: BehaviorPrefsView()) { Text("Behavior") } - NavigationButton(destination: AdvancedPrefsView()) { + NavigationLink(destination: AdvancedPrefsView()) { Text("Advanced") } } diff --git a/Tusker/Screens/Preferences/SilentActionPrefs.swift b/Tusker/Screens/Preferences/SilentActionPrefs.swift index b45cb4a01f..e917ac4e38 100644 --- a/Tusker/Screens/Preferences/SilentActionPrefs.swift +++ b/Tusker/Screens/Preferences/SilentActionPrefs.swift @@ -34,7 +34,7 @@ struct SilentActionPrefs : View { @EnvironmentObject var preferences: Preferences var body: some View { - List(Array(preferences.silentActions.keys).identified(by: \.self)) { source in + List(Array(preferences.silentActions.keys), id: \.self) { source in SilentActionPermissionCell(source: source) }.listStyle(.grouped) // List(Array(silentActions.keys).identified(by: \.self)) { application in diff --git a/Tusker/Screens/Utilities/EnhancedTableViewController.swift b/Tusker/Screens/Utilities/EnhancedTableViewController.swift index b97f4c93d3..55fcc195a3 100644 --- a/Tusker/Screens/Utilities/EnhancedTableViewController.swift +++ b/Tusker/Screens/Utilities/EnhancedTableViewController.swift @@ -47,7 +47,7 @@ extension EnhancedTableViewController { return nil } let actionProvider: UIContextMenuActionProvider = { (elements) in - return UIMenu.create(title: "test", children: elements + actionsProvider()) + return UIMenu(title: "test", children: elements + actionsProvider()) } return UIContextMenuConfiguration(identifier: nil, previewProvider: previewProvider, actionProvider: actionProvider) } else { From 8bdfa7f09fd573636772d3b1346bc94425e8cb65 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 27 Jul 2019 18:27:47 -0400 Subject: [PATCH 3/8] Use monospace digit font for character counter Fixes #29 --- Tusker/Screens/Compose/ComposeViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tusker/Screens/Compose/ComposeViewController.swift b/Tusker/Screens/Compose/ComposeViewController.swift index 1e277833ab..ae100243a7 100644 --- a/Tusker/Screens/Compose/ComposeViewController.swift +++ b/Tusker/Screens/Compose/ComposeViewController.swift @@ -156,6 +156,8 @@ class ComposeViewController: UIViewController { stackView.insertArrangedSubview(replyLabelContainer, at: 1) } + // we have to set the font here, because the monospaced digit font is not available in IB + charactersRemainingLabel.font = .monospacedDigitSystemFont(ofSize: 17, weight: .regular) updateCharactersRemaining() updatePlaceholder() From e269e2352777318b17a1939889422194332230c8 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 27 Jul 2019 18:31:55 -0400 Subject: [PATCH 4/8] Fix main thread checker warning on login --- Tusker/Screens/Onboarding/OnboardingViewController.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tusker/Screens/Onboarding/OnboardingViewController.swift b/Tusker/Screens/Onboarding/OnboardingViewController.swift index b40d62a30c..1e6f612988 100644 --- a/Tusker/Screens/Onboarding/OnboardingViewController.swift +++ b/Tusker/Screens/Onboarding/OnboardingViewController.swift @@ -69,8 +69,10 @@ class OnboardingViewController: UIViewController { } } } - self.authenticationSession!.presentationContextProvider = self - self.authenticationSession!.start() + DispatchQueue.main.async { + self.authenticationSession!.presentationContextProvider = self + self.authenticationSession!.start() + } } } From 7d7b45757569786632b31910fd139f9a1256c950 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 27 Jul 2019 18:53:07 -0400 Subject: [PATCH 5/8] Fix context menu actions in beta 4 --- .../EnhancedTableViewController.swift | 3 +- Tusker/Screens/Utilities/Previewing.swift | 36 ++++++++++--------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Tusker/Screens/Utilities/EnhancedTableViewController.swift b/Tusker/Screens/Utilities/EnhancedTableViewController.swift index 55fcc195a3..91f43c9b92 100644 --- a/Tusker/Screens/Utilities/EnhancedTableViewController.swift +++ b/Tusker/Screens/Utilities/EnhancedTableViewController.swift @@ -47,7 +47,8 @@ extension EnhancedTableViewController { return nil } let actionProvider: UIContextMenuActionProvider = { (elements) in - return UIMenu(title: "test", children: elements + actionsProvider()) + return UIMenu(title: "", image: nil, identifier: nil, options: [], children: elements + actionsProvider()) +// return UIMenu(title: "test", children: elements + actionsProvider()) } return UIContextMenuConfiguration(identifier: nil, previewProvider: previewProvider, actionProvider: actionProvider) } else { diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index b68c367122..1bd95e2e95 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -27,26 +27,26 @@ extension MenuPreviewProvider { func actionsForProfile(accountID: String) -> [UIAction] { guard let account = MastodonCache.account(for: accountID) else { return [] } return [ - UIAction(__title: "Open in Safari", image: UIImage(systemName: "safari")) { (_) in + createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in self.present(SFSafariViewController(url: account.url)) - }, - UIAction(__title: "Send Message", image: UIImage(systemName: "envelope")) { (_) in + }), + createAction(identifier: "sendmessage", title: "Send Message", systemImageName: "envelope", handler: { (_) in self.present(UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct))) - }, - UIAction(__title: "Share...", image: UIImage(systemName: "square.and.arrow.up")) { (_) in + }), + createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { (_) in self.present(UIActivityViewController(activityItems: [account.url], applicationActivities: nil)) - } + }) ] } func actionsForURL(_ url: URL) -> [UIAction] { return [ - UIAction(__title: "Open in Safari", image: UIImage(systemName: "safari")) { (_) in + createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in self.present(SFSafariViewController(url: url)) - }, - UIAction(__title: "Share...", image: UIImage(systemName: "square.and.arrow.up")) { (_) in + }), + createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { (_) in self.present(UIActivityViewController(activityItems: [url], applicationActivities: nil)) - } + }) ] } @@ -57,16 +57,20 @@ extension MenuPreviewProvider { func actionsForStatus(statusID: String) -> [UIAction] { guard let status = MastodonCache.status(for: statusID) else { return [] } return [ - UIAction(__title: "Reply", image: UIImage(systemName: "arrowshape.turn.up.left")) { (_) in + createAction(identifier: "reply", title: "Reply", systemImageName: "arrowshape.turn.up.left", handler: { (_) in self.present(UINavigationController(rootViewController: ComposeViewController(inReplyTo: statusID))) - }, - UIAction(__title: "Open in Safari", image: UIImage(systemName: "safari")) { (_) in + }), + createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in self.present(SFSafariViewController(url: status.url!)) - }, - UIAction(__title: "Share...", image: UIImage(systemName: "square.and.arrow.up")) { (_) in + }), + createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { (_) in self.present(UIActivityViewController(activityItems: [status.url!], applicationActivities: nil)) - } + }) ] } + private func createAction(identifier: String, title: String, systemImageName: String, handler: @escaping UIActionHandler) -> UIAction { + return UIAction(title: title, image: UIImage(systemName: systemImageName), identifier: UIAction.Identifier(identifier), discoverabilityTitle: nil, attributes: [], state: .off, handler: handler) + } + } From a1c6a34f5492f14e5a41ec8387dc8ed717f5fe06 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 27 Jul 2019 21:34:20 -0400 Subject: [PATCH 6/8] Preferences Picker titles --- Tusker/Screens/Preferences/AdvancedPrefsView.swift | 3 ++- Tusker/Screens/Preferences/BehaviorPrefsView.swift | 3 ++- Tusker/Screens/Preferences/SilentActionPrefs.swift | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Tusker/Screens/Preferences/AdvancedPrefsView.swift b/Tusker/Screens/Preferences/AdvancedPrefsView.swift index 9cbf3dff18..b948c631b9 100644 --- a/Tusker/Screens/Preferences/AdvancedPrefsView.swift +++ b/Tusker/Screens/Preferences/AdvancedPrefsView.swift @@ -17,7 +17,8 @@ struct AdvancedPrefsView : View { Picker(selection: _statusContentType.binding, label: Text("Post Content Type")) { ForEach(StatusContentType.allCases, id: \.self) { type in Text(type.displayName).tag(type) - } + }//.navigationBarTitle("Post Content Type") + // see FB6838291 } } diff --git a/Tusker/Screens/Preferences/BehaviorPrefsView.swift b/Tusker/Screens/Preferences/BehaviorPrefsView.swift index 02b090353b..7fcb1c9e50 100644 --- a/Tusker/Screens/Preferences/BehaviorPrefsView.swift +++ b/Tusker/Screens/Preferences/BehaviorPrefsView.swift @@ -23,7 +23,8 @@ struct BehaviorPrefsView : View { Text(visibility.displayName) } .tag(visibility) - } + }//.navigationBarTitle("Default Post Visibility") + // navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291 } Toggle(isOn: _automaticallySaveDrafts.binding) { Text("Automatically Save Drafts") diff --git a/Tusker/Screens/Preferences/SilentActionPrefs.swift b/Tusker/Screens/Preferences/SilentActionPrefs.swift index e917ac4e38..ccda62a415 100644 --- a/Tusker/Screens/Preferences/SilentActionPrefs.swift +++ b/Tusker/Screens/Preferences/SilentActionPrefs.swift @@ -36,7 +36,10 @@ struct SilentActionPrefs : View { var body: some View { List(Array(preferences.silentActions.keys), id: \.self) { source in SilentActionPermissionCell(source: source) - }.listStyle(.grouped) + } + .listStyle(.grouped) +// .navigationBarTitle("Silent Action Permissions") + // see FB6838291 // List(Array(silentActions.keys).identified(by: \.self)) { application in // Text(application) //// Toggle(isOn: Binding(getValue: { self.silentActions[application] == .accepted }, setValue: { self.silentActions[application] = $0 ? .accepted : .rejected }), label: Text(application)) From 2afe98cf77bd4d879b061d693aa00c819944ad8b Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 27 Jul 2019 21:43:02 -0400 Subject: [PATCH 7/8] Remove old Preferences view code --- .../AdvancedTableViewController.swift | 56 --- .../AppearanceTableViewController.swift | 49 -- .../BehaviorTableViewController.swift | 53 -- .../Preferences/Preferences.storyboard | 464 ------------------ .../PreferencesTableViewController.swift | 22 - ...ActionPermissionsTableViewController.swift | 49 -- 6 files changed, 693 deletions(-) delete mode 100644 Tusker/Screens/Preferences/AdvancedTableViewController.swift delete mode 100644 Tusker/Screens/Preferences/AppearanceTableViewController.swift delete mode 100644 Tusker/Screens/Preferences/BehaviorTableViewController.swift delete mode 100644 Tusker/Screens/Preferences/Preferences.storyboard delete mode 100644 Tusker/Screens/Preferences/PreferencesTableViewController.swift delete mode 100644 Tusker/Screens/Preferences/SilentActionPermissionsTableViewController.swift diff --git a/Tusker/Screens/Preferences/AdvancedTableViewController.swift b/Tusker/Screens/Preferences/AdvancedTableViewController.swift deleted file mode 100644 index a8ebdd942d..0000000000 --- a/Tusker/Screens/Preferences/AdvancedTableViewController.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// AdvancedTableViewController.swift -// Tusker -// -// Created by Shadowfacts on 1/12/19. -// Copyright © 2019 Shadowfacts. All rights reserved. -// - -import UIKit -import Pachyderm - -class AdvancedTableViewController: UITableViewController { - - @IBOutlet weak var postContentTypeLabel: UILabel! - - override func viewDidLoad() { - super.viewDidLoad() - - postContentTypeLabel.text = Preferences.shared.statusContentType.displayName - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard indexPath.section == 1 && indexPath.row == 0 else { - return - } - tableView.deselectRow(at: indexPath, animated: true) - - let alertController = UIAlertController(title: "Post Content Type", message: nil, preferredStyle: .actionSheet) - for contentType in StatusContentType.allCases { - let action = UIAlertAction(title: contentType.displayName, style: .default) { (_) in - Preferences.shared.statusContentType = contentType - self.postContentTypeLabel.text = contentType.displayName - } - if contentType == Preferences.shared.statusContentType { - action.setValue(true, forKey: "checked") - } - alertController.addAction(action) - } - alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - present(alertController, animated: true) - } - -} - -extension StatusContentType { - var displayName: String { - switch self { - case .plain: - return "Plain" - case .markdown: - return "Markdown" - case .html: - return "HTML" - } - } -} diff --git a/Tusker/Screens/Preferences/AppearanceTableViewController.swift b/Tusker/Screens/Preferences/AppearanceTableViewController.swift deleted file mode 100644 index 1e9d8ce0cf..0000000000 --- a/Tusker/Screens/Preferences/AppearanceTableViewController.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// AppearanceTableViewController.swift -// Tusker -// -// Created by Shadowfacts on 10/2/18. -// Copyright © 2018 Shadowfacts. All rights reserved. -// - -import UIKit - -class AppearanceTableViewController: UITableViewController { - - @IBOutlet weak var showRepliesInProfilesSwitch: UISwitch! - @IBOutlet weak var circularAvatarsSwitch: UISwitch! - @IBOutlet weak var hideCustomEmojiInUsernamesSwitch: UISwitch! - - override func viewDidLoad() { - super.viewDidLoad() - - showRepliesInProfilesSwitch.setOn(Preferences.shared.showRepliesInProfiles, animated: false) - circularAvatarsSwitch.setOn(Preferences.shared.avatarStyle == .circle, animated: false) - hideCustomEmojiInUsernamesSwitch.setOn(Preferences.shared.hideCustomEmojiInUsernames, animated: false) - } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - - // MARK: - Interaction - - @IBAction func showRepliesInProfilesChanged(_ sender: Any) { - Preferences.shared.showRepliesInProfiles = showRepliesInProfilesSwitch.isOn - } - - @IBAction func circularAvatarsChanged(_ sender: Any) { - Preferences.shared.avatarStyle = circularAvatarsSwitch.isOn ? .circle : .roundRect - } - - @IBAction func hideCustomEmojiInUsernamesChanged(_ sender: Any) { - Preferences.shared.hideCustomEmojiInUsernames = hideCustomEmojiInUsernamesSwitch.isOn - } - -} diff --git a/Tusker/Screens/Preferences/BehaviorTableViewController.swift b/Tusker/Screens/Preferences/BehaviorTableViewController.swift deleted file mode 100644 index c72ba06ad6..0000000000 --- a/Tusker/Screens/Preferences/BehaviorTableViewController.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// BehaviorTableViewController.swift -// Tusker -// -// Created by Shadowfacts on 10/23/18. -// Copyright © 2018 Shadowfacts. All rights reserved. -// - -import UIKit - -class BehaviorTableViewController: UITableViewController { - - @IBOutlet weak var defaultPostVisibilityLabel: UILabel! - @IBOutlet weak var automaticallySaveDraftsSwitch: UISwitch! - @IBOutlet weak var openLinksInAppsSwitch: UISwitch! - - override func viewDidLoad() { - super.viewDidLoad() - - defaultPostVisibilityLabel.text = Preferences.shared.defaultPostVisibility.displayName - automaticallySaveDraftsSwitch.setOn(Preferences.shared.automaticallySaveDrafts, animated: false) - openLinksInAppsSwitch.setOn(Preferences.shared.openLinksInApps, animated: false) - } - - override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - if indexPath.row == 0 { - return indexPath - } else { - return nil - } - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: true) - - let alertController = UIAlertController(currentVisibility: Preferences.shared.defaultPostVisibility) { (visibility) in - guard let visibility = visibility else { return } - Preferences.shared.defaultPostVisibility = visibility - self.defaultPostVisibilityLabel.text = visibility.displayName - } - present(alertController, animated: true) - } - - @IBAction func automaticallySaveDraftsChanged(_ sender: Any) { - Preferences.shared.automaticallySaveDrafts = automaticallySaveDraftsSwitch.isOn - } - - @IBAction func openLinksInAppsChanged(_ sender: Any) { - Preferences.shared.openLinksInApps = openLinksInAppsSwitch.isOn - } - - -} diff --git a/Tusker/Screens/Preferences/Preferences.storyboard b/Tusker/Screens/Preferences/Preferences.storyboard deleted file mode 100644 index ac24a88fe3..0000000000 --- a/Tusker/Screens/Preferences/Preferences.storyboard +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This option is only supported for Pleroma instances with formatting enabled. On all other instances, formatting symbols will remain in the plain, unformatted text. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tusker/Screens/Preferences/PreferencesTableViewController.swift b/Tusker/Screens/Preferences/PreferencesTableViewController.swift deleted file mode 100644 index 26607b9ef0..0000000000 --- a/Tusker/Screens/Preferences/PreferencesTableViewController.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// PreferencesTableViewController.swift -// Tusker -// -// Created by Shadowfacts on 8/28/18. -// Copyright © 2018 Shadowfacts. All rights reserved. -// - -import UIKit - -class PreferencesTableViewController: UITableViewController { - - static func create() -> UINavigationController { - guard let navigationController = UIStoryboard(name: "Preferences", bundle: nil).instantiateInitialViewController() as? UINavigationController else { fatalError() } - return navigationController - } - - @IBAction func donePressed(_ sender: Any) { - dismiss(animated: true) - } - -} diff --git a/Tusker/Screens/Preferences/SilentActionPermissionsTableViewController.swift b/Tusker/Screens/Preferences/SilentActionPermissionsTableViewController.swift deleted file mode 100644 index 047bfcb50e..0000000000 --- a/Tusker/Screens/Preferences/SilentActionPermissionsTableViewController.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// SilentActionPermissionsTableViewController.swift -// Tusker -// -// Created by Shadowfacts on 9/30/18. -// Copyright © 2018 Shadowfacts. All rights reserved. -// - -import UIKit - -class SilentActionPermissionsTableViewController: UITableViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.register(UINib(nibName: "SilentActionPermissionCell", bundle: nil), forCellReuseIdentifier: "permissionCell") - } - - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return Preferences.shared.silentActions.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: "permissionCell", for: indexPath) as? SilentActionPermissionTableViewCell else { fatalError() } - - let index = Preferences.shared.silentActions.index(Preferences.shared.silentActions.startIndex, offsetBy: indexPath.row) - let (source, permission) = Preferences.shared.silentActions[index] - cell.updateUI(source: source, permission: permission) - - return cell - } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - -} From 1e8ba5000bd178e08f8a73e21b25d23f90994266 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 27 Jul 2019 21:43:08 -0400 Subject: [PATCH 8/8] Cleanup code --- .../Preferences/AdvancedPrefsView.swift | 53 +++++++++++++------ .../Preferences/BehaviorPrefsView.swift | 47 +++++++++------- 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/Tusker/Screens/Preferences/AdvancedPrefsView.swift b/Tusker/Screens/Preferences/AdvancedPrefsView.swift index b948c631b9..cfff61c27e 100644 --- a/Tusker/Screens/Preferences/AdvancedPrefsView.swift +++ b/Tusker/Screens/Preferences/AdvancedPrefsView.swift @@ -13,23 +13,46 @@ struct AdvancedPrefsView : View { var body: some View { List { - Section(footer: Text("This option is only supported for Pleroma and Mastodon instances with formatting enabled. On all other instances, formatting symbols will remain in the unformatted plain text.").lineLimit(nil)) { - Picker(selection: _statusContentType.binding, label: Text("Post Content Type")) { - ForEach(StatusContentType.allCases, id: \.self) { type in - Text(type.displayName).tag(type) - }//.navigationBarTitle("Post Content Type") - // see FB6838291 - } - } - - Section(header: Text("AUTOMATION")) { - NavigationLink(destination: SilentActionPrefs()) { - Text("Silent Action Permissions") - } + formattingSection + automationSection + }.listStyle(.grouped) + .navigationBarTitle(Text("Advanced")) + } + + var formattingFooter: some View { + Text("This option is only supported for Pleroma and Mastodon instances with formatting enabled. On all other instances, formatting symbols will remain in the unformatted plain text.").lineLimit(nil) + } + + var formattingSection: some View { + Section(footer: formattingFooter) { + Picker(selection: _statusContentType.binding, label: Text("Post Content Type")) { + ForEach(StatusContentType.allCases, id: \.self) { type in + Text(type.displayName).tag(type) + }//.navigationBarTitle("Post Content Type") + // see FB6838291 } } - .listStyle(.grouped) - .navigationBarTitle(Text("Advanced")) + } + + var automationSection: some View { + Section(header: Text("AUTOMATION")) { + NavigationLink(destination: SilentActionPrefs()) { + Text("Silent Action Permissions") + } + } + } +} + +extension StatusContentType { + var displayName: String { + switch self { + case .plain: + return "Plain" + case .markdown: + return "Markdown" + case .html: + return "HTML" + } } } diff --git a/Tusker/Screens/Preferences/BehaviorPrefsView.swift b/Tusker/Screens/Preferences/BehaviorPrefsView.swift index 7fcb1c9e50..a7b971d0fb 100644 --- a/Tusker/Screens/Preferences/BehaviorPrefsView.swift +++ b/Tusker/Screens/Preferences/BehaviorPrefsView.swift @@ -15,29 +15,36 @@ struct BehaviorPrefsView : View { var body: some View { List { - Section { - Picker(selection: _defaultPostVisibility.binding, label: Text("Default Post Visibility")) { - ForEach(Status.Visibility.allCases, id: \.self) { visibility in - HStack { - Image(systemName: visibility.imageName) - Text(visibility.displayName) - } - .tag(visibility) - }//.navigationBarTitle("Default Post Visibility") - // navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291 - } - Toggle(isOn: _automaticallySaveDrafts.binding) { - Text("Automatically Save Drafts") - } + section1 + section2 + }.listStyle(.grouped) + .navigationBarTitle(Text("Behavior")) + } + + var section1: some View { + Section { + Picker(selection: _defaultPostVisibility.binding, label: Text("Default Post Visibility")) { + ForEach(Status.Visibility.allCases, id: \.self) { visibility in + HStack { + Image(systemName: visibility.imageName) + Text(visibility.displayName) + } + .tag(visibility) + }//.navigationBarTitle("Default Post Visibility") + // navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291 } - Section { - Toggle(isOn: _openLinksInApps.binding) { - Text("Open Links in Apps") - } + Toggle(isOn: _automaticallySaveDrafts.binding) { + Text("Automatically Save Drafts") + } + } + } + + var section2: some View { + Section { + Toggle(isOn: _openLinksInApps.binding) { + Text("Open Links in Apps") } } - .listStyle(.grouped) - .navigationBarTitle(Text("Behavior")) } }