fix(ios): improve fleet overview and app identity
- Show stable group health in a fixed 2x2 metric grid - Add link-chain state to fleet cards and parse hardware/control/SIM/cellular - Replace the wrapped icon with a full-bleed app icon - Bump the IPA build number
This commit is contained in:
@@ -3,13 +3,24 @@ import SwiftUI
|
||||
struct InstanceFormView: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@ObservedObject var model: FleetViewModel
|
||||
let instance: Instance?
|
||||
@State private var name = ""
|
||||
@State private var originText = ""
|
||||
@State private var tagsText = ""
|
||||
@State private var password = ""
|
||||
@State private var selectedGroupId: UUID?
|
||||
@State private var validationMessage: String?
|
||||
@State private var isSaving = false
|
||||
|
||||
init(model: FleetViewModel, instance: Instance? = nil) {
|
||||
self.model = model
|
||||
self.instance = instance
|
||||
_name = State(initialValue: instance?.name ?? "")
|
||||
_originText = State(initialValue: instance?.origin.absoluteString ?? "")
|
||||
_tagsText = State(initialValue: instance?.tags.joined(separator: ", ") ?? "")
|
||||
_selectedGroupId = State(initialValue: instance?.groupId)
|
||||
}
|
||||
|
||||
private var canSave: Bool {
|
||||
!name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
&& !originText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
@@ -24,7 +35,13 @@ struct InstanceFormView: View {
|
||||
field("名称", text: $name, placeholder: "Home Node")
|
||||
field("地址", text: $originText, placeholder: "http://192.168.1.10:3000")
|
||||
field("标签", text: $tagsText, placeholder: "home, primary")
|
||||
field("实例密码", text: $password, placeholder: "可选,保存在本机沙盒", secure: true)
|
||||
groupPicker
|
||||
field(
|
||||
"实例密码",
|
||||
text: $password,
|
||||
placeholder: instance == nil ? "可选,保存在本机沙盒" : "留空则不修改密码",
|
||||
secure: true
|
||||
)
|
||||
}
|
||||
}
|
||||
if let validationMessage {
|
||||
@@ -56,13 +73,37 @@ struct InstanceFormView: View {
|
||||
}
|
||||
}
|
||||
.background(AITheme.canvas.ignoresSafeArea())
|
||||
.navigationTitle("添加实例")
|
||||
.navigationTitle(instance == nil ? "添加实例" : "编辑实例")
|
||||
#if os(iOS)
|
||||
.scrollDismissesKeyboard(.interactively)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private var groupPicker: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack(spacing: 8) {
|
||||
AIFieldLabel("分组")
|
||||
Spacer()
|
||||
Button {
|
||||
model.showingGroupManager = true
|
||||
} label: {
|
||||
Label("管理", systemImage: "folder.badge.gearshape")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .secondary, size: .toolbarInline, fixedWidth: 72))
|
||||
}
|
||||
Picker("分组", selection: $selectedGroupId) {
|
||||
Text("未分组").tag(UUID?.none)
|
||||
ForEach(model.groups) { group in
|
||||
Text(group.name).tag(UUID?.some(group.id))
|
||||
}
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
.aiSelectSurface()
|
||||
}
|
||||
.accessibilityElement(children: .contain)
|
||||
}
|
||||
|
||||
private func field(
|
||||
_ title: String,
|
||||
text: Binding<String>,
|
||||
@@ -111,11 +152,16 @@ struct InstanceFormView: View {
|
||||
name: normalizedName,
|
||||
origin: origin,
|
||||
tags: tags,
|
||||
groupId: selectedGroupId,
|
||||
password: password.isEmpty ? nil : password
|
||||
)
|
||||
Task {
|
||||
do {
|
||||
try await model.add(input)
|
||||
if let instance {
|
||||
try await model.update(instance.id, input)
|
||||
} else {
|
||||
try await model.add(input)
|
||||
}
|
||||
} catch {
|
||||
validationMessage = "保存失败,请检查地址是否重复。"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user