aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-18 18:20:27 +0200
committerDanilo M. <danix@danix.xyz>2026-09-18 18:20:27 +0200
commit37cabe2fea2f86d481516aae6ddaeb14bac2e64f (patch)
tree1249429fa55c501f5b6fa74823ce6eba8130ea88 /lib
parent46d5607764fb29ae5dbbe001519571f934379917 (diff)
downloadconky-theme-udt-37cabe2fea2f86d481516aae6ddaeb14bac2e64f.tar.gz
conky-theme-udt-37cabe2fea2f86d481516aae6ddaeb14bac2e64f.zip
feat: add a breaktimer card
Replaces the Waybar module that used to show breaktimer.sh with a card on the dashboard. The card's big value is the phase countdown, coloured by phase with the same language the Waybar module used, and two rows name the phase and what the countdown leads to. Data comes from bin/breaktimer-sample.sh, run by conky at execi 5, which reads the daemon's runtime files into a cache. The sampler owns the kill -0 liveness check, because conky's Lua cannot run a process and a dead daemon must read as 'fermo' rather than a stale 'running'. Drops outside the work-hours window freeze the countdown while the phase stays 'working'. The sampler detects this from the remain file's age and the card reads it as 'outside working hours', which also covers a hung daemon. The phase words and colour roles live in data.breaktimer_parse so they are unit-tested; the card only draws the result.
Diffstat (limited to 'lib')
-rw-r--r--lib/data.lua73
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/data.lua b/lib/data.lua
index 6f1f7ea..8e60d6d 100644
--- a/lib/data.lua
+++ b/lib/data.lua
@@ -517,5 +517,78 @@ function M.month_shape(year, month)
return last.day, (first.wday + 5) % 7 + 1
end
+-- The breaktimer cache written by bin/breaktimer-sample.sh.
+--
+-- Returns a table describing the daemon, or nil when the cache is absent or
+-- carries no 'generated' key (the sampler never ran). The display strings are
+-- derived here rather than in the widget so the phase-to-word and
+-- phase-to-colour decisions can be tested without Cairo:
+--
+-- { running, state, phase, frozen, remain,
+-- countdown = '24:31' or '--',
+-- phase_label = 'working' | 'micro-pausa' | 'pausa lunga' | 'in pausa'
+-- | 'outside working hours' | 'fermo',
+-- next = 'pausa' | 'lavoro' | '--',
+-- role = 'ok' | 'heading' | 'highlight' | 'warning' | 'label' }
+--
+-- `frozen` is the sampler's read of whether the clock is ticking: the phase is
+-- 'working' but the remain file has stopped being rewritten. Outside the work
+-- window that is normal and reads as such; a hung daemon looks the same, and
+-- should.
+--
+-- The countdown leads to the next phase, but the daemon keeps the cycle count
+-- in memory and never writes it, so whether the NEXT break is a micro or a long
+-- one is not knowable here. 'pausa' is the honest answer; the phase word carries
+-- the rest.
+function M.breaktimer_parse(text)
+ if type(text) ~= 'string' then return nil end
+ local kv = M.kv_parse(text)
+ if not kv.generated then return nil end
+
+ local running = kv.running == 'yes'
+ local state = kv.state or 'stopped'
+ local phase = kv.phase or 'stopped'
+ local remain = tonumber(kv.remain) or 0
+ if remain < 0 then remain = 0 end
+
+ local out = {
+ running = running,
+ state = state,
+ phase = phase,
+ frozen = kv.frozen == 'yes',
+ remain = remain,
+ }
+
+ -- Not running and stopped are the same thing on the card. The sampler's
+ -- liveness check is what turns a dead PID into this reading: the state file
+ -- can still say 'running' after a crash or a kill -9.
+ if not running or state == 'stopped' then
+ out.countdown = '--'
+ out.phase_label = 'fermo'
+ out.next = '--'
+ out.role = 'label'
+ return out
+ end
+
+ out.countdown = string.format('%d:%02d', math.floor(remain / 60), remain % 60)
+
+ if state == 'paused' then
+ out.phase_label = 'in pausa'
+ out.role = 'warning'
+ elseif out.frozen then
+ out.phase_label = 'outside working hours'
+ out.role = 'label'
+ else
+ local labels = { working = 'working', breaking = 'micro-pausa',
+ longbreak = 'pausa lunga' }
+ local roles = { working = 'ok', breaking = 'heading',
+ longbreak = 'highlight' }
+ out.phase_label = labels[phase] or phase
+ out.role = roles[phase] or 'value'
+ end
+
+ out.next = (phase == 'working') and 'pausa' or 'lavoro'
+ return out
+end
return M