mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 00:27:01 +01:00
Some checks failed
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Python tests / test (push) Has been cancelled
New `lightbulb` glyph (filled bulb over a two-bar screw base) in a new _glyph_art_extra.py module, registered for ~/src/tutor/app. `generate --web` overwrites a Flutter app's web/favicon.png and web/icons/Icon-*.png from the same registry entry; the maskable variants reuse the full render because SAFE_BOX fits inside the 40% maskable safe circle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YADHKXzZhhePzQ2rNoXFcK
216 lines
6.2 KiB
Python
216 lines
6.2 KiB
Python
"""Command-line entry point for the shared app-icon generator.
|
|
|
|
Usage:
|
|
PYTHONPATH=~/src/testsAndMisc python -m python_pkg.app_icons list
|
|
PYTHONPATH=~/src/testsAndMisc python -m python_pkg.app_icons preview -o sheet.png
|
|
PYTHONPATH=~/src/testsAndMisc python -m python_pkg.app_icons generate --app todo
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
from python_pkg.app_icons import apps, generate, glyphs, preview, render, style
|
|
|
|
|
|
def _emit(message: str) -> None:
|
|
"""Write a line to stdout.
|
|
|
|
Parameters:
|
|
message (str): Line to write, without a trailing newline.
|
|
"""
|
|
sys.stdout.write(f"{message}\n")
|
|
|
|
|
|
def _add_app_argument(parser: argparse.ArgumentParser) -> None:
|
|
"""Attach the repeatable ``--app`` selector to a subparser.
|
|
|
|
Parameters:
|
|
parser (argparse.ArgumentParser): Subparser to extend.
|
|
"""
|
|
parser.add_argument(
|
|
"--app",
|
|
action="append",
|
|
dest="app_keys",
|
|
choices=sorted(apps.APPS),
|
|
help="app to act on; repeatable. Defaults to every registered app.",
|
|
)
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
"""Construct the argument parser.
|
|
|
|
Returns:
|
|
argparse.ArgumentParser: Parser with the ``list``, ``preview`` and
|
|
``generate`` subcommands.
|
|
"""
|
|
parser = argparse.ArgumentParser(
|
|
prog="python -m python_pkg.app_icons",
|
|
description="Generate on-style launcher icons for kuhy's Flutter apps.",
|
|
)
|
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
|
|
subparsers.add_parser("list", help="show registered apps and available glyphs")
|
|
|
|
preview_parser = subparsers.add_parser(
|
|
"preview", help="render a contact sheet for visual review"
|
|
)
|
|
_add_app_argument(preview_parser)
|
|
preview_parser.add_argument(
|
|
"-o",
|
|
"--output",
|
|
type=Path,
|
|
default=Path("icon_review_sheet.png"),
|
|
help="where to write the contact sheet",
|
|
)
|
|
|
|
generate_parser = subparsers.add_parser(
|
|
"generate", help="write icon assets into the app repositories"
|
|
)
|
|
_add_app_argument(generate_parser)
|
|
generate_parser.add_argument(
|
|
"--android",
|
|
action="store_true",
|
|
help="also run flutter_launcher_icons to rebuild the Android mipmaps",
|
|
)
|
|
generate_parser.add_argument(
|
|
"--web",
|
|
action="store_true",
|
|
help="also overwrite favicon + PWA icons in the app's web/ directory",
|
|
)
|
|
generate_parser.add_argument(
|
|
"--linux-out",
|
|
type=Path,
|
|
default=None,
|
|
help=(
|
|
"directory to write hicolor PNGs into for apps with a Linux target; "
|
|
"skipped when omitted"
|
|
),
|
|
)
|
|
return parser
|
|
|
|
|
|
def _selected(app_keys: list[str] | None) -> list[str]:
|
|
"""Resolve the ``--app`` selection to a concrete ordered list.
|
|
|
|
Parameters:
|
|
app_keys (list[str] | None): Keys given on the command line, if any.
|
|
|
|
Returns:
|
|
list[str]: Keys to act on, in registry order.
|
|
"""
|
|
if app_keys:
|
|
return [key for key in apps.APPS if key in set(app_keys)]
|
|
return list(apps.APPS)
|
|
|
|
|
|
def _cmd_list() -> int:
|
|
"""Print the app registry and glyph library.
|
|
|
|
Returns:
|
|
int: Process exit status.
|
|
"""
|
|
_emit("Apps:")
|
|
for app in apps.APPS.values():
|
|
linux = " +linux" if app.linux else ""
|
|
_emit(f" {app.key:16} {app.accent} {app.glyph}{linux} {app.repo}")
|
|
_emit("\nGlyphs:")
|
|
for glyph in glyphs.GLYPHS.values():
|
|
_emit(f" {glyph.name:16} {glyph.description}")
|
|
return 0
|
|
|
|
|
|
def _cmd_preview(app_keys: list[str] | None, output: Path) -> int:
|
|
"""Render the review contact sheet.
|
|
|
|
Parameters:
|
|
app_keys (list[str] | None): Selection from the command line.
|
|
output (Path): Where to write the sheet.
|
|
|
|
Returns:
|
|
int: Process exit status.
|
|
"""
|
|
sheet = preview.build_contact_sheet(_selected(app_keys), output)
|
|
_emit(f"wrote {sheet}")
|
|
return 0
|
|
|
|
|
|
def _write_web(app: apps.AppIcon) -> None:
|
|
"""Write web icons for one app, skipping apps without a web build.
|
|
|
|
Parameters:
|
|
app (apps.AppIcon): App to act on.
|
|
"""
|
|
if not app.web_dir.is_dir():
|
|
_emit(f" skipped web icons: no {app.web_dir}")
|
|
return
|
|
icons = generate.write_web_icons(app)
|
|
_emit(f" wrote {len(icons)} web icons to {app.web_dir}")
|
|
|
|
|
|
def _cmd_generate(
|
|
app_keys: list[str] | None,
|
|
*,
|
|
android: bool,
|
|
web: bool,
|
|
linux_out: Path | None,
|
|
) -> int:
|
|
"""Write icon assets, optionally driving the platform generators.
|
|
|
|
Parameters:
|
|
app_keys (list[str] | None): Selection from the command line.
|
|
android (bool): Run flutter_launcher_icons afterwards.
|
|
web (bool): Write favicon + PWA icons into apps that have a ``web/`` dir.
|
|
linux_out (Path | None): Directory for hicolor PNGs, or None to skip.
|
|
|
|
Returns:
|
|
int: Process exit status.
|
|
"""
|
|
for key in _selected(app_keys):
|
|
app = apps.get_app(key)
|
|
written = generate.write_assets(app)
|
|
_emit(f"{app.key}: wrote {len(written)} asset files to {app.asset_dir}")
|
|
|
|
overflow = render.safe_box_overflow(glyphs.get_glyph(app.glyph), app.accent)
|
|
if any(overflow):
|
|
_emit(
|
|
f" warning: glyph exceeds the {style.SAFE_BOX}px safe box "
|
|
f"by {overflow[0]}x{overflow[1]}px; a launcher mask may clip it"
|
|
)
|
|
|
|
if linux_out is not None and app.linux:
|
|
icons = generate.write_linux_icons(app, linux_out)
|
|
_emit(f" wrote {len(icons)} hicolor PNGs to {linux_out}")
|
|
|
|
if web:
|
|
_write_web(app)
|
|
|
|
if android:
|
|
generate.run_flutter_launcher_icons(app)
|
|
_emit(" regenerated Android mipmaps")
|
|
return 0
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
"""Run the command-line interface.
|
|
|
|
Parameters:
|
|
argv (list[str] | None): Arguments to parse; defaults to ``sys.argv[1:]``.
|
|
|
|
Returns:
|
|
int: Process exit status.
|
|
"""
|
|
args = build_parser().parse_args(argv)
|
|
if args.command == "list":
|
|
return _cmd_list()
|
|
if args.command == "preview":
|
|
return _cmd_preview(args.app_keys, args.output)
|
|
return _cmd_generate(
|
|
args.app_keys,
|
|
android=args.android,
|
|
web=args.web,
|
|
linux_out=args.linux_out,
|
|
)
|