bugger/Sources/Views/Settings/SettingsView.swift

127 lines
4.5 KiB
Swift

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)
HStack {
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)
}
}
}
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(width: 440, height: 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)"
} catch {
connectionResult = "Failed: \(error.localizedDescription)"
}
isTestingConnection = false
}
}
}