feat: the apps' icons as one family, drawn by one tool (ADR 0031)
tool/app_icons.py at the root replaces Learn's and Todo's scripts: each app's Lucide glyph (lucide-static 1.50.0) drawn by librsvg, fading from cobalt through the colours ADR 0031 names, then every platform's launcher icon through flutter_launcher_icons, Windows' .ico with every size, and Learn's snap icon. Learn's icon becomes the graduation cap, its window's on Linux too, with Lucide's notice in its licence list; the kingfisher stays the emblem on the rail and the launch screen. Todo's becomes list-todo, Train's bike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
|
|
@ -6,7 +6,7 @@ Halkyon's apps and the packages they share, in one repository and one pub worksp
|
|||
|
||||
## Layout
|
||||
|
||||
- **`apps/<app>/`**: each app's packages, as `serverpod create` lays them out (`halkyon_<app>_server`, `_client`, `_flutter`), plus what is the app's alone (Learn's curator, the scripts writing Learn's assets in `apps/learn/tool/`, run from `apps/learn`). Learn is the app that runs; Todo is still Serverpod's scaffold, and Train a shell like it (ADR 0030); Meditate is to come.
|
||||
- **`apps/<app>/`**: each app's packages, as `serverpod create` lays them out (`halkyon_<app>_server`, `_client`, `_flutter`), plus what is the app's alone (Learn's curator, the scripts writing Learn's assets in `apps/learn/tool/`, run from `apps/learn`; the apps' icons are the root's `tool/app_icons.py`, ADR 0031). Learn is the app that runs; Todo is still Serverpod's scaffold, and Train a shell like it (ADR 0030); Meditate is to come.
|
||||
- **`packages/`**: what the apps share, each with its README and licence, which the apps take by path (`path: ../../../packages/<package>`), so a change to a shared package and to the apps using it is one commit:
|
||||
- `halkyon_ui`: Halkyon's look, the theme around cobalt and copper, Noto Sans bundled, the window-size classes and the widgets every screen is built of, with texts of its own (English, German).
|
||||
- `halkyon_base_server`, `halkyon_base_client`: the Serverpod module every Halkyon server includes (ADR 0014): signing in (a password with TOTP and the resets of ADR 0017, SimpleLogin on `halkyon_oidc`, email codes proving an address; no anonymous accounts since ADR 0020, D25, nor GitHub since D36), an account's ways in and its deletion with a hook for each app's own data, the pruning, the instance's basics, people's handles and public profiles, who may sign up (`SIGN_UP`: open, approval, closed) with the accounts waiting for approval and the instance's operators who approve them (Halkyon Learn's ADR 0021, step 1), the operator's assistants forwarded on halkyon_llm with their grants, each person's budget, the efforts they allow and counted figures, and the instance's privacy page made from its settings (step 2), and the instance's register (ADR 0016): one account per person across an operator's services, held by one service (Learn's server on learn.halkyon.eu) and asked by the others, its members (`ACCOUNT_REGISTER_URL`), all sharing a secret (`INSTANCE_SECRET`); its README says how.
|
||||
|
|
@ -82,7 +82,7 @@ Checklist after doing changes, in this order:
|
|||
- Check `serverpod` MCP `tail_server_logs` and `tail_flutter_logs` for any issues.
|
||||
|
||||
- **Melos** (decided 2026-10-19, ADR 0015) runs scripts across the workspace's packages: a dev dependency of the root (`dart run melos …`, its version in the lock), its scripts under `melos:` in the root `pubspec.yaml`: `analyze`; `test:dart` (the packages without Flutter, one at a time, as each server's tests start a PostgreSQL of their own on the same port); `test:flutter` (`flutter test -x requires-server`, one package at a time); `generate` (Serverpod's code generation in every package with a `config/generator.yaml`, the CLI on the PATH); `check` (`tool/check.dart`). Every script takes Melos' filters: `dart run melos run test:flutter --scope=halkyon_app`, or `--diff=origin/main --include-dependents` for what changed and what depends on it; `dart run melos list` lists the packages. The root overrides `cli_util` to 0.5.2 for it: Learn's `flutter_launcher_icons` (0.14.4, its latest) asks for ^0.4.1 and uses only the logger, which 0.5 keeps; drop the override once that package allows 0.5.
|
||||
- **Tools are Dart where they hold logic** (decided 2026-10-19): conditions, parsing, parallel work, anything worth a test, as `tool/check.dart` (its file selection in `tool/src/check_files.dart`, tested in the root's `test/`). **Bash for glue**, short and linear (`tool/pre-push`, `tool/check_signatures.sh`, `tool/workspace_only.sh`, which narrows the root pubspec's workspace to the packages an image builds), **and for everything run on the production host**, which has no Dart SDK and gets none (`deploy/redeploy.sh`, `deploy/backup.sh`). **Python only where a library exists only there** (Learn's icons with Pillow, its Anki fixtures with Anki itself); Learn's data scripts and `packages/halkyon_app/tool/subdivision_names.py` need nothing but Python's standard library and may move to Dart when they next change. **Releases come from `tool/release.dart`** (decided 2026-10-19, ADR 0015), shared by the apps, each configured in Dart beside it (`apps/<id>/release.dart`, typed and commented, registered in `tool/src/release/apps.dart`): `dart run tool/release.dart learn [major | minor | patch] [--dry-run]`, on a developer's laptop, never in CI. Tags are per app (`learn-v0.19.0`; an app's earlier tags, Learn's `v…`, count as its history), and only commits touching the app decide its version: its folder, the shared packages its packages use by path (transitively), the root pubspec and lock, its release files (key pins, F-Droid listing, snap recipe) and where its packages were before a move. `--dry-run` reads everything a release would (the version, the commits that count and what each touches, the steps, the notes it would publish), changes nothing, asks for no secret, and lists what a release would refuse. Its pure logic is in `tool/src/release/`, tested in the root's `test/release/`. `tool/fdroid_repo.sh` stays Bash (glue for fdroidserver). Build 21 (`v0.18.0`) was the last release of `tool/release.sh`, the Bash script it replaced, removed since.
|
||||
- **Tools are Dart where they hold logic** (decided 2026-10-19): conditions, parsing, parallel work, anything worth a test, as `tool/check.dart` (its file selection in `tool/src/check_files.dart`, tested in the root's `test/`). **Bash for glue**, short and linear (`tool/pre-push`, `tool/check_signatures.sh`, `tool/workspace_only.sh`, which narrows the root pubspec's workspace to the packages an image builds), **and for everything run on the production host**, which has no Dart SDK and gets none (`deploy/redeploy.sh`, `deploy/backup.sh`). **Python only where a library exists only there** (the apps' icons with librsvg and Pillow, `tool/app_icons.py`, its Anki fixtures with Anki itself); Learn's data scripts and `packages/halkyon_app/tool/subdivision_names.py` need nothing but Python's standard library and may move to Dart when they next change. **Releases come from `tool/release.dart`** (decided 2026-10-19, ADR 0015), shared by the apps, each configured in Dart beside it (`apps/<id>/release.dart`, typed and commented, registered in `tool/src/release/apps.dart`): `dart run tool/release.dart learn [major | minor | patch] [--dry-run]`, on a developer's laptop, never in CI. Tags are per app (`learn-v0.19.0`; an app's earlier tags, Learn's `v…`, count as its history), and only commits touching the app decide its version: its folder, the shared packages its packages use by path (transitively), the root pubspec and lock, its release files (key pins, F-Droid listing, snap recipe) and where its packages were before a move. `--dry-run` reads everything a release would (the version, the commits that count and what each touches, the steps, the notes it would publish), changes nothing, asks for no secret, and lists what a release would refuse. Its pure logic is in `tool/src/release/`, tested in the root's `test/release/`. `tool/fdroid_repo.sh` stays Bash (glue for fdroidserver). Build 21 (`v0.18.0`) was the last release of `tool/release.sh`, the Bash script it replaced, removed since.
|
||||
|
||||
## CI and deploys
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ The repository's packages carry different licences, each package's full text in
|
|||
|
||||
The servers and the module build on Serverpod's core, which is under the SSPL, and so are
|
||||
under it too. The apps and the shared Flutter packages link only permissively licensed
|
||||
packages (Todo's and Train's icons are Lucide's, under the ISC licence, whose notice each app registers), and the client packages are generated from our own model definitions, so all of
|
||||
packages (the apps' icons are Lucide's, under the ISC licence, whose notice each app registers), and the client packages are generated from our own model definitions, so all of
|
||||
them are under the AGPL. The curator depends on neither a server nor Serverpod: Learn's
|
||||
server reads the files it writes, never its code.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ What holds for every app and package of this repository (how work is done here,
|
|||
|
||||
A spaced-repetition learning app: studysets of flashcards, reviewed on an FSRS schedule. Content is rich text (`appflowy_editor` documents) everywhere. Targets: Linux, Windows, macOS, Android, iOS. There is no web build.
|
||||
|
||||
- **Packages** (`apps/learn/`): `halkyon_learn_server` (endpoints, models, migrations), `halkyon_learn_client` (generated, never edited), `halkyon_learn_flutter` (the app, ID `app.halkyon.learn`), `halkyon_learn_curator` (the dictionaries' converter, below), and `tool/` with the scripts that write the app's assets (maps, icons, Anki fixtures; run them from `apps/learn`). What every Halkyon server has comes from the Serverpod module `halkyon_base` (ADR 0014, decided 2026-10-19; `packages/halkyon_base_server` and `packages/halkyon_base_client`, which Learn's packages take by path): signing in, the account's ways in and its deletion, the pruning, and the instance's basics. The server sets it up for Learn before it starts (`HalkyonBase.configure(pod, learnBase(accounts: learnAccounts()))` in `server.dart`; `lib/src/auth/learn_base.dart`: Learn holds the instance's register of accounts (ADR 0016), `learnAccounts` reading the members from `INSTANCE_MEMBERS` and refusing to start with `ACCOUNT_REGISTER_URL`; the app it serves, `learn`, which its instances name in their basics and the app checks (never change it), the app's name in sign-in mails, this project's source, `minimumAppBuild`, Learn's own deletion as a hook), its endpoints are `client.modules.base` in the app, its tables (`email_identity`, `email_code_request`) are the module's, and tests that delete people or ask `instance.info()` set it up as the server does (`useLearnBase(sessionBuilder)`). What every Halkyon app's shell has comes from `halkyon_app` on the module's client (ADR 0014, `packages/halkyon_app`; with `halkyon_core`'s `SerialQueue` and `CoalescingRunner`): the instances and the first start, signing in and switching person, the gates (`InstanceGate`, `SessionGate`, `PersonScope`, `AppScope`), the sync service and where it stands, with texts of its own (`HalkyonAppLocalizations`, in `appLocalizationsDelegates`) that name the app from `learnFrame`. Change what they hold there, not here.
|
||||
- **Packages** (`apps/learn/`): `halkyon_learn_server` (endpoints, models, migrations), `halkyon_learn_client` (generated, never edited), `halkyon_learn_flutter` (the app, ID `app.halkyon.learn`), `halkyon_learn_curator` (the dictionaries' converter, below), and `tool/` with the scripts that write the app's assets (maps, Anki fixtures; run them from `apps/learn`; its icon, Lucide's graduation cap since ADR 0031, is the root's `tool/app_icons.py`'s, the kingfisher staying the emblem atop the rail and on the launch screen, `assets/icon/halkyon_icon.png`). What every Halkyon server has comes from the Serverpod module `halkyon_base` (ADR 0014, decided 2026-10-19; `packages/halkyon_base_server` and `packages/halkyon_base_client`, which Learn's packages take by path): signing in, the account's ways in and its deletion, the pruning, and the instance's basics. The server sets it up for Learn before it starts (`HalkyonBase.configure(pod, learnBase(accounts: learnAccounts()))` in `server.dart`; `lib/src/auth/learn_base.dart`: Learn holds the instance's register of accounts (ADR 0016), `learnAccounts` reading the members from `INSTANCE_MEMBERS` and refusing to start with `ACCOUNT_REGISTER_URL`; the app it serves, `learn`, which its instances name in their basics and the app checks (never change it), the app's name in sign-in mails, this project's source, `minimumAppBuild`, Learn's own deletion as a hook), its endpoints are `client.modules.base` in the app, its tables (`email_identity`, `email_code_request`) are the module's, and tests that delete people or ask `instance.info()` set it up as the server does (`useLearnBase(sessionBuilder)`). What every Halkyon app's shell has comes from `halkyon_app` on the module's client (ADR 0014, `packages/halkyon_app`; with `halkyon_core`'s `SerialQueue` and `CoalescingRunner`): the instances and the first start, signing in and switching person, the gates (`InstanceGate`, `SessionGate`, `PersonScope`, `AppScope`), the sync service and where it stands, with texts of its own (`HalkyonAppLocalizations`, in `appLocalizationsDelegates`) that name the app from `learnFrame`. Change what they hold there, not here.
|
||||
- **Instances**: anyone may run one. The app takes the server URL from `--dart-define=SERVER_URL=…`, so never hard-code a host.
|
||||
|
||||
## Working on Learn
|
||||
|
|
|
|||
|
|
@ -68,9 +68,10 @@ instance's basics; a Serverpod module), `halkyon_app` (instances, sign-in, sync)
|
|||
Mode.
|
||||
- **No Docker** for development: `serverpod start` and the server's tests run an embedded
|
||||
PostgreSQL. Docker Compose is only for running an instance (below).
|
||||
- **For Learn's scripts in `apps/learn/tool/`**, run from `apps/learn`: Python 3
|
||||
(`tool/app_icons.py` also needs Pillow, `python3-pil`); for releases what
|
||||
[Releases](#releases) lists.
|
||||
- **For Learn's scripts in `apps/learn/tool/`**, run from `apps/learn`: Python 3; for
|
||||
the apps' icons (the repository's `tool/app_icons.py`, run from the root) also Pillow,
|
||||
PyGObject with librsvg and pycairo (`python3-pil`, `python3-gi`, `gir1.2-rsvg-2.0`,
|
||||
`python3-cairo`); for releases what [Releases](#releases) lists.
|
||||
|
||||
The rich-text editor comes from our fork of AppFlowy Editor
|
||||
([project-halkyon/appflowy-editor](https://code.halkyon.app/project-halkyon/appflowy-editor)),
|
||||
|
|
@ -155,7 +156,7 @@ may choose another there, and keep accounts on several.
|
|||
`learn-vX.Y.Z`, and only commits touching Learn count for its version. It shows the version and its commits and asks
|
||||
first, then writes the version into the pubspec in a signed release commit with a
|
||||
signed tag, builds the APK and the snap (`snap/snapcraft.yaml`, built in LXD; its icon
|
||||
comes from `apps/learn/tool/app_icons.py`), checks both, signs the checksums, pushes, and
|
||||
comes from the repository's `tool/app_icons.py`), checks both, signs the checksums, pushes, and
|
||||
publishes on code.halkyon.app, in the F-Droid repository and in the Snap Store's edge
|
||||
channel (`snapcraft login` first). Besides Flutter and the Android SDK, it uses snapcraft with
|
||||
LXD, a JDK (keytool), GnuPG, curl, jq, unzip, squashfs-tools, rsync and fdroidserver.
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 4 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 5.3 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
ISC License
|
||||
|
||||
Copyright (c) 2026 Lucide Icons and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
The following Lucide icons are derived from the Feather project:
|
||||
|
||||
airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
|
||||
|
||||
The MIT License (MIT) (for the icons listed above)
|
||||
|
||||
Copyright (c) 2013-present Cole Bemis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 380 B |
|
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 941 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |