refactor: make stats strip much more compact

Reduce vertical padding from 10→6pt, drop large icons, shrink font,
value color now matches stat type (green/red/grey). Strip is ~40% shorter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Robin Kutesa
2026-05-16 18:47:54 +03:00
parent 2e40aa5683
commit a40ec86362

View File

@@ -26,7 +26,7 @@ struct BackupView: View {
// Compact stats strip (always visible) // Compact stats strip (always visible)
statsStrip statsStrip
.padding(.horizontal, AppTheme.hPad) .padding(.horizontal, AppTheme.hPad)
.padding(.bottom, 20) .padding(.bottom, 12)
.transition(.opacity.combined(with: .scale(scale: 0.97))) .transition(.opacity.combined(with: .scale(scale: 0.97)))
Spacer(minLength: 0) Spacer(minLength: 0)
@@ -249,46 +249,43 @@ struct BackupView: View {
// MARK: Compact stats strip // MARK: Compact stats strip
private var statsStrip: some View { private var statsStrip: some View {
VStack(spacing: 8) { VStack(spacing: 5) {
HStack(spacing: 0) { HStack(spacing: 0) {
compactStat("\(engine.job.uploadedFiles)", label: "up", icon: "arrow.up.circle.fill", color: AppTheme.positive) compactStat("\(engine.job.uploadedFiles)", label: "up", color: AppTheme.positive)
thinDivider thinDivider
compactStat("\(engine.job.skippedFiles)", label: "skip", icon: "minus.circle.fill", color: AppTheme.inkQuaternary) compactStat("\(engine.job.skippedFiles)", label: "skip", color: AppTheme.inkQuaternary)
thinDivider thinDivider
compactStat("\(engine.job.failedFiles)", label: "err", icon: "xmark.circle.fill", compactStat("\(engine.job.failedFiles)", label: "err",
color: engine.job.failedFiles > 0 ? AppTheme.destructive : AppTheme.inkQuaternary) color: engine.job.failedFiles > 0 ? AppTheme.destructive : AppTheme.inkQuaternary)
thinDivider thinDivider
compactStat("\(max(0, engine.job.totalFiles - engine.job.uploadedFiles - engine.job.skippedFiles - engine.job.failedFiles))", label: "left", icon: "clock.fill", color: AppTheme.inkSecondary) compactStat("\(max(0, engine.job.totalFiles - engine.job.uploadedFiles - engine.job.skippedFiles - engine.job.failedFiles))", label: "left", color: AppTheme.inkSecondary)
} }
.background(AppTheme.surfaceSunken) .background(AppTheme.surfaceSunken)
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous)) .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
pageIndicator pageIndicator
} }
} }
private func compactStat(_ value: String, label: String, icon: String, color: Color) -> some View { private func compactStat(_ value: String, label: String, color: Color) -> some View {
HStack(spacing: 5) { HStack(spacing: 4) {
Image(systemName: icon)
.font(.system(size: 10, weight: .medium))
.foregroundStyle(color.opacity(0.7))
Text(value) Text(value)
.font(.system(size: 13, weight: .semibold)) .font(.system(size: 12, weight: .semibold))
.foregroundStyle(AppTheme.ink) .foregroundStyle(color)
.monospacedDigit() .monospacedDigit()
Text(label) Text(label)
.font(.system(size: 10, weight: .regular)) .font(.system(size: 10, weight: .regular))
.foregroundStyle(AppTheme.inkTertiary) .foregroundStyle(AppTheme.inkQuaternary)
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.padding(.vertical, 10) .padding(.vertical, 6)
} }
private var thinDivider: some View { private var thinDivider: some View {
Rectangle() Rectangle()
.fill(AppTheme.separator) .fill(AppTheme.separator)
.frame(width: 0.5) .frame(width: 0.5)
.padding(.vertical, 8) .padding(.vertical, 5)
} }
// MARK: NAS status row // MARK: NAS status row