Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,11 @@ coverage/lcov.info
**/.idea/uiDesigner.xml

# VS Code
**/.vscode/launch.json
# VS Code (keep launch.json tracked, ignore tasks to stay client-side)
**/.vscode/extensions.json
**/.vscode/settings.json (optional - remove if you want to track workspace settings)
**/.vscode/settings.json
**/.vscode/tasks.json
tool/bootstrap.sh

# Dart Observatory/DevTools
**/observatory_tool
Expand Down
52 changes: 52 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Flutter: Android (pick device)",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"args": []
},
{
"name": "Flutter: iOS Simulator (if configured)",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"args": []
},
{
"name": "Flutter: Chrome (Web)",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"deviceId": "chrome",
"args": []
},
{
"name": "Flutter: macOS Desktop",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"deviceId": "macos",
"args": []
}
,
{
"name": "Flutter: Windows Desktop",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"deviceId": "windows",
"args": []
},
{
"name": "Flutter: Linux Desktop",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"deviceId": "linux",
"args": []
}
]
}
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ android {

defaultConfig {
applicationId "com.example.wordlist_elicitation"
minSdk 21
minSdkVersion flutter.minSdkVersion
targetSdk 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.9.0'
ext.kotlin_version = '1.9.24'
repositories {
google()
mavenCentral()
}

dependencies {
classpath "com.android.tools.build:gradle:8.1.0"
classpath "com.android.tools.build:gradle:8.5.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
5 changes: 5 additions & 0 deletions android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
9 changes: 5 additions & 4 deletions lib/providers/wordlist_provider.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/foundation.dart';
import '../utils/logger.dart';
import '../models/wordlist_entry.dart';
import '../services/database_service.dart';

Expand All @@ -25,8 +26,8 @@ class WordlistProvider extends ChangeNotifier {
try {
_entries = await _db.getAllWordlistEntries();
_currentIndex = 0;
} catch (e) {
print('Error loading wordlist: $e');
} catch (e, st) {
Log.e('Error loading wordlist', e, st);
} finally {
_isLoading = false;
notifyListeners();
Expand All @@ -41,8 +42,8 @@ class WordlistProvider extends ChangeNotifier {
_entries[index] = entry;
notifyListeners();
}
} catch (e) {
print('Error updating entry: $e');
} catch (e, st) {
Log.e('Error updating entry', e, st);
}
}

Expand Down
5 changes: 2 additions & 3 deletions lib/services/export_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import 'dart:io';
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
import 'package:archive/archive_io.dart';
import '../models/wordlist_entry.dart';
import '../models/consent_record.dart';
import 'xml_service.dart';
import 'database_service.dart';

Expand All @@ -26,7 +24,8 @@ class ExportService {
final entries = await _db.getAllWordlistEntries();
final xmlContent = await _xmlService.exportDekerekeXml(entries);
final xmlFile = File('${exportDir.path}/wordlist_data.xml');
await xmlFile.writeAsString(xmlContent, encoding: utf16);
// Write XML as UTF-8 (standard, widely compatible). Ensure XML header matches.
await xmlFile.writeAsString(xmlContent, encoding: utf8);

// 2. Copy audio files
final audioExportDir = Directory('${exportDir.path}/audio');
Expand Down
10 changes: 6 additions & 4 deletions lib/services/xml_service.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:xml/xml.dart';
import '../utils/logger.dart';
import '../models/wordlist_entry.dart';
import 'database_service.dart';

Expand Down Expand Up @@ -44,8 +45,8 @@ class XmlImportService {

await _db.insertWordlistEntry(entry);
importCount++;
} catch (e) {
print('Error parsing entry: $e');
} catch (e, st) {
Log.w('Error parsing entry', e, st);
// Continue with next entry
}
}
Expand All @@ -60,8 +61,9 @@ class XmlImportService {

/// Export to Dekereke XML format
Future<String> exportDekerekeXml(List<WordlistEntry> entries) async {
final builder = XmlBuilder();
builder.processing('xml', 'version="1.0" encoding="UTF-16"');
final builder = XmlBuilder();
// Match the file write encoding (UTF-8)
builder.processing('xml', 'version="1.0" encoding="UTF-8"');

builder.element('Wordlist', nest: () {
for (final entry in entries) {
Expand Down
30 changes: 30 additions & 0 deletions lib/utils/logger.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter/foundation.dart';

/// Tiny logging helper that is safe for production (no prints) and
/// concise for development. Uses debugPrint to avoid console flooding.
class Log {
static void d(String message) {
if (kDebugMode) debugPrint('[DEBUG] $message');
}

static void i(String message) {
debugPrint('[INFO] $message');
}

static void w(String message, [Object? error, StackTrace? stackTrace]) {
final suffix = _formatSuffix(error, stackTrace);
debugPrint('[WARN] $message$suffix');
}

static void e(String message, [Object? error, StackTrace? stackTrace]) {
final suffix = _formatSuffix(error, stackTrace);
debugPrint('[ERROR] $message$suffix');
}

static String _formatSuffix(Object? error, StackTrace? stackTrace) {
final parts = <String>[];
if (error != null) parts.add(error.toString());
if (stackTrace != null) parts.add('\n$stackTrace');
return parts.isEmpty ? '' : ' :: ${parts.join(' :: ')}';
}
}
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ dependencies:
archive: ^3.4.9

# Audio Recording & Playback
record: ^5.0.4
record: ^6.1.2
audioplayers: ^5.2.1
permission_handler: ^11.1.0

# UI Components
intl: ^0.18.1
intl: ^0.20.2
share_plus: ^7.2.1

dev_dependencies:
Expand Down
Binary file modified test_data/sample_wordlist.xml
Binary file not shown.