Ever wondered how Focus Timers work under the hood? In this tutorial, we’ll walk you through building a simple Pomodoro-style timer using Swift.

The Basic Concept

A focus timer works by dividing your work into intervals, traditionally 25 minutes of work followed by a 5-minute break. Here’s how we implemented it in Flowiz:

import Foundation
import Combine

class FocusTimer: ObservableObject {
    @Published var remainingSeconds: Int = 25 * 60
    @Published var isRunning: Bool = false
    
    private var timer: Timer?
    private var workDuration: Int
    private var breakDuration: Int
    
    init(workMinutes: Int = 25, breakMinutes: Int = 5) {
        self.workDuration = workMinutes * 60
        self.breakDuration = breakMinutes * 60
        self.remainingSeconds = workDuration
    }
    
    func start() {
        isRunning = true
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.tick()
        }
    }
    
    func pause() {
        isRunning = false
        timer?.invalidate()
        timer = nil
    }
    
    func reset() {
        pause()
        remainingSeconds = workDuration
    }
    
    private func tick() {
        if remainingSeconds > 0 {
            remainingSeconds -= 1
        } else {
            pause()
            // Trigger notification or sound
        }
    }
}

The User Interface

We designed the timer UI to be calming rather than stressful. Notice how we avoid harsh red colors and instead use gentle animations.

Focus Timer UI Design

The circular progress indicator uses SwiftUI’s Circle() shape with a custom trim modifier to show progress without counting down visibly.

Adding Sound Effects

Research shows that subtle audio cues help maintain focus without causing anxiety. Here’s how we implemented optional tick sounds:

import AVFoundation

class SoundManager {
    static let shared = SoundManager()
    private var tickPlayer: AVAudioPlayer?
    
    func playTick() {
        guard UserDefaults.standard.bool(forKey: "soundEnabled") else { return }
        tickPlayer?.play()
    }
    
    func loadSounds() {
        tickPlayer = try? AVAudioPlayer(contentsOf: Bundle.main.url(forResource: "tick", withExtension: "wav")!)
        tickPlayer?.volume = 0.1 // Keep it subtle
    }
}

Video Tutorial

Watch this step-by-step video guide to building your own focus timer:

Key Takeaways

  • Simplicity wins - Don’t overcomplicate the timer logic
  • Audio matters - Use subtle sounds, not jarring alerts
  • Visual feedback - Show progress visually, not just numerically
  • Customizable - Let users set their own work/break durations

Want to see more coding tutorials? Let us know in the comments!