import Foundation import SwiftUI enum ClientState { /// The initial state after app launch case initial /// There are no keys stored locally on the client. New keys must be generated before use. case noKeysAvailable /// New keys have been generated and can now be transmitted to the device. case newKeysGenerated /// The device status could not be determined case statusRequestFailed /// The status received from the server could not be decoded case unknownDeviceStatus /// The remote device is not connected (no socket opened) case deviceDisconnected /// The device is connected and ready to receive a key case deviceConnected /// The key is being transmitted and a response is awaited case waitingForResponse /// The transmitted key was rejected (multiple possible reasons) case keyRejected /// Internal errors with the implementation case internalError /// The configuration of the devices doesn't match case configurationError /// The device responded that the opening action was started case openSesame /// All keys have been used case allKeysUsed var canSendKey: Bool { switch self { case .deviceConnected, .openSesame, .keyRejected: return true default: return false } } init(keyResult: KeyResult) { switch keyResult { case .textReceived, .unexpectedSocketEvent, .unknownDeviceError: self = .unknownDeviceStatus case .invalidPayloadSize, .invalidKeyIndex, .invalidKey: self = .configurationError case .keyAlreadyUsed, .keyWasSkipped: self = .keyRejected case .keyAccepted: self = .openSesame case .noBodyData, .corruptkeyData: self = .internalError case .deviceNotConnected, .deviceTimedOut: self = .deviceDisconnected } } var description: String { switch self { case .initial: return "Checking state..." case .noKeysAvailable: return "No keys found" case .newKeysGenerated: return "New keys generated" case .deviceDisconnected: return "Device not connected" case .statusRequestFailed: return "Unable to get device status" case .unknownDeviceStatus: return "Unknown device status" case .deviceConnected: return "Device connected" case .waitingForResponse: return "Waiting for response" case .internalError: return "An internal error occured" case .configurationError: return "Configuration error" case .allKeysUsed: return "No fresh keys available" case .keyRejected: return "The key was rejected" case .openSesame: return "Unlocked" } } var openButtonText: String { switch self { case .initial, .statusRequestFailed, .unknownDeviceStatus, .deviceDisconnected, .newKeysGenerated, .configurationError, .internalError: return "Connect" case .allKeysUsed, .noKeysAvailable: return "Disabled" case .deviceConnected, .keyRejected, .openSesame: return "Unlock" case .waitingForResponse: return "Unlocking..." } } var openButtonColor: Color { switch self { case .initial, .newKeysGenerated, .statusRequestFailed, .waitingForResponse: return .yellow case .noKeysAvailable, .allKeysUsed, .deviceDisconnected, .unknownDeviceStatus, .keyRejected, .configurationError, .internalError: return .red case .deviceConnected, .openSesame: return .green } } var openActionIsEnabled: Bool { switch self { case .allKeysUsed, .noKeysAvailable, .waitingForResponse: return false default: return true } } }