TrayTempo v0.2.0 : minuteur Pomodoro Windows en Nim avec interface intuitive
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
## timer.nim
|
||||
## =========
|
||||
## Machine à états du minuteur Pomodoro. Aucune dépendance Win32 : le module
|
||||
## ne fait que compter les secondes et décider des transitions de phase.
|
||||
##
|
||||
## Phases : idle, working, shortBreak, longBreak, paused.
|
||||
|
||||
import config
|
||||
|
||||
type
|
||||
TimerPhase* = enum
|
||||
phIdle, phWorking, phShortBreak, phLongBreak, phPaused
|
||||
|
||||
## Événement renvoyé par tick() à la fin d'une période.
|
||||
TickEvent* = enum
|
||||
evNone ## Rien à signaler.
|
||||
evWorkCompleted ## Une période de travail vient de se terminer.
|
||||
evBreakCompleted ## Une pause vient de se terminer.
|
||||
|
||||
PomodoroTimer* = object
|
||||
phase*: TimerPhase
|
||||
prevPhase*: TimerPhase ## Phase avant mise en pause (pour reprendre).
|
||||
remainingSecs*: int
|
||||
cycleCount*: int ## Pomodoros complétés dans le cycle courant.
|
||||
|
||||
proc formatTime*(secs: int): string =
|
||||
## Formate une durée en secondes sous la forme M:SS ou H:MM:SS.
|
||||
let m = secs div 60
|
||||
let s = secs mod 60
|
||||
if m >= 60:
|
||||
let h = m div 60
|
||||
let mm = m mod 60
|
||||
result = $h & ":" & (if mm < 10: "0" else: "") & $mm &
|
||||
":" & (if s < 10: "0" else: "") & $s
|
||||
else:
|
||||
result = $m & ":" & (if s < 10: "0" else: "") & $s
|
||||
|
||||
proc initTimer*(): PomodoroTimer =
|
||||
PomodoroTimer(phase: phIdle, prevPhase: phIdle, remainingSecs: 0, cycleCount: 0)
|
||||
|
||||
proc startWork*(t: var PomodoroTimer, p: Profile) =
|
||||
t.phase = phWorking
|
||||
t.prevPhase = phWorking
|
||||
t.remainingSecs = p.workMin * 60
|
||||
|
||||
proc startBreak*(t: var PomodoroTimer, p: Profile, longBreak: bool) =
|
||||
if longBreak:
|
||||
t.phase = phLongBreak
|
||||
t.remainingSecs = p.longBreakMin * 60
|
||||
else:
|
||||
t.phase = phShortBreak
|
||||
t.remainingSecs = p.shortBreakMin * 60
|
||||
t.prevPhase = t.phase
|
||||
|
||||
proc pause*(t: var PomodoroTimer) =
|
||||
if t.phase in {phWorking, phShortBreak, phLongBreak}:
|
||||
t.prevPhase = t.phase
|
||||
t.phase = phPaused
|
||||
|
||||
proc resume*(t: var PomodoroTimer) =
|
||||
if t.phase == phPaused:
|
||||
t.phase = t.prevPhase
|
||||
|
||||
proc stop*(t: var PomodoroTimer) =
|
||||
t.phase = phIdle
|
||||
t.remainingSecs = 0
|
||||
t.prevPhase = phIdle
|
||||
# On remet le cycle à zéro : après un arrêt, le prochain démarrage repart
|
||||
# d'un cycle complet (sinon la pause longue arrivait au mauvais moment).
|
||||
t.cycleCount = 0
|
||||
|
||||
proc isBreak*(t: PomodoroTimer): bool =
|
||||
## Vrai si le minuteur est dans une pause (courte ou longue).
|
||||
t.phase in {phShortBreak, phLongBreak}
|
||||
|
||||
proc skipBreak*(t: var PomodoroTimer, p: Profile) =
|
||||
## Saute la pause courante et repart immédiatement en travail.
|
||||
if t.isBreak():
|
||||
t.startWork(p)
|
||||
|
||||
proc extendBreak*(t: var PomodoroTimer, minutes: int) =
|
||||
## Prolonge la pause courante de `minutes` minutes.
|
||||
if t.isBreak() and minutes > 0:
|
||||
t.remainingSecs += minutes * 60
|
||||
|
||||
proc isRunning*(t: PomodoroTimer): bool =
|
||||
t.phase in {phWorking, phShortBreak, phLongBreak}
|
||||
|
||||
proc tick*(t: var PomodoroTimer, p: Profile): TickEvent =
|
||||
## Décrémente le temps restant d'une seconde. Retourne un événement quand
|
||||
## une période se termine et enchaîne automatiquement sur la suivante.
|
||||
if t.phase notin {phWorking, phShortBreak, phLongBreak}:
|
||||
return evNone
|
||||
if t.remainingSecs > 0:
|
||||
dec t.remainingSecs
|
||||
if t.remainingSecs > 0:
|
||||
return evNone
|
||||
|
||||
case t.phase
|
||||
of phWorking:
|
||||
inc t.cycleCount
|
||||
let longBreak = (p.cycles > 0) and (t.cycleCount mod p.cycles == 0)
|
||||
t.startBreak(p, longBreak)
|
||||
return evWorkCompleted
|
||||
of phShortBreak, phLongBreak:
|
||||
t.startWork(p)
|
||||
return evBreakCompleted
|
||||
else:
|
||||
return evNone
|
||||
Reference in New Issue
Block a user