Thanks for taking an interest in contributing! This guide covers the conventions you need to follow so your pull request can be merged smoothly.
For environment setup (Flutter / Android SDK / IDE), see GettingStarted.md.
Looking for a small first contribution? See the seed list in docs/first-timer-backlog.md — concrete “good first issue” ideas with file paths and acceptance criteria. Agent and architecture conventions live in AGENTS.md.
All pull requests must target the develop branch, not main.
main is reserved for release merges only — it receives a single batched develop → main PR per release. If you open a PR against main, a maintainer will repoint it to develop before review.
- Check the public board before picking something up — it shows what is already in progress, so you don't duplicate work that is underway.
- Create your branch from the latest
develop:git fetch origin git checkout -b feature/<short-name> origin/develop
- Keep changes scoped. Smaller, focused PRs are easier to review and faster to merge than sweeping ones.
- If you are fixing or implementing an open issue, mention it in the PR description (e.g.
Closes #123).
Source strings live in lib/l10n/intl_en.arb. Translations live in a separate ARB file per supported locale, plus manually-maintained Dart files under lib/generated/.
Important
For now, the files under lib/generated/ carry a // GENERATED CODE - DO NOT MODIFY BY HAND header but are maintained manually in this project — the upstream generator's output conflicts with the repo's 120-character formatting and would fail CI. Until the generation pipeline is reconciled with the formatting rules, edit those files by hand. Do not run intl_translation:generate_from_arb — this caveat will go away once the generator output is fixed.
When adding a new string key in the same PR you must:
-
Add the key to every ARB file under
lib/l10n/. The currently supported locales are:File Language intl_en.arbEnglish (source) intl_de.arbGerman intl_cs.arbCzech intl_it.arbItalian intl_pl.arbPolish intl_sk.arbSlovak intl_tr.arbTurkish intl_uk.arbUkrainian intl_zh.arbChinese (Simplified) Provide a real translation for each locale — do not leave the English string in as a placeholder. If you only speak one of the languages, machine translation is acceptable as a starting point; native-speaker review is welcome post-merge.
-
Add a getter to
lib/generated/l10n.dart, following the existing style. -
Add a matching
MessageLookupByLibrary.simpleMessage(...)entry to eachlib/generated/intl/messages_<locale>.dartfile, one per locale. -
Verify with
just check_intl— this is what CI runs and will fail the PR if any of the above is missing or out of sync.
Some files are produced by build_runner (Hive type adapters and JSON serialization). Run just build after touching any @HiveType, @HiveField, or @JsonSerializable source file. See AGENTS.md for the full list of triggers.
- 120-character line width (configured in
analysis_options.yaml). - Format with
just formatbefore committing — this targets onlylib/core,lib/features,lib/l10n, andtestand deliberately skipslib/generated/. - Run
flutter analyzeandjust testlocally before opening the PR. just ciruns the full CI pipeline (install, format check, intl check, build, analyze, test) and is the closest thing to a one-shot pre-flight check.
Use a short imperative subject line, optionally with a type(scope): prefix. Examples:
feat(activity): add high-intensity interval exercise
fix(home): correct kcal budget after onboarding
i18n(activity): wire HIIT codes 02210/02214 to translated strings
A body explaining the why is welcome but not required for small changes.
OpenNutriTracker ships on both iOS and Android. Any new dependency must support both platforms — check pub.dev before adding. Any platform-specific code must have a corresponding implementation for the other platform (or an explicit fallback). New runtime permissions on Android need a matching Info.plist entry on iOS, and vice versa.
If you're unsure about anything, open a draft PR or an issue and ask — early feedback is much cheaper than reworking a finished change.