#!/usr/bin/env bash # TUI timer setter — vim keys, big-digit hh:mm:ss # ── Setup ────────────────────────────────────────────────────────────────────── cleanup() { tput cnorm; tput rmcup; } trap cleanup EXIT INT TERM tput smcup tput civis # ── Colors ───────────────────────────────────────────────────────────────────── R="$(tput sgr0)" NORMAL="$(tput bold)$(tput setaf 7)" SELECT="$(tput bold)$(tput setaf 6)" # cyan — active field TITLE="$(tput bold)$(tput setaf 5)" # magenta DIM="$(tput dim)$(tput setaf 7)" ERR="$(tput bold)$(tput setaf 1)" # red # ── Block digits — DIGITS[digit*5 + row] ─────────────────────────────────────── DIGITS=( "█████" "█ █" "█ █" "█ █" "█████" # 0 " █ " " █ " " █ " " █ " " █ " # 1 "█████" " █" "█████" "█ " "█████" # 2 "█████" " █" "█████" " █" "█████" # 3 "█ █" "█ █" "█████" " █" " █" # 4 "█████" "█ " "█████" " █" "█████" # 5 "█████" "█ " "█████" "█ █" "█████" # 6 "█████" " █" " █" " █" " █" # 7 "█████" "█ █" "█████" "█ █" "█████" # 8 "█████" "█ █" "█████" " █" "█████" # 9 ) COLON=(" " "█" " " "█" " ") # ── State ────────────────────────────────────────────────────────────────────── VALUES=(0 0 0) LIMITS=(23 59 59) LABELS=("HOURS" "MINUTES" "SECONDS") FIELD=0 SHOW_ERR=0 # ── Draw helpers ─────────────────────────────────────────────────────────────── draw_field() { # draw_field row col val active local y=$1 x=$2 val=$3 active=$4 local tens=$((val / 10)) units=$((val % 10)) local color; [[ $active -eq 1 ]] && color=$SELECT || color=$NORMAL for row in 0 1 2 3 4; do tput cup $((y + row)) $x printf '%s%s %s%s' \ "$color" \ "${DIGITS[$((tens * 5 + row))]}" \ "${DIGITS[$((units * 5 + row))]}" \ "$R" done } draw_colon() { # draw_colon row col local y=$1 x=$2 for row in 0 1 2 3 4; do tput cup $((y + row)) $((x + 1)) printf '%s%s%s' "$DIM" "${COLON[$row]}" "$R" done } draw() { local W H W=$(tput cols); H=$(tput lines) printf '\033[2J\033[H' # clear + home (no flicker vs tput clear) # Title local title="─── T I M E R ───" tput cup 2 $(( (W - ${#title}) / 2 )) printf '%s%s%s' "$TITLE" "$title" "$R" # Layout: field(11) + colon(3) + field(11) + colon(3) + field(11) = 39 wide local sx=$(( (W - 39) / 2 )) local dy=$(( (H - 5) / 2 - 1 )) (( dy < 4 )) && dy=4 local -a fx=( $sx $((sx + 14)) $((sx + 28)) ) local -a cx=( $((sx + 11)) $((sx + 25)) ) for i in 0 1 2; do local active=0; [[ $i -eq $FIELD ]] && active=1 draw_field $dy "${fx[$i]}" "${VALUES[$i]}" $active done for x in "${cx[@]}"; do draw_colon $dy $x done # Labels local ly=$((dy + 6)) for i in 0 1 2; do local label="${LABELS[$i]}" local lx=$(( fx[$i] + (11 - ${#label}) / 2 )) tput cup $ly $lx if [[ $i -eq $FIELD ]]; then printf '%s%s%s' "$SELECT" "$label" "$R" else printf '%s%s%s' "$DIM" "$label" "$R" fi done # Error if [[ $SHOW_ERR -eq 1 ]]; then local msg="set a non-zero time first" tput cup $((ly + 2)) $(( (W - ${#msg}) / 2 )) printf '%s%s%s' "$ERR" "$msg" "$R" fi # Hint local hint="h/l field j/k adjust Enter start q cancel" tput cup $((H - 2)) $(( (W - ${#hint}) / 2 )) printf '%s%s%s' "$DIM" "$hint" "$R" } # ── Key reader — handles ESC sequences (arrow keys) ─────────────────────────── read_key() { local key seq IFS= read -rsn1 key if [[ "$key" == $'\033' ]]; then IFS= read -rsn2 -t 0.05 seq 2>/dev/null || true key="$key$seq" fi printf '%s' "$key" } # ── Main loop ────────────────────────────────────────────────────────────────── while true; do draw SHOW_ERR=0 key=$(read_key) case "$key" in q|$'\033') exit 0 ;; h|$'\033[D') FIELD=$(( (FIELD + 2) % 3 )) ;; l|$'\033[C') FIELD=$(( (FIELD + 1) % 3 )) ;; k|$'\033[A') VALUES[$FIELD]=$(( (VALUES[$FIELD] + 1) % (LIMITS[$FIELD] + 1) )) ;; j|$'\033[B') VALUES[$FIELD]=$(( (VALUES[$FIELD] - 1 + LIMITS[$FIELD] + 1) % (LIMITS[$FIELD] + 1) )) ;; $'\n'|$'\r') total=$(( VALUES[0] * 3600 + VALUES[1] * 60 + VALUES[2] )) if (( total == 0 )); then SHOW_ERR=1 else label=$(printf '%02d:%02d:%02d' "${VALUES[0]}" "${VALUES[1]}" "${VALUES[2]}") setsid bash "$HOME/.config/scripts/timer-notify.sh" "$total" "$label" &>/dev/null & disown exit 0 fi ;; esac done