feat(ios): unify list cards and loading states

This commit is contained in:
chick
2026-09-10 01:35:12 +08:00
parent 995206ac23
commit c841748971
32 changed files with 1297 additions and 607 deletions
@@ -2,41 +2,107 @@ import SwiftUI
@main
struct MultiSimAdminApp: App {
@State private var tab: AppTab
init() {
let arguments = ProcessInfo.processInfo.arguments
if arguments.contains("--tab-messages") {
_tab = State(initialValue: .messages)
} else if arguments.contains("--tab-notifications") {
_tab = State(initialValue: .notifications)
} else if arguments.contains("--tab-logs") {
_tab = State(initialValue: .logs)
} else if arguments.contains("--tab-settings") {
_tab = State(initialValue: .settings)
} else {
_tab = State(initialValue: .fleet)
}
}
var body: some Scene {
WindowGroup {
TabView {
NavigationStack {
FleetView()
}
.tabItem {
Label("节点", systemImage: "server.rack")
}
NavigationStack {
MessagesView()
}
.tabItem {
Label("消息", systemImage: "message")
}
NavigationStack {
NotificationsView()
}
.tabItem {
Label("通知", systemImage: "bell")
}
NavigationStack {
LogsView()
}
.tabItem {
Label("日志", systemImage: "doc.text")
}
NavigationStack {
SettingsView()
}
.tabItem {
Label("设置", systemImage: "gearshape")
VStack(spacing: 0) {
switch tab {
case .fleet:
NavigationStack { FleetView().aiInlineTitle() }
case .messages:
NavigationStack { MessagesView().aiInlineTitle() }
case .notifications:
NavigationStack { NotificationsView().aiInlineTitle() }
case .logs:
NavigationStack { LogsView().aiInlineTitle() }
case .settings:
NavigationStack { SettingsView().aiInlineTitle() }
}
AITabBar(selection: $tab)
}
.tint(AITheme.primary)
.preferredColorScheme(.light)
#if os(iOS)
.toolbarBackground(AITheme.canvas, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
#endif
}
}
}
#if os(iOS)
private extension View {
func aiInlineTitle() -> some View {
navigationBarTitleDisplayMode(.inline)
}
}
#else
private extension View {
func aiInlineTitle() -> some View { self }
}
#endif
enum AppTab: Hashable {
case fleet
case messages
case notifications
case logs
case settings
}
struct AITabBar: View {
@Binding var selection: AppTab
var body: some View {
HStack(spacing: 0) {
tab(.fleet, "节点", "server.rack")
tab(.messages, "消息", "message")
tab(.notifications, "通知", "bell")
tab(.logs, "日志", "doc.text")
tab(.settings, "设置", "gearshape")
}
.frame(height: 58)
.background(AITheme.surface)
.overlay(alignment: .top) {
Rectangle()
.fill(AITheme.line)
.frame(height: 1)
}
.background(AITheme.surface.ignoresSafeArea(edges: .bottom))
}
private func tab(_ value: AppTab, _ title: String, _ systemImage: String) -> some View {
let isSelected = selection == value
return Button {
selection = value
} label: {
VStack(spacing: 4) {
Image(systemName: systemImage)
.font(.system(size: 18, weight: .semibold))
Text(title)
.font(.caption2.weight(.semibold))
}
.foregroundStyle(isSelected ? AITheme.primary : AITheme.muted)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.buttonStyle(.plain)
.accessibilityLabel(title)
.accessibilityAddTraits(isSelected ? [.isSelected] : [])
}
}