What's Changed
- chore(deps): bump excon from 0.112.0 to 1.5.0 in /ios by @dependabot[bot] in #527
- chore(deps): bump faraday from 1.10.5 to 1.10.6 in /android by @dependabot[bot] in #526
- chore(deps): bump concurrent-ruby from 1.3.6 to 1.3.7 in /ios by @dependabot[bot] in #507
- fix(export): catch silent 0-byte export writes by @munzzyy in #513
- chore(deps): configure Dependabot to target develop branch by @simonoppowa in #528
- fix(ui): keep row titles on one line instead of wrapping by @jordan-lee-code in #536
- Add animated splash screen with logo and system integration by @simonoppowa in #529
- Apply pending macro text input in Macro Split dialog save flow by @simonoppowa with @Copilot in #525
- Fix weight logging and refresh Trends page on updates by @simonoppowa in #537
- Fix weight logging on profile update and refresh Trends page by @simonoppowa in #539
- feat(profile): add weight history range selector by @Xmemo in #508
- add bug report issue template by @simonoppowa in #544
- Fix issue with app not saving data in version 2.0.0 by @simonoppowa with @Copilot in #542
- Add year-long demo data seeder and onboarding sample data flow by @simonoppowa in #543
- feat(l10n): migrate to Flutter's built-in gen-l10n by @simonoppowa in #550
- Guard link taps in FastingWarningDialog with canLaunchUrl by @simonoppowa in #551
- Fix iOS integration test timeouts and disable SPM by @simonoppowa in #581
- docs: add contributor code of conduct by @simonoppowa in #574
- fix(ui): stop AppCard's corner radius clipping its own content by @simonoppowa in #591
- chore(deps): batch safe Dependabot bumps by @simonoppowa in #584
- fix(diary): apply day-start offset to entries, not the selected day by @simonoppowa in #588
- feat(demo): bundle demo meal photos instead of hotlinking Unsplash by @simonoppowa in #594
- ci: add newly filed issues to the project boards by @simonoppowa in #598
- docs: modernize the README and re-shoot the screenshots on 2.0.1 by @simonoppowa in #592
- feat(onboarding): rework the first-run flow by @simonoppowa in #603
- feat(add-meal): deterministic meal-text parser by @laurenlliu in #616
- feat(add-meal): resolve parsed meal items against the food search by @simonoppowa in #618
- feat(add-meal): add the multi-item review screen and entry point by @simonoppowa in #619
- fix(l10n): make the Ukrainian and Chinese bulk-add hints parseable by @simonoppowa in #624
- fix(add-meal): read a bare count as servings, not grams by @simonoppowa in #627
- test(add-meal): cover the bulk-add screen with widget tests by @simonoppowa in #630
- fix(l10n): localize the bulk-add parser errors by @simonoppowa in #632
- feat(add-meal): add a model-assisted meal-text interpreter (#633) by @simonoppowa in #636
- feat(settings): store a bring-your-own API key for AI meal assistance (#634) by @simonoppowa in #640
- feat(add-meal): read the meal line with a model when a key is configured (#635) by @simonoppowa in #643
- fix(add-meal): parse and rank languages that write without spaces (#623) by @simonoppowa in #645
- fix(add-meal): reuse one http client, and reject non-finite quantities by @simonoppowa in #644
- fix(add-meal): stop the model mis-mapping units it was not offered by @simonoppowa in #646
- fix(add-meal): trust the model when it answers "no food here" by @simonoppowa in #647
- feat(add-meal): read a meal photo into the multi-item screen (tier 2b) by @simonoppowa in #650
- feat(core): give the AI credential store a slot per provider by @simonoppowa in #674
- feat(add-meal): give OpenRouter a sibling client behind a shared schema by @simonoppowa in #673
- feat(settings): let the user pick a provider, and make OpenRouter reachable by @simonoppowa in #676
- fix(add-meal): the photo ephemerality quote omits its exception by @simonoppowa in #708
- test(add-meal): pin the client discipline every provider must obey by @simonoppowa in #707
- docs(add-meal): fix why strict is skipped, and write down the rule by @simonoppowa in #701
- fix(ci): make the pod fallback run on the bash it actually gets by @simonoppowa in #700
- refactor(add-meal): let each client classify its own failures by @simonoppowa in #699
- fix(meal-detail): read a serving the app can actually scale (#629) by @simonoppowa in #649
- feat(l10n): add the OpenAI disclosure paragraphs to all nine locales by @simonoppowa in #711
- fix(settings): open the German privacy policy, and report a link that cannot open by @simonoppowa in #714
- feat(add-meal): add OpenAiMealItemsApi, held to the client contract by @simonoppowa in #722
- feat(settings): offer OpenAI as a third AI provider by @simonoppowa in #723
- docs: re-cut the provider comparison for three providers by @simonoppowa in #724
- feat(settings): mark AI meal assistance as experimental by @simonoppowa in #725
- feat(settings): offer the OpenAI models through OpenRouter by @simonoppowa in #727
- feat(onboarding): offer AI meal assistance from Other options by @simonoppowa in #729
- refactor(core): resolve the active provider once per row refresh by @simonoppowa in #731
- fix(core): stop an unknown provider tag meaning Anthropic by @simonoppowa in #760
- feat(add-meal): point the OpenAI-compatible client at any endpoint by @simonoppowa in #761
- feat(core): store an endpoint, and generalise what "configured" means by @simonoppowa in #762
- fix(navigation): keep the stack alive when the unwind target is absent by @EugeneSusla in #718
- fix(scanner): report a not-found barcode as not found by @EugeneSusla in #712
- fix(profile): stop stone weights from showing a full stone of pounds by @munzzyy in #615
- chore(deps): consolidate Dependabot upgrades by @simonoppowa in #752
- feat(add-meal): suggest a meal type from the current time (#580) by @ibrahim-iqbal in #590
- feat: opt-in workout import from Health Connect / Apple Health by @EugeneSusla in #651
- fix(android): expose per-app language picker via localeConfig by @t-khush in #672
- feat(add-meal): send JPEG to a server the user runs by @simonoppowa in #783
- fix(add-meal): give a server the user runs time to load its model by @simonoppowa in #776
- feat(core): refuse plaintext to anything that is not private by @simonoppowa in #785
- feat(core): ask an endpoint what it can do, and remember the answer by @simonoppowa in #784
- feat(settings): offer "Your own server" in Settings by @simonoppowa in #767
- chore: remove GitHub Pages website by @simonoppowa in #786
- feat(settings): run the probe on save, and say what it found (#780) by @simonoppowa in #788
- feat(add-meal): offer the camera once photos have been proven (#781) by @simonoppowa in #789
- feat(settings): fetch the model list when asked (#757) by @simonoppowa in #787
- fix(add-meal): stop telling an empty OpenAI balance to try again later by @simonoppowa in #793
- fix(add-meal): tell a model that found nothing from one that answered nothing by @simonoppowa in #792
- style(onboarding): align a named argument with its siblings by @simonoppowa in #797
- fix(settings): read a pasted model-list URL as the base it names by @simonoppowa in #795
- fix(settings): stop a model list outliving the address it was asked for by @simonoppowa in #798
- test(settings): point the doc reference at the field that exists by @simonoppowa in #799
- feat(add-meal): take the camera away when the model stops being able to see by @simonoppowa in #800
- fix(core): read a selection as one act, the way it is written as one act by @simonoppowa in #814
- docs: say what leaves the device for a server the user runs by @simonoppowa in #815
- fix(add-meal): let the advice out of the sentence that was truncating it by @simonoppowa in #821
- fix(add-meal): stop the entry block squeezing the rows off the screen by @simonoppowa in #825
- refactor(core): give the AI disclosure one source (#834) by @simonoppowa in #837
- fix: close the review findings on the AI consent flow by @simonoppowa in #841
- fix(diary): give the weekday headings room to grow (#766) by @simonoppowa in #829
- fix(core): stop a deleted profile's reminder from outliving it (#764) by @simonoppowa in #828
- ci: bound each integration attempt so a hang can be retried (#823) by @simonoppowa in #827
- fix(add-meal): give a row's controls a line of their own (#824) by @simonoppowa in #826
- feat(add-meal): say that a model could read this (#844) by @simonoppowa in #845
- fix(add-meal): keep the brand on screen when a row is doubted (#847) by @simonoppowa in #855
- fix(add-meal): land the model-failure notice on the AI settings (#852) by @simonoppowa in #858
- fix(l10n): drop the second comma from four own-server disclosures (#849) by @simonoppowa in #857
- fix(settings): put the provider back when the dialog is dismissed (#848) by @simonoppowa in #856
- fix(settings): make the setup check own both the wait and the answer (#850, #851) by @simonoppowa in #859
- fix(settings): stop a refusal outliving the address it judged (#853) by @simonoppowa in #860
- test(core): pin the probe's verdicts and make one survive a restart (#854) by @simonoppowa in #861
- style(settings): bring the disclosure line back under 120 (#648 review) by @simonoppowa in #862
- feat(add-meal): say the word the food uses, and admit when the amount is ours by @simonoppowa in #865
- docs: a visual overview of the AI implementation, staged for the wiki by @simonoppowa in #863
- fix(core): keep the diary out of crash reports by @simonoppowa in #879
- docs: correct onboarding demo privacy-policy gate in AGENTS.md by @simonoppowa in #880
- docs: write down the parts of a release nothing automates by @simonoppowa in #866
- docs: correct what the README claims about the wire by @simonoppowa in #891
- refactor: remove the unused direct USDA FDC HTTP client and its API key by @simonoppowa in #881
- fix(core): bring main's crash-report fix and AGENTS.md correction back to develop by @simonoppowa in #893
- docs: say what happens to a fix that goes straight to main by @simonoppowa in #896
- fix(core): stop crash reports carrying a per-install identifier by @simonoppowa in #901
- docs: correct what the README claims about the wire by @simonoppowa in #899
- fix(settings): stop calling crash reports anonymous by @simonoppowa in #902
- feat(add-meal): search the food backend over a POST body, not a URL (#882) by @simonoppowa in #911
- docs: describe the real localization workflow by @simonoppowa in #904
- docs: fix the localization steps aimed at first-timers by @simonoppowa in #905
- fix(core): take the AI credentials with a profile reset (#892) by @simonoppowa in #908
- fix(core): send crash reports, not a report every time the app opens by @simonoppowa in #917
- docs: a language code leaves the device, not a country code by @simonoppowa in #916
- fix(l10n): stop telling eight languages their recipes are deleted by @simonoppowa in #918
- fix(add-meal): strip a photo's metadata when no encoder ran by @simonoppowa in #914
- feat(core): tell existing users the privacy policy changed by @simonoppowa in #921
- ci: keep a change record of the published privacy policy, and check it by @simonoppowa in #923
- fix(core): stop the health-import tombstone list growing forever by @simonoppowa in #924
- chore: bump version to 2.1.0+62 by @jordan-lee-code in #772
- docs(core): say what the policy revision constant does not prove by @simonoppowa in #928
- feat(core): say what the health import reads, and answer when Health Connect asks by @simonoppowa in #929
- ci(l10n): fail the build when a locale is missing a key by @simonoppowa in #909
- ci: stop the project-board adds racing each other by @simonoppowa in #931
- fix(ios): declare why the app may touch the local network by @simonoppowa in #932
- chore: record the published policy after the 2.1.0 clause paste by @simonoppowa in #933
- fix(core): keep a workout import inside the profile that started it by @simonoppowa in #945
- feat(core): do not show the policy-change notice for revision 1 by @simonoppowa in #955
- Release 2.1.0: workout import, crash-report and privacy-policy corrections, food search over POST by @simonoppowa in #934
- fix(ios): declare the HealthKit write purpose string TestFlight demands by @simonoppowa in #957
- fix(ios): declare the HealthKit write purpose string TestFlight demands by @simonoppowa in #958
- ci(android): tolerate the known Play health-declaration defect, nothing else by @simonoppowa in #960
- docs(android): record what the minSdk 26 floor actually costs by @simonoppowa in #961
- docs: reword the gateway retention clause so it cannot go stale by @simonoppowa in #962
- docs: say that
Fixes #Ndoes not close issues merged into develop by @simonoppowa in #964 - docs: write our own App Store Connect clause instead of iubenda's by @simonoppowa in #965
- chore: take develop, for the crash-report fixes this branch was missing by @simonoppowa in #910
- ci(ios): retry the integration suite on a second runner, not in place by @simonoppowa in #912
- fix(add-meal): stop showing an English portion word in eight other languages by @simonoppowa in #966
- feat(add-meal): show a food's portion in the reader's language by @simonoppowa in #967
- feat(add-meal): let a row pick which portion it means by @simonoppowa in #968
- feat(add-meal): let the word someone typed pick the portion by @simonoppowa in #969
- feat(add-meal): let a model name a portion, as a key and not a number by @simonoppowa in #970
- chore: take develop, resolving the conflicts #648 had accumulated by @simonoppowa in #971
- chore: record develop as an ancestor, which the squash discarded by @simonoppowa in #972
- fix(add-meal): keep an amount the app cannot vouch for out of the batch by @simonoppowa in #975
- fix(add-meal): only hold back an amount that would actually be wrong by @simonoppowa in #978
- fix(settings): offer a way to confirm a switch to a keyed provider by @simonoppowa in #980
- fix(add-meal): drop a unit the user never wrote by @simonoppowa in #981
- feat: AI-assisted meal logging — multi-item entry, offline by default, optional model and camera (#599) by @simonoppowa in #648
- fix(settings): stop the embedded form being a viewport inside a viewport by @simonoppowa in #983
- chore: bump to 2.2.0+63, and keep the feature/** trigger by @simonoppowa in #984
- fix(settings): stop the consent screen promising nothing is sent by @simonoppowa in #986
- fix(calc): apply the IOM activity coefficient to the height term too (2.2.0) by @simonoppowa in #994
- fix(net): three plaintext-guard fixes for 2.2.0, and CI on release PRs by @simonoppowa in #1004
- Release 2.2.0: AI-assisted meal logging, workout import, and the 2.1.0 work that never shipped by @simonoppowa in #988
- fix(ci): stop a skipped retry job taking the whole deploy chain with it by @simonoppowa in #1008
New Contributors
- @munzzyy made their first contribution in #513
- @simonoppowa with @Copilot made their first contribution in #525
- @Xmemo made their first contribution in #508
- @laurenlliu made their first contribution in #616
- @EugeneSusla made their first contribution in #718
- @ibrahim-iqbal made their first contribution in #590
- @t-khush made their first contribution in #672
Full Changelog: v2.0.2...v2.2.0