feat(ios): simplify navigation and ship 0.2.0
Move diagnostics into settings, remove the app-local notification module, unify the global theme switcher, refine privacy copy and the instance detail experience, and rebuild the app icon.
This commit is contained in:
@@ -38,40 +38,95 @@ struct InstanceDetailView: View {
|
||||
}
|
||||
|
||||
private var header: some View {
|
||||
AICard {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
AISectionTitle(
|
||||
"设备详情",
|
||||
systemImage: "iphone.gen3",
|
||||
actionTitle: revealsSensitive ? "隐藏敏感值" : "显示敏感值",
|
||||
actionSystemImage: revealsSensitive ? "eye.slash" : "eye"
|
||||
) {
|
||||
revealsSensitive.toggle()
|
||||
AICard(padding: 18) {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
HStack(alignment: .top, spacing: 14) {
|
||||
Image(systemName: "cpu")
|
||||
.font(.system(size: 21, weight: .semibold))
|
||||
.foregroundStyle(AITheme.primary)
|
||||
.frame(width: 46, height: 46)
|
||||
.background(AITheme.primary.opacity(0.11))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous))
|
||||
.accessibilityHidden(true)
|
||||
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text(model.instance.name)
|
||||
.font(.title3.weight(.bold))
|
||||
.kerning(-0.2)
|
||||
.foregroundStyle(AITheme.ink)
|
||||
.lineLimit(2)
|
||||
Text(model.instance.origin.absoluteString)
|
||||
.font(.caption)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
.lineLimit(2)
|
||||
.truncationMode(.middle)
|
||||
}
|
||||
}
|
||||
Text(model.instance.origin.absoluteString)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
.lineLimit(2)
|
||||
.truncationMode(.middle)
|
||||
|
||||
HStack(spacing: 10) {
|
||||
AITag(revealsSensitive ? "敏感值已显示" : "敏感值已隐藏", tint: AITheme.primary)
|
||||
if let availableCount {
|
||||
AITag("\(availableCount)/6 模块", tint: AITheme.success)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
withAnimation(.easeOut(duration: 0.18)) {
|
||||
revealsSensitive.toggle()
|
||||
}
|
||||
} label: {
|
||||
Label(
|
||||
revealsSensitive ? "隐藏敏感值" : "显示敏感值",
|
||||
systemImage: revealsSensitive ? "eye.slash" : "eye"
|
||||
)
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .secondary, size: .compact, fixedWidth: 112))
|
||||
|
||||
if model.isLoading {
|
||||
Text("正在读取设备详情…")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
AILoadingCard("正在读取设备详情")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var availableCount: Int? {
|
||||
guard let snapshot = model.snapshot else { return nil }
|
||||
return snapshot.sections.filter { !$0.values.isEmpty }.count
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func sectionCard(_ section: DeviceSection) -> some View {
|
||||
AICard {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
AISectionTitle(section.title, systemImage: "list.bullet.rectangle")
|
||||
if section.values.isEmpty {
|
||||
Text("此模块当前不可用或未返回数据。")
|
||||
.font(.subheadline)
|
||||
if section.values.isEmpty {
|
||||
AICard(padding: 14) {
|
||||
HStack(spacing: 10) {
|
||||
Image(systemName: "wifi.slash")
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.foregroundStyle(AITheme.muted)
|
||||
} else {
|
||||
ForEach(sortedValues(section.values), id: \.key) { item in
|
||||
.frame(width: 32, height: 32)
|
||||
.background(AITheme.control)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 11, style: .continuous))
|
||||
.accessibilityHidden(true)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(section.title)
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.foregroundStyle(AITheme.ink)
|
||||
Text("模块未返回数据")
|
||||
.font(.caption)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AICard(padding: 18) {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
AISectionTitle(section.title, systemImage: sectionIcon(section.id))
|
||||
Divider()
|
||||
.overlay(AITheme.line)
|
||||
ForEach(Array(sortedValues(section.values).enumerated()), id: \.element.key) { index, item in
|
||||
if index > 0 {
|
||||
Divider()
|
||||
.overlay(AITheme.line.opacity(0.6))
|
||||
}
|
||||
AIKeyValueRow(fieldLabel(item.key), value: display(item.key, item.value))
|
||||
}
|
||||
}
|
||||
@@ -79,6 +134,18 @@ struct InstanceDetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func sectionIcon(_ id: String) -> String {
|
||||
switch id {
|
||||
case "device": return "iphone.gen3"
|
||||
case "sim": return "simcard"
|
||||
case "network": return "antenna.radiowaves.left.and.right"
|
||||
case "stats": return "gauge.with.needle"
|
||||
case "cpu": return "cpu"
|
||||
case "connectivity": return "dot.radiowaves.left.and.right"
|
||||
default: return "list.bullet.rectangle"
|
||||
}
|
||||
}
|
||||
|
||||
private let fieldLabels: [String: String] = [
|
||||
"model": "型号",
|
||||
"manufacturer": "制造商",
|
||||
|
||||
Reference in New Issue
Block a user