app_icons: register habit_stack with a new chain-link glyph; whitelist it
Some checks failed
Pre-commit checks / pre-commit (push) Has been cancelled
Python tests / test (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled

New Flutter app (~/habit_stack) gets an on-style launcher icon from the
shared family: two interlocking stadium-ring outlines, sized so the
72px stroke leaves a genuinely hollow interior at launcher size. Accent
matches the app's own ThemeData seedColor (#66BB6A), not already
claimed by a sibling app.

Also whitelists com.kuhy.habit_stack in phone_focus_mode/config.sh (both
the always-on productive-apps list and the night/curfew health-tool
list) and redeploys, since an unwhitelisted com.kuhy.* app is killed
within ~1s and would otherwise look like an install failure.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-07-20 11:09:23 +02:00
parent 5d4d3b9e24
commit ae458d92cf
4 changed files with 67 additions and 0 deletions

View File

@ -0,0 +1,40 @@
{
"intent": "Register a new app_icons entry for habit_stack (a new Flutter app) so it gets an on-style launcher icon from the shared family, and whitelist its package id in phone_focus_mode so the app isn't killed on-device.",
"scope": [
"python_pkg/app_icons/glyphs.py",
"python_pkg/app_icons/apps.py",
"phone_focus_mode/config.sh",
"No changes to any other package's behavior"
],
"changes": [
"Added a new chain-link glyph (_CHAIN_LINK) to glyphs.py: two interlocking stadium-ring outlines, sized so the 72px stroke leaves a genuinely hollow interior at launcher size",
"Registered habit_stack in apps.py's APPS dict (accent #66BB6A matching the app's own ThemeData seedColor, glyph chain-link, icon_name habit-stack, linux=False)",
"Added com.kuhy.habit_stack to phone_focus_mode/config.sh in both places a companion-app package id needs to appear (the always-on productive-apps whitelist and the night/curfew health-tool whitelist), then redeployed to the phone"
],
"verification": [
{
"command": "source .venv/bin/activate && python3 meta/scripts/pytest_changed_packages.py <changed files>",
"result": "pass",
"evidence": "877 passed in 1.91s; TOTAL coverage 100.00% (2816 stmts, 758 branches, 0 missed). Note: an earlier run against the pyenv global Python (not this repo's .venv) spuriously failed on a missing markdownify import in the unrelated archwiki_rag package -- confirmed pre-existing and environment-only, not a real gap; re-running via .venv resolved it."
},
{
"command": "PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons preview -o <scratch>/icon_sheet.png",
"result": "pass",
"evidence": "Visual review of the generated contact sheet (full size, circle-masked, 48dp) confirmed the chain-link glyph reads clearly as two interlocking rings at all three sizes, no safe-box warnings from the CLI"
},
{
"command": "ADB_SERIAL=BL9000EEA0000102 bash phone_focus_mode/deploy.sh",
"result": "pass",
"evidence": "Deploy completed successfully; config.sh (including the new com.kuhy.habit_stack entries) pushed to device and daemon restarted"
}
],
"risks": [
"New glyph geometry was hand-derived (stroke width vs. ring interior hollow space); mitigated by visual review of the actual rendered preview sheet before committing to the design",
"phone_focus_mode/config.sh is a live-deployed config; a bad edit could affect other whitelisted apps -- mitigated by adding only new lines, never touching existing entries, and confirming via deploy.sh's own status output that other apps' whitelist state was unaffected"
],
"rollback": [
"git revert this commit",
"Re-run PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons generate --app habit_stack --android is then a no-op since the app entry no longer exists; the habit_stack repo's already-generated assets/icon/ files are unaffected (that's a separate repo)",
"Redeploy phone_focus_mode (ADB_SERIAL=BL9000EEA0000102 bash phone_focus_mode/deploy.sh) to push the reverted config.sh back to the phone"
]
}

View File

@ -338,6 +338,7 @@ com.kuhy.focusstatus
com.stronglifts.app
com.kuhy.workout_app
com.kuhy.diet_guard_app
com.kuhy.habit_stack
com.shazam.android
com.ichi2.anki
com.metrolist.music
@ -537,6 +538,9 @@ dev.kuhy.todo
# --- Diet guard companion (log meals; health tool, not a scroll trap) ---
com.kuhy.diet_guard_app
# --- Habit Stack companion (habit tracking; health tool, not a scroll trap) ---
com.kuhy.habit_stack
# --- Good-for-you apps (not scroll traps; kept per your request) ---
# Remove any of these if you want a stricter night.
com.stronglifts.app

View File

@ -87,6 +87,14 @@ APPS: Final[dict[str, AppIcon]] = {
icon_name="todo",
linux=True,
),
AppIcon(
key="habit_stack",
repo=_HOME / "habit_stack",
accent="#66BB6A",
glyph="chain-link",
icon_name="habit-stack",
linux=False,
),
)
}

View File

@ -78,6 +78,20 @@ _CHECKLIST = """\
<path d="M 272 620 L 346 694 L 478 562"/>
<path d="M 594 648 L 752 648"/>"""
# Two interlocking stadium (pill-ring) outlines, both rotated -45 deg and
# offset along the anti-diagonal so their strokes overlap in the middle --
# reads as both "habit-stacking" (linked items) and "don't break the chain".
# Ring height is tall enough that the 72px stroke leaves a genuinely hollow
# interior (height - 2*stroke-width well above MIN_NEGATIVE_SPACE); a
# shorter ring's stroke fills the interior solid and reads as a blob.
_CHAIN_LINK = """\
<g transform="translate(467,557) rotate(-45) translate(-150,-110)">
<rect x="0" y="0" width="300" height="220" rx="110" ry="110"/>
</g>
<g transform="translate(557,467) rotate(-45) translate(-150,-110)">
<rect x="0" y="0" width="300" height="220" rx="110" ry="110"/>
</g>"""
GLYPHS: Final[dict[str, Glyph]] = {
glyph.name: glyph
@ -87,6 +101,7 @@ GLYPHS: Final[dict[str, Glyph]] = {
Glyph("clock", "Clock face with hands", _CLOCK),
Glyph("shield-cutlery", "Shield guarding a fork and knife", _SHIELD_CUTLERY),
Glyph("checklist", "Two ticked-off list rows", _CHECKLIST),
Glyph("chain-link", "Two interlocking chain links", _CHAIN_LINK),
)
}