Refactor settings into subsections
This commit is contained in:
65
damus/Views/Settings/AppearanceSettingsView.swift
Normal file
65
damus/Views/Settings/AppearanceSettingsView.swift
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// TextFormattingSettings.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-04-05.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
|
||||
struct AppearanceSettingsView: View {
|
||||
@ObservedObject var settings: UserSettingsStore
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text(NSLocalizedString("Text Truncation", comment: "Section header for damus text truncation user configuration"))) {
|
||||
Toggle(NSLocalizedString("Truncate timeline text", comment: "Setting to truncate text in timeline"), isOn: $settings.truncate_timeline_text)
|
||||
.toggleStyle(.switch)
|
||||
Toggle(NSLocalizedString("Truncate notification mention text", comment: "Setting to truncate text in mention notifications"), isOn: $settings.truncate_mention_text)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
|
||||
Section(header: Text(NSLocalizedString("Accessibility", comment: "Section header for accessibility settings"))) {
|
||||
Toggle(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen"), isOn: $settings.left_handed)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
|
||||
Section(NSLocalizedString("Images", comment: "Section title for images configuration.")) {
|
||||
Toggle(NSLocalizedString("Disable animations", comment: "Button to disable image animation"), isOn: $settings.disable_animation)
|
||||
.toggleStyle(.switch)
|
||||
.onChange(of: settings.disable_animation) { _ in
|
||||
clear_kingfisher_cache()
|
||||
}
|
||||
Toggle(NSLocalizedString("Always show images", comment: "Setting to always show and never blur images"), isOn: $settings.always_show_images)
|
||||
.toggleStyle(.switch)
|
||||
|
||||
Picker(NSLocalizedString("Select image uploader", comment: "Prompt selection of user's image uploader"),
|
||||
selection: $settings.default_media_uploader) {
|
||||
ForEach(MediaUploader.allCases, id: \.self) { uploader in
|
||||
Text(uploader.model.displayName)
|
||||
.tag(uploader.model.tag)
|
||||
}
|
||||
}
|
||||
|
||||
Button(NSLocalizedString("Clear Cache", comment: "Button to clear image cache.")) {
|
||||
clear_kingfisher_cache()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.navigationTitle("Appearance")
|
||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct TextFormattingSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
AppearanceSettingsView(settings: UserSettingsStore())
|
||||
}
|
||||
}
|
||||
133
damus/Views/Settings/KeySettingsView.swift
Normal file
133
damus/Views/Settings/KeySettingsView.swift
Normal file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// KeySettingsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-04-05.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import LocalAuthentication
|
||||
|
||||
struct KeySettingsView: View {
|
||||
let keypair: Keypair
|
||||
|
||||
@State var privkey: String
|
||||
@State var privkey_copied: Bool = false
|
||||
@State var pubkey_copied: Bool = false
|
||||
@State var show_privkey: Bool = false
|
||||
@State var has_authenticated_locally: Bool = false
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
init(keypair: Keypair) {
|
||||
_privkey = State(initialValue: keypair.privkey_bech32 ?? "")
|
||||
self.keypair = keypair
|
||||
}
|
||||
|
||||
var ShowSecToggle: some View {
|
||||
Toggle(NSLocalizedString("Show", comment: "Toggle to show or hide user's secret account login key."), isOn: $show_privkey)
|
||||
.onChange(of: show_privkey) { newValue in
|
||||
if newValue {
|
||||
authenticate_locally(has_authenticated_locally) { success in
|
||||
show_privkey = success
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: (jb55) could be more general but not gonna worry about it atm
|
||||
func CopyButton(is_pk: Bool) -> some View {
|
||||
return Button(action: {
|
||||
let copyKey = {
|
||||
UIPasteboard.general.string = is_pk ? self.keypair.pubkey_bech32 : self.privkey
|
||||
self.privkey_copied = !is_pk
|
||||
self.pubkey_copied = is_pk
|
||||
|
||||
let generator = UIImpactFeedbackGenerator(style: .light)
|
||||
generator.impactOccurred()
|
||||
}
|
||||
|
||||
if is_pk {
|
||||
copyKey()
|
||||
return
|
||||
}
|
||||
|
||||
if has_authenticated_locally {
|
||||
copyKey()
|
||||
return
|
||||
}
|
||||
|
||||
authenticate_locally(has_authenticated_locally) { success in
|
||||
if success {
|
||||
copyKey()
|
||||
}
|
||||
}
|
||||
}) {
|
||||
let copied = is_pk ? self.pubkey_copied : self.privkey_copied
|
||||
Image(systemName: copied ? "checkmark.circle" : "doc.on.doc")
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(NSLocalizedString("Public Account ID", comment: "Section title for the user's public account ID.")) {
|
||||
HStack {
|
||||
Text(keypair.pubkey_bech32)
|
||||
|
||||
CopyButton(is_pk: true)
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 5))
|
||||
}
|
||||
|
||||
if let sec = keypair.privkey_bech32 {
|
||||
Section(NSLocalizedString("Secret Account Login Key", comment: "Section title for user's secret account login key.")) {
|
||||
HStack {
|
||||
if show_privkey == false || !has_authenticated_locally {
|
||||
SecureField(NSLocalizedString("Private Key", comment: "Title of the secure field that holds the user's private key."), text: $privkey)
|
||||
.disabled(true)
|
||||
} else {
|
||||
Text(sec)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 5))
|
||||
}
|
||||
|
||||
CopyButton(is_pk: false)
|
||||
}
|
||||
|
||||
ShowSecToggle
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.navigationTitle("Keys")
|
||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct KeySettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let kp = generate_new_keypair()
|
||||
KeySettingsView(keypair: kp)
|
||||
}
|
||||
}
|
||||
|
||||
func authenticate_locally(_ has_authenticated_locally: Bool, completion: @escaping (Bool) -> Void) {
|
||||
// Need to authenticate only once while ConfigView is presented
|
||||
guard !has_authenticated_locally else {
|
||||
completion(true)
|
||||
return
|
||||
}
|
||||
let context = LAContext()
|
||||
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) {
|
||||
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: NSLocalizedString("Local authentication to access private key", comment: "Face ID usage description shown when trying to access private key")) { success, error in
|
||||
DispatchQueue.main.async {
|
||||
completion(success)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If there's no authentication set up on the device, let the user copy the key without it
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import SwiftUI
|
||||
|
||||
struct NotificationSettingsView: View {
|
||||
@ObservedObject var settings: UserSettingsStore
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
@@ -30,6 +32,10 @@ struct NotificationSettingsView: View {
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Notifications")
|
||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
160
damus/Views/Settings/TranslationSettingsView.swift
Normal file
160
damus/Views/Settings/TranslationSettingsView.swift
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// TranslationSettingsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-04-05.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TranslationSettingsView: View {
|
||||
@ObservedObject var settings: UserSettingsStore
|
||||
|
||||
@State var show_api_key: Bool = false
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(NSLocalizedString("Translations", comment: "Section title for selecting the translation service.")) {
|
||||
Toggle(NSLocalizedString("Show only preferred languages on Universe feed", comment: "Toggle to show notes that are only in the device's preferred languages on the Universe feed and hide notes that are in other languages."), isOn: $settings.show_only_preferred_languages)
|
||||
.toggleStyle(.switch)
|
||||
|
||||
Picker(NSLocalizedString("Service", comment: "Prompt selection of translation service provider."), selection: $settings.translation_service) {
|
||||
ForEach(TranslationService.allCases, id: \.self) { server in
|
||||
Text(server.model.displayName)
|
||||
.tag(server.model.tag)
|
||||
}
|
||||
}
|
||||
|
||||
if settings.translation_service == .libretranslate {
|
||||
Picker(NSLocalizedString("Server", comment: "Prompt selection of LibreTranslate server to perform machine translations on notes"), selection: $settings.libretranslate_server) {
|
||||
ForEach(LibreTranslateServer.allCases, id: \.self) { server in
|
||||
Text(server.model.displayName)
|
||||
.tag(server.model.tag)
|
||||
}
|
||||
}
|
||||
|
||||
if settings.libretranslate_server == .custom {
|
||||
TextField(NSLocalizedString("URL", comment: "Example URL to LibreTranslate server"), text: $settings.libretranslate_url)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
}
|
||||
|
||||
SecureField(NSLocalizedString("API Key (optional)", comment: "Prompt for optional entry of API Key to use translation server."), text: $settings.libretranslate_api_key)
|
||||
.disableAutocorrection(true)
|
||||
.disabled(settings.translation_service != .libretranslate)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
}
|
||||
|
||||
if settings.translation_service == .deepl {
|
||||
Picker(NSLocalizedString("Plan", comment: "Prompt selection of DeepL subscription plan to perform machine translations on notes"), selection: $settings.deepl_plan) {
|
||||
ForEach(DeepLPlan.allCases, id: \.self) { server in
|
||||
Text(server.model.displayName)
|
||||
.tag(server.model.tag)
|
||||
}
|
||||
}
|
||||
|
||||
SecureField(NSLocalizedString("API Key (required)", comment: "Prompt for required entry of API Key to use translation server."), text: $settings.deepl_api_key)
|
||||
.disableAutocorrection(true)
|
||||
.disabled(settings.translation_service != .deepl)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
|
||||
if settings.deepl_api_key == "" {
|
||||
Link(NSLocalizedString("Get API Key", comment: "Button to navigate to DeepL website to get a translation API key."), destination: URL(string: "https://www.deepl.com/pro-api")!)
|
||||
}
|
||||
}
|
||||
|
||||
if settings.translation_service != .none {
|
||||
Toggle(NSLocalizedString("Automatically translate notes", comment: "Toggle to automatically translate notes."), isOn: $settings.auto_translate)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Translation")
|
||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
var libretranslate_view: some View {
|
||||
VStack {
|
||||
Picker(NSLocalizedString("Server", comment: "Prompt selection of LibreTranslate server to perform machine translations on notes"), selection: $settings.libretranslate_server) {
|
||||
ForEach(LibreTranslateServer.allCases, id: \.self) { server in
|
||||
Text(server.model.displayName)
|
||||
.tag(server.model.tag)
|
||||
}
|
||||
}
|
||||
|
||||
TextField(NSLocalizedString("URL", comment: "Example URL to LibreTranslate server"), text: $settings.libretranslate_url)
|
||||
.disableAutocorrection(true)
|
||||
.disabled(settings.libretranslate_server != .custom)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
HStack {
|
||||
let libretranslate_api_key_placeholder = NSLocalizedString("API Key (optional)", comment: "Prompt for optional entry of API Key to use translation server.")
|
||||
if show_api_key {
|
||||
TextField(libretranslate_api_key_placeholder, text: $settings.libretranslate_api_key)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
if settings.libretranslate_api_key != "" {
|
||||
Button(NSLocalizedString("Hide API Key", comment: "Button to hide the LibreTranslate server API key.")) {
|
||||
show_api_key = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SecureField(libretranslate_api_key_placeholder, text: $settings.libretranslate_api_key)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
if settings.libretranslate_api_key != "" {
|
||||
Button(NSLocalizedString("Show API Key", comment: "Button to show the LibreTranslate server API key.")) {
|
||||
show_api_key = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var deepl_view: some View {
|
||||
VStack {
|
||||
Picker(NSLocalizedString("Plan", comment: "Prompt selection of DeepL subscription plan to perform machine translations on notes"), selection: $settings.deepl_plan) {
|
||||
ForEach(DeepLPlan.allCases, id: \.self) { server in
|
||||
Text(server.model.displayName)
|
||||
.tag(server.model.tag)
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
let deepl_api_key_placeholder = NSLocalizedString("API Key (required)", comment: "Prompt for required entry of API Key to use translation server.")
|
||||
if show_api_key {
|
||||
TextField(deepl_api_key_placeholder, text: $settings.deepl_api_key)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
if settings.deepl_api_key != "" {
|
||||
Button(NSLocalizedString("Hide API Key", comment: "Button to hide the DeepL translation API key.")) {
|
||||
show_api_key = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SecureField(deepl_api_key_placeholder, text: $settings.deepl_api_key)
|
||||
.disableAutocorrection(true)
|
||||
.autocapitalization(UITextAutocapitalizationType.none)
|
||||
if settings.deepl_api_key != "" {
|
||||
Button(NSLocalizedString("Show API Key", comment: "Button to show the DeepL translation API key.")) {
|
||||
show_api_key = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if settings.deepl_api_key == "" {
|
||||
Link(NSLocalizedString("Get API Key", comment: "Button to navigate to DeepL website to get a translation API key."), destination: URL(string: "https://www.deepl.com/pro-api")!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TranslationSettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TranslationSettingsView(settings: UserSettingsStore())
|
||||
}
|
||||
}
|
||||
66
damus/Views/Settings/ZapSettingsView.swift
Normal file
66
damus/Views/Settings/ZapSettingsView.swift
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// WalletSettingsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by William Casarin on 2023-04-05.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
struct ZapSettingsView: View {
|
||||
let pubkey: String
|
||||
@ObservedObject var settings: UserSettingsStore
|
||||
|
||||
@State var default_zap_amount: String
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
init(pubkey: String, settings: UserSettingsStore) {
|
||||
self.pubkey = pubkey
|
||||
let zap_amt = get_default_zap_amount(pubkey: pubkey).map({ "\($0)" }) ?? "1000"
|
||||
_default_zap_amount = State(initialValue: zap_amt)
|
||||
self._settings = ObservedObject(initialValue: settings)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section("Wallet") {
|
||||
|
||||
Toggle(NSLocalizedString("Show wallet selector", comment: "Toggle to show or hide selection of wallet."), isOn: $settings.show_wallet_selector).toggleStyle(.switch)
|
||||
Picker(NSLocalizedString("Select default wallet", comment: "Prompt selection of user's default wallet"),
|
||||
selection: $settings.default_wallet) {
|
||||
ForEach(Wallet.allCases, id: \.self) { wallet in
|
||||
Text(wallet.model.displayName)
|
||||
.tag(wallet.model.tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section("Zaps") {
|
||||
Toggle(NSLocalizedString("Zap Vibration", comment: "Setting to enable vibration on zap"), isOn: $settings.zap_vibration)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
|
||||
Section("Default Zap Amount in sats") {
|
||||
TextField(String("1000"), text: $default_zap_amount)
|
||||
.keyboardType(.numberPad)
|
||||
.onReceive(Just(default_zap_amount)) { newValue in
|
||||
if let parsed = handle_string_amount(new_value: newValue) {
|
||||
self.default_zap_amount = String(parsed)
|
||||
set_default_zap_amount(pubkey: self.pubkey, amount: parsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Zaps")
|
||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WalletSettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ZapSettingsView(pubkey: "pubkey", settings: UserSettingsStore())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user