project focustimer
Step 3: Countdown
System Text-to-Speech Ready
Slide: 0:00 / 0:00
Slide 1 of 0Interactive Deck
Full Lesson Reference
Implement countdown logic with start, pause, and reset.
Where We Are
You have a good-looking timer UI. Now let's make it count down.
Add Timer State
terminal
Add state variables to track:
- Total duration in seconds (default: 25 * 60)
- Remaining seconds
- Whether the timer is running
Calculate the progress value (0.0 to 1.0) from remaining / total.
Use this to drive the ring's .trim(from:to:) value.Start the Countdown
terminal
When the user taps Start:
- Create a Timer that fires every second
- Each tick, decrease remaining seconds by 1
- Update the progress ring with animation
- When remaining hits 0, stop the timer
Use Timer.publish(every: 1, on: .main, in: .common) and .onReceive.The Start button should change to a Pause button (SF Symbol: "pause.fill") when the timer is running.
Animate the Ring
terminal
Add a smooth animation to the ring progress so it doesn't jump.
Use .animation(.linear(duration: 1)) on the trim value
so the ring smoothly decreases each second.Pause and Reset
terminal
Pause: Stop the timer but keep the remaining time. The button
should switch back to "play.fill".
Reset: Stop the timer and set remaining time back to the full duration.
The ring should animate back to full.Format the Time
terminal
Display the remaining time as "MM:SS" format.
- 25 minutes = "25:00"
- 1 minute 5 seconds = "01:05"
- 0 seconds = "00:00"
Always show two digits for both minutes and seconds.Test It
- Run the app
- Tap Start — the ring should shrink smoothly, time counts down
- Tap Pause — it stops
- Tap Start again — it resumes
- Tap Reset — ring goes back to full, time resets to 25:00
- Let it run to 00:00 — it should stop automatically
Checkpoint
By now you should have:
- Timer counts down from 25:00
- Ring animates smoothly as time decreases
- Start/Pause toggle works
- Reset returns to full duration
- Timer stops at 00:00
What You Learned
- Timer.publish for periodic updates
- SwiftUI animation with .animation()
- State management for play/pause/reset
- Time formatting with String(format:)
Exercises
- Add the timer state and countdown logic, then run the app and watch the ring shrink as the time counts down — confirm it stops automatically at 00:00.
- Test the full control flow: Start, Pause, Start again, Reset. Verify the play/pause icon toggles correctly each time.
- Temporarily change the default duration to a short value (e.g., 10 seconds) to watch the MM:SS formatting hit "00:09", "00:08" cleanly, then set it back to 25 minutes.