release(ios): 发布 0.2.1 并重构图标与界面细节

- 应用图标改用与 Web favicon 同源的扁平标记,金色 SIM 卡体加三格递增信号,29pt 下仍可读
- 标签统一为胶囊形状,提高深色主题下的描边权重,避免标签在暗色下消失
- 消息卡片与详情分区卡片收紧行距,单屏信息密度明显提升
- 详情头部指标精简为 4 行,数据模块改为单条读数
- 批量选择勾选框移出名称区域,工具栏控件统一为等高 34pt
- 分组编辑器改为点选即生效,移除说明文字与常驻禁用按钮
This commit is contained in:
chick
2026-09-14 16:30:39 +08:00
parent 27687868ef
commit 3607eddc9f
34 changed files with 2656 additions and 1213 deletions
@@ -7,13 +7,21 @@ struct MultiSimAdminApp: App {
init() {
let arguments = ProcessInfo.processInfo.arguments
var initial: AppTab = .fleet
if arguments.contains("--tab-messages") {
_tab = State(initialValue: .messages)
initial = .messages
} else if arguments.contains("--tab-settings") {
_tab = State(initialValue: .settings)
} else {
_tab = State(initialValue: .fleet)
initial = .settings
}
#if DEBUG
if arguments.contains("--tab-detail") {
initial = .debugDetail
}
if arguments.contains("--tab-logs") {
initial = .debugLogs
}
#endif
_tab = State(initialValue: initial)
}
var body: some Scene {
@@ -26,6 +34,12 @@ struct MultiSimAdminApp: App {
NavigationStack { MessagesView().aiInlineTitle() }
case .settings:
NavigationStack { SettingsView().aiInlineTitle() }
#if DEBUG
case .debugDetail:
NavigationStack { DebugDetailView().aiInlineTitle() }
case .debugLogs:
NavigationStack { LogsView().aiInlineTitle() }
#endif
}
}
.safeAreaInset(edge: .bottom, spacing: 0) {
@@ -57,8 +71,40 @@ enum AppTab: Hashable {
case fleet
case messages
case settings
#if DEBUG
case debugDetail
case debugLogs
#endif
}
#if DEBUG
/// 本地截图验证用的入口,Release 构建不包含。
struct DebugDetailView: View {
@State private var target: (Instance, String?)?
var body: some View {
Group {
if let (instance, groupName) = target {
InstanceDetailView(instance: instance, groupName: groupName)
} else {
ProgressView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.task {
let repository = FileInstanceRepository(location: DefaultContainer.documentFileURL("instances.json"))
let groups = FileInstanceGroupStore(location: DefaultContainer.documentFileURL("instance-groups.json"))
guard let listed = try? await repository.list(InstanceQuery()), listed.isEmpty == false else { return }
// 截图验证优先看可达节点(3000),否则详情页全是空态,看不出真实排版。
let instance =
listed.first { $0.origin.port == 3000 } ?? listed[0]
let name = (try? await groups.list())?.first { $0.id == instance.groupId }?.name
target = (instance, name)
}
}
}
#endif
struct AITabBar: View {
@Binding var selection: AppTab