From 05a579e2f7251299105181ea7c2b5d4ccbdf9ef6 Mon Sep 17 00:00:00 2001 From: kutesir Date: Thu, 28 May 2026 18:55:09 +0300 Subject: [PATCH] feat: replace workout progress bar with dot-grid indicator 7 rows of dots fill left-to-right, top-to-bottom as sets complete. Filled dots: AppColors.green solid. Empty: green at 12% opacity. Also: strip emoji from completion banner, tighten copy. --- KisaniCal/Views/TodayView.swift | 81 +++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/KisaniCal/Views/TodayView.swift b/KisaniCal/Views/TodayView.swift index 0ef37ff..cf89f39 100644 --- a/KisaniCal/Views/TodayView.swift +++ b/KisaniCal/Views/TodayView.swift @@ -445,8 +445,8 @@ struct WorkoutSessionSheet: View { } .padding(.horizontal, 20).padding(.top, 20).padding(.bottom, 14) - // ── Progress Bar ── - VStack(spacing: 6) { + // ── Dot Grid Progress ── + VStack(spacing: 8) { HStack { Text("PROGRESS") .font(AppFonts.mono(8.5, weight: .bold)) @@ -454,37 +454,24 @@ struct WorkoutSessionSheet: View { Spacer() Text(vm.totalSets > 0 ? "\(Int(vm.progress * 100))%" : "0%") .font(AppFonts.mono(10, weight: .bold)) - .foregroundColor(vm.progress >= 1 ? AppColors.green : AppColors.accent) + .foregroundColor(vm.progress >= 1 ? AppColors.green : AppColors.text2(cs)) } - GeometryReader { geo in - ZStack(alignment: .leading) { - RoundedRectangle(cornerRadius: 5) - .fill(AppColors.borderHi(cs)) - .frame(height: 8) - if vm.totalSets > 0 { - RoundedRectangle(cornerRadius: 5) - .fill(vm.progress >= 1 ? AppColors.green : AppColors.accent) - .frame(width: geo.size.width * CGFloat(min(vm.progress, 1)), height: 8) - .animation(KisaniSpring.entrance, value: vm.progress) - } - } - } - .frame(height: 8) + DotGridProgress(progress: vm.totalSets > 0 ? vm.progress : 0, cs: cs) } .padding(.horizontal, 20).padding(.bottom, 14) // ── Completion Banner ── if vm.progress >= 1 && vm.totalSets > 0 { HStack(spacing: 8) { - Image(systemName: "checkmark.seal.fill") - .font(.system(size: 15)).foregroundColor(AppColors.green) - Text("Workout complete! Great work 🎉") - .font(AppFonts.sans(12.5, weight: .semibold)) + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 14)).foregroundColor(AppColors.green) + Text("All sets done") + .font(AppFonts.mono(11, weight: .bold)) .foregroundColor(AppColors.green) Spacer() } - .padding(.horizontal, 20).padding(.vertical, 11) - .background(AppColors.green.opacity(0.09)) + .padding(.horizontal, 20).padding(.vertical, 10) + .background(AppColors.green.opacity(0.08)) } Divider().background(AppColors.border(cs)) @@ -1088,3 +1075,51 @@ struct AddTaskSheet: View { dismiss() } } + +// MARK: - Dot Grid Progress + +struct DotGridProgress: View { + let progress: Double + let cs: ColorScheme + + private let dotSize: CGFloat = 7.5 + private let gap: CGFloat = 2.5 + private let rows = 7 + + var body: some View { + GeometryReader { geo in + let cols = max(1, Int((geo.size.width + gap) / (dotSize + gap))) + let total = cols * rows + let filled = Int(Double(total) * min(max(progress, 0), 1)) + + VStack(alignment: .leading, spacing: gap) { + ForEach(0..