Files
clojure-tui/examples/timer.clj
2026-01-22 10:50:26 -05:00

82 lines
2.1 KiB
Clojure

(ns examples.timer
"Countdown timer example - demonstrates async commands.
Mirrors bubbletea's stopwatch/timer examples."
(:require [tui.core :as tui]))
;; === Model ===
(def initial-model
{:seconds 10
:running true
:done false})
;; === Update ===
(defn update-model [model msg]
(cond
;; Quit
(or (tui/key= msg "q")
(tui/key= msg [:ctrl \c]))
[model tui/quit]
;; Tick - decrement timer
(= (first msg) :tick)
(if (:running model)
(let [new-seconds (dec (:seconds model))]
(if (<= new-seconds 0)
;; Timer done
[(assoc model :seconds 0 :done true :running false) nil]
;; Continue countdown
[(assoc model :seconds new-seconds) (tui/tick 1000)]))
[model nil])
;; Space - pause/resume
(tui/key= msg " ")
(let [new-running (not (:running model))]
[(assoc model :running new-running)
(when new-running (tui/tick 1000))])
;; r - reset
(tui/key= msg "r")
[(assoc model :seconds 10 :done false :running true)
(tui/tick 1000)]
:else
[model nil]))
;; === View ===
(defn format-time [seconds]
(let [mins (quot seconds 60)
secs (mod seconds 60)]
(format "%02d:%02d" mins secs)))
(defn view [{:keys [seconds running done]} _size]
[:col {:gap 1}
[:box {:border :rounded :padding [1 2]}
[:col
[:text {:bold true} "Countdown Timer"]
[:text ""]
[:text {:fg (cond
done :green
(< seconds 5) :red
:else :cyan)
:bold true}
(if done
"Time's up!"
(format-time seconds))]
[:text ""]
[:text {:fg :gray}
(cond
done "Press r to restart"
running "Running..."
:else "Paused")]]]
[:text {:fg :gray} "space: pause/resume r: reset q: quit"]])
;; === Main ===
(defn -main [& _args]
(println "Starting timer...")
(let [final-model (tui/run {:init initial-model
:update update-model
:view view
:init-cmd (tui/tick 1000)})]
(when (:done final-model)
(println "Timer completed!"))))