diff --git a/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..ca17e4f Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-hdpi/ic_launcher_monochrome.png b/android/app/src/main/res/drawable-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..30c8cce Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..9c98ad5 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_launcher_monochrome.png b/android/app/src/main/res/drawable-mdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..252c319 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..679d576 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/drawable-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..e9c062d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..cd943f7 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..490c199 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2372679 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..6623284 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..d506366 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..27b9a78 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..97a48f9 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..5c34c68 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..3e404b0 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..efa79eb 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..610f420 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #1B1D21 + \ No newline at end of file diff --git a/assets/icon/icon.png b/assets/icon/icon.png new file mode 100644 index 0000000..439cf86 Binary files /dev/null and b/assets/icon/icon.png differ diff --git a/assets/icon/icon.svg b/assets/icon/icon.svg new file mode 100644 index 0000000..4fcb929 --- /dev/null +++ b/assets/icon/icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icon/icon_foreground.png b/assets/icon/icon_foreground.png new file mode 100644 index 0000000..b425862 Binary files /dev/null and b/assets/icon/icon_foreground.png differ diff --git a/assets/icon/icon_foreground.svg b/assets/icon/icon_foreground.svg new file mode 100644 index 0000000..89731a1 --- /dev/null +++ b/assets/icon/icon_foreground.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icon/icon_monochrome.png b/assets/icon/icon_monochrome.png new file mode 100644 index 0000000..87e2855 Binary files /dev/null and b/assets/icon/icon_monochrome.png differ diff --git a/assets/icon/icon_monochrome.svg b/assets/icon/icon_monochrome.svg new file mode 100644 index 0000000..c278c8f --- /dev/null +++ b/assets/icon/icon_monochrome.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/linux/icons/128/todo.png b/linux/icons/128/todo.png new file mode 100644 index 0000000..8c080b9 Binary files /dev/null and b/linux/icons/128/todo.png differ diff --git a/linux/icons/16/todo.png b/linux/icons/16/todo.png new file mode 100644 index 0000000..06b86e6 Binary files /dev/null and b/linux/icons/16/todo.png differ diff --git a/linux/icons/24/todo.png b/linux/icons/24/todo.png new file mode 100644 index 0000000..3c0b1a5 Binary files /dev/null and b/linux/icons/24/todo.png differ diff --git a/linux/icons/256/todo.png b/linux/icons/256/todo.png new file mode 100644 index 0000000..0efb2a1 Binary files /dev/null and b/linux/icons/256/todo.png differ diff --git a/linux/icons/32/todo.png b/linux/icons/32/todo.png new file mode 100644 index 0000000..3c45b30 Binary files /dev/null and b/linux/icons/32/todo.png differ diff --git a/linux/icons/48/todo.png b/linux/icons/48/todo.png new file mode 100644 index 0000000..defd2a4 Binary files /dev/null and b/linux/icons/48/todo.png differ diff --git a/linux/icons/512/todo.png b/linux/icons/512/todo.png new file mode 100644 index 0000000..a9cc144 Binary files /dev/null and b/linux/icons/512/todo.png differ diff --git a/linux/icons/64/todo.png b/linux/icons/64/todo.png new file mode 100644 index 0000000..76d01f8 Binary files /dev/null and b/linux/icons/64/todo.png differ diff --git a/linux/install_desktop_entry.sh b/linux/install_desktop_entry.sh new file mode 100755 index 0000000..f10bf5f --- /dev/null +++ b/linux/install_desktop_entry.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +# ============================================================================ +# Install the todo launcher icon and .desktop entry for the Linux desktop. +# +# Flutter's GTK runner has no icon of its own: my_application.cc calls +# gtk_window_set_icon_name("todo"), which resolves through the hicolor icon +# theme. This script is what puts the icon into that theme, plus a .desktop +# entry so the app appears in application menus. +# +# Icon PNGs are pre-rendered and committed under linux/icons/, so this script +# needs no image tooling at run time. Regenerate them with: +# PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons \ +# generate --app todo --linux-out linux/icons +# ============================================================================ + +set -euo pipefail + +SCRIPT_NAME="$(basename "$0")" +LINUX_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_DIR="$(dirname "$LINUX_DIR")" +readonly SCRIPT_NAME LINUX_DIR REPO_DIR +readonly ICON_NAME="todo" +readonly BINARY_NAME="todo" +# GTK derives WM_CLASS from the GApplication id in linux/CMakeLists.txt, +# not from the binary name; verified with xprop on the running window. +readonly WM_CLASS="dev.kuhy.todo" +readonly ICON_SRC_DIR="$LINUX_DIR/icons" +readonly ICON_THEME_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/icons/hicolor" +readonly DESKTOP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications" +readonly BUNDLE_BIN="$REPO_DIR/build/linux/x64/release/bundle/$BINARY_NAME" + +usage() { + echo "Usage: $SCRIPT_NAME" + echo "Installs the todo icon into the hicolor theme and writes a .desktop entry." + exit 0 +} + +validate_requirements() { + if [[ ! -d "$ICON_SRC_DIR" ]]; then + echo "Error: $ICON_SRC_DIR is missing; regenerate the icons first" >&2 + exit 1 + fi +} + +ensure_theme_index() { + # A user-local hicolor tree created from scratch has no index.theme, and + # without it gtk-update-icon-cache refuses to build a cache ("No theme + # index file"). Seed it from the system theme when one is available. + local system_index="/usr/share/icons/hicolor/index.theme" + if [[ ! -f "$ICON_THEME_DIR/index.theme" && -f "$system_index" ]]; then + install -Dm644 "$system_index" "$ICON_THEME_DIR/index.theme" + fi +} + +install_icons() { + local size_dir size icon + for size_dir in "$ICON_SRC_DIR"/*/; do + size="$(basename "$size_dir")" + icon="$size_dir$ICON_NAME.png" + [[ -f "$icon" ]] || continue + install -Dm644 "$icon" \ + "$ICON_THEME_DIR/${size}x${size}/apps/$ICON_NAME.png" + done + # Refresh the theme cache so GTK picks the icon up without a re-login. + # Harmless if the tool is absent: the icon still resolves, just slower. + if command -v gtk-update-icon-cache >/dev/null; then + gtk-update-icon-cache --quiet --force "$ICON_THEME_DIR" || true + fi +} + +install_desktop_entry() { + mkdir -p "$DESKTOP_DIR" + # StartupWMClass must match the window's actual WM class, or the taskbar + # shows a generic icon for the running window even though the launcher + # entry itself looks right. + cat > "$DESKTOP_DIR/$ICON_NAME.desktop" </dev/null; then + update-desktop-database "$DESKTOP_DIR" || true + fi +} + +main() { + validate_requirements + ensure_theme_index + install_icons + install_desktop_entry + echo "Installed $ICON_NAME icon into $ICON_THEME_DIR" + echo "Installed $DESKTOP_DIR/$ICON_NAME.desktop" + if [[ ! -x "$BUNDLE_BIN" ]]; then + echo "Note: $BUNDLE_BIN does not exist yet." + echo " Run 'flutter build linux --release' to make the entry launchable." + fi +} + +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +main "$@" diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index 37cfb39..9d02fa3 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -54,6 +54,11 @@ static void my_application_activate(GApplication* application) { gtk_window_set_default_size(window, 1280, 720); + // Resolved from the hicolor icon theme, which linux/install_desktop_entry.sh + // populates from linux/icons/. Without this the GTK runner shows a generic + // placeholder in the taskbar, since Flutter never sets a window icon itself. + gtk_window_set_icon_name(window, "todo"); + g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments( project, self->dart_entrypoint_arguments); diff --git a/pubspec.lock b/pubspec.lock index 6f116ea..fa49fbe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + url: "https://pub.dev" + source: hosted + version: "4.0.9" args: dependency: transitive description: @@ -41,6 +49,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: @@ -223,6 +247,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" + url: "https://pub.dev" + source: hosted + version: "0.14.4" flutter_lints: dependency: "direct dev" description: @@ -321,6 +353,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + image: + dependency: transitive + description: + name: image + sha256: "6300175e00616bbc832e2fc91bfa4d776af5402c81c7151bee6905bb08473c52" + url: "https://pub.dev" + source: hosted + version: "4.9.1" jni: dependency: transitive description: @@ -337,6 +377,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" + url: "https://pub.dev" + source: hosted + version: "4.12.0" leak_tracker: dependency: transitive description: @@ -489,6 +537,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.dev" + source: hosted + version: "7.0.2" platform: dependency: transitive description: @@ -513,6 +569,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.2" + posix: + dependency: transitive + description: + name: posix + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.dev" + source: hosted + version: "6.5.0" process_run: dependency: transitive description: @@ -846,6 +910,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4" + url: "https://pub.dev" + source: hosted + version: "7.0.1" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a2b574e..f572762 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,6 +57,9 @@ dependencies: # libsecret) instead of plaintext SharedPreferences. flutter_secure_storage: ^10.3.1 dev_dependencies: + # Generates the Android launcher icons from assets/icon/ (see + # python_pkg/app_icons in testsAndMisc for the shared style). + flutter_launcher_icons: ^0.14.4 flutter_test: sdk: flutter @@ -117,3 +120,15 @@ flutter: # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package + +# Launcher icon generation. Source art is produced by the shared generator: +# PYTHONPATH=~/testsAndMisc python3 -m python_pkg.app_icons generate --app +# then run: dart run flutter_launcher_icons +flutter_launcher_icons: + android: true + ios: false + image_path: "assets/icon/icon.png" + adaptive_icon_background: "#1B1D21" + adaptive_icon_foreground: "assets/icon/icon_foreground.png" + adaptive_icon_monochrome: "assets/icon/icon_monochrome.png" + min_sdk_android: 21