diff --git a/Development Assets/DevelopmentModels.swift b/Development Assets/DevelopmentModels.swift index e90872a..a2e9600 100644 --- a/Development Assets/DevelopmentModels.swift +++ b/Development Assets/DevelopmentModels.swift @@ -138,4 +138,8 @@ extension IdentitiesViewModel { static let development = SecondaryNavigationViewModel.development.identitiesViewModel() } +extension IdentityPreferencesViewModel { + static let development = SecondaryNavigationViewModel.development.identityPreferencesViewModel() +} + // swiftlint:enable force_try diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index fcec68e..f101d76 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -7,10 +7,10 @@ objects = { /* Begin PBXBuildFile section */ - D0091B6824DC10B30040E8D2 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* PreferencesView.swift */; }; - D0091B6924DC10B30040E8D2 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* PreferencesView.swift */; }; - D0091B6B24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */; }; - D0091B6C24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */; }; + D0091B6824DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */; }; + D0091B6924DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */; }; + D0091B6B24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */; }; + D0091B6C24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */; }; D047FAAE24C3E21200AF17C5 /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D047FA8524C3E21000AF17C5 /* MetatextApp.swift */; }; D047FAAF24C3E21200AF17C5 /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D047FA8524C3E21000AF17C5 /* MetatextApp.swift */; }; D047FAB224C3E21200AF17C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D047FA8724C3E21200AF17C5 /* Assets.xcassets */; }; @@ -163,8 +163,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - D0091B6724DC10B30040E8D2 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = ""; }; - D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewModel.swift; sourceTree = ""; }; + D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityPreferencesView.swift; sourceTree = ""; }; + D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityPreferencesViewModel.swift; sourceTree = ""; }; D047FA8524C3E21000AF17C5 /* MetatextApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetatextApp.swift; sourceTree = ""; }; D047FA8724C3E21200AF17C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -385,7 +385,7 @@ children = ( D0DB6EF324C5228A00D965FE /* AddIdentityView.swift */, D06BAB5024D942CF0081B8FD /* IdentitiesView.swift */, - D0091B6724DC10B30040E8D2 /* PreferencesView.swift */, + D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */, D0BEC93A24C96FD500E864C4 /* RootView.swift */, D04FD73224D48F37007D572D /* SecondaryNavigationView.swift */, D0BEC94924CA231200E864C4 /* TimelineView.swift */, @@ -412,7 +412,7 @@ D0DB6F0824C65AC000D965FE /* AddIdentityViewModel.swift */, D06BAB4D24D942BC0081B8FD /* IdentitiesViewModel.swift */, D052BBDF24D805E300A80A7A /* MainNavigationViewModel.swift */, - D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */, + D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */, D0BEC93724C9632800E864C4 /* RootViewModel.swift */, D04FD73524D49506007D572D /* SecondaryNavigationViewModel.swift */, D0BEC94624CA22C400E864C4 /* TimelineViewModel.swift */, @@ -715,7 +715,7 @@ D0C963FB24CC359D003BD330 /* AlertItem.swift in Sources */, D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */, - D0091B6B24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */, + D0091B6B24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */, D0666A5724C6C63400F3F04B /* MastodonDecoder.swift in Sources */, D0DB6EF424C5228A00D965FE /* AddIdentityView.swift in Sources */, D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */, @@ -736,7 +736,7 @@ D0CD847C24DBEA9F00CF380C /* Unknowable.swift in Sources */, D0666A6F24C6DFB300F3F04B /* AccessToken.swift in Sources */, D0ED1BCB24CF744200B4899C /* MastodonClient.swift in Sources */, - D0091B6824DC10B30040E8D2 /* PreferencesView.swift in Sources */, + D0091B6824DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */, D0CD847624DBDF3C00CF380C /* Status.swift in Sources */, D052BBE024D805E300A80A7A /* MainNavigationViewModel.swift in Sources */, ); @@ -787,7 +787,7 @@ D0C963FC24CC359D003BD330 /* AlertItem.swift in Sources */, D0DC174724CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, D0DC174E24CFF1F100A75C65 /* Stubbing.swift in Sources */, - D0091B6C24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */, + D0091B6C24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */, D0666A5824C6C63400F3F04B /* MastodonDecoder.swift in Sources */, D0DB6EF524C5233E00D965FE /* AddIdentityView.swift in Sources */, D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */, @@ -808,7 +808,7 @@ D0CD847D24DBEA9F00CF380C /* Unknowable.swift in Sources */, D0666A7024C6DFB300F3F04B /* AccessToken.swift in Sources */, D0ED1BCC24CF744200B4899C /* MastodonClient.swift in Sources */, - D0091B6924DC10B30040E8D2 /* PreferencesView.swift in Sources */, + D0091B6924DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */, D0CD847724DBDF3C00CF380C /* Status.swift in Sources */, D052BBE124D805E300A80A7A /* MainNavigationViewModel.swift in Sources */, ); diff --git a/Shared/Localizations/Localizable.strings b/Shared/Localizations/Localizable.strings index 3048ab8..0c37c4e 100644 --- a/Shared/Localizations/Localizable.strings +++ b/Shared/Localizations/Localizable.strings @@ -3,4 +3,19 @@ "go" = "Go"; "add-identity.instance-url" = "Instance URL"; "oauth.error.code-not-found" = "OAuth error: code not found"; -"accounts" = "Accounts"; +"secondary-navigation.accounts" = "Accounts"; +"secondary-navigation.identity-preferences" = "Preferences"; +"preferences.title.%@" = "Preferences for %@"; +"preferences.posting" = "Posting"; +"preferences.use-preferences-from-server" = "Use preferences from server"; +"preferences.posting-default-visiblility" = "Default visibility"; +"preferences.posting-default-sensitive" = "Mark content sensitive by default"; +"preferences.reading" = "Reading"; +"preferences.reading-expand-media" = "Expand media"; +"preferences.expand-media.default" = "Hide sensitive"; +"preferences.expand-media.show-all" = "Show all"; +"preferences.expand-media.hide-all" = "Hide all"; +"preferences.reading-expand-spoilers" = "Always expand content warnings"; +"status.visibility.public" = "Public"; +"status.visibility.unlisted" = "Unlisted"; +"status.visibility.private" = "Private"; diff --git a/Shared/Model/Identity.swift b/Shared/Model/Identity.swift index e31175f..0bfb1ae 100644 --- a/Shared/Model/Identity.swift +++ b/Shared/Model/Identity.swift @@ -52,3 +52,24 @@ extension Identity { var image: URL? { account?.avatar ?? instance?.thumbnail } } + +extension Identity.Preferences { + var shouldUseAnyServerPreferences: Bool { + useServerPostingPreferences || useServerReadingPreferences + } + + func updated(from serverPreferences: MastodonPreferences) -> Self { + var mutable = self + if useServerPostingPreferences { + mutable.postingDefaultVisibility = serverPreferences.postingDefaultVisibility + mutable.postingDefaultSensitive = serverPreferences.postingDefaultSensitive + } + + if useServerReadingPreferences { + mutable.readingExpandMedia = serverPreferences.readingExpandMedia + mutable.readingExpandSpoilers = serverPreferences.readingExpandSpoilers + } + + return mutable + } +} diff --git a/Shared/Model/IdentityDatabase.swift b/Shared/Model/IdentityDatabase.swift index e845aae..8d59cd7 100644 --- a/Shared/Model/IdentityDatabase.swift +++ b/Shared/Model/IdentityDatabase.swift @@ -80,6 +80,18 @@ extension IdentityDatabase { .eraseToAnyPublisher() } + func updatePreferences(_ preferences: Identity.Preferences, + forIdentityID identityID: String) -> AnyPublisher { + databaseQueue.writePublisher { + let data = try StoredIdentity.databaseJSONEncoder(for: "preferences").encode(preferences) + + try StoredIdentity + .filter(Column("id") == identityID) + .updateAll($0, Column("preferences").set(to: data)) + } + .eraseToAnyPublisher() + } + func identityObservation(id: String) -> AnyPublisher { ValueObservation.tracking( StoredIdentity diff --git a/Shared/Model/Unknowable.swift b/Shared/Model/Unknowable.swift index 2b35993..54ba0c5 100644 --- a/Shared/Model/Unknowable.swift +++ b/Shared/Model/Unknowable.swift @@ -11,3 +11,7 @@ extension Unknowable { self = Self.allCases.first { $0.rawValue == rawValue } ?? Self.unknownCase } } + +extension Unknowable { + static var allCasesExceptUnknown: [Self] { allCases.filter { $0 != unknownCase } } +} diff --git a/Shared/Networking/Mastodon API/PreferencesEndpoint.swift b/Shared/Networking/Mastodon API/PreferencesEndpoint.swift index c903da3..7b1f8a3 100644 --- a/Shared/Networking/Mastodon API/PreferencesEndpoint.swift +++ b/Shared/Networking/Mastodon API/PreferencesEndpoint.swift @@ -11,7 +11,7 @@ extension PreferencesEndpoint: MastodonEndpoint { var pathComponentsInContext: [String] { switch self { - case .preferences: return ["instance"] + case .preferences: return ["preferences"] } } diff --git a/Shared/View Models/IdentityPreferencesViewModel.swift b/Shared/View Models/IdentityPreferencesViewModel.swift new file mode 100644 index 0000000..f3eb859 --- /dev/null +++ b/Shared/View Models/IdentityPreferencesViewModel.swift @@ -0,0 +1,52 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation +import Combine + +class IdentityPreferencesViewModel: ObservableObject { + @Published var preferences: Identity.Preferences + @Published var alertItem: AlertItem? + let handle: String + + private let environment: IdentifiedEnvironment + private var cancellables = Set() + + init(environment: IdentifiedEnvironment) { + self.environment = environment + preferences = environment.identity.preferences + handle = environment.identity.handle + + environment.$identity.map(\.preferences) + .dropFirst() + .removeDuplicates() + .handleEvents(receiveOutput: { [weak self] in + if $0.shouldUseAnyServerPreferences { + self?.refreshPreferences() + } + }) + .assign(to: &$preferences) + + let id = environment.identity.id + + $preferences.dropFirst() + .map { ($0, id) } + .flatMap(environment.appEnvironment.identityDatabase.updatePreferences) + .assignErrorsToAlertItem(to: \.alertItem, on: self) + .sink(receiveValue: {}) + .store(in: &cancellables) + } +} + +extension IdentityPreferencesViewModel { + func refreshPreferences() { + let id = environment.identity.id + let capturedPreferences = preferences + + environment.networkClient.request(PreferencesEndpoint.preferences) + .map { (capturedPreferences.updated(from: $0), id) } + .flatMap(environment.appEnvironment.identityDatabase.updatePreferences) + .assignErrorsToAlertItem(to: \.alertItem, on: self) + .sink(receiveValue: {}) + .store(in: &cancellables) + } +} diff --git a/Shared/View Models/MainNavigationViewModel.swift b/Shared/View Models/MainNavigationViewModel.swift index dd440ed..b1a69e0 100644 --- a/Shared/View Models/MainNavigationViewModel.swift +++ b/Shared/View Models/MainNavigationViewModel.swift @@ -22,12 +22,6 @@ class MainNavigationViewModel: ObservableObject { .recentIdentitiesObservation(excluding: environment.identity.id) .assignErrorsToAlertItem(to: \.alertItem, on: self) .assign(to: &$recentIdentities) - - environment.appEnvironment.identityDatabase - .updateLastUsedAt(identityID: environment.identity.id) - .assignErrorsToAlertItem(to: \.alertItem, on: self) - .sink(receiveValue: {}) - .store(in: &cancellables) } } @@ -42,6 +36,17 @@ extension MainNavigationViewModel { .assignErrorsToAlertItem(to: \.alertItem, on: self) .sink(receiveValue: {}) .store(in: &cancellables) + + if identity.preferences.shouldUseAnyServerPreferences { + let capturedPreferences = identity.preferences + + environment.networkClient.request(PreferencesEndpoint.preferences) + .map { (capturedPreferences.updated(from: $0), id) } + .flatMap(environment.appEnvironment.identityDatabase.updatePreferences) + .assignErrorsToAlertItem(to: \.alertItem, on: self) + .sink(receiveValue: {}) + .store(in: &cancellables) + } } environment.networkClient.request(InstanceEndpoint.instance) diff --git a/Shared/View Models/PreferencesViewModel.swift b/Shared/View Models/PreferencesViewModel.swift deleted file mode 100644 index 742dd52..0000000 --- a/Shared/View Models/PreferencesViewModel.swift +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -class PreferencesViewModel: ObservableObject { - @Published var preferences: Identity.Preferences - - private let environment: IdentifiedEnvironment - - init(environment: IdentifiedEnvironment) { - self.environment = environment - preferences = environment.identity.preferences - environment.$identity.map(\.preferences).assign(to: &$preferences) - } -} diff --git a/Shared/View Models/RootViewModel.swift b/Shared/View Models/RootViewModel.swift index 232493a..7a96e8d 100644 --- a/Shared/View Models/RootViewModel.swift +++ b/Shared/View Models/RootViewModel.swift @@ -17,6 +17,11 @@ class RootViewModel: ObservableObject { extension RootViewModel { func newIdentitySelected(id: String) { identityID = id + + environment.identityDatabase + .updateLastUsedAt(identityID: id) + .sink(receiveCompletion: { _ in }, receiveValue: {}) + .store(in: &cancellables) } func addIdentityViewModel() -> AddIdentityViewModel { diff --git a/Shared/View Models/SecondaryNavigationViewModel.swift b/Shared/View Models/SecondaryNavigationViewModel.swift index 48c9a2b..ecf2a6d 100644 --- a/Shared/View Models/SecondaryNavigationViewModel.swift +++ b/Shared/View Models/SecondaryNavigationViewModel.swift @@ -17,4 +17,8 @@ extension SecondaryNavigationViewModel { func identitiesViewModel() -> IdentitiesViewModel { IdentitiesViewModel(environment: environment) } + + func identityPreferencesViewModel() -> IdentityPreferencesViewModel { + IdentityPreferencesViewModel(environment: environment) + } } diff --git a/Shared/Views/IdentityPreferencesView.swift b/Shared/Views/IdentityPreferencesView.swift new file mode 100644 index 0000000..bdcf119 --- /dev/null +++ b/Shared/Views/IdentityPreferencesView.swift @@ -0,0 +1,56 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import SwiftUI + +struct IdentityPreferencesView: View { + @StateObject var viewModel: IdentityPreferencesViewModel + + var body: some View { + Form { + Section(header: Text("preferences.posting")) { + Toggle("preferences.use-preferences-from-server", + isOn: $viewModel.preferences.useServerPostingPreferences) + VStack(alignment: .leading) { + Text("preferences.posting-default-visiblility") + Picker("", selection: $viewModel.preferences.postingDefaultVisibility, + content: { + Text("status.visibility.public").tag(Status.Visibility.public) + Text("status.visibility.unlisted").tag(Status.Visibility.unlisted) + Text("status.visibility.private").tag(Status.Visibility.private) + }) + .pickerStyle(SegmentedPickerStyle()) + } + .disabled(viewModel.preferences.useServerPostingPreferences) + Toggle("preferences.posting-default-sensitive", + isOn: $viewModel.preferences.postingDefaultSensitive) + .disabled(viewModel.preferences.useServerPostingPreferences) + } + Section(header: Text("preferences.reading")) { + Toggle("preferences.use-preferences-from-server", + isOn: $viewModel.preferences.useServerReadingPreferences) + VStack(alignment: .leading) { + Text("preferences.reading-expand-media") + Picker("", selection: $viewModel.preferences.readingExpandMedia, + content: { + Text("preferences.expand-media.default").tag(MastodonPreferences.ExpandMedia.default) + Text("preferences.expand-media.show-all").tag(MastodonPreferences.ExpandMedia.showAll) + Text("preferences.expand-media.hide-all").tag(MastodonPreferences.ExpandMedia.hideAll) + }) + .pickerStyle(SegmentedPickerStyle()) + } + .disabled(viewModel.preferences.useServerReadingPreferences) + Toggle("preferences.reading-expand-spoilers", + isOn: $viewModel.preferences.readingExpandSpoilers) + .disabled(viewModel.preferences.useServerReadingPreferences) + } + } + .navigationTitle("preferences.title.\(viewModel.handle)") + .alertItem($viewModel.alertItem) + } +} + +struct PreferencesView_Previews: PreviewProvider { + static var previews: some View { + IdentityPreferencesView(viewModel: .development) + } +} diff --git a/Shared/Views/PreferencesView.swift b/Shared/Views/PreferencesView.swift index d84e6c9..ab465ba 100644 --- a/Shared/Views/PreferencesView.swift +++ b/Shared/Views/PreferencesView.swift @@ -2,14 +2,53 @@ import SwiftUI -struct PreferencesView: View { +struct IdentityPreferencesView: View { + @StateObject var viewModel: IdentityPreferencesViewModel var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + Form { + Section(header: Text("preferences.posting")) { + Toggle("preferences.use-preferences-from-server", + isOn: $viewModel.preferences.useServerPostingPreferences) + VStack(alignment: .leading) { + Text("preferences.posting-default-visiblility") + Picker("", selection: $viewModel.preferences.postingDefaultVisibility, + content: { + Text("status.visibility.public").tag(Status.Visibility.public) + Text("status.visibility.unlisted").tag(Status.Visibility.unlisted) + Text("status.visibility.private").tag(Status.Visibility.private) + }) + .pickerStyle(SegmentedPickerStyle()) + } + .disabled(viewModel.preferences.useServerPostingPreferences) + Toggle("preferences.posting-default-sensitive", + isOn: $viewModel.preferences.postingDefaultSensitive) + .disabled(viewModel.preferences.useServerPostingPreferences) + } + Section(header: Text("preferences.reading")) { + Toggle("preferences.use-preferences-from-server", + isOn: $viewModel.preferences.useServerReadingPreferences) + VStack(alignment: .leading) { + Text("preferences.reading-expand-media") + Picker("", selection: $viewModel.preferences.readingExpandMedia, + content: { + Text("preferences.expand-media.default").tag(MastodonPreferences.ExpandMedia.default) + Text("preferences.expand-media.show-all").tag(MastodonPreferences.ExpandMedia.showAll) + Text("preferences.expand-media.hide-all").tag(MastodonPreferences.ExpandMedia.hideAll) + }) + .pickerStyle(SegmentedPickerStyle()) + } + .disabled(viewModel.preferences.useServerReadingPreferences) + Toggle("preferences.reading-expand-spoilers", + isOn: $viewModel.preferences.readingExpandSpoilers) + .disabled(viewModel.preferences.useServerReadingPreferences) + } + } + .navigationTitle("preferences.title.\(viewModel.handle)") } } struct PreferencesView_Previews: PreviewProvider { static var previews: some View { - PreferencesView() + IdentityPreferencesView(viewModel: .development) } } diff --git a/Shared/Views/SecondaryNavigationView.swift b/Shared/Views/SecondaryNavigationView.swift index ebc85e9..39ccd9c 100644 --- a/Shared/Views/SecondaryNavigationView.swift +++ b/Shared/Views/SecondaryNavigationView.swift @@ -13,24 +13,31 @@ struct SecondaryNavigationView: View { VStack(spacing: 0) { NavigationView { Form { - NavigationLink( - destination: IdentitiesView(viewModel: viewModel.identitiesViewModel()) - .environmentObject(rootViewModel), - label: { - HStack { - KFImage(viewModel.identity.image, - options: .downsampled(dimension: 50, scaleFactor: displayScale)) - VStack { - Text(viewModel.identity.handle) - .font(.headline) - .lineLimit(1) - .minimumScaleFactor(0.5) - Spacer() - Text("accounts").font(.subheadline) + Section { + NavigationLink( + destination: IdentitiesView(viewModel: viewModel.identitiesViewModel()) + .environmentObject(rootViewModel), + label: { + HStack { + KFImage(viewModel.identity.image, + options: .downsampled(dimension: 50, scaleFactor: displayScale)) + VStack(alignment: .leading) { + Text(viewModel.identity.handle) + .font(.headline) + .lineLimit(1) + .minimumScaleFactor(0.5) + Spacer() + Text("secondary-navigation.accounts") + .font(.subheadline) + .foregroundColor(.secondary) + } + .padding() } - .padding() - } - }) + }) + NavigationLink( + "secondary-navigation.identity-preferences", + destination: IdentityPreferencesView(viewModel: viewModel.identityPreferencesViewModel())) + } } .navigationItems(presentationMode: presentationMode) } diff --git a/macOS/SidebarNavigation.swift b/macOS/SidebarNavigation.swift index 2e7ca51..8896be9 100644 --- a/macOS/SidebarNavigation.swift +++ b/macOS/SidebarNavigation.swift @@ -8,7 +8,6 @@ import struct Kingfisher.RoundCornerImageProcessor struct SidebarNavigation: View { @StateObject var viewModel: MainNavigationViewModel @EnvironmentObject var rootViewModel: RootViewModel - @Environment(\.displayScale) var displayScale: CGFloat var sidebar: some View { List(selection: $viewModel.selectedTab) { @@ -57,20 +56,14 @@ private extension SidebarNavigation { struct Pocket: View { @EnvironmentObject var viewModel: MainNavigationViewModel @EnvironmentObject var rootViewModel: RootViewModel + @Environment(\.displayScale) var displayScale: CGFloat var body: some View { VStack(alignment: .leading, spacing: 0) { Divider() Button(action: { viewModel.presentingSettings.toggle() }) { KFImage(viewModel.identity.image, - options: [ - .processor( - DownsamplingImageProcessor(size: CGSize(width: 50, height: 50)) - .append(another: RoundCornerImageProcessor(radius: .widthFraction(0.5))) - ), - .scaleFactor(displayScale), - .cacheOriginalImage - ]) + options: .downsampled(dimension: 28, scaleFactor: displayScale)) .placeholder { Image(systemName: "gear") } .renderingMode(.original) .resizable()