Skip to content

Development Setup

github-actions[bot] edited this page Oct 22, 2026 · 1 revision

Development setup

Source of truth: this wiki page.

Requirements

  • 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

First checkout

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 run

The application id is app.fluenough. Changing it later means touching the Gradle config, the iOS bundle id and every signing setup, so do not.

Immutable Linux distributions

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-tools

adb reaches a USB device from inside the container when /dev/bus/usb is available; wireless debugging sidesteps the question entirely.

Testing on a device

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.

Accessibility

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

Before opening a pull request

python3 tools/validate_decks.py decks/   # if you touched decks
dart format --set-exit-if-changed .
flutter analyze
flutter test

CI 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

Clone this wiki locally