import ServiceManagement import SwiftUI struct SettingsView: View { @State private var config: AppConfig @State private var isTestingConnection = false @State private var connectionResult: String? init() { _config = State(initialValue: AppStateService.shared.config ?? AppConfig()) } var body: some View { Form { Section("Feishu Bitable") { TextField("App Token (from Bitable URL)", text: $config.appToken) TextField("Table ID", text: $config.tableId) TextField("Your Name (as in Assignee column, optional)", text: $config.assigneeName) TextField("Feishu domain", text: $config.feishuBaseDomain) VStack(alignment: .leading, spacing: 4) { HStack(spacing: 8) { Button("Test Connection") { testConnection() } .disabled(isTestingConnection || !config.isConfigured) if isTestingConnection { ProgressView() .scaleEffect(0.7) } } if let connectionResult { Text(connectionResult) .font(.caption) .foregroundStyle(connectionResult.contains("✓") ? .green : .red) .lineLimit(3) .fixedSize(horizontal: false, vertical: true) } } } Section("Polling") { Picker("Check every", selection: $config.pollIntervalSeconds) { Text("1 minute").tag(60) Text("5 minutes").tag(300) Text("10 minutes").tag(600) Text("30 minutes").tag(1800) } } Section("Display") { Toggle("Show floating widget", isOn: $config.showFloatingWidget) .onChange(of: config.showFloatingWidget) { _, enabled in if enabled { AppDelegate.shared?.showFloatingWidget() } else { AppDelegate.shared?.hideFloatingWidget() } } Toggle("Launch at login", isOn: $config.launchAtLogin) } Section("Field Mappings") { TextField("Title field", text: $config.fieldMappings.titleField) TextField("Priority field", text: $config.fieldMappings.priorityField) TextField("Status field", text: $config.fieldMappings.statusField) TextField("Assignee field", text: $config.fieldMappings.assigneeField) TextField("Reporter field", text: $config.fieldMappings.reporterField) TextField("Created At field", text: $config.fieldMappings.createdAtField) TextField("Updated At field", text: $config.fieldMappings.updatedAtField) } HStack { Button("Save") { save() } .keyboardShortcut(.return) Button("Disconnect Feishu") { TokenManager.shared.clearTokens() PollerService.shared.stop() } .foregroundStyle(.red) } } .padding() .frame(minWidth: 500, idealWidth: 520, minHeight: 560) } private func save() { AppStateService.shared.saveConfig(config) connectionResult = "Saved ✓" if config.launchAtLogin { try? SMAppService.mainApp.register() } else { try? SMAppService.mainApp.unregister() } if config.showFloatingWidget { AppDelegate.shared?.showFloatingWidget() } else { AppDelegate.shared?.hideFloatingWidget() } Task { PollerService.shared.restart(interval: TimeInterval(config.pollIntervalSeconds)) } } private func testConnection() { isTestingConnection = true connectionResult = nil Task { do { let token = try await TokenManager.shared.getAccessToken() let count = try await FeishuService().fetchRecordCount( appToken: config.appToken, tableId: config.tableId, accessToken: token ) connectionResult = "Connected ✓ (\(count) records in table)" } catch { connectionResult = "Failed: \(error.localizedDescription)" } isTestingConnection = false } } }