Sesame-iOS/Sesame-Watch Watch App/ContentView.swift
2023-08-09 16:29:18 +02:00

135 lines
4.1 KiB
Swift

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())
}
}