A spaced-repetition flashcard app for learning Armenian vocabulary. Study anywhere with full offline support—no internet required. Tested on iPhone (physical device).
Offline-first architecture: All data persists locally in SQLite. Fully functional without internet.
lib/
├── core/
│ ├── constants.dart # GradeConfig, AppColors, asset paths
│ └── utils/
│ ├── hash.dart # SHA-256 externalRowId
│ └── slug.dart # URL-safe deck slugs
├── domain/srs/
│ ├── fsrs.dart # FSRS scheduler (SM-2 variant, pure Dart)
│ └── mastery.dart # Bidirectional mastery gate
├── data/
│ ├── database/app_database.dart # SQLite singleton, DDL, migrations
│ ├── models/ # deck, card, card_state, review_log
│ ├── repositories/ # deck, card, card_state, review_log
│ └── csv/
│ ├── csv_parser.dart # 7-col / 8-col Armenian Anki CSV
│ └── csv_exporter.dart # Export to 8-col CSV
├── presentation/
│ ├── providers/ # Riverpod: deck, card, study
│ ├── screens/ # home, study, deck_detail, settings
│ └── widgets/ # flashcard, grade_buttons, deck_list_tile
├── services/
│ ├── sample_deck_service.dart # Idempotent Hayeren 1 installer
│ └── backup_service.dart # Phase 2: Google Drive backup/restore
├── app.dart # MaterialApp, Material 3 theme
└── main.dart # ProviderScope entry point
State management: flutter_riverpod — AsyncNotifier + FamilyAsyncNotifier
Persistence: sqflite + path_provider, versioned migrations
SRS: Direct Dart port of fsrs.ts + mastery.ts from the Next.js repo
| Tool | Minimum version |
|---|---|
| Flutter | 3.16 |
| Dart | 3.2 |
| Xcode | 15 (iOS 13.0+ deployment target) |
| Android Studio | Hedgehog / minSdkVersion 21 |
cd armenian_anki_flutter
flutter pub getcd ios && pod install && cd ..
open ios/Runner.xcworkspaceIn Xcode:
- Select the Runner target → Signing & Capabilities
- Set Team to your Personal Team (free Apple ID is sufficient for simulator/device)
- Change Bundle Identifier to something unique, e.g.
com.yourname.armenianAnki - Close Xcode, then:
flutter run # simulator or connected device
flutter build ipa # release IPA (paid account required for distribution)flutter emulators # list available emulators
flutter emulators --launch <emulator_id> # start one
flutter run # hot-reload debug run
flutter build apk --release # release APK
flutter build appbundle --release # App Bundle for Play StoreRelease APK is written to build/app/outputs/flutter-apk/app-release.apk.
flutter test| File | What it covers |
|---|---|
test/fsrs_test.dart |
Lapse path, SM-2 interval progressions, ease clamping |
test/mastery_test.dart |
Forward/reverse flag transitions, mastery gate |
test/csv_parser_test.dart |
7-col/8-col parsing, comment stripping, bad input |
Armenian Script | Translit. | English Meaning | Example Sentence + [Translation] | Grammar | Cheat Phrase | Topic
Difficulty | Armenian Script | Translit. | English Meaning | Example Sentence + [Translation] | Grammar | Cheat Phrase | Topic
Example sentence cell format: Armenian sentence. - [English Translation]
A sample file is bundled at assets/samples/hayeren1.csv and can be installed from Settings → Install Hayeren 1 Deck.
| Grade | Label | Effect |
|---|---|---|
| 0 | Again | Lapse: interval = 1 day, ease − 0.20, resets direction-learned flag |
| 1 | Hard | Correct: ease − 0.14 |
| 2 | Good | Correct: ease unchanged |
| 3 | Easy | Correct: ease + 0.10 |
Ease factor is clamped to [1.3, 2.5]. A card is mastered when both forward (Armenian → English) and reverse (English → Armenian) have been answered correctly (grade ≥ 1) at least once.
Implemented in lib/services/backup_service.dart, surfaced in Settings → Google Drive Backup.
The core app works fully offline; signing in is optional.
- Enable the Google Drive API.
- Create OAuth 2.0 Client IDs for iOS and Android.
- iOS: Download
GoogleService-Info.plist, add to the Xcode Runner target, and add the reversed client ID toInfo.plistURL schemes. - Android: Download
google-services.json, place inandroid/app/, and apply thecom.google.gms.google-servicesGradle plugin.
Backup stores all four tables (decks, cards, card_states, review_logs) as a single JSON file in the Drive appDataFolder (hidden from the user's Drive UI).
