fix(app): the app has its own icon instead of Flutter's
The launcher showed Flutter's logo: the project template's icons were
never replaced. tool/app_icons.py now makes every icon from the
kingfisher (assets/icon/halkyon_icon.png), through flutter_launcher_icons
v0.14.4 configured in the app's pubspec: Android's adaptive icon (the
kingfisher inset 16 % on white, for each launcher to cut to its shape)
and the square one before Android 8; iOS's, without transparency;
macOS's, the rounded tile on Apple's grid (824 of 1024 pixels); and
Windows', the rounded tile, its .ico with every size from 16 to 256
pixels (the tool writes only 256). It keeps the iOS project file as it
was, which the tool would break (flutter_launcher_icons issue 634), and
writes the snap's icon as tool/snap_icon.py did, which it replaces.
The Linux runner gives its window the bundled icon too, for desktops
that don't take it from the desktop file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-06 22:49:25 +02:00
|
|
|
#!/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).
|
|
|
|
|
|
build: Melos, a Dart check and every path for the single repository
- 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>
2026-10-19 20:39:09 +02:00
|
|
|
- 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 %).
|
fix(app): the app has its own icon instead of Flutter's
The launcher showed Flutter's logo: the project template's icons were
never replaced. tool/app_icons.py now makes every icon from the
kingfisher (assets/icon/halkyon_icon.png), through flutter_launcher_icons
v0.14.4 configured in the app's pubspec: Android's adaptive icon (the
kingfisher inset 16 % on white, for each launcher to cut to its shape)
and the square one before Android 8; iOS's, without transparency;
macOS's, the rounded tile on Apple's grid (824 of 1024 pixels); and
Windows', the rounded tile, its .ico with every size from 16 to 256
pixels (the tool writes only 256). It keeps the iOS project file as it
was, which the tool would break (flutter_launcher_icons issue 634), and
writes the snap's icon as tool/snap_icon.py did, which it replaces.
The Linux runner gives its window the bundled icon too, for desktops
that don't take it from the desktop file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-06 22:49:25 +02:00
|
|
|
- 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.
|
|
|
|
|
|
build: Melos, a Dart check and every path for the single repository
- 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>
2026-10-19 20:39:09 +02:00
|
|
|
Run from apps/learn with Python 3 and Pillow (python3-pil on Ubuntu), the
|
fix(app): the app has its own icon instead of Flutter's
The launcher showed Flutter's logo: the project template's icons were
never replaced. tool/app_icons.py now makes every icon from the
kingfisher (assets/icon/halkyon_icon.png), through flutter_launcher_icons
v0.14.4 configured in the app's pubspec: Android's adaptive icon (the
kingfisher inset 16 % on white, for each launcher to cut to its shape)
and the square one before Android 8; iOS's, without transparency;
macOS's, the rounded tile on Apple's grid (824 of 1024 pixels); and
Windows', the rounded tile, its .ico with every size from 16 to 256
pixels (the tool writes only 256). It keeps the iOS project file as it
was, which the tool would break (flutter_launcher_icons issue 634), and
writes the snap's icon as tool/snap_icon.py did, which it replaces.
The Linux runner gives its window the bundled icon too, for desktops
that don't take it from the desktop file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-06 22:49:25 +02:00
|
|
|
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"
|
build: Melos, a Dart check and every path for the single repository
- 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>
2026-10-19 20:39:09 +02:00
|
|
|
SNAP_ICON = Path("../../snap/gui/halkyon-learn.png")
|
fix(app): the app has its own icon instead of Flutter's
The launcher showed Flutter's logo: the project template's icons were
never replaced. tool/app_icons.py now makes every icon from the
kingfisher (assets/icon/halkyon_icon.png), through flutter_launcher_icons
v0.14.4 configured in the app's pubspec: Android's adaptive icon (the
kingfisher inset 16 % on white, for each launcher to cut to its shape)
and the square one before Android 8; iOS's, without transparency;
macOS's, the rounded tile on Apple's grid (824 of 1024 pixels); and
Windows', the rounded tile, its .ico with every size from 16 to 256
pixels (the tool writes only 256). It keeps the iOS project file as it
was, which the tool would break (flutter_launcher_icons issue 634), and
writes the snap's icon as tool/snap_icon.py did, which it replaces.
The Linux runner gives its window the bundled icon too, for desktops
that don't take it from the desktop file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-06 22:49:25 +02:00
|
|
|
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()
|