UserPreferences -> Observable

This commit is contained in:
Thomas Ricouard 2023-09-19 09:18:20 +02:00
parent fd09276d49
commit 6c23569d15
32 changed files with 390 additions and 122 deletions

View file

@ -113,7 +113,7 @@ extension View {
func withEnvironments() -> some View {
environment(CurrentAccount.shared)
.environmentObject(UserPreferences.shared)
.environment(UserPreferences.shared)
.environment(CurrentInstance.shared)
.environment(Theme.shared)
.environment(AppAccountsManager.shared)

View file

@ -18,7 +18,7 @@ struct IceCubesApp: App {
@State private var appAccountsManager = AppAccountsManager.shared
@State private var currentInstance = CurrentInstance.shared
@State private var currentAccount = CurrentAccount.shared
@StateObject private var userPreferences = UserPreferences.shared
@State private var userPreferences = UserPreferences.shared
@State private var pushNotificationsService = PushNotificationsService.shared
@State private var watcher = StreamWatcher()
@State private var quickLook = QuickLook()
@ -48,7 +48,7 @@ struct IceCubesApp: App {
.environment(quickLook)
.environment(currentAccount)
.environment(currentInstance)
.environmentObject(userPreferences)
.environment(userPreferences)
.environment(theme)
.environment(watcher)
.environment(pushNotificationsService)

View file

@ -13,7 +13,7 @@ extension View {
@MainActor
private struct SafariRouter: ViewModifier {
@Environment(Theme.self) private var theme
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(RouterPath.self) private var routerPath
@State private var safariManager = InAppSafariManager()

View file

@ -5,12 +5,13 @@ import Env
import Models
import SwiftUI
@MainActor
struct SideBarView<Content: View>: View {
@Environment(AppAccountsManager.self) private var appAccounts
@Environment(CurrentAccount.self) private var currentAccount
@Environment(Theme.self) private var theme
@Environment(StreamWatcher.self) private var watcher
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
@Environment(RouterPath.self) private var routerPath
@Binding var selectedTab: Tab

View file

@ -7,9 +7,10 @@ import Network
import Shimmer
import SwiftUI
@MainActor
struct ExploreTab: View {
@Environment(Theme.self) private var theme
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(CurrentAccount.self) private var currentAccount
@Environment(Client.self) private var client
@State private var routerPath = RouterPath()

View file

@ -7,6 +7,7 @@ import Notifications
import SwiftUI
import Timeline
@MainActor
struct NotificationsTab: View {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
@Environment(\.scenePhase) private var scenePhase
@ -16,7 +17,7 @@ struct NotificationsTab: View {
@Environment(StreamWatcher.self) private var watcher
@Environment(AppAccountsManager.self) private var appAccount
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
@Environment(PushNotificationsService.self) private var pushNotificationsService
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab

View file

@ -7,11 +7,13 @@ import NukeUI
import SwiftUI
import UserNotifications
@MainActor
struct ContentSettingsView: View {
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
@Environment(Theme.self) private var theme
var body: some View {
@Bindable var userPreferences = userPreferences
Form {
Section("settings.content.boosts") {
Toggle(isOn: $userPreferences.suppressDupeReblogs) {

View file

@ -18,12 +18,13 @@ import SwiftUI
init() {}
}
@MainActor
struct DisplaySettingsView: View {
typealias FontState = Theme.FontState
@Environment(\.colorScheme) private var colorScheme
@Environment(Theme.self) private var theme
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
@State private var localValues = DisplaySettingsLocalValues()
@ -180,6 +181,7 @@ struct DisplaySettingsView: View {
@ViewBuilder
private var layoutSection: some View {
@Bindable var theme = theme
@Bindable var userPreferences = userPreferences
Section("settings.display.section.display") {
Picker("settings.display.avatar.position", selection: $theme.avatarPosition) {
ForEach(Theme.AvatarPosition.allCases, id: \.rawValue) { position in
@ -210,6 +212,7 @@ struct DisplaySettingsView: View {
@ViewBuilder
private var platformsSection: some View {
@Bindable var userPreferences = userPreferences
if UIDevice.current.userInterfaceIdiom == .phone {
Section("iPhone") {
Toggle("settings.display.show-tab-label", isOn: $userPreferences.showiPhoneTabLabel)

View file

@ -4,11 +4,13 @@ import Models
import Status
import SwiftUI
@MainActor
struct HapticSettingsView: View {
@Environment(Theme.self) private var theme
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
var body: some View {
@Bindable var userPreferences = userPreferences
Form {
Section {
Toggle("settings.haptic.timeline", isOn: $userPreferences.hapticTimelineEnabled)

View file

@ -9,11 +9,12 @@ import Nuke
import SwiftUI
import Timeline
@MainActor
struct SettingsTabs: View {
@Environment(\.dismiss) private var dismiss
@Environment(PushNotificationsService.self) private var pushNotifications
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Client.self) private var client
@Environment(CurrentInstance.self) private var currentInstance
@Environment(AppAccountsManager.self) private var appAccountsManager
@ -158,7 +159,9 @@ struct SettingsTabs: View {
.listRowBackground(theme.primaryBackgroundColor)
}
@ViewBuilder
private var otherSections: some View {
@Bindable var preferences = preferences
Section("settings.section.other") {
if !ProcessInfo.processInfo.isiOSAppOnMac {
Picker(selection: $preferences.preferredBrowser) {

View file

@ -2,11 +2,13 @@ import DesignSystem
import Env
import SwiftUI
@MainActor
struct SwipeActionsSettingsView: View {
@Environment(Theme.self) private var theme
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
var body: some View {
@Bindable var userPreferences = userPreferences
Form {
Section {
Label("settings.swipeactions.status.leading", systemImage: "arrow.right")

View file

@ -2,26 +2,19 @@ import DesignSystem
import Env
import SwiftUI
@MainActor
struct TranslationSettingsView: View {
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@State private var apiKey: String = ""
var body: some View {
Form {
Toggle(isOn: preferences.$alwaysUseDeepl) {
Text("settings.translation.always-deepl")
}
.listRowBackground(theme.primaryBackgroundColor)
deepLToggle
if preferences.alwaysUseDeepl {
Section("settings.translation.user-api-key") {
Picker("settings.translation.api-key-type", selection: $preferences.userDeeplAPIFree) {
Text("DeepL API Free").tag(true)
Text("DeepL API Pro").tag(false)
}
deepLPicker
SecureField("settings.translation.user-api-key", text: $apiKey)
.textContentType(.password)
}
@ -40,14 +33,7 @@ struct TranslationSettingsView: View {
.listRowBackground(theme.primaryBackgroundColor)
}
}
Section {
Toggle(isOn: preferences.$autoDetectPostLanguage) {
Text("settings.translation.auto-detect-post-language")
}
} footer: {
Text("settings.translation.auto-detect-post-language-footer")
}
autoDetectSection
}
.navigationTitle("settings.translation.navigation-title")
.scrollContentBackground(.hidden)
@ -57,6 +43,36 @@ struct TranslationSettingsView: View {
}
.onAppear(perform: updatePrefs)
}
@ViewBuilder
private var deepLToggle: some View {
@Bindable var preferences = preferences
Toggle(isOn: $preferences.alwaysUseDeepl) {
Text("settings.translation.always-deepl")
}
.listRowBackground(theme.primaryBackgroundColor)
}
@ViewBuilder
private var deepLPicker: some View {
@Bindable var preferences = preferences
Picker("settings.translation.api-key-type", selection: $preferences.userDeeplAPIFree) {
Text("DeepL API Free").tag(true)
Text("DeepL API Pro").tag(false)
}
}
@ViewBuilder
private var autoDetectSection: some View {
@Bindable var preferences = preferences
Section {
Toggle(isOn: $preferences.autoDetectPostLanguage) {
Text("settings.translation.auto-detect-post-language")
}
} footer: {
Text("settings.translation.auto-detect-post-language-footer")
}
}
private func writeNewValue() {
writeNewValue(value: apiKey)
@ -82,6 +98,6 @@ struct TranslationSettingsView: View {
struct TranslationSettingsView_Previews: PreviewProvider {
static var previews: some View {
TranslationSettingsView()
.environmentObject(UserPreferences.shared)
.environment(UserPreferences.shared)
}
}

View file

@ -7,10 +7,11 @@ import NukeUI
import Shimmer
import SwiftUI
@MainActor
struct AddRemoteTimelineView: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@State private var instanceName: String = ""

View file

@ -7,10 +7,11 @@ import NukeUI
import Shimmer
import SwiftUI
@MainActor
struct EditTagGroupView: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@State private var title: String = ""

View file

@ -7,11 +7,12 @@ import Network
import SwiftUI
import Timeline
@MainActor
struct TimelineTab: View {
@Environment(AppAccountsManager.self) private var appAccount
@Environment(Theme.self) private var theme
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Client.self) private var client
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab

View file

@ -27,7 +27,7 @@ class ShareViewController: UIViewController {
if let item = extensionContext?.inputItems.first as? NSExtensionItem {
if let attachments = item.attachments {
let view = StatusEditorView(mode: .shareExtension(items: attachments))
.environmentObject(UserPreferences.shared)
.environment(UserPreferences.shared)
.environment(appAccountsManager)
.environment(client)
.environment(account)

View file

@ -6,7 +6,7 @@ public struct AccountDetailContextMenu: View {
@Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath
@Environment(CurrentInstance.self) private var currentInstance
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
var viewModel: AccountDetailViewModel

View file

@ -7,6 +7,7 @@ import Shimmer
import Status
import SwiftUI
@MainActor
public struct AccountDetailView: View {
@Environment(\.openURL) private var openURL
@Environment(\.redactionReasons) private var reasons
@ -14,7 +15,7 @@ public struct AccountDetailView: View {
@Environment(StreamWatcher.self) private var watcher
@Environment(CurrentAccount.self) private var currentAccount
@Environment(CurrentInstance.self) private var currentInstance
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath

View file

@ -4,6 +4,7 @@ import Models
import Network
import SwiftUI
@MainActor
public struct FiltersListView: View {
@Environment(\.dismiss) private var dismiss

View file

@ -3,11 +3,12 @@ import EmojiText
import Env
import SwiftUI
@MainActor
public struct AppAccountView: View {
@Environment(Theme.self) private var theme
@Environment(RouterPath.self) private var routerPath
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@State var viewModel: AppAccountViewModel

View file

@ -2,8 +2,9 @@ import DesignSystem
import Env
import SwiftUI
@MainActor
public struct AppAccountsSelectorView: View {
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(CurrentAccount.self) private var currentAccount
@Environment(AppAccountsManager.self) private var appAccounts
@Environment(Theme.self) private var theme

View file

@ -5,8 +5,9 @@ import Network
import Shimmer
import SwiftUI
@MainActor
public struct ConversationsListView: View {
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(RouterPath.self) private var routerPath
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client

View file

@ -55,7 +55,7 @@ public struct StatusEditorToolbarItem: ToolbarContent {
@MainActor
public struct SecondaryColumnToolbarItem: ToolbarContent {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
public init() {}

View file

@ -5,63 +5,250 @@ import Network
import SwiftUI
@MainActor
public class UserPreferences: ObservableObject {
@Observable public class UserPreferences {
class Storage {
@AppStorage("remote_local_timeline") public var remoteLocalTimelines: [String] = []
@AppStorage("tag_groups") public var tagGroups: [TagGroup] = []
@AppStorage("preferred_browser") public var preferredBrowser: PreferredBrowser = .inAppSafari
@AppStorage("draft_posts") public var draftsPosts: [String] = []
@AppStorage("show_translate_button_inline") public var showTranslateButton: Bool = true
@AppStorage("is_open_ai_enabled") public var isOpenAIEnabled: Bool = true
@AppStorage("recently_used_languages") public var recentlyUsedLanguages: [String] = []
@AppStorage("social_keyboard_composer") public var isSocialKeyboardEnabled: Bool = true
@AppStorage("use_instance_content_settings") public var useInstanceContentSettings: Bool = true
@AppStorage("app_auto_expand_spoilers") public var appAutoExpandSpoilers = false
@AppStorage("app_auto_expand_media") public var appAutoExpandMedia: ServerPreferences.AutoExpandMedia = .hideSensitive
@AppStorage("app_default_post_visibility") public var appDefaultPostVisibility: Models.Visibility = .pub
@AppStorage("app_default_reply_visibility") public var appDefaultReplyVisibility: Models.Visibility = .pub
@AppStorage("app_default_posts_sensitive") public var appDefaultPostsSensitive = false
@AppStorage("autoplay_video") public var autoPlayVideo = true
@AppStorage("always_use_deepl") public var alwaysUseDeepl = false
@AppStorage("user_deepl_api_free") public var userDeeplAPIFree = true
@AppStorage("auto_detect_post_language") public var autoDetectPostLanguage = true
@AppStorage("suppress_dupe_reblogs") public var suppressDupeReblogs: Bool = false
@AppStorage("inAppBrowserReaderView") public var inAppBrowserReaderView = false
@AppStorage("haptic_tab") public var hapticTabSelectionEnabled = true
@AppStorage("haptic_timeline") public var hapticTimelineEnabled = true
@AppStorage("haptic_button_press") public var hapticButtonPressEnabled = true
@AppStorage("sound_effect_enabled") public var soundEffectEnabled = true
@AppStorage("show_tab_label_iphone") public var showiPhoneTabLabel = true
@AppStorage("show_alt_text_for_media") public var showAltTextForMedia = true
@AppStorage("show_second_column_ipad") public var showiPadSecondaryColumn = true
@AppStorage("swipeactions-status-trailing-right") public var swipeActionsStatusTrailingRight = StatusAction.favorite
@AppStorage("swipeactions-status-trailing-left") public var swipeActionsStatusTrailingLeft = StatusAction.boost
@AppStorage("swipeactions-status-leading-left") public var swipeActionsStatusLeadingLeft = StatusAction.reply
@AppStorage("swipeactions-status-leading-right") public var swipeActionsStatusLeadingRight = StatusAction.none
@AppStorage("swipeactions-use-theme-color") public var swipeActionsUseThemeColor = false
@AppStorage("swipeactions-icon-style") public var swipeActionsIconStyle: SwipeActionsIconStyle = .iconWithText
@AppStorage("requested_review") public var requestedReview = false
@AppStorage("collapse-long-posts") public var collapseLongPosts = true
@AppStorage("share-button-behavior") public var shareButtonBehavior: PreferredShareButtonBehavior = .linkAndText
init() { }
}
public static let sharedDefault = UserDefaults(suiteName: "group.com.thomasricouard.IceCubesApp")
public static let shared = UserPreferences()
private let storage = Storage()
private var client: Client?
@AppStorage("remote_local_timeline") public var remoteLocalTimelines: [String] = []
@AppStorage("tag_groups") public var tagGroups: [TagGroup] = []
@AppStorage("preferred_browser") public var preferredBrowser: PreferredBrowser = .inAppSafari
@AppStorage("draft_posts") public var draftsPosts: [String] = []
@AppStorage("show_translate_button_inline") public var showTranslateButton: Bool = true
@AppStorage("is_open_ai_enabled") public var isOpenAIEnabled: Bool = true
@AppStorage("recently_used_languages") public var recentlyUsedLanguages: [String] = []
@AppStorage("social_keyboard_composer") public var isSocialKeyboardEnabled: Bool = true
@AppStorage("use_instance_content_settings") public var useInstanceContentSettings: Bool = true
@AppStorage("app_auto_expand_spoilers") public var appAutoExpandSpoilers = false
@AppStorage("app_auto_expand_media") public var appAutoExpandMedia: ServerPreferences.AutoExpandMedia = .hideSensitive
@AppStorage("app_default_post_visibility") public var appDefaultPostVisibility: Models.Visibility = .pub
@AppStorage("app_default_reply_visibility") public var appDefaultReplyVisibility: Models.Visibility = .pub
@AppStorage("app_default_posts_sensitive") public var appDefaultPostsSensitive = false
@AppStorage("autoplay_video") public var autoPlayVideo = true
@AppStorage("always_use_deepl") public var alwaysUseDeepl = false
@AppStorage("user_deepl_api_free") public var userDeeplAPIFree = true
@AppStorage("auto_detect_post_language") public var autoDetectPostLanguage = true
@AppStorage("suppress_dupe_reblogs") public var suppressDupeReblogs: Bool = false
@AppStorage("inAppBrowserReaderView") public var inAppBrowserReaderView = false
@AppStorage("haptic_tab") public var hapticTabSelectionEnabled = true
@AppStorage("haptic_timeline") public var hapticTimelineEnabled = true
@AppStorage("haptic_button_press") public var hapticButtonPressEnabled = true
@AppStorage("sound_effect_enabled") public var soundEffectEnabled = true
@AppStorage("show_tab_label_iphone") public var showiPhoneTabLabel = true
@AppStorage("show_alt_text_for_media") public var showAltTextForMedia = true
@AppStorage("show_second_column_ipad") public var showiPadSecondaryColumn = true
@AppStorage("swipeactions-status-trailing-right") public var swipeActionsStatusTrailingRight = StatusAction.favorite
@AppStorage("swipeactions-status-trailing-left") public var swipeActionsStatusTrailingLeft = StatusAction.boost
@AppStorage("swipeactions-status-leading-left") public var swipeActionsStatusLeadingLeft = StatusAction.reply
@AppStorage("swipeactions-status-leading-right") public var swipeActionsStatusLeadingRight = StatusAction.none
@AppStorage("swipeactions-use-theme-color") public var swipeActionsUseThemeColor = false
@AppStorage("swipeactions-icon-style") public var swipeActionsIconStyle: SwipeActionsIconStyle = .iconWithText
@AppStorage("requested_review") public var requestedReview = false
@AppStorage("collapse-long-posts") public var collapseLongPosts = true
@AppStorage("share-button-behavior") public var shareButtonBehavior: PreferredShareButtonBehavior = .linkAndText
public var remoteLocalTimelines: [String] {
didSet {
storage.remoteLocalTimelines = remoteLocalTimelines
}
}
public var tagGroups: [TagGroup] {
didSet {
storage.tagGroups = tagGroups
}
}
public var preferredBrowser: PreferredBrowser {
didSet {
storage.preferredBrowser = preferredBrowser
}
}
public var draftsPosts: [String] {
didSet {
storage.draftsPosts = draftsPosts
}
}
public var showTranslateButton: Bool {
didSet {
storage.showTranslateButton = showTranslateButton
}
}
public var isOpenAIEnabled: Bool {
didSet {
storage.isOpenAIEnabled = isOpenAIEnabled
}
}
public var recentlyUsedLanguages: [String] {
didSet {
storage.recentlyUsedLanguages = recentlyUsedLanguages
}
}
public var isSocialKeyboardEnabled: Bool {
didSet {
storage.isSocialKeyboardEnabled = isSocialKeyboardEnabled
}
}
public var useInstanceContentSettings: Bool {
didSet {
storage.useInstanceContentSettings = useInstanceContentSettings
}
}
public var appAutoExpandSpoilers: Bool {
didSet {
storage.appAutoExpandSpoilers = appAutoExpandSpoilers
}
}
public var appAutoExpandMedia: ServerPreferences.AutoExpandMedia {
didSet {
storage.appAutoExpandMedia = appAutoExpandMedia
}
}
public var appDefaultPostVisibility: Models.Visibility {
didSet {
storage.appDefaultPostVisibility = appDefaultPostVisibility
}
}
public var appDefaultReplyVisibility: Models.Visibility {
didSet {
storage.appDefaultReplyVisibility = appDefaultReplyVisibility
}
}
public var appDefaultPostsSensitive: Bool {
didSet {
storage.appDefaultPostsSensitive = appDefaultPostsSensitive
}
}
public var autoPlayVideo: Bool {
didSet {
storage.autoPlayVideo = autoPlayVideo
}
}
public var alwaysUseDeepl: Bool {
didSet {
storage.alwaysUseDeepl = alwaysUseDeepl
}
}
public var userDeeplAPIFree: Bool {
didSet {
storage.userDeeplAPIFree = userDeeplAPIFree
}
}
public var autoDetectPostLanguage: Bool {
didSet {
storage.autoDetectPostLanguage = autoDetectPostLanguage
}
}
public var suppressDupeReblogs: Bool {
didSet {
storage.suppressDupeReblogs = suppressDupeReblogs
}
}
public var inAppBrowserReaderView: Bool {
didSet {
storage.inAppBrowserReaderView = inAppBrowserReaderView
}
}
public var hapticTabSelectionEnabled: Bool {
didSet {
storage.hapticTabSelectionEnabled = hapticTabSelectionEnabled
}
}
public var hapticTimelineEnabled: Bool {
didSet {
storage.hapticTimelineEnabled = hapticTimelineEnabled
}
}
public var hapticButtonPressEnabled: Bool {
didSet {
storage.hapticButtonPressEnabled = hapticButtonPressEnabled
}
}
public var soundEffectEnabled: Bool {
didSet {
storage.soundEffectEnabled = soundEffectEnabled
}
}
public var showiPhoneTabLabel: Bool {
didSet {
storage.showiPhoneTabLabel = showiPhoneTabLabel
}
}
public var showAltTextForMedia: Bool {
didSet {
storage.showAltTextForMedia = showAltTextForMedia
}
}
public var showiPadSecondaryColumn: Bool {
didSet {
storage.showiPadSecondaryColumn = showiPadSecondaryColumn
}
}
public var swipeActionsStatusTrailingRight: StatusAction {
didSet {
storage.swipeActionsStatusTrailingRight = swipeActionsStatusTrailingRight
}
}
public var swipeActionsStatusTrailingLeft: StatusAction {
didSet {
storage.swipeActionsStatusTrailingLeft = swipeActionsStatusTrailingLeft
}
}
public var swipeActionsStatusLeadingLeft: StatusAction {
didSet {
storage.swipeActionsStatusLeadingLeft = swipeActionsStatusLeadingLeft
}
}
public var swipeActionsStatusLeadingRight: StatusAction {
didSet {
storage.swipeActionsStatusLeadingRight = swipeActionsStatusLeadingRight
}
}
public var swipeActionsUseThemeColor: Bool {
didSet {
storage.swipeActionsUseThemeColor = swipeActionsUseThemeColor
}
}
public var swipeActionsIconStyle: SwipeActionsIconStyle {
didSet {
storage.swipeActionsIconStyle = swipeActionsIconStyle
}
}
public var requestedReview: Bool {
didSet {
storage.requestedReview = requestedReview
}
}
public var collapseLongPosts: Bool {
didSet {
storage.collapseLongPosts = collapseLongPosts
}
}
public var shareButtonBehavior: PreferredShareButtonBehavior {
didSet {
storage.shareButtonBehavior = shareButtonBehavior
}
}
public enum SwipeActionsIconStyle: String, CaseIterable {
case iconWithText, iconOnly
public var description: LocalizedStringKey {
switch self {
case .iconWithText:
@ -70,7 +257,7 @@ public class UserPreferences: ObservableObject {
"enum.swipeactions.icon-only"
}
}
// Have to implement this manually here due to compiler not implicitly
// inserting `nonisolated`, which leads to a warning:
//
@ -81,7 +268,7 @@ public class UserPreferences: ObservableObject {
[.iconWithText, .iconOnly]
}
}
public var postVisibility: Models.Visibility {
if useInstanceContentSettings {
serverPreferences?.postVisibility ?? .pub
@ -89,26 +276,26 @@ public class UserPreferences: ObservableObject {
appDefaultPostVisibility
}
}
public func conformReplyVisibilityConstraints() {
appDefaultReplyVisibility = getReplyVisibility()
}
private func getReplyVisibility() -> Models.Visibility {
getMinVisibility(postVisibility, appDefaultReplyVisibility)
}
public func getReplyVisibility(of status: Status) -> Models.Visibility {
getMinVisibility(getReplyVisibility(), status.visibility)
}
private func getMinVisibility(_ vis1: Models.Visibility, _ vis2: Models.Visibility) -> Models.Visibility {
let no1 = Self.getIntOfVisibility(vis1)
let no2 = Self.getIntOfVisibility(vis2)
return no1 < no2 ? vis1 : vis2
}
public var postIsSensitive: Bool {
if useInstanceContentSettings {
serverPreferences?.postIsSensitive ?? false
@ -116,7 +303,7 @@ public class UserPreferences: ObservableObject {
appDefaultPostsSensitive
}
}
public var autoExpandSpoilers: Bool {
if useInstanceContentSettings {
serverPreferences?.autoExpandSpoilers ?? true
@ -124,7 +311,7 @@ public class UserPreferences: ObservableObject {
appAutoExpandSpoilers
}
}
public var autoExpandMedia: ServerPreferences.AutoExpandMedia {
if useInstanceContentSettings {
serverPreferences?.autoExpandMedia ?? .hideSensitive
@ -132,8 +319,8 @@ public class UserPreferences: ObservableObject {
appAutoExpandMedia
}
}
@Published public var notificationsCount: [OauthToken: Int] = [:] {
public var notificationsCount: [OauthToken: Int] = [:] {
didSet {
for (key, value) in notificationsCount {
Self.sharedDefault?.set(value, forKey: "push_notifications_count_\(key.createdAt)")
@ -152,22 +339,20 @@ public class UserPreferences: ObservableObject {
}
}
@Published public var serverPreferences: ServerPreferences?
private init() {}
public var serverPreferences: ServerPreferences?
public func setClient(client: Client) {
self.client = client
Task {
await refreshServerPreferences()
}
}
public func refreshServerPreferences() async {
guard let client, client.isAuth else { return }
serverPreferences = try? await client.get(endpoint: Accounts.preferences)
}
public func markLanguageAsSelected(isoCode: String) {
var copy = recentlyUsedLanguages
if let index = copy.firstIndex(of: isoCode) {
@ -176,7 +361,7 @@ public class UserPreferences: ObservableObject {
copy.insert(isoCode, at: 0)
recentlyUsedLanguages = Array(copy.prefix(3))
}
public static func getIntOfVisibility(_ vis: Models.Visibility) -> Int {
switch vis {
case .direct:
@ -189,4 +374,43 @@ public class UserPreferences: ObservableObject {
3
}
}
private init() {
remoteLocalTimelines = storage.remoteLocalTimelines
tagGroups = storage.tagGroups
preferredBrowser = storage.preferredBrowser
draftsPosts = storage.draftsPosts
showTranslateButton = storage.showTranslateButton
isOpenAIEnabled = storage.isOpenAIEnabled
recentlyUsedLanguages = storage.recentlyUsedLanguages
isSocialKeyboardEnabled = storage.isSocialKeyboardEnabled
useInstanceContentSettings = storage.useInstanceContentSettings
appAutoExpandSpoilers = storage.appAutoExpandSpoilers
appAutoExpandMedia = storage.appAutoExpandMedia
appDefaultPostVisibility = storage.appDefaultPostVisibility
appDefaultReplyVisibility = storage.appDefaultReplyVisibility
appDefaultPostsSensitive = storage.appDefaultPostsSensitive
autoPlayVideo = storage.autoPlayVideo
alwaysUseDeepl = storage.alwaysUseDeepl
userDeeplAPIFree = storage.userDeeplAPIFree
autoDetectPostLanguage = storage.autoDetectPostLanguage
suppressDupeReblogs = storage.suppressDupeReblogs
inAppBrowserReaderView = storage.inAppBrowserReaderView
hapticTabSelectionEnabled = storage.hapticTabSelectionEnabled
hapticTimelineEnabled = storage.hapticTimelineEnabled
hapticButtonPressEnabled = storage.hapticButtonPressEnabled
soundEffectEnabled = storage.soundEffectEnabled
showiPhoneTabLabel = storage.showiPhoneTabLabel
showAltTextForMedia = storage.showAltTextForMedia
showiPadSecondaryColumn = storage.showiPadSecondaryColumn
swipeActionsStatusTrailingRight = storage.swipeActionsStatusTrailingRight
swipeActionsStatusTrailingLeft = storage.swipeActionsStatusTrailingLeft
swipeActionsStatusLeadingLeft = storage.swipeActionsStatusLeadingLeft
swipeActionsStatusLeadingRight = storage.swipeActionsStatusLeadingRight
swipeActionsUseThemeColor = storage.swipeActionsUseThemeColor
swipeActionsIconStyle = storage.swipeActionsIconStyle
requestedReview = storage.requestedReview
collapseLongPosts = storage.collapseLongPosts
shareButtonBehavior = storage.shareButtonBehavior
}
}

View file

@ -5,8 +5,9 @@ import NukeUI
import PhotosUI
import SwiftUI
@MainActor
struct StatusEditorAccessoryView: View {
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@Environment(CurrentInstance.self) private var currentInstance
@Environment(\.colorScheme) private var colorScheme

View file

@ -14,7 +14,7 @@ import UIKit
@MainActor
public struct StatusEditorView: View {
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@Environment(Client.self) private var client
@Environment(CurrentAccount.self) private var currentAccount

View file

@ -51,7 +51,7 @@ import SwiftUI
struct VideoPlayerView: View {
@Environment(\.scenePhase) private var scenePhase
@Environment(\.isCompact) private var isCompact
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
@State var viewModel: VideoPlayerViewModel

View file

@ -4,11 +4,12 @@ import Models
import Network
import SwiftUI
@MainActor
struct StatusRowActionsView: View {
@Environment(Theme.self) private var theme
@Environment(CurrentAccount.self) private var currentAccount
@Environment(StatusDataController.self) private var statusDataController
@EnvironmentObject private var userPreferences: UserPreferences
@Environment(UserPreferences.self) private var userPreferences
@Environment(\.isStatusFocused) private var isFocused

View file

@ -10,7 +10,7 @@ struct StatusRowContextMenu: View {
@Environment(Client.self) private var client
@Environment(SceneDelegate.self) private var sceneDelegate
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(CurrentAccount.self) private var account
@Environment(CurrentInstance.self) private var currentInstance
@Environment(StatusDataController.self) private var statusDataController
@ -87,7 +87,7 @@ struct StatusRowContextMenu: View {
}
.environment(\.isInCaptureMode, true)
.environment(Theme.shared)
.environmentObject(preferences)
.environment(preferences)
.environment(account)
.environment(currentInstance)
.environment(SceneDelegate())

View file

@ -5,6 +5,7 @@ import Nuke
import NukeUI
import SwiftUI
@MainActor
public struct StatusRowMediaPreviewView: View {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
@Environment(\.extraLeadingInset) private var extraLeadingInset: CGFloat
@ -12,7 +13,7 @@ public struct StatusRowMediaPreviewView: View {
@Environment(\.isCompact) private var isCompact: Bool
@Environment(SceneDelegate.self) private var sceneDelegate
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(QuickLook.self) private var quickLook
@Environment(Theme.self) private var theme

View file

@ -3,9 +3,10 @@ import Env
import Models
import SwiftUI
@MainActor
struct StatusRowSwipeView: View {
@Environment(Theme.self) private var theme
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
@Environment(CurrentAccount.self) private var currentAccount
@Environment(StatusDataController.self) private var statusDataController

View file

@ -3,11 +3,12 @@ import Env
import Models
import SwiftUI
@MainActor
struct StatusRowTranslateView: View {
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
@Environment(\.isCompact) private var isCompact: Bool
@EnvironmentObject private var preferences: UserPreferences
@Environment(UserPreferences.self) private var preferences
var viewModel: StatusRowViewModel