import SwiftUI import SFSafeSymbols import CryptoKit struct ContentView: View { @AppStorage("server") var serverPath: String = "https://christophhagen.de/sesame/" @AppStorage("localIP") var localAddress: String = "192.168.178.104/" @AppStorage("counter") var nextMessageCounter: Int = 0 @AppStorage("compensate") var isCompensatingDaylightTime: Bool = false @AppStorage("local") private var useLocalConnection = false @AppStorage("deviceId") private var deviceId: Int = 0 @EnvironmentObject var keyManager: KeyManagement @State var state: ClientState = .noKeyAvailable let server = Client() let history = HistoryManager() var buttonBackground: Color { state.allowsAction ? .white.opacity(0.2) : .black.opacity(0.2) } var buttonColor: Color { state.allowsAction ? .white : .gray } var body: some View { HStack { Spacer() VStack(alignment: .center) { Image(systemSymbol: .lock) .resizable() .aspectRatio(contentMode: .fit) .fontWeight(.ultraLight) .padding() .onTapGesture(perform: mainButtonPressed) .disabled(!state.allowsAction) Text(state.actionText) .font(.subheadline) } Spacer() } .background(state.color) .animation(.easeInOut, value: state.color) .onAppear { if keyManager.hasAllKeys, state == .noKeyAvailable { state = .ready } } } func mainButtonPressed() { guard let key = keyManager.get(.remoteKey), let token = keyManager.get(.authToken)?.data, let deviceId = UInt8(exactly: deviceId) else { return } let count = UInt32(nextMessageCounter) let sentTime = Date() // Add time to compensate that the device is using daylight savings time let timeCompensation: UInt32 = isCompensatingDaylightTime ? 3600 : 0 let content = Message.Content( time: sentTime.timestamp + timeCompensation, id: count, device: deviceId) let message = content.authenticate(using: key) let historyItem = HistoryItem(sent: message.content, date: sentTime, local: useLocalConnection) state = .waitingForResponse print("Sending message \(count)") Task { let (newState, responseMessage) = await send(message, authToken: token) let receivedTime = Date.now //responseTime = receivedTime state = newState let finishedItem = historyItem.didReceive(response: newState, date: receivedTime, message: responseMessage?.content) guard let key = keyManager.get(.deviceKey) else { save(historyItem: finishedItem.notAuthenticated()) return } guard let responseMessage else { save(historyItem: finishedItem) return } guard responseMessage.isValid(using: key) else { save(historyItem: finishedItem.invalidated()) return } nextMessageCounter = Int(responseMessage.content.id) save(historyItem: finishedItem) } } private func send(_ message: Message, authToken: Data) async -> (state: ClientState, response: Message?) { if useLocalConnection { return await server.sendMessageOverLocalNetwork(message, server: localAddress) } else { return await server.send(message, server: serverPath, authToken: authToken) } } private func save(historyItem: HistoryItem) { do { try history.save(item: historyItem) } catch { print("Failed to save item: \(error)") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() .environmentObject(KeyManagement()) } }