docs: modernize the README and re-shoot the screenshots on 2.0.1 - #592
Conversation
- Use the wordmark banner (light/dark variants) as a hero instead of the 128px square icon, and add a tagline plus a quick-links row. - Fix the license badge, which linked to the MIT license page while reading GPLv3; point it at the repo LICENSE instead. - Unify badges on flat-square and add release, CI status, and platform. - Normalize the store buttons to a fixed height so the App Store and Play banners line up (both source images are 150px tall; the previous width="30%" rendered them at different heights). - Caption the screenshots in a table. - Condense the 16-bullet feature list into a scannable table, keeping the full prose in a <details> block. - Move the APK signature verification steps into <details>. - Render the disclaimer as GitHub alert callouts. - Add a "built with" line for contributors, linking AGENTS.md.
The four screenshots in the README and the Play listing were added in b757332 and predate the 2.x redesign entirely. They showed the old Material 3 look and the old four-tab nav, and their captions — Home, Barcode scanner, Food details, Profile — no longer matched the app's tabs, which are Home, Diary, Trends and You. Replace them with six captures of the current UI, ordered as the loop a visitor needs to understand the product: log, review, understand, track, progress, control. Every shot comes from the seeded demo fixture, so the app looks like something someone actually uses. The 17 captures in docs/ui-overhaul/ could not be reused for exactly that reason: they were taken on an empty account, showing "0 / 7 days on track" over a flat zero line and "Nothing added" under an empty calendar. Screenshots like that argue against the app. They are deleted here. Tooling to reproduce the set: * DemoSeedOptions gains markAsDemoData, defaulting true so the dev and onboarding presets are untouched. The new screenshots preset turns it off, which keeps the demo banner out of frame — it would have sat on top of four of the six captures and not the other two. * lib/dev/main_screenshots.dart pins theme, locale and Material You. All three otherwise follow the device, which is how the previous set came out purple: Material You defaults on and takes the accent from the wallpaper. * tools/adb/capture-screenshots.sh drives the six, checking after every step that the app still holds focus. One back-press too many lands on the launcher, after which each later tap silently drives whatever is on screen instead. * adb-driver.sh now reads the device serial with cut rather than awk; wireless-debugging serials contain a space, and splitting on whitespace truncated them into "device not found". The README and the landing page share one 540-wide set under docs/site/screenshots/ rather than keeping separate copies. The site is published with docs/site as its root, so it cannot reference a path above that directory. Play keeps the full-resolution 1080x2205 set. Status and gesture bars are cropped so all six frame identically. Total image weight drops from 12.9 MB to 2.0 MB.
fonts/Fredoka.ttf is not a font. Its first bytes are eight newlines followed by "<!DOCTYPE html>" — it is a 306 KB GitHub HTML page saved under a .ttf name, presumably a curl of a repository URL that returned the rendered page instead of the raw file. fontTools refuses to open it with "Not a TrueType or OpenType font (bad sfntVersion)". It has been declared as a family in pubspec.yaml and bundled into every build since f0ebc84, and no code has ever referenced it: the only matches for "Fredoka" in the tree are the two pubspec lines removed here. Delete both. Also note in passing why the neighbouring Nunito entry needs no weight declarations — it is a variable font and Flutter instances the wght axis from TextStyle.fontWeight.
There was a problem hiding this comment.
Pull request overview
This PR modernizes the project’s public-facing documentation and assets by rewriting README.md and replacing outdated UI screenshots with a reproducible, up-to-date capture pipeline driven from a dedicated dev entry point and ADB tooling.
Changes:
- Replace README screenshots and update
docs/siteto present a 6-shot current UI set (and adjust the site grid to match). - Add a reproducible screenshot-capture flow (
just screenshots+lib/dev/main_screenshots.dart+tools/adb/capture-screenshots.sh) and tweak the demo seeder to optionally suppress the demo banner. - Remove the unused/bogus
Fredokafont declaration frompubspec.yaml.
Reviewed changes
Copilot reviewed 9 out of 39 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/adb/capture-screenshots.sh | New scripted ADB flow to relaunch, navigate tabs, and capture the 6-shot screenshot set reliably. |
| tools/adb/adb-driver.sh | Adjusts default device-serial detection to better handle wireless-debugging serial formats. |
| README.md | Rewrites README structure, adds 6 current screenshots, and expands privacy/translation/mentions sections. |
| pubspec.yaml | Removes Fredoka font family entry and documents Nunito variable-font usage. |
| lib/dev/main_screenshots.dart | New dev-only entry point to seed data and pin theme/locale/Material You for consistent screenshots. |
| lib/core/utils/demo/demo_seeder.dart | Adds markAsDemoData option and a screenshots preset to seed without showing the demo banner. |
| justfile | Adds screenshots recipe to run the dedicated screenshot entry point. |
| docs/site/style.css | Updates screenshot grid sizing to render a clean 3×2 layout for six images. |
| docs/site/index.html | Updates screenshot set and alt text to match the new 6-image sequence. |
| # cut -f1 rather than awk $1: serials from wireless debugging contain spaces | ||
| # (e.g. "adb-18101FDF60010M-c9jbnv (2)._adb-tls-connect._tcp"), and splitting on | ||
| # whitespace truncates them into a "device not found". | ||
| DEVICE="${DEVICE:-$(adb devices | sed -n '2p' | cut -f1)}" |
| **What leaves your device** — these four destinations, nothing else: | ||
|
|
||
| | Destination | When | What is sent | | ||
| | :-- | :-- | :-- | | ||
| | [Open Food Facts](https://world.openfoodfacts.org/) | Food search or barcode scan | The search term or barcode, plus a country tag from your device locale for ranking | | ||
| | [USDA FoodData Central](https://fdc.nal.usda.gov/) | Food search | The search term and the app's API key | | ||
| | Supabase reference backend | Food search, when that source is enabled | The search term | |
The table is headed "what leaves your device — these four destinations, nothing else", so a wrong row overstates egress in the one section that promises to be auditable rather than trusted. Two rows were wrong. USDA FoodData Central was listed as receiving "the search term and the app's API key". The device never contacts api.nal.usda.gov. The FDC search path (SearchProductsUseCase.searchFDCFoodByString) calls ProductsRepository.getSupabaseFoodsByString, which queries the Supabase food_summary view. ProductsRepository.getFDCFoodsByString — the only code that would reach USDA directly — has no callers, so the obfuscated FDC_API_KEY is never sent anywhere at runtime. The Supabase row said "food search, when that source is enabled", which reads as one option among several. It is in fact the sole path for all seven datasets the backend serves: four FDC subsets, BLS, INDB, TBCA. The Settings toggles pick which of those a search covers, not whether Supabase is contacted. Drop the USDA row, correct the Supabase row, and say plainly underneath that USDA, BLS, INDB and TBCA are where the data comes from rather than places the device talks to — the datasets are ingested server-side. Reported by Copilot on #592. Also fix the device autodetection this branch touched: matching the state field exactly, with the tab as the field separator, keeps space-bearing wireless serials intact while skipping offline and unauthorized entries and the blank trailing line. The previous sed -n '2p' preserved the serial but would happily return an unusable device.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 39 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (6)
tools/adb/capture-screenshots.sh:128
- tap_id failures are not checked here, so the script can proceed even if the FAB id is missing (e.g. on a different screen) and the following steps will capture the wrong UI state.
tools/adb/capture-screenshots.sh:129 - tap_id failures are ignored here (stderr suppressed, exit code unchecked). If the meal target id isn't found, the script still sleeps and takes the screenshot, producing a misleading frame.
tools/adb/capture-screenshots.sh:134 - If neither meal name is found, both _tap_text calls return non-zero but the script continues anyway, so the later screenshot may not be a meal-detail view.
tools/adb/capture-screenshots.sh:145 - tap_id failures are not checked here. If navigation fails, the script will still capture and label the screenshot as Diary, which can silently produce an incorrect set.
tools/adb/capture-screenshots.sh:149 - tap_id failures are not checked here, so the Trends screenshot can be taken from the wrong screen without the script failing.
tools/adb/capture-screenshots.sh:153 - tap_id failures are not checked here, so the You/Profile screenshot can be taken from the wrong tab without the script failing.
| # second app that cannot see — let alone reseed — the production install's | ||
| # data. What *is* destructive is running it against a device where $PKG is | ||
| # someone's actual tracker, so refuse if the seeded demo profile isn't there. | ||
| if ! _adb shell pm list packages | grep -q "^package:$PKG$"; then |
| # Pin the clock, battery and signal so all shots match and carry no | ||
| # notification clutter. Restored by demo_exit on exit. | ||
| demo_enter() { | ||
| _adb shell settings put global sysui_demo_allowed 1 | ||
| local c="am broadcast -a com.android.systemui.demo" | ||
| _adb shell $c -e command clock -e hhmm 0930 >/dev/null | ||
| _adb shell $c -e command battery -e level 100 -e plugged false >/dev/null | ||
| _adb shell $c -e command network -e wifi show -e level 4 >/dev/null | ||
| _adb shell $c -e command network -e mobile show -e level 4 -e datatype none >/dev/null | ||
| _adb shell $c -e command notifications -e visible false >/dev/null | ||
| } | ||
| demo_exit() { | ||
| _adb shell am broadcast -a com.android.systemui.demo -e command exit >/dev/null 2>&1 | ||
| } |
| relaunch | ||
|
|
||
| # 1 — Home: the ring part-consumed, macros part-filled, a real breakfast | ||
| tap_id 'nav-home' 2>/dev/null |
| # whitespace truncates them into a "device not found". Match the state | ||
| # exactly so an offline/unauthorized entry, or the blank trailing line, is | ||
| # never picked. | ||
| DEVICE="${DEVICE:-$(adb devices | awk -F'\t' '$2 == "device" {print $1; exit}')}" |
| /// * the seed preset — [DemoSeedOptions.screenshots] leaves `isDemoData` | ||
| /// unset, so the demo banner stays out of the frame (see | ||
| /// `demo_mode_banner.dart`); |
The README explained what the app does but never why someone would pick it over the big-name trackers. The differentiators were real but scattered across Acknowledgments, Contributing, and Privacy, or absent entirely. Adds a compact evidence-led table between Screenshots and Key features, each row linking to its proof rather than restating the feature list that follows it. Contrast stays at category level; no competitor is named. Drops the entries the new section now covers: the "Private and free" row from the feature table, and the "Privacy first" and "No subscriptions" bullets from the detail list. Both bullets are deliberately KEPT in fastlane/metadata/android/en-US/full_description.txt, since a store shopper never sees the why table -- do not re-sync them away. Also rewrites the generic opening paragraph, and rewords the APK verification line to name the release key rather than a person.
Both still described the food database as "Open Food Facts plus USDA FDC", predating the multi-source Supabase backend that added the German Bundeslebensmittelschluessel with per-source selection in Settings. The website's closing clause called all sources "community-maintained", which is inaccurate for the BLS -- a Max Rubner-Institut product -- so that becomes "openly licensed". Also drops the personal attribution from the site tagline in favour of the developer community. The signing certificate's common name is left alone: it is read off the release cert by update-release-fingerprint.yml and has to match what apksigner prints.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 40 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
README.md:140
- The docs say “Settings → Food sources” here, but the in-app screen/label and other docs consistently call this “Food databases” (e.g. settingsFoodSourcesLabel in intl_en.arb and SPConst docs). This mismatch makes the README harder to follow when users try to find the setting.
[USDA FoodData Central](https://fdc.nal.usda.gov/), the German [BLS](https://www.blsdb.de), INDB and TBCA are where the food *data* comes from, not places your device talks to. Those datasets are ingested into the Supabase backend ahead of time ([self-hosting guide](docs/supabase-fdc-self-hosting.md)), so a search reaches that backend and stops there. Settings → Food sources chooses which of the seven datasets a search covers.
tools/adb/adb-driver.sh:29
- If no device is connected/authorized, this resolves DEVICE to an empty string, and all later
adb -s "$DEVICE" ...calls fail in ways that are hard to diagnose. Add an explicit empty check with a clear error so callers like capture-screenshots.sh fail fast.
tools/adb/capture-screenshots.sh:22 - This script is intended to produce a reproducible screenshot set, but without
-eit can continue after failed adb/tap operations and still write images (potentially of the wrong screen) without stopping. Enablingset -emakes failures fail-fast and avoids silently shipping an incorrect set.
"Nutrition tracking that stays on your phone" led with locality, which the intro paragraph, the Local-first row of the why table, and the whole Privacy section already cover three times below the fold. "Cited" is the claim nothing else in the category makes, and it points at the in-app Sources & References screen rather than repeating privacy a fourth time.
"Built in the open" was the eleventh and last row, the least-read spot in the section. Moves it to second, directly under "Free, permanently". Leads the row with translations, which are the genuinely community-run part of the project -- nine languages written on Weblate with no maintainer involvement -- rather than implying collective authorship of the app, which the commit distribution would not support. Corrects "40+ contributors" to 40: git shortlog reports 43 distinct authors, three of which are Copilot and bot accounts. Drops the now-duplicated community clause from the adjacent "Independent" row, which instead makes the sharper point that the licence leaves no exit that could paywall the project.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 40 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
tools/adb/capture-screenshots.sh:130
- Several
tap_idcalls ignore the return code (and sometimes suppress stderr), so a missing/renamed Semantics id can lead to capturing the wrong screen without any failure signal. Make these required taps fail fast.
tools/adb/capture-screenshots.sh:154 - These navigation
tap_idcalls also ignore failures, which can silently produce a mislabeled screenshot set if a nav identifier changes. Treat them as required steps and stop on failure.
lib/dev/main_screenshots.dart:17 - The doc comment says the screenshots preset leaves
isDemoData"unset", but the seeder now explicitly sets it viamarkAsDemoData: false. Update this to reflect what actually happens.
tools/adb/capture-screenshots.sh:90 shot()prints "captured" even ifscreenshotfails, so the script can silently produce missing/empty PNGs. Capture should abort (or at least report an error) when the screencap command fails.
Privacy: the "what leaves your device" table omitted images.unsplash.com. Sample meals seeded by "Try it with sample data" carry hotlinked Unsplash URLs rendered through CachedNetworkImage at display time, so a demo-mode device does talk to that host. Adds it as a fourth row, scoped to when it applies and noting nothing about the user is sent. Export: "export everything" overstated it. Water intake, fasting history, settings, and the user profile stay in Hive; CSV is narrower still, covering only intakes, activities, and tracked days. Both the why-table row and the detail bullet now list what is and isn't in the bundle. Food sources: settingsSelectableFoodSources holds five entries, not seven. INDB and TBCA exist in the schema but carry no data yet. Notifications: "no re-engagement notifications" read as absolute while a daily reminder and a fasting-completion notification both exist. Reworded to the accurate claim -- neither fires unless the user turns it on.
"Built in the open" described the process; "Community driven" names the property a reader is looking for. Swaps "written by the community" for "contributed by users" in the body so the word isn't repeated.
The section had grown to eleven rows in which the four most generic open-source claims held positions 1-4, while the three things almost nothing else in the category can say sat at 6, 9 and 11. A skimmer read four rows and got only the generic ones. The banner also reads "Free. Open. Cited." now, so a reader arrives primed for Cited and found it sixth. Reorders to lead with Cited and the eating-disorder row, and merges the duplicated pairs: "Free, permanently" absorbed "Independent", and "Local-first" absorbed "Auditable" (both had deferred to the Privacy section that follows in full thirty lines later). No claim was dropped -- "Micronutrients, unpaywalled" folded into Free as the concrete proof of what free buys, rather than standing as the only feature-level row in a values-level table, duplicating Key features one screen below. Labels are now single words in one grammar, replacing a mix of adjective, noun phrase, appositive, prepositional and adjectival-clause forms. Corrects the contributor count: "40" came from git shortlog's distinct author name strings, which double-counts people with several name/email configs and includes commits never linked to a GitHub account. The contributors API -- the same source as the avatar grid further down this README -- reports 32 accounts, 30 human. Now "over 30 developers", plus the stronger and equally checkable fact that most merged pull requests come from someone other than the maintainer.
Em dashes were doing the work of commas, colons and full stops in 33
places across the file, including three lines that stacked two. Prose
dashes are now at zero; the only ones left start the quote-attribution
lines under the reviews, where they are typographic convention.
Also removes:
- "The OpenNutriTracker project was inspired by the need for a simple
and effective nutrition tracking tool" -- every tool was inspired by
the need for that tool.
- A sentence in the APK section that restated the sentence before it,
and "reasonably" from the one before that.
- Two self-answered question pairs ("Found a bug or missing feature?",
"Written or talked about OpenNutriTracker somewhere?") in adjacent
sections, now statements.
- "Contributions are welcome!" boilerplate and "feel free to".
- Mid-sentence bold used for emphasis rather than as a label: AES-256,
Flutter and Dart, Sources & References.
The construction "no account, no subscription, no ads" appeared three
times in the first 130 lines. Privacy keeps it; the banner subline and
the why table are reworded. The subline now names the platforms instead,
which appeared nowhere outside a badge.
Screenshot caption "the shape of a month" is now "calories against your
goal", matching the plainer register of the other five.
"Free. Open. Cited." stays.
The demo meal photos ship as bundled assets since #594, so images.unsplash.com is no longer a host the app contacts. On develop, demo_content.dart leaves thumbnailImageUrl and mainImageUrl null and sets localImagePath from assets/demo/meals/, and no hotlink call remains -- the one surviving unsplashImageUrl call builds a string for the photographer-credit lookup and makes no request. Back to three destinations.
The six screenshots are shot and committed, and the tooling that produced them was only ever meant for that one pass. Keeping it means carrying a dev entry point, an ADB script and a seeder option that nobody runs and that would quietly rot against the next UI change. Removes lib/dev/main_screenshots.dart, tools/adb/capture-screenshots.sh and the `screenshots` just recipe, and reverts DemoSeedOptions to its original shape — markAsDemoData and the screenshots preset existed only to keep the demo banner out of frame. demo_seeder.dart and justfile are now byte-identical to this branch's base, so the branch no longer touches either. The screenshots themselves, the README table and the site grid all stay. tools/adb/adb-driver.sh keeps its device-detection fix: that is a general correction to a shared driver used by walk-onboarding.sh and run-branch-tests.sh, not screenshot-specific.
The privacy section said "Settings -> Food sources" while the feature list two sections up said "Settings -> Food databases". The ARB string the screen actually renders, settingsFoodSourcesLabel, is "Food databases" (the identifier says sources, the visible text does not), so the feature list and the store description were right and the privacy section was wrong.
Trends is a whole tab, the largest visual change in 2.x, and screenshot 5 of 6 — and neither the README feature list nor the Play description mentioned it once. A reader of either would not know it exists. Add it to both, in the same position and wording: streak card, calories against the goal line, macro averages, water, weight against target with weeks-to-goal, over 7/30/90 days or all history. The export claim was overstated in both, differently. The store copy promised "your full diary, activities, and custom catalogue"; the README promised custom meals, the weight log and activity templates on top of that. ExportImportBloc writes exactly four datasets — user_intake, user_activity, user_tracked_day and user_recipes — with CSV companions for the first three. The custom-meal catalogue, weight log and activity templates are not among them, and neither are profile, settings, water or fasting history. Say what the zip contains and name what stays out. full_description.txt is 3632 bytes, within Play's 4000 cap.
Summary
The README has been rewritten over this branch, and the screenshots it showed were the last piece still describing an app that no longer exists. The four images in the README and the Play listing were added in
b7573323and predate the 2.x redesign entirely — old Material 3 look, old four-tab nav, and captions (Barcode scanner,Profile) naming tabs the app no longer has. They are replaced with six captures of the current UI.Type of change
Changes
Screenshots — six captures ordered as the loop a visitor needs to understand the product: log → review → understand → track → progress → control. Home / Add food / Food detail / Diary / Trends / You.
Every shot comes from the seeded demo fixture, so the app looks like something a person actually uses. The 17 captures already sitting in
docs/ui-overhaul/could not be reused for exactly that reason — they were taken on an empty account, showing0 / 7 days on trackover a flat zero line andNothing addedunder an empty calendar. Screenshots like that argue against the app. They are deleted here.How the set was produced — a dev entry point, an ADB capture script and a
DemoSeedOptions.screenshotspreset drove the six shots, pinning theme, locale and Material You so the accent didn't come from the capture device's wallpaper (which is how the previous set came out purple). That tooling was a one-off and is removed again in99a931ad, so this PR does not add it:demo_seeder.dartandjustfileend up byte-identical to the branch base.tools/adb/adb-driver.shdoes keep a device-detection fix. It matched the serial on whitespace, which truncated space-bearing wireless-debugging serials intodevice not found, and it is a shared driver used bywalk-onboarding.shandrun-branch-tests.shrather than anything screenshot-specific.Fonts —
fonts/Fredoka.ttfis deleted in its own commit. It is not a font: the first bytes are eight newlines followed by<!DOCTYPE html>, a 306 KB GitHub HTML page saved under a.ttfname. It has been declared inpubspec.yamland bundled into every build sincef0ebc845, referenced by no code.Earlier commits on this branch rewrote the README structure, condensed the feature table and privacy section, and added the mentions, translation-status and store-review sections.
Notes for the reviewer
AppCardclipping fix in fix(ui): stop AppCard's corner radius clipping its own content #591, which has since merged, so the ordering caveat that used to sit here is resolved.docs/site/screenshots/rather than keeping a second copy.deploy-site.ymlpublishesdocs/siteas the artifact root, so the page cannot reference a path above that directory. Play keeps the full-resolution 1080x2205 set..screenshot-gridwas sized for four images; six would have landed as a ragged 4+2, so theminmaxfloor moved 180px → 240px for a clean 3x2.fastlane/metadata/android/, which carries onlyen-US.Screenshots / recordings
The six are in the diff under
docs/site/screenshots/and render in the README table on this branch.Test plan
Steps
just screenshotsboots past onboarding with no demo banner on any tab; Material You off, leaf-green accent, Trends showing a real curve rather than a flat zero line.tools/adb/capture-screenshots.shproduced all six on a Pixel 6, identical dimensions, identical pinned status bar.README.mdanddocs/site/index.htmlexists on disk, and that no reference to the deleteddocs/ui-overhaul/survives.docs/sitelocally and measured the grid: 3 columns at 1280px and 900px, 2 at 700px, 1 below 520px; no broken images, no horizontal overflow.fvm flutter analyzeclean on the two Dart files;bash -nclean on both shell scripts.Checklist
just format/ 120-char line width)Semantics(identifier: '...')where needed (n/a)lib/generated/when user-facing strings change (n/a).envvalues committed