Add history and settings to watch app

This commit is contained in:
Christoph Hagen
2023-08-09 16:29:18 +02:00
parent e5ea8c4951
commit 5f9af35542
20 changed files with 604 additions and 175 deletions

View File

@ -0,0 +1,77 @@
import SwiftUI
import CryptoKit
struct SettingsKeyInputView: View {
let type: KeyManagement.KeyType
@State
private var text: String = ""
let footnote: String
@EnvironmentObject
private var keys: KeyManagement
private var hasKey: Bool {
keys.has(type)
}
private var displayText: String {
keys.get(type)?.displayString ?? "-"
}
private var copyText: String {
guard let key = keys.get(type)?.data else {
return ""
}
guard type.usesHashing else {
return key.hexEncoded
}
return SHA256.hash(data: key).hexEncoded
}
var body: some View {
ScrollView {
VStack(alignment: .leading) {
TextField(type.displayName, text: $text)
.onSubmit(validateText)
.foregroundColor(.accentColor)
Text(footnote)
.font(.footnote)
.foregroundColor(.secondary)
}
.navigationTitle(type.displayName)
.onAppear {
if text == "" {
text = displayText
print("Text inserted")
}
}
}
}
private func validateText() {
let cleanText = text.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
guard let keyData = Data(fromHexEncodedString: cleanText) else {
print("Invalid key string")
return
}
let keyLength = type.keyLength.bitCount
guard keyData.count * 8 == keyLength else {
print("Invalid key length \(keyData.count * 8) bits, expected \(keyLength) (Input: '\(text)')")
return
}
keys.save(type, data: keyData)
print("Key \(type) saved")
}
}
struct SettingsKeyInputView_Previews: PreviewProvider {
static var previews: some View {
SettingsKeyInputView(
type: .remoteKey,
footnote: "Some text describing the purpose of the key.")
.environmentObject(KeyManagement())
}
}

View File

@ -0,0 +1,47 @@
import SwiftUI
struct SettingsKeyItemLink: View {
let type: KeyManagement.KeyType
let footnote: String
@EnvironmentObject
private var keys: KeyManagement
@State
private var keyText = "..."
var body: some View {
NavigationLink {
SettingsKeyInputView(
type: type,
footnote: footnote)
.environmentObject(keys)
} label: {
SettingsListTextItem(
title: type.displayName,
value: keyText)
.onAppear(perform: updateKeyText)
}
.buttonStyle(PlainButtonStyle())
}
private func updateKeyText() {
Task {
let key = keys.get(type)?.displayString ?? "Not set"
DispatchQueue.main.async {
keyText = key
}
}
}
}
struct SettingsKeyItemLink_Previews: PreviewProvider {
static var previews: some View {
SettingsKeyItemLink(
type: .deviceKey,
footnote: "Some text describing the purpose of the key.")
.environmentObject(KeyManagement())
}
}

View File

@ -0,0 +1,31 @@
import SwiftUI
struct SettingsListTextItem: View {
let title: String
let value: String
var body: some View {
VStack(alignment: .leading) {
HStack {
Text(title)
.foregroundColor(.primary)
Spacer()
}
Text(value)
.font(.footnote)
.foregroundColor(.secondary)
.lineLimit(1)
}
.padding()
}
}
struct SettingsListTextItem_Previews: PreviewProvider {
static var previews: some View {
SettingsListTextItem(
title: "Title",
value: "Some longer text")
}
}

View File

@ -0,0 +1,28 @@
import SwiftUI
struct SettingsListToggleItem: View {
let title: String
@Binding
var value: Bool
let subtitle: String
var body: some View {
VStack(alignment: .leading) {
Toggle(title, isOn: $value)
Text(subtitle)
.font(.footnote)
.foregroundColor(.secondary)
}
.padding()
.cornerRadius(8)
}
}
struct SettingsListToggleItem_Previews: PreviewProvider {
static var previews: some View {
SettingsListToggleItem(title: "Toggle", value: .constant(true), subtitle: "Some longer text explaining what the toggle does")
}
}

View File

@ -0,0 +1,45 @@
import SwiftUI
struct SettingsNumberInputView: View {
let title: String
@Binding
var value: Int
@State
private var text: String = ""
let footnote: String
var body: some View {
VStack(alignment: .leading) {
TextField(title, text: $text)
.onSubmit {
guard let newValue = Int(text) else {
return
}
value = newValue
}
.foregroundColor(.accentColor)
Text(footnote)
.font(.footnote)
.foregroundColor(.secondary)
Spacer()
}
.navigationTitle(title)
.navigationBarBackButtonHidden(false)
.onAppear {
text = "\(value)"
}
}
}
struct SettingsNumberInputView_Previews: PreviewProvider {
static var previews: some View {
SettingsNumberInputView(
title: "Title",
value: .constant(0),
footnote: "Some more text explaining the purpose of the text field.")
}
}

View File

@ -0,0 +1,30 @@
import SwiftUI
struct SettingsNumberItemLink: View {
let title: String
@Binding
var value: Int
let footnote: String
var body: some View {
NavigationLink {
SettingsNumberInputView(
title: title,
value: $value,
footnote: footnote
)
} label: {
SettingsListTextItem(title: title, value: "\(value)")
}
.buttonStyle(PlainButtonStyle())
}
}
struct SettingsNumberItemLink_Previews: PreviewProvider {
static var previews: some View {
SettingsNumberItemLink(title: "Title", value: .constant(0), footnote: "Some more text explaining the purpose of the text field.")
}
}

View File

@ -0,0 +1,33 @@
import SwiftUI
struct SettingsTextInputView: View {
let title: String
@Binding
var text: String
let footnote: String
var body: some View {
VStack(alignment: .leading) {
TextField(title, text: $text)
.foregroundColor(.accentColor)
Text(footnote)
.font(.footnote)
.foregroundColor(.secondary)
Spacer()
}
.navigationTitle(title)
.navigationBarBackButtonHidden(false)
}
}
struct SettingsTextInputView_Previews: PreviewProvider {
static var previews: some View {
SettingsTextInputView(
title: "Title",
text: .constant("Text"),
footnote: "Some more text explaining the purpose of the text field.")
}
}

View File

@ -0,0 +1,30 @@
import SwiftUI
struct SettingsTextItemLink: View {
let title: String
@Binding
var value: String
let footnote: String
var body: some View {
NavigationLink {
SettingsTextInputView(
title: title,
text: $value,
footnote: footnote
)
} label: {
SettingsListTextItem(title: title, value: value)
}
.buttonStyle(PlainButtonStyle())
}
}
struct SettingsTextItemLink_Previews: PreviewProvider {
static var previews: some View {
SettingsTextItemLink(title: "Title", value: .constant("Some value"), footnote: "Some more text explaining the purpose of the text field.")
}
}