Preferences
This commit is contained in:
parent
08bf8f1b8b
commit
56f1b63fb9
|
@ -138,4 +138,8 @@ extension IdentitiesViewModel {
|
||||||
static let development = SecondaryNavigationViewModel.development.identitiesViewModel()
|
static let development = SecondaryNavigationViewModel.development.identitiesViewModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension IdentityPreferencesViewModel {
|
||||||
|
static let development = SecondaryNavigationViewModel.development.identityPreferencesViewModel()
|
||||||
|
}
|
||||||
|
|
||||||
// swiftlint:enable force_try
|
// swiftlint:enable force_try
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
D0091B6824DC10B30040E8D2 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* PreferencesView.swift */; };
|
D0091B6824DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */; };
|
||||||
D0091B6924DC10B30040E8D2 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* PreferencesView.swift */; };
|
D0091B6924DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */; };
|
||||||
D0091B6B24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */; };
|
D0091B6B24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */; };
|
||||||
D0091B6C24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */; };
|
D0091B6C24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */; };
|
||||||
D047FAAE24C3E21200AF17C5 /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D047FA8524C3E21000AF17C5 /* MetatextApp.swift */; };
|
D047FAAE24C3E21200AF17C5 /* MetatextApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D047FA8524C3E21000AF17C5 /* MetatextApp.swift */; };
|
||||||
D047FAAF24C3E21200AF17C5 /* 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 */; };
|
D047FAB224C3E21200AF17C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D047FA8724C3E21200AF17C5 /* Assets.xcassets */; };
|
||||||
|
@ -163,8 +163,8 @@
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
D0091B6724DC10B30040E8D2 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityPreferencesView.swift; sourceTree = "<group>"; };
|
||||||
D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewModel.swift; sourceTree = "<group>"; };
|
D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityPreferencesViewModel.swift; sourceTree = "<group>"; };
|
||||||
D047FA8524C3E21000AF17C5 /* MetatextApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetatextApp.swift; sourceTree = "<group>"; };
|
D047FA8524C3E21000AF17C5 /* MetatextApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetatextApp.swift; sourceTree = "<group>"; };
|
||||||
D047FA8724C3E21200AF17C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
D047FA8724C3E21200AF17C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -385,7 +385,7 @@
|
||||||
children = (
|
children = (
|
||||||
D0DB6EF324C5228A00D965FE /* AddIdentityView.swift */,
|
D0DB6EF324C5228A00D965FE /* AddIdentityView.swift */,
|
||||||
D06BAB5024D942CF0081B8FD /* IdentitiesView.swift */,
|
D06BAB5024D942CF0081B8FD /* IdentitiesView.swift */,
|
||||||
D0091B6724DC10B30040E8D2 /* PreferencesView.swift */,
|
D0091B6724DC10B30040E8D2 /* IdentityPreferencesView.swift */,
|
||||||
D0BEC93A24C96FD500E864C4 /* RootView.swift */,
|
D0BEC93A24C96FD500E864C4 /* RootView.swift */,
|
||||||
D04FD73224D48F37007D572D /* SecondaryNavigationView.swift */,
|
D04FD73224D48F37007D572D /* SecondaryNavigationView.swift */,
|
||||||
D0BEC94924CA231200E864C4 /* TimelineView.swift */,
|
D0BEC94924CA231200E864C4 /* TimelineView.swift */,
|
||||||
|
@ -412,7 +412,7 @@
|
||||||
D0DB6F0824C65AC000D965FE /* AddIdentityViewModel.swift */,
|
D0DB6F0824C65AC000D965FE /* AddIdentityViewModel.swift */,
|
||||||
D06BAB4D24D942BC0081B8FD /* IdentitiesViewModel.swift */,
|
D06BAB4D24D942BC0081B8FD /* IdentitiesViewModel.swift */,
|
||||||
D052BBDF24D805E300A80A7A /* MainNavigationViewModel.swift */,
|
D052BBDF24D805E300A80A7A /* MainNavigationViewModel.swift */,
|
||||||
D0091B6A24DC10CE0040E8D2 /* PreferencesViewModel.swift */,
|
D0091B6A24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift */,
|
||||||
D0BEC93724C9632800E864C4 /* RootViewModel.swift */,
|
D0BEC93724C9632800E864C4 /* RootViewModel.swift */,
|
||||||
D04FD73524D49506007D572D /* SecondaryNavigationViewModel.swift */,
|
D04FD73524D49506007D572D /* SecondaryNavigationViewModel.swift */,
|
||||||
D0BEC94624CA22C400E864C4 /* TimelineViewModel.swift */,
|
D0BEC94624CA22C400E864C4 /* TimelineViewModel.swift */,
|
||||||
|
@ -715,7 +715,7 @@
|
||||||
D0C963FB24CC359D003BD330 /* AlertItem.swift in Sources */,
|
D0C963FB24CC359D003BD330 /* AlertItem.swift in Sources */,
|
||||||
D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
|
D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
|
||||||
D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */,
|
D0DC174D24CFF1F100A75C65 /* Stubbing.swift in Sources */,
|
||||||
D0091B6B24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */,
|
D0091B6B24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */,
|
||||||
D0666A5724C6C63400F3F04B /* MastodonDecoder.swift in Sources */,
|
D0666A5724C6C63400F3F04B /* MastodonDecoder.swift in Sources */,
|
||||||
D0DB6EF424C5228A00D965FE /* AddIdentityView.swift in Sources */,
|
D0DB6EF424C5228A00D965FE /* AddIdentityView.swift in Sources */,
|
||||||
D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */,
|
D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */,
|
||||||
|
@ -736,7 +736,7 @@
|
||||||
D0CD847C24DBEA9F00CF380C /* Unknowable.swift in Sources */,
|
D0CD847C24DBEA9F00CF380C /* Unknowable.swift in Sources */,
|
||||||
D0666A6F24C6DFB300F3F04B /* AccessToken.swift in Sources */,
|
D0666A6F24C6DFB300F3F04B /* AccessToken.swift in Sources */,
|
||||||
D0ED1BCB24CF744200B4899C /* MastodonClient.swift in Sources */,
|
D0ED1BCB24CF744200B4899C /* MastodonClient.swift in Sources */,
|
||||||
D0091B6824DC10B30040E8D2 /* PreferencesView.swift in Sources */,
|
D0091B6824DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */,
|
||||||
D0CD847624DBDF3C00CF380C /* Status.swift in Sources */,
|
D0CD847624DBDF3C00CF380C /* Status.swift in Sources */,
|
||||||
D052BBE024D805E300A80A7A /* MainNavigationViewModel.swift in Sources */,
|
D052BBE024D805E300A80A7A /* MainNavigationViewModel.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
@ -787,7 +787,7 @@
|
||||||
D0C963FC24CC359D003BD330 /* AlertItem.swift in Sources */,
|
D0C963FC24CC359D003BD330 /* AlertItem.swift in Sources */,
|
||||||
D0DC174724CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
|
D0DC174724CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
|
||||||
D0DC174E24CFF1F100A75C65 /* Stubbing.swift in Sources */,
|
D0DC174E24CFF1F100A75C65 /* Stubbing.swift in Sources */,
|
||||||
D0091B6C24DC10CE0040E8D2 /* PreferencesViewModel.swift in Sources */,
|
D0091B6C24DC10CE0040E8D2 /* IdentityPreferencesViewModel.swift in Sources */,
|
||||||
D0666A5824C6C63400F3F04B /* MastodonDecoder.swift in Sources */,
|
D0666A5824C6C63400F3F04B /* MastodonDecoder.swift in Sources */,
|
||||||
D0DB6EF524C5233E00D965FE /* AddIdentityView.swift in Sources */,
|
D0DB6EF524C5233E00D965FE /* AddIdentityView.swift in Sources */,
|
||||||
D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */,
|
D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */,
|
||||||
|
@ -808,7 +808,7 @@
|
||||||
D0CD847D24DBEA9F00CF380C /* Unknowable.swift in Sources */,
|
D0CD847D24DBEA9F00CF380C /* Unknowable.swift in Sources */,
|
||||||
D0666A7024C6DFB300F3F04B /* AccessToken.swift in Sources */,
|
D0666A7024C6DFB300F3F04B /* AccessToken.swift in Sources */,
|
||||||
D0ED1BCC24CF744200B4899C /* MastodonClient.swift in Sources */,
|
D0ED1BCC24CF744200B4899C /* MastodonClient.swift in Sources */,
|
||||||
D0091B6924DC10B30040E8D2 /* PreferencesView.swift in Sources */,
|
D0091B6924DC10B30040E8D2 /* IdentityPreferencesView.swift in Sources */,
|
||||||
D0CD847724DBDF3C00CF380C /* Status.swift in Sources */,
|
D0CD847724DBDF3C00CF380C /* Status.swift in Sources */,
|
||||||
D052BBE124D805E300A80A7A /* MainNavigationViewModel.swift in Sources */,
|
D052BBE124D805E300A80A7A /* MainNavigationViewModel.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,4 +3,19 @@
|
||||||
"go" = "Go";
|
"go" = "Go";
|
||||||
"add-identity.instance-url" = "Instance URL";
|
"add-identity.instance-url" = "Instance URL";
|
||||||
"oauth.error.code-not-found" = "OAuth error: code not found";
|
"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";
|
||||||
|
|
|
@ -52,3 +52,24 @@ extension Identity {
|
||||||
|
|
||||||
var image: URL? { account?.avatar ?? instance?.thumbnail }
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -80,6 +80,18 @@ extension IdentityDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updatePreferences(_ preferences: Identity.Preferences,
|
||||||
|
forIdentityID identityID: String) -> AnyPublisher<Void, Error> {
|
||||||
|
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<Identity, Error> {
|
func identityObservation(id: String) -> AnyPublisher<Identity, Error> {
|
||||||
ValueObservation.tracking(
|
ValueObservation.tracking(
|
||||||
StoredIdentity
|
StoredIdentity
|
||||||
|
|
|
@ -11,3 +11,7 @@ extension Unknowable {
|
||||||
self = Self.allCases.first { $0.rawValue == rawValue } ?? Self.unknownCase
|
self = Self.allCases.first { $0.rawValue == rawValue } ?? Self.unknownCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Unknowable {
|
||||||
|
static var allCasesExceptUnknown: [Self] { allCases.filter { $0 != unknownCase } }
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ extension PreferencesEndpoint: MastodonEndpoint {
|
||||||
|
|
||||||
var pathComponentsInContext: [String] {
|
var pathComponentsInContext: [String] {
|
||||||
switch self {
|
switch self {
|
||||||
case .preferences: return ["instance"]
|
case .preferences: return ["preferences"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<AnyCancellable>()
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,12 +22,6 @@ class MainNavigationViewModel: ObservableObject {
|
||||||
.recentIdentitiesObservation(excluding: environment.identity.id)
|
.recentIdentitiesObservation(excluding: environment.identity.id)
|
||||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||||
.assign(to: &$recentIdentities)
|
.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)
|
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||||
.sink(receiveValue: {})
|
.sink(receiveValue: {})
|
||||||
.store(in: &cancellables)
|
.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)
|
environment.networkClient.request(InstanceEndpoint.instance)
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,6 +17,11 @@ class RootViewModel: ObservableObject {
|
||||||
extension RootViewModel {
|
extension RootViewModel {
|
||||||
func newIdentitySelected(id: String) {
|
func newIdentitySelected(id: String) {
|
||||||
identityID = id
|
identityID = id
|
||||||
|
|
||||||
|
environment.identityDatabase
|
||||||
|
.updateLastUsedAt(identityID: id)
|
||||||
|
.sink(receiveCompletion: { _ in }, receiveValue: {})
|
||||||
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addIdentityViewModel() -> AddIdentityViewModel {
|
func addIdentityViewModel() -> AddIdentityViewModel {
|
||||||
|
|
|
@ -17,4 +17,8 @@ extension SecondaryNavigationViewModel {
|
||||||
func identitiesViewModel() -> IdentitiesViewModel {
|
func identitiesViewModel() -> IdentitiesViewModel {
|
||||||
IdentitiesViewModel(environment: environment)
|
IdentitiesViewModel(environment: environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func identityPreferencesViewModel() -> IdentityPreferencesViewModel {
|
||||||
|
IdentityPreferencesViewModel(environment: environment)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,14 +2,53 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct PreferencesView: View {
|
struct IdentityPreferencesView: View {
|
||||||
|
@StateObject var viewModel: IdentityPreferencesViewModel
|
||||||
var body: some View {
|
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 {
|
struct PreferencesView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
PreferencesView()
|
IdentityPreferencesView(viewModel: .development)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,24 +13,31 @@ struct SecondaryNavigationView: View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
Form {
|
Form {
|
||||||
NavigationLink(
|
Section {
|
||||||
destination: IdentitiesView(viewModel: viewModel.identitiesViewModel())
|
NavigationLink(
|
||||||
.environmentObject(rootViewModel),
|
destination: IdentitiesView(viewModel: viewModel.identitiesViewModel())
|
||||||
label: {
|
.environmentObject(rootViewModel),
|
||||||
HStack {
|
label: {
|
||||||
KFImage(viewModel.identity.image,
|
HStack {
|
||||||
options: .downsampled(dimension: 50, scaleFactor: displayScale))
|
KFImage(viewModel.identity.image,
|
||||||
VStack {
|
options: .downsampled(dimension: 50, scaleFactor: displayScale))
|
||||||
Text(viewModel.identity.handle)
|
VStack(alignment: .leading) {
|
||||||
.font(.headline)
|
Text(viewModel.identity.handle)
|
||||||
.lineLimit(1)
|
.font(.headline)
|
||||||
.minimumScaleFactor(0.5)
|
.lineLimit(1)
|
||||||
Spacer()
|
.minimumScaleFactor(0.5)
|
||||||
Text("accounts").font(.subheadline)
|
Spacer()
|
||||||
|
Text("secondary-navigation.accounts")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
}
|
}
|
||||||
.padding()
|
})
|
||||||
}
|
NavigationLink(
|
||||||
})
|
"secondary-navigation.identity-preferences",
|
||||||
|
destination: IdentityPreferencesView(viewModel: viewModel.identityPreferencesViewModel()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationItems(presentationMode: presentationMode)
|
.navigationItems(presentationMode: presentationMode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import struct Kingfisher.RoundCornerImageProcessor
|
||||||
struct SidebarNavigation: View {
|
struct SidebarNavigation: View {
|
||||||
@StateObject var viewModel: MainNavigationViewModel
|
@StateObject var viewModel: MainNavigationViewModel
|
||||||
@EnvironmentObject var rootViewModel: RootViewModel
|
@EnvironmentObject var rootViewModel: RootViewModel
|
||||||
@Environment(\.displayScale) var displayScale: CGFloat
|
|
||||||
|
|
||||||
var sidebar: some View {
|
var sidebar: some View {
|
||||||
List(selection: $viewModel.selectedTab) {
|
List(selection: $viewModel.selectedTab) {
|
||||||
|
@ -57,20 +56,14 @@ private extension SidebarNavigation {
|
||||||
struct Pocket: View {
|
struct Pocket: View {
|
||||||
@EnvironmentObject var viewModel: MainNavigationViewModel
|
@EnvironmentObject var viewModel: MainNavigationViewModel
|
||||||
@EnvironmentObject var rootViewModel: RootViewModel
|
@EnvironmentObject var rootViewModel: RootViewModel
|
||||||
|
@Environment(\.displayScale) var displayScale: CGFloat
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Divider()
|
Divider()
|
||||||
Button(action: { viewModel.presentingSettings.toggle() }) {
|
Button(action: { viewModel.presentingSettings.toggle() }) {
|
||||||
KFImage(viewModel.identity.image,
|
KFImage(viewModel.identity.image,
|
||||||
options: [
|
options: .downsampled(dimension: 28, scaleFactor: displayScale))
|
||||||
.processor(
|
|
||||||
DownsamplingImageProcessor(size: CGSize(width: 50, height: 50))
|
|
||||||
.append(another: RoundCornerImageProcessor(radius: .widthFraction(0.5)))
|
|
||||||
),
|
|
||||||
.scaleFactor(displayScale),
|
|
||||||
.cacheOriginalImage
|
|
||||||
])
|
|
||||||
.placeholder { Image(systemName: "gear") }
|
.placeholder { Image(systemName: "gear") }
|
||||||
.renderingMode(.original)
|
.renderingMode(.original)
|
||||||
.resizable()
|
.resizable()
|
||||||
|
|
Loading…
Reference in New Issue