mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-11 17:33:56 +01:00
Every locker screen, the status window and the credit toast now show glyphs (screen_locker/_glyphs.py) and numbers, coloured by state. Sentences that carried a reason (verifier message, sync diagnosis, sick refusal, form rejection) go to the log at warning instead. New pre-commit hook text-free runs scripts/verify_text_free.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
"""The locker's pictograms: one place, so a glyph means one thing everywhere.
|
|
|
|
textgate (kuhy, 2026-11-08): nothing he sees carries words. Every screen is
|
|
built from these plus numbers, each paired with a palette colour as the
|
|
second channel (success / warning / danger / muted). Plain geometric
|
|
characters only: a colour-emoji fallback font can crash Tk 8.6, so no
|
|
U+1Fxxx and nothing with an emoji presentation by default.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Final
|
|
|
|
LIFT: Final = "●━━●" # a barbell: the StrongLifts workout / "go work out"
|
|
RUN: Final = "⇝" # a RunnerUp run
|
|
PHONE: Final = "▯" # the phone (adb)
|
|
WAIT: Final = "⋯" # checking / unlocking in progress
|
|
OK: Final = "✓"
|
|
FAIL: Final = "✗"
|
|
RETRY: Final = "↻"
|
|
CLOSE: Final = "✕"
|
|
BACK: Final = "↩"
|
|
GO: Final = "▶"
|
|
SKIP: Final = "↷"
|
|
SYNC: Final = "⇅" # a sync backend (Firebase)
|
|
CLOCK: Final = "◷" # time, the system clock
|
|
SHORT: Final = "◔" # a session shorter than the minimum
|
|
FORM: Final = "≡" # the manual-workout evidence form
|
|
SICK: Final = "✚" # a sick day
|
|
SHUTDOWN: Final = "⏻" # the PC's shutdown time
|
|
STREAK: Final = "▰" # one week of the streak
|
|
WEEK_DONE: Final = "●" # a counted day
|
|
WEEK_SICK: Final = "✚" # a sick day in the week row
|
|
WEEK_EMPTY: Final = "○" # a day with nothing counted
|
|
HEAT: Final = "▲" # the outdoor temperature
|
|
LOCK: Final = "■" # the lock fired
|
|
UNLOCK: Final = "□" # the lock stood down
|
|
OPTIONAL: Final = "◇" # Tue-Thu: a workout is optional today
|
|
GIFT: Final = "+" # an earned reward, always followed by its amount
|
|
|
|
# Startup phone-check status -> the glyph that replaces its sentence.
|
|
STATUS_GLYPH: Final[dict[str, str]] = {
|
|
"too_short": SHORT,
|
|
"clock_tampered": f"{CLOCK}{FAIL}",
|
|
"stale": f"{CLOCK}{FAIL}",
|
|
"no_exercises": f"{LIFT} 0",
|
|
"not_verified": FAIL,
|
|
"no_phone": f"{PHONE}{FAIL}",
|
|
"error": f"{PHONE}{FAIL}",
|
|
}
|
|
|
|
|
|
# log.json entry ``type`` -> glyph, for the status window's day cells.
|
|
ENTRY_GLYPH: Final[dict[str, str]] = {
|
|
"phone_verified": LIFT,
|
|
"strength": LIFT,
|
|
"pc_workout_verified": LIFT,
|
|
"runnerup_verified": RUN,
|
|
"running": RUN,
|
|
"manual_workout": FORM,
|
|
"heat_skip": HEAT,
|
|
"relaxed_day_skip": SKIP,
|
|
"early_bird": OK,
|
|
}
|
|
|
|
|
|
# Lock-decision stage (``_compliance_state._STEPS`` names) -> glyph. A stage
|
|
# not listed shows only the lock/unlock square and its colour.
|
|
STAGE_GLYPH: Final[dict[str, str]] = {
|
|
"scheduled_skip": SKIP,
|
|
"early_bird_pending_expired": CLOCK,
|
|
"early_bird_window_open": CLOCK,
|
|
"sick_day": SICK,
|
|
"already_logged": OK,
|
|
"wake_alarm_skip": CLOCK,
|
|
"test_hold_active": WAIT,
|
|
"relaxed_day_already_skipped": f"{OPTIONAL}{SKIP}",
|
|
"relaxed_day": OPTIONAL,
|
|
"weekly_minimum_met": WEEK_DONE,
|
|
"evening_lockdown_today": SHUTDOWN,
|
|
"would_lock": LIFT,
|
|
}
|
|
|
|
|
|
def entry_glyphs(types: tuple[str, ...]) -> str:
|
|
"""Glyphs for a day's entry types; an unknown type shows as ``OK``."""
|
|
return " ".join(ENTRY_GLYPH.get(t, OK) for t in types)
|
|
|
|
|
|
def dots(done: int, total: int) -> str:
|
|
"""``●●○○ 2/4``: progress as filled dots plus the numbers (two channels)."""
|
|
filled = max(0, min(done, total))
|
|
return f"{WEEK_DONE * filled}{WEEK_EMPTY * (total - filled)} {done}/{total}"
|
|
|
|
|
|
def status_glyph(status: str) -> str:
|
|
"""Return the glyph for a phone-check *status* (``FAIL`` if unknown)."""
|
|
return STATUS_GLYPH.get(status, FAIL)
|