diet-guard/app
Krzysztof kuhy Rudnicki 66650ca3cc
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
file-length / file length <= 250 lines (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Has been cancelled
Tests / test (push) Has been cancelled
release-apk / release (APK) (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Catering fill: honour the "Log for later" date
Fill all with catering always fetched and filled today, so picking 24.10
on 23.10 reported "No catering delivery today." FillAllFlow.tap now takes
the picked day: fetch, slot schedule, occupancy and dedup all resolve
against it, and logDishes stamps each dish at its slot time on that day.

- A plan only confirms onto the day it was proposed for; changing the
  date (or back to today) disarms it.
- A later-day fill leaves today's delivery queue and prefill alone and
  returns the form to today, as a manual "Log for later" does.
- Only today's fetch records the single-day "already fetched" marker;
  recording a later date would skip that day's automatic fetch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwYgigocPkPWa73QZRtU38
2026-10-23 19:01:44 +02:00
..
.agents/skills Fix pre-existing CI failures (deps, lint, whitespace) 2026-07-10 23:55:56 +02:00
android deps: gradle 9.8.2, fl_chart 1.3.0, web 1.1.2, coverage 7.17.0, ruff 0.17.2 (newest stable) 2026-10-23 18:49:15 +02:00
assets/icon Launcher: label DietGuard (Android, desktop entry, PKGBUILD), icon fitted to the shared 340px ink circle 2026-10-23 14:36:31 +02:00
bin Finish the three sync bugs: gate, SIGKILL flag, and silent catches 2026-08-09 22:28:18 +02:00
desktop Launcher: label DietGuard (Android, desktop entry, PKGBUILD), icon fitted to the shared 340px ink circle 2026-10-23 14:36:31 +02:00
lib Catering fill: honour the "Log for later" date 2026-10-23 19:01:44 +02:00
test Catering fill: honour the "Log for later" date 2026-10-23 19:01:44 +02:00
web Launcher: label DietGuard (Android, desktop entry, PKGBUILD), icon fitted to the shared 340px ink circle 2026-10-23 14:36:31 +02:00
.gitignore Add Flutter companion app skeleton with local meal logging 2026-06-22 18:22:42 +02:00
.metadata app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
analysis_options.yaml Persist the CI-mirror's analyzer excludes and dependency upgrades 2026-08-14 16:13:46 +02:00
install_arch.sh app: package the desktop app as the web build, and delete the Linux embedder 2026-07-20 16:32:24 +02:00
pubspec.lock deps: gradle 9.8.2, fl_chart 1.3.0, web 1.1.2, coverage 7.17.0, ruff 0.17.2 (newest stable) 2026-10-23 18:49:15 +02:00
pubspec.yaml Catering fill: honour the "Log for later" date 2026-10-23 19:01:44 +02:00
README.md Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 19:53:03 +02:00
run.sh app: package the desktop app as the web build, and delete the Linux embedder 2026-07-20 16:32:24 +02:00
skills-lock.json Add Flutter/Dart agent skills and AI rules for Claude Code 2026-06-22 22:53:06 +02:00

diet_guard_app

Companion app for diet_guard: log meals on the phone, and on the Linux desktop, sharing one food log through GitHub-backed sync.

Two targets, and only two

Target What it is
Android a normal Flutter app (flutter build apk)
Linux desktop the Flutter web build, served by a local wrapper and shown in a Chrome --app window

There is no linux/ directory. Flutter's GTK embedder manages ~20fps at 3840x2160 -- measured on a stock flutter create counter app, so it is the toolkit rather than this code -- where the same Dart rendered by Chrome sustains ~144fps (~/src/todo/docs/DOCS-desktop-performance-findings.md). Running flutter create --platforms linux here would silently restore the slow path.

Commands

flutter test                     # the app's suite
flutter analyze
bash run.sh                      # build the web bundle and launch the desktop app
bash install_arch.sh             # build + install the pacman package and .desktop entry
flutter build apk --release      # the phone build
adb install -r build/app/outputs/flutter-apk/app-release.apk

Never adb uninstall or pm clear this package: both wipe the on-device log.

The desktop wrapper

bin/diet_guard_desktop.dart is the other half of the desktop app, because a browser cannot touch the filesystem. It:

  • serves the built web assets from build/web (or /opt/diet-guard-app/web once packaged);
  • keeps an on-disk copy of every document and photo under ~/.local/share/diet-guard-desktop/, which is what makes a wiped Chrome profile recoverable -- for photos it is the only copy, since they never sync;
  • holds the GitHub token (~/.config/diet_guard_app/sync_token, falling back to the PC gate's ~/.config/diet_guard/sync_token) and proxies api.github.com plus the device flow, whose endpoints send no CORS headers and so cannot be called from a page at all.

The port (8732) and the Chrome --user-data-dir must stay fixed. IndexedDB is keyed by origin and lives inside that profile, so changing either looks to the app like a device with no history.

Platform seams

dart:io does not fail a web compile; it becomes a stub that throws at runtime, so the symptom of a missed seam is a blank white window rather than a build error. Every platform edge is a conditional export -- document_store*, blob_store*, background_tasks*, notification_backend*, token_vault*, github_client_factory*, attached_image*. Branch on kIsWeb before any Platform.is…, which itself throws on web.

What the desktop genuinely loses, by design rather than omission:

  • Background reminders. A browser runs nothing once its window is closed, so the due-slot check runs in-page every 5 minutes while the window is open. On the PC the real backstop is diet-guard-gate.timer, which locks the screen.
  • Camera capture. The browser picker is a file input.
  • Photo sharing between devices -- unchanged: imagePath was always stripped before push.

Sync identity

Three devices push under diet-guard-sync/devices/: pc (the Python gate), phone, and desktop. Each must keep its own id -- two devices sharing one would overwrite each other's pushed log on every tick.