Multi-Server implementiert
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import SwiftUI
|
||||
import SafariServices
|
||||
import SwiftData
|
||||
|
||||
struct SettingsView: View {
|
||||
@AppStorage("onboardingComplete") private var onboardingComplete = false
|
||||
@@ -8,11 +9,11 @@ struct SettingsView: View {
|
||||
@AppStorage("appTheme") private var appTheme = "system"
|
||||
@AppStorage("accentTheme") private var accentThemeRaw = AccentTheme.ocean.rawValue
|
||||
@AppStorage("loggingEnabled") private var loggingEnabled = false
|
||||
@Environment(ServerProfileStore.self) private var profileStore
|
||||
|
||||
private var selectedTheme: AccentTheme {
|
||||
AccentTheme(rawValue: accentThemeRaw) ?? .ocean
|
||||
}
|
||||
@State private var serverURL = UserDefaults.standard.string(forKey: "serverURL") ?? ""
|
||||
@State private var showSignOutAlert = false
|
||||
@State private var isSyncing = false
|
||||
@State private var lastSynced = UserDefaults.standard.object(forKey: "lastSynced") as? Date
|
||||
@@ -20,6 +21,11 @@ struct SettingsView: View {
|
||||
@State private var selectedLanguage: LanguageManager.Language = LanguageManager.shared.current
|
||||
@State private var showLogViewer = false
|
||||
@State private var shareItems: [Any]? = nil
|
||||
@Environment(\.modelContext) private var modelContext
|
||||
@State private var showAddServer = false
|
||||
@State private var profileToSwitch: ServerProfile? = nil
|
||||
@State private var profileToDelete: ServerProfile? = nil
|
||||
@State private var profileToEdit: ServerProfile? = nil
|
||||
|
||||
private let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0"
|
||||
private let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1"
|
||||
@@ -93,33 +99,56 @@ struct SettingsView: View {
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
|
||||
// Account section
|
||||
Section(L("settings.account")) {
|
||||
HStack {
|
||||
Image(systemName: "person.circle.fill")
|
||||
.font(.title)
|
||||
.foregroundStyle(.blue)
|
||||
VStack(alignment: .leading) {
|
||||
Text(L("settings.account.connected"))
|
||||
.font(.headline)
|
||||
Text(serverURL)
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
// Servers section
|
||||
Section(L("settings.servers")) {
|
||||
ForEach(profileStore.profiles) { profile in
|
||||
Button {
|
||||
if profile.id != profileStore.activeProfileId {
|
||||
profileToSwitch = profile
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: profile.id == profileStore.activeProfileId
|
||||
? "checkmark.circle.fill" : "circle")
|
||||
.foregroundStyle(profile.id == profileStore.activeProfileId
|
||||
? Color.accentColor : .secondary)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(profile.name)
|
||||
.font(.body)
|
||||
.foregroundStyle(.primary)
|
||||
Text(profile.serverURL)
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Spacer()
|
||||
if profile.id == profileStore.activeProfileId {
|
||||
Text(L("settings.servers.active"))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||
Button(role: .destructive) {
|
||||
profileToDelete = profile
|
||||
} label: {
|
||||
Label(L("settings.servers.delete.confirm"), systemImage: "trash")
|
||||
}
|
||||
.tint(.red)
|
||||
Button {
|
||||
profileToEdit = profile
|
||||
} label: {
|
||||
Label(L("settings.servers.edit"), systemImage: "pencil")
|
||||
}
|
||||
.tint(.blue)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
|
||||
Button {
|
||||
UIPasteboard.general.string = serverURL
|
||||
showAddServer = true
|
||||
} label: {
|
||||
Label(L("settings.account.copyurl"), systemImage: "doc.on.doc")
|
||||
}
|
||||
|
||||
Button(role: .destructive) {
|
||||
showSignOutAlert = true
|
||||
} label: {
|
||||
Label(L("settings.account.signout"), systemImage: "rectangle.portrait.and.arrow.right")
|
||||
Label(L("settings.servers.add"), systemImage: "plus.circle")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,11 +236,58 @@ struct SettingsView: View {
|
||||
.onAppear {
|
||||
loggingEnabled = LogManager.shared.isEnabled
|
||||
}
|
||||
.alert(L("settings.signout.alert.title"), isPresented: $showSignOutAlert) {
|
||||
Button(L("settings.signout.alert.confirm"), role: .destructive) { signOut() }
|
||||
Button(L("settings.signout.alert.cancel"), role: .cancel) {}
|
||||
// Switch server confirmation
|
||||
.alert(L("settings.servers.switch.title"), isPresented: Binding(
|
||||
get: { profileToSwitch != nil },
|
||||
set: { if !$0 { profileToSwitch = nil } }
|
||||
)) {
|
||||
Button(L("settings.servers.switch.confirm")) {
|
||||
if let p = profileToSwitch { profileStore.activate(p) }
|
||||
profileToSwitch = nil
|
||||
}
|
||||
Button(L("settings.signout.alert.cancel"), role: .cancel) { profileToSwitch = nil }
|
||||
} message: {
|
||||
Text(L("settings.signout.alert.message"))
|
||||
if let p = profileToSwitch {
|
||||
Text(String(format: L("settings.servers.switch.message"), p.name))
|
||||
}
|
||||
}
|
||||
// Delete inactive server confirmation
|
||||
.alert(L("settings.servers.delete.title"), isPresented: Binding(
|
||||
get: { profileToDelete != nil && profileToDelete?.id != profileStore.activeProfileId },
|
||||
set: { if !$0 { profileToDelete = nil } }
|
||||
)) {
|
||||
Button(L("settings.servers.delete.confirm"), role: .destructive) {
|
||||
if let p = profileToDelete { removeProfile(p) }
|
||||
profileToDelete = nil
|
||||
}
|
||||
Button(L("settings.signout.alert.cancel"), role: .cancel) { profileToDelete = nil }
|
||||
} message: {
|
||||
if let p = profileToDelete {
|
||||
Text(String(format: L("settings.servers.delete.message"), p.name))
|
||||
}
|
||||
}
|
||||
// Delete ACTIVE server — stronger warning
|
||||
.alert(L("settings.servers.delete.active.title"), isPresented: Binding(
|
||||
get: { profileToDelete != nil && profileToDelete?.id == profileStore.activeProfileId },
|
||||
set: { if !$0 { profileToDelete = nil } }
|
||||
)) {
|
||||
Button(L("settings.servers.delete.confirm"), role: .destructive) {
|
||||
if let p = profileToDelete { removeProfile(p) }
|
||||
profileToDelete = nil
|
||||
}
|
||||
Button(L("settings.signout.alert.cancel"), role: .cancel) { profileToDelete = nil }
|
||||
} message: {
|
||||
if let p = profileToDelete {
|
||||
Text(String(format: L("settings.servers.delete.active.message"), p.name))
|
||||
}
|
||||
}
|
||||
// Add server sheet
|
||||
.sheet(isPresented: $showAddServer) {
|
||||
AddServerView()
|
||||
}
|
||||
// Edit server sheet
|
||||
.sheet(item: $profileToEdit) { profile in
|
||||
EditServerView(profile: profile)
|
||||
}
|
||||
.sheet(item: $showSafari) { url in
|
||||
SafariView(url: url)
|
||||
@@ -233,11 +309,13 @@ struct SettingsView: View {
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
private func signOut() {
|
||||
Task {
|
||||
try? await KeychainService.shared.deleteCredentials()
|
||||
UserDefaults.standard.removeObject(forKey: "serverURL")
|
||||
UserDefaults.standard.removeObject(forKey: "lastSynced")
|
||||
private func removeProfile(_ profile: ServerProfile) {
|
||||
profileStore.remove(profile)
|
||||
// Always clear the cache — it may contain content from this server
|
||||
try? SyncService.shared.clearAllCache(context: modelContext)
|
||||
lastSynced = nil
|
||||
// If no profiles remain, return to onboarding
|
||||
if profileStore.profiles.isEmpty {
|
||||
onboardingComplete = false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user