testsAndMisc/python_pkg/app_icons
Krzysztof Rudnicki 5b654fc286 app_icons: finish the epopeja_karta entry; whitelist it on the phone
Registers the new Epopeja character-sheet app (~/epopeja_karta, its own
repo at kuhyx/epopeja_karta) in the shared icon family and lets it run
under focus mode.

The quill-nib glyph and the initial APPS entry already landed in c600760
("Move billsplit Flutter app into the monorepo"), which picked them up
from the working tree while they were still in progress. This commit adds
what was still outstanding:

- phone_focus_mode/config.sh: whitelist com.kuhy.epopeja_karta, without
  which focus mode kills it within ~1s at home. Not deployed to the device
  yet, so config and phone are out of sync until deploy.sh runs.
- apps.py: correct the epopeja_karta comment. It claimed there was no
  desktop target; a linux/ target was since added so the app can be driven
  on the desktop during development. linux stays False - the app ships no
  desktop entry and gets no hicolor set.
- The evidence and contract artifacts the pre-commit hooks require.

Verified: 44 app_icons tests pass, 100% branch coverage on the package,
safe_box_overflow for quill-nib is (0, 0), and the generated mipmaps show
the nib rather than the stock Flutter icon.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 12:41:13 +02:00
..
tests Move billsplit Flutter app into the monorepo 2026-08-03 12:22:22 +02:00
__init__.py Add shared launcher-icon generator for the Flutter apps 2026-07-19 16:55:48 +02:00
__main__.py Add shared launcher-icon generator for the Flutter apps 2026-07-19 16:55:48 +02:00
apps.py app_icons: finish the epopeja_karta entry; whitelist it on the phone 2026-08-03 12:41:13 +02:00
cli.py Add shared launcher-icon generator for the Flutter apps 2026-07-19 16:55:48 +02:00
generate.py app_icons: auto-sync pubspec.yaml's adaptive_icon_background 2026-07-21 21:38:22 +02:00
glyphs.py Move billsplit Flutter app into the monorepo 2026-08-03 12:22:22 +02:00
preview.py Add shared launcher-icon generator for the Flutter apps 2026-07-19 16:55:48 +02:00
README.md app_icons: warm-tint the shared icon family palette 2026-07-21 21:20:41 +02:00
render.py Add shared launcher-icon generator for the Flutter apps 2026-07-19 16:55:48 +02:00
style.py app_icons: warm-tint the shared icon family palette 2026-07-21 21:20:41 +02:00

app_icons — shared launcher icons for the Flutter apps

One icon family across every Flutter/Dart app: a charcoal #211D1B field with a single glyph in the shared unified-design-system accent (#B8862E), drawn at one stroke weight and optically centred so a row of them lines up.

Commands

# what is registered
PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons list

# contact sheet for visual review: full size / circle-masked / 48dp
PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons preview -o /tmp/sheet.png

# write assets into every app repo and rebuild the Android mipmaps
PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons generate --android

# one app, plus the hicolor PNGs for a Linux desktop target
PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons \
    generate --app todo --android --linux-out ~/todo/linux/icons

What gets written

Per app, into <repo>/assets/icon/:

Layer Purpose
icon Charcoal field + glyph. Legacy square launcher icon and Linux icon.
icon_foreground Glyph only, transparent. Adaptive-icon foreground layer.
icon_monochrome Glyph only, white. Android 13+ themed icons.

Both an .svg source and a 1024px .png are written for each, so a build never needs rsvg-convert. flutter_launcher_icons then turns the PNGs into the density buckets and mipmap-anydpi-v26/ic_launcher.xml.

Design constraints that bite

  • Negative space ≥ half the stroke weight. Strokes closer than that merge into a solid blob at launcher size. A fork whose tines sat exactly one stroke width apart rendered as a tulip.
  • Ink must stay inside the 560px safe box. Android masks adaptive icons to roughly the inner 66% of the canvas. generate warns when a glyph overflows.
  • Stroked outlines can read wrong. A stroked three-tine fork reads as a trident; a filled fork-and-knife pair reads as cutlery. Prefer a filled silhouette when the outline is ambiguous.
  • Glyph positioning inside the fragment is irrelevant — render.centre_offset measures the rendered ink and recentres it. Only the extents matter.

Adding an app

See the app-icon skill (~/.claude/skills/app-icon/SKILL.md) for the full procedure. In short: add a glyph to glyphs.py, register the app in apps.py, wire flutter_launcher_icons into its pubspec.yaml, generate, review the contact sheet, then verify on the phone.

Tests

cd ~/testsAndMisc
python3 -m pytest python_pkg/app_icons --cov=python_pkg.app_icons \
    --cov-report=term-missing

External tools (rsvg-convert, magick, dart) are mocked; the suite needs none of them installed.