diff --git a/cc_stats_app/swift/L10n.swift b/cc_stats_app/swift/L10n.swift index f8ed41d..5ebd3ab 100644 --- a/cc_stats_app/swift/L10n.swift +++ b/cc_stats_app/swift/L10n.swift @@ -59,6 +59,7 @@ enum L10n { static var refresh: String { isChinese ? "刷新" : "Refresh" } // MARK: - Empty/Loading + static var loading: String { isChinese ? "加载中" : "Loading" } static var noData: String { isChinese ? "暂无会话数据" : "No session data" } static var noDataHint: String { isChinese ? "启动 Claude Code 会话即可查看统计数据。" : "Start a Claude Code session to see statistics." } diff --git a/cc_stats_app/swift/StatsViewModel.swift b/cc_stats_app/swift/StatsViewModel.swift index ccfbbb2..8360e47 100644 --- a/cc_stats_app/swift/StatsViewModel.swift +++ b/cc_stats_app/swift/StatsViewModel.swift @@ -104,6 +104,7 @@ final class StatsViewModel: ObservableObject { func selectSource(_ source: DataSource) { selectedSource = source + activeTab = (source == .cursor) ? .cursor : .claudeCode refresh() } diff --git a/cc_stats_app/swift/Views/DashboardView.swift b/cc_stats_app/swift/Views/DashboardView.swift index 92b095c..80db853 100644 --- a/cc_stats_app/swift/Views/DashboardView.swift +++ b/cc_stats_app/swift/Views/DashboardView.swift @@ -70,6 +70,33 @@ struct DashboardView: View { } .animation(.easeInOut(duration: 0.25), value: toastMessage != nil) } + + // Full-view loading overlay + ZStack { + if viewModel.isLoading { + Color.black.opacity(0.4) + .ignoresSafeArea() + + VStack(spacing: 16) { + TimelineView(.animation) { timeline in + Circle() + .trim(from: 0, to: 0.7) + .stroke(Theme.cyan, style: StrokeStyle(lineWidth: 3, lineCap: .round)) + .frame(width: 40, height: 40) + .rotationEffect(.degrees(timeline.date.timeIntervalSince1970 * 200)) + } + + Text(L10n.loading) + .font(.system(size: 13, weight: .semibold)) + .foregroundColor(Theme.textPrimary) + } + .padding(28) + .background( + RoundedRectangle(cornerRadius: 16, style: .continuous) + .fill(Theme.cardBackground.opacity(0.95)) + ) + } + } } .frame(width: 480) .frame(maxHeight: 640) @@ -112,7 +139,8 @@ struct DashboardView: View { ) .contentShape(Rectangle()) .onTapGesture { - viewModel.activeTab = tab + let source: DataSource = tab == .claudeCode ? .claudeCode : .cursor + viewModel.selectSource(source) } } }