testsAndMisc/linux_configuration/i3blocks/screen_locker.sh
Krzysztof kuhy Rudnicki 2713ae9d66
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Put the screen-locker status back on the i3 bar
The GTK tray icon was the only status surface, and it had been commented out
of ~/.config/i3/config since 2026-08-21. With nothing in the bar, the locker
miscounted the week for a fortnight and the machine never said so.

Shows "<count>/<minimum> · <gaming budget>", read from the local status API
(screen-locker-web.service on 127.0.0.1:8770); clicking opens the full UI.

Three things it deliberately will not do quietly:
- a dead status server renders "status server down" in red, or the last known
  value marked (stale) in orange -- never a blank block. That server is what
  the gaming budget reads, so its absence costs two hours;
- a disarmed or unscheduled timer overrides the compliance colour entirely
  and shows "DISARMED" in red. A locker that cannot fire is the worse
  problem and the one that hides;
- clicking only opens the UI. There is no bar action that can clear a lock.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fcwu78wk17FWMHbbfbyicc
2026-08-29 22:55:24 +02:00

85 lines
2.7 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# Screen-locker status for i3blocks.
#
# Replaces the GTK tray icon that sat commented out in ~/.config/i3/config from
# 2026-08-21, during which the locker miscounted the week and nothing on the
# machine said so. The point of this block is that a broken or disarmed locker
# is visible without being asked: it is never blank and never silently green.
#
# Reads the local status API (screen-locker-web.service). Click opens the UI.
# ============================================================================
set -euo pipefail
readonly API='http://127.0.0.1:8770/api/status'
readonly HEALTH='http://127.0.0.1:8770/api/health'
readonly UI='http://127.0.0.1:8770/'
readonly CACHE="${XDG_RUNTIME_DIR:-/tmp}/i3blocks-screen-locker.cache"
# Dracula-ish palette, matching the other blocks in this bar.
readonly RED='#FF5555'
readonly YELLOW='#F1FA8C'
readonly GREEN='#50FA7B'
readonly ORANGE='#FFB86C'
emit() {
# full_text, short_text, color — the three lines i3blocks reads.
printf '%s\n%s\n%s\n' "$1" "$2" "$3"
}
# A click opens the web UI rather than doing anything destructive; there is no
# action here that could clear a lock.
if [[ ${BLOCK_BUTTON:-0} -ne 0 ]]; then
xdg-open "$UI" >/dev/null 2>&1 &
fi
if ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
emit '💪 no curl/jq' '💪 ?' "$ORANGE"
exit 0
fi
status_json=$(curl -fsS --max-time 2 "$API" 2>/dev/null || true)
if [[ -z $status_json ]]; then
# The server being down is itself news: it is what the gaming budget reads,
# and it failing closed costs two hours. Say so instead of showing nothing.
if [[ -r $CACHE ]]; then
emit "$(cat "$CACHE") (stale)" '💪 ?' "$ORANGE"
else
emit '💪 status server down' '💪 ?' "$RED"
fi
exit 0
fi
count=$(jq -r '.snapshot.week.counted_count' <<<"$status_json")
minimum=$(jq -r '.snapshot.week.minimum' <<<"$status_json")
state=$(jq -r '.compliance_state' <<<"$status_json")
workout_today=$(jq -r '.gaming.workout_today' <<<"$status_json")
if [[ $workout_today == 'true' ]]; then
hours='8h'
else
hours='6h'
fi
health_json=$(curl -fsS --max-time 2 "$HEALTH" 2>/dev/null || true)
armed=$(jq -r '.armed' <<<"${health_json:-{\}}" 2>/dev/null || echo 'unknown')
text="💪 ${count}/${minimum} · ${hours}"
case $state in
lock) color=$RED ;;
warn) color=$YELLOW ;;
*) color=$GREEN ;;
esac
# Arming beats compliance: a locker that cannot fire is the worse problem, and
# it is the one that hides. Never render it as a green tick.
if [[ $armed != 'true' ]]; then
text="$text ⚠ DISARMED"
color=$RED
fi
printf '%s' "$text" >"$CACHE"
emit "$text" "💪 ${count}/${minimum}" "$color"