Repository navigation
Development Setup
Source of truth: this wiki page.
- Flutter 3.47+ (ships Dart 3.13+)
- JDK 21 and the Android SDK, for Android builds
- Python 3.11+ and PyYAML, for the deck tools only
The android/ and ios/ folders are generated, not committed. Recreate them:
flutter create . --org app --project-name fluenough --platforms=android,ios
rm -f test/widget_test.dart # generated boilerplate; references MyApp, not ours
python3 tools/brand_android.py # icon, label, launch screen, permissions, updater, voice settings
flutter pub get
dart run build_runner build
flutter runThe application id is app.fluenough. Changing it later means touching the
Gradle config, the iOS bundle id and every signing setup, so do not.
On Fedora Silverblue, Kinoite, Bazzite and similar, do not layer the JDK and Android SDK onto the base image. Use a container:
distrobox create --name fluenough-dev --image fedora:latest
distrobox enter fluenough-dev
# inside: dnf install java-21-openjdk-devel, then Flutter and Android cmdline-toolsadb reaches a USB device from inside the container when /dev/bus/usb is
available; wireless debugging sidesteps the question entirely.
Three options, in descending order of usefulness:
A physical phone. The only environment with real TTS voices and a real IME. Production drills for Japanese, Chinese and Korean cannot be meaningfully tested anywhere else.
An Android emulator (AVD) with a Google APIs system image. Hardware
accelerated where /dev/kvm exists. Has real Google TTS voices. Budget 2–3 GB
of RAM.
Waydroid. Fine for UI iteration and fast to start. But Waydroid images are LineageOS-based and ship without Google Play Services, which is what provides the TTS voices — so listening drills will be silent unless you add GApps or install a standalone TTS engine APK. Never conclude that audio is broken from a Waydroid run alone.
test/accessibility_test.dart checks automatically (#26):
- Flutter's tap-target, label and WCAG AA contrast guidelines on every drill state, the four tabs and the pushed screens, in both themes
- tap targets and no clipping at font scale 2.0, Android's largest
- no answer on the screen reader's tree before it is given
- deck content in feedback marked with the deck's language
A test cannot hear a voice. After a change to a drill, run TalkBack on a phone with the deck's voice installed. Check that:
- a card's word is read in the deck's language, not English
- the feedback is announced as it appears, with the answer in the deck's language
- recognition does not read the meaning before "Show answer"
- every button says what it does
python3 tools/validate_decks.py decks/ # if you touched decks
dart format --set-exit-if-changed .
flutter analyze
flutter testCI runs all four, so do not run them for a docs-only change. Write a test only as AGENTS.md says, "Tests check behaviour".
The wiki/ folder is published to the GitHub wiki by .github/workflows/wiki-sync.yml; edits made in the wiki's web editor are overwritten by the next sync.
See also: Contributing · Home
1. Learner guides
- Learner Guide
- Getting Started
- Today and Daily Lessons
- Drills and Skills
- Courses and Paths
- Proficiency Levels
- Scripts and Readings
- Readings ISO 15919
- Speaking and Listening
- Progress and Stats
- Profiles and Settings
- Backup and Restore
- Reporting a Problem
2. Deck building guides
- Deck Building Guide
- Deck Format
- Romanising Indic Languages
- Deck Licences and Quoted Books
- Deck Tools
3. Review guides
4. Translation guide
5. Building on iOS
6. Roadmap
7. Sources and attributions
8. Contribution and agentic coding