pommedoro/Sources/Pommedoro/CountdownPulseSchedule.swift

51 lines
2.3 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
/// Single source of truth for countdown pulse timing. Used by both default and debug modes
/// 5 min3 min: once per minute; 3 min1 min: every 30s; last minute: every 10s5s2s; last 5s: solid.
enum CountdownPulseSchedule {
/// Whether we are in the "flashing" phase (remaining within countdown window).
static func isInCountdownPhase(remainingSeconds: Int, countdownDuration: Int, workTimerDuration: Int) -> Bool {
let effective = min(countdownDuration, workTimerDuration)
return remainingSeconds <= effective && remainingSeconds > 0
}
/// Whether to trigger a blink this second.
/// 5 min3 min: once per minute; 3 min1 min: every 30s; last minute: every 10s, then 5s, then 2s; last 5s: solid.
static func shouldBlink(remainingSeconds: Int) -> Bool {
let s = remainingSeconds
if s <= 5 { return false } // last 5: solid
if s <= 15 { return s % 2 == 0 } // 615: every 2s
if s <= 30 { return s % 5 == 0 } // 1630: every 5s
if s <= 60 { return s % 10 == 0 } // 3160: every 10s (last minute)
if s <= 180 { return s % 30 == 0 } // 61180: every 30s (last 3 min)
return s % 60 == 0 // 181300: once per minute (5 min 3 min)
}
/// When remaining <= 5, show solid overlay instead of blinking.
static func shouldBeSolid(remainingSeconds: Int) -> Bool {
return remainingSeconds > 0 && remainingSeconds <= 5
}
/// Blink animation durations (seconds). Single place so overlay timing matches schedule.
struct BlinkDurations {
var fadeIn: Double
var hold: Double
var fadeOut: Double
}
static func blinkDurations(remainingSeconds: Int, durationScale: Double) -> BlinkDurations {
let scale = durationScale
if remainingSeconds > 60 {
return BlinkDurations(fadeIn: 1.0 * scale, hold: 0.8 * scale, fadeOut: 1.0 * scale)
}
if remainingSeconds > 30 {
return BlinkDurations(fadeIn: 0.8 * scale, hold: 0.6 * scale, fadeOut: 0.8 * scale)
}
if remainingSeconds > 10 {
return BlinkDurations(fadeIn: 0.5 * scale, hold: 0.4 * scale, fadeOut: 0.6 * scale)
}
return BlinkDurations(fadeIn: 0.3 * scale, hold: 0.3 * scale, fadeOut: 0.4 * scale)
}
}