- Melos 8.9 as the root's dev dependency, with scripts across the workspace (analyze, test:dart, test:flutter, generate, check) and its filters (--diff, --include-dependents); cli_util overridden to 0.5.2 for it, since Learn's flutter_launcher_icons asks for 0.4 and uses only its logger, unchanged in 0.5. - tool/check.dart in place of tool/check.sh: packages, formatting of our own files, analysis, the tools' tests, then every package's tests through Melos (--changed-since=<commit> for only what changed and what depends on it). tool/pre-push is the hook: the signature check, then the checks. CI generates every server's code and runs the same check. - The images build from the root with a workspace narrowed to what they need (tool/workspace_only.sh); compose, the deploy's migration test, the snap, the release script, the editor's launch files and Learn's asset tools (run from apps/learn) follow the new layout. - The project's source is named as project-halkyon/halkyon (source link, snap, F-Droid listing, release uploads); the AGPL packages carry the licence's own text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
85 lines
3.4 KiB
Python
Executable file
85 lines
3.4 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Makes the app's icons for every platform from its own, the kingfisher on white
|
|
(halkyon_learn_flutter/assets/icon/halkyon_icon.png).
|
|
|
|
- The snap's, snap/gui/halkyon-learn.png at the repository's root (512 x 512
|
|
pixels, the Snap Store's size), which the Store and the desktop file show as they
|
|
are: the picture with rounded corners, as other apps' white tiles have (radius
|
|
142.222 of 512, about 28 %).
|
|
- Through flutter_launcher_icons, configured in the app's pubspec: Android's adaptive
|
|
icon and its older square one, iOS's, macOS's (the rounded tile on Apple's grid,
|
|
824 of 1024 pixels) and Windows' (the rounded tile).
|
|
- Windows' .ico once more, with every size Windows shows (16 to 256 pixels): the tool
|
|
writes only the 256 one and leaves Windows to scale it down for its small views.
|
|
- The iOS project file as it was: the tool sets every build setting with ASSETCATALOG
|
|
in its name to the icon set's name, Xcode's yes-or-no
|
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS too, which breaks the
|
|
project (flutter_launcher_icons issue 634); the project names its icon set already.
|
|
|
|
The derived images it hands to the tool go to halkyon_learn_flutter/build/icons/,
|
|
which git ignores. The rounded corners' mask is drawn at four times the size and
|
|
scaled down, so their edges are smooth.
|
|
|
|
Run from apps/learn with Python 3 and Pillow (python3-pil on Ubuntu), the
|
|
app's dependencies fetched:
|
|
|
|
python3 tool/app_icons.py
|
|
"""
|
|
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
APP = Path("halkyon_learn_flutter")
|
|
SOURCE = APP / "assets/icon/halkyon_icon.png"
|
|
DERIVED = APP / "build/icons"
|
|
SNAP_ICON = Path("../../snap/gui/halkyon-learn.png")
|
|
WINDOWS_ICON = APP / "windows/runner/resources/app_icon.ico"
|
|
IOS_PROJECT = APP / "ios/Runner.xcodeproj/project.pbxproj"
|
|
RADIUS = 142.222 / 512
|
|
SUPERSAMPLING = 4
|
|
# Apple's grid: the tile is 824 of the icon's 1024 pixels, centred.
|
|
MACOS_CANVAS = 1024
|
|
MACOS_TILE = 824
|
|
WINDOWS_SIZES = [16, 20, 24, 32, 40, 48, 64, 128, 256]
|
|
|
|
|
|
def rounded(size: int) -> Image.Image:
|
|
"""The icon at [size] pixels, its corners rounded off to transparency."""
|
|
icon = Image.open(SOURCE).convert("RGBA").resize((size, size), Image.LANCZOS)
|
|
large = size * SUPERSAMPLING
|
|
mask = Image.new("L", (large, large), 0)
|
|
ImageDraw.Draw(mask).rounded_rectangle(
|
|
(0, 0, large - 1, large - 1), radius=RADIUS * large, fill=255
|
|
)
|
|
mask = mask.resize((size, size), Image.LANCZOS)
|
|
# Keeps what the icon itself makes transparent, and takes the corners away.
|
|
transparent = Image.new("L", (size, size), 0)
|
|
icon.putalpha(Image.composite(icon.getchannel("A"), transparent, mask))
|
|
return icon
|
|
|
|
|
|
def main() -> None:
|
|
rounded(512).save(SNAP_ICON, optimize=True)
|
|
print(f"Wrote {SNAP_ICON}.")
|
|
|
|
DERIVED.mkdir(parents=True, exist_ok=True)
|
|
rounded(1024).save(DERIVED / "rounded.png")
|
|
macos = Image.new("RGBA", (MACOS_CANVAS, MACOS_CANVAS), (0, 0, 0, 0))
|
|
margin = (MACOS_CANVAS - MACOS_TILE) // 2
|
|
macos.alpha_composite(rounded(MACOS_TILE), (margin, margin))
|
|
macos.save(DERIVED / "macos.png")
|
|
|
|
ios_project = IOS_PROJECT.read_bytes()
|
|
subprocess.run(["dart", "run", "flutter_launcher_icons"], cwd=APP, check=True)
|
|
IOS_PROJECT.write_bytes(ios_project)
|
|
|
|
rounded(256).save(
|
|
WINDOWS_ICON, format="ICO", sizes=[(size, size) for size in WINDOWS_SIZES]
|
|
)
|
|
print(f"Wrote {WINDOWS_ICON} with {len(WINDOWS_SIZES)} sizes.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|