Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
analyze-and-test:
name: Analyze & test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.35.6
cache: true

- name: Install dependencies
run: flutter pub get

- name: Analyze
run: flutter analyze

- name: Run tests
run: flutter test

build-apk:
name: Build APK
runs-on: ubuntu-latest
needs: analyze-and-test
steps:
- uses: actions/checkout@v4

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'

- uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.35.6
cache: true

- name: Install dependencies
run: flutter pub get

# Release build signed with debug keys (see android/app/build.gradle.kts),
# suitable for sideloading onto fieldwork devices.
- name: Build release APK
run: flutter build apk --release

- name: Upload APK artifact
uses: actions/upload-artifact@v4
with:
name: wordlist-elicitation-apk
path: build/app/outputs/flutter-apk/app-release.apk
retention-days: 30
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ audio/*.*

# Package Files #
*.jar
# ...but the Gradle wrapper jar must be committed so CI can build
!android/gradle/wrapper/gradle-wrapper.jar
*.war
*.nar
*.ear
Expand All @@ -49,7 +51,6 @@ replay_pid*

# Flutter/Dart/Pub related
**/build/
**/pubspec.lock
**/.dart_tool/
**/.flutter-plugins
**/.flutter-plugins-dependencies
Expand All @@ -76,8 +77,6 @@ replay_pid*
**/android/app/release
**/android/.gradle/
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
Expand Down Expand Up @@ -126,6 +125,8 @@ test/.test_coverage.dart
coverage/lcov.info

# IntelliJ/Android Studio
.idea/
*.iml
**/.idea/workspace.xml
**/.idea/tasks.xml
**/.idea/gradle.xml
Expand Down
20 changes: 15 additions & 5 deletions .metadata
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.

version:
revision: "stable"
revision: "9f455d2486bcb28cad87b062475f42edc959f636"
channel: "stable"

project_type: app
Expand All @@ -13,8 +13,18 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: stable
base_revision: stable
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: android
create_revision: stable
base_revision: stable
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
45 changes: 43 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed - Make the app actually work (2026-07)
- **XML import rewritten for the real Dekereke format.** The importer now
reads the actual QWOM data file: UTF-16 little-endian encoding (with BOM
detection for UTF-16 LE/BE and UTF-8) and the `<phon_data>/<data_form>`
record structure. Previously the app expected a `<Wordlist>/<Entry>`
structure that real data files do not use, and read UTF-16 files as
UTF-8, so imports of real data failed entirely. The simplified structure
is still accepted for test files.
- **Duplicate/failed inserts fixed.** Entries were inserted with an explicit
`id: 0` for every row, breaking SQLite auto-increment. Ids are now
auto-assigned, references are enforced UNIQUE at the schema level
(v2 migration included), imports run in a single transaction, and
duplicate references within a file are skipped with a report.
- **Compile error fixed.** The export service referenced a nonexistent
`utf16` codec; export now writes real UTF-16 LE bytes with BOM.
- **Export ZIP layout fixed.** Contents are no longer nested inside an
`export_temp/` folder; stale export archives are cleaned up; the consent
log is always included.
- **Elicitation session resume.** Revisiting a completed word now shows its
saved transcription and recording (previously fields were blank);
sessions resume at the first incomplete word; recordings in progress are
stopped on save and discarded on navigation.
- **Recording filenames.** Recordings use the wordlist-assigned
`<SoundFile>` name (e.g. `0002skin.wav`), with sanitized fallback names
for glosses containing spaces or punctuation.
- **Android project made buildable.** The android/ scaffold was missing the
Gradle wrapper, resources, and launch themes; it has been regenerated
(minSdk 23 for the audio recorder) and CI now builds APK artifacts.

### Added
- Consent screen (written + optional verbal recording) gating elicitation,
with persistent consent log — an MVP ethics requirement.
- Merge-on-import option that updates the wordlist while preserving
collected transcriptions and recordings.
- Indonesian and Tok Pisin gloss display on the elicitation screen.
- Picture display when researcher-supplied images exist under
`<app documents>/pictures/`.
- Comprehensive test suite (XML parsing/round-trip, UTF-16 handling,
database migration, duplicate prevention, provider logic, widget smoke
tests) runnable headless in CI.
- GitHub Actions workflow: analyze, test, and APK artifact builds.

### Planned Features
- Consent screen UI with verbal/written options
- LIFT XML export format support
- Image display for wordlist entries with Picture field
- Cloud sync capabilities
- Custom font integration (Charis SIL, Doulos SIL)
- Enhanced keyboard support for IPA input
- Data validation and quality checks
- Batch import/export operations
- Configurable consent text (per-language, via bundling wizard)

## [1.0.0] - 2024-10-12

Expand Down
43 changes: 24 additions & 19 deletions FLUTTER_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,41 +147,46 @@ The app follows Clean Architecture principles with:

## XML Format

### Dekereke XML Import Structure
```xml
<Wordlist>
<Entry>
<Reference>0001</Reference>
<Gloss>body</Gloss>
<Picture>optional_image.jpg</Picture>
</Entry>
</Wordlist>
```
The app reads and writes the real Dekereke XML structure used by the
[QWOM data file](https://github.com/rulingAnts/QWOM_Data): a UTF-16
little-endian file with a `<phon_data>` root containing one `<data_form>`
record per word. All fields in each record are preserved on import and
written back on export, with `<Phonetic>` filled from the collected
transcription and `<SoundFile>` pointing at the recorded WAV file.

### Dekereke XML Export Structure
```xml
<Wordlist>
<Entry>
<?xml version="1.0" encoding="utf-16" standalone="yes" ?>
<phon_data>
<data_form>
<Reference>0001</Reference>
<CAWL>1</CAWL>
<Category>N</Category>
<Gloss>body</Gloss>
<LocalWord>IPA transcription</LocalWord>
<SoundFile>0001body.wav</SoundFile>
<Picture>optional_image.jpg</Picture>
</Entry>
</Wordlist>
<Image_File>0001body.png</Image_File>
<GlossTokPisin>bodi</GlossTokPisin>
<GlossIndonesian>tubuh, badan</GlossIndonesian>
<Phonetic>bɔdi</Phonetic>
<SemanticDomain>Body parts</SemanticDomain>
...
</data_form>
</phon_data>
```

A simplified `<Wordlist>/<Entry>` structure (Reference/Gloss/Picture) is
also accepted for hand-made test files, and UTF-8 files are detected
automatically.

## Future Enhancements

### Planned Features (Phase 2+)
- [ ] Consent screen UI for verbal/written consent
- [ ] LIFT XML export format
- [ ] Image display for wordlist entries
- [ ] Cloud sync capabilities
- [ ] Custom font integration (Charis SIL, Doulos SIL)
- [ ] Enhanced keyboard support (Keyman integration)
- [ ] Offline-first architecture improvements
- [ ] Data validation and quality checks
- [ ] Configurable consent text (per-language, via bundling wizard)

## License

Expand Down
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,22 @@ This documentation, including the project goals, feature set, and technical scop

---

## 🚧 Project Status: Seeking Initial Contributors 🚀

**This project is currently in the conceptual and planning phase.** We are actively seeking **Android Developers** interested in linguistic fieldwork and open-source software to help build the initial application structure and core features. If you are looking for a high-impact project, please check the **Issues** tab to see initial feature discussions!
## 🚧 Project Status: Working MVP (Flutter) 🚀

**A working Flutter implementation now lives in this repository** covering the
MVP feature set: Dekereke XML import/export (real `phon_data`/`data_form`
format, UTF-16), audio recording with correct WAV naming, session resume,
informed-consent capture, and ZIP export. See [FLUTTER_README.md](FLUTTER_README.md)
for developer documentation and [CHANGELOG.md](CHANGELOG.md) for what has been
fixed and added.

**Getting an APK without building locally:** every push to `main` runs the
[GitHub Actions CI workflow](.github/workflows/ci.yml), which analyzes, tests,
and builds an installable APK. Open the repository's **Actions** tab, select
the latest successful run, and download the `wordlist-elicitation-apk`
artifact for sideloading.

Contributions remain very welcome — check the **Issues** tab!

## Core Features and Technical Scope (MVP Focus)

Expand Down
14 changes: 14 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
Comment on lines +1 to +6
GeneratedPluginRegistrant.java
.cxx/

# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
61 changes: 0 additions & 61 deletions android/app/build.gradle

This file was deleted.

Loading
Loading