diff --git a/Sesame/Common/RequestCoordinator.swift b/Sesame/Common/RequestCoordinator.swift index 74e3880..f7b5f21 100644 --- a/Sesame/Common/RequestCoordinator.swift +++ b/Sesame/Common/RequestCoordinator.swift @@ -41,6 +41,23 @@ final class RequestCoordinator: ObservableObject { } } + func checkConnection(using route: TransmissionType? = nil) { + guard !isPerformingRequest else { + return + } + isPerformingRequest = true + Task { + let route = route ?? connectionType.transmissionTypes.first! + let (finalResult, _) = await performChallenge(route: route) + DispatchQueue.main.async { + self.state = finalResult.result + self.isPerformingRequest = false + } + print("Finished connection test: \(finalResult)") + scheduleReturnToReadyState() + } + } + func startUnlock() { guard !isPerformingRequest else { return diff --git a/Sesame/ContentView.swift b/Sesame/ContentView.swift index 2263a2c..0cf6432 100644 --- a/Sesame/ContentView.swift +++ b/Sesame/ContentView.swift @@ -73,7 +73,8 @@ struct ContentView: View { .animation(.easeInOut, value: coordinator.state.color) .sheet(isPresented: $showSettingsSheet) { SettingsView( - keyManager: coordinator.keyManager, + keyManager: coordinator.keyManager, + coordinator: coordinator, serverAddress: $coordinator.serverPath, localAddress: $coordinator.localAddress) } diff --git a/Sesame/SettingsView.swift b/Sesame/SettingsView.swift index 96c4220..3434f63 100644 --- a/Sesame/SettingsView.swift +++ b/Sesame/SettingsView.swift @@ -1,9 +1,14 @@ import SwiftUI +import SwiftData +import SFSafeSymbols struct SettingsView: View { let keyManager: KeyManagement + @ObservedObject + var coordinator: RequestCoordinator + @Binding var serverAddress: String @@ -20,6 +25,19 @@ struct SettingsView: View { TextField("Server address", text: $serverAddress) .foregroundColor(.secondary) .padding(.leading, 8) + HStack { + Button("Test") { + coordinator.checkConnection(using: .throughServer) + }.padding(8) + if coordinator.state == .deviceAvailable { + Image(systemSymbol: .checkmarkCircle) + .foregroundColor(.green) + } else if coordinator.state != .notChecked { + Text(coordinator.state.description) + .font(.caption) + .foregroundStyle(.secondary) + } + } }.padding(.vertical, 8) VStack(alignment: .leading) { Text("Local address") @@ -44,11 +62,20 @@ struct SettingsView: View { } } -struct SettingsView_Previews: PreviewProvider { - static var previews: some View { - SettingsView( +#Preview { + do { + let config = ModelConfiguration(isStoredInMemoryOnly: true) + let container = try ModelContainer(for: HistoryItem.self, configurations: config) + + let item = HistoryItem.mock + container.mainContext.insert(item) + try container.mainContext.save() + return SettingsView( keyManager: KeyManagement(), + coordinator: .init(modelContext: container.mainContext), serverAddress: .constant("https://example.com"), localAddress: .constant("192.168.178.42")) + } catch { + fatalError("Failed to create model container.") } }