Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
749b4a4
feat: Add speech-to-text functionality with language preferences
ibrahimozkn Nov 17, 2025
7c1b7b7
feat: Implement speech-to-text WebSocket reconnection
ibrahimozkn Nov 20, 2025
ea0facd
chore: Apply static analysis changes
ibrahimozkn Nov 20, 2025
fa976e1
Merge branch 'dev' into feat/stt
ibrahimozkn Nov 20, 2025
444d804
refactor: remove speech-to-text language selection and persistence fu…
ibrahimozkn Nov 20, 2025
d6ace17
feat: Add `STUDYU_STT_WEBSOCKET_URL` environment variable for Speech-…
ibrahimozkn Nov 20, 2025
a45f4a1
lint: Apply final newline changes
ibrahimozkn Nov 20, 2025
d5e69d0
refactor: Add WebSocket STT server URL validation and remove redundan…
ibrahimozkn Nov 21, 2025
b7dbe42
Merge branch 'dev' into feat/stt
ibrahimozkn Nov 25, 2025
ab07ca7
feat: Enhance free text question UI with continuous speech-to-text in…
ibrahimozkn Nov 28, 2025
d4c751b
refactor: improve WebSocket error logging and update InputDecoration …
ibrahimozkn Nov 28, 2025
10e21ba
chore: Apply static analysis changes
ibrahimozkn Nov 28, 2025
ef579dd
Update app/lib/services/speech/websocket_speech_controller_io.dart
ibrahimozkn Nov 28, 2025
bec2a5d
Update app/lib/widgets/questionnaire/questions/free_text_question_wid…
ibrahimozkn Nov 28, 2025
84c8724
Update app/ios/Runner/Info.plist
ibrahimozkn Nov 28, 2025
0076519
chore: Apply static analysis changes
ibrahimozkn Nov 28, 2025
1dd6e6f
feat: Add localization for speech-to-text connection errors and stop …
ibrahimozkn Nov 28, 2025
fe60bd2
refactor: Introduce constants for reconnection and EOF delays and add…
ibrahimozkn Nov 28, 2025
c02720a
Merge branch 'dev' into feat/stt
ibrahimozkn Jan 10, 2026
17c785c
Merge branch 'dev' into feat/stt
ibrahimozkn Jan 29, 2026
4cb371d
Merge branch 'dev' into feat/stt
johannesvedder Feb 25, 2026
07f3327
Merge branch 'dev' into feat/stt
ibrahimozkn Mar 7, 2026
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
1 change: 1 addition & 0 deletions app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

<!-- Begin flutter_local_notifications -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Expand Down
2 changes: 2 additions & 0 deletions app/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for speech input and study recordings.</string>
<key>NSCameraUsageDescription</key>
<string>Need to access your camera to capture a photo for trial observations.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
Expand Down
31 changes: 30 additions & 1 deletion app/lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@
}
}
},
"free_text_answer_hint": "Geben Sie Ihre Antwort hier ein...",
"app_outdated_message": "Eine neue Version der StudyU App ist verfügbar. Bitte führen Sie eine Aktualisierung durch, um die neuesten Funktionen und Verbesserungen zu erhalten. Vielen Dank für Ihre Unterstützung!",
"update_now": "Jetzt aktualisieren",

Expand Down Expand Up @@ -455,5 +456,33 @@
"preview_mode_description": "Sie befinden sich derzeit im Vorschau-Modus. Dies ermöglicht Ihnen:\n\n• Schneller Vorlauf durch Studientage mit der \"Nächster Tag\" Schaltfläche\n• Mehrfaches Abschließen von Aufgaben ohne Einschränkungen\n• Erleben des vollständigen Studienablaufs ohne Beeinflussung echter Daten\n\nWichtig: Ergebnisse und Daten aus dem Vorschau-Modus werden nicht gespeichert oder mit tatsächlichen Teilnehmerergebnissen aus laufenden Studien vermischt.",
"preview_mode_results_not_saved": "Ergebnisse werden zum Schutz der Studienintegrität nicht gespeichert.",
"ok": "OK",
"submit" : "Absenden"
"submit" : "Absenden",
"speech_to_text_title": "Sprach-zu-Text",
"speech_to_text_description": "Diktiere Antworten mit der integrierten Spracherkennung deines Geräts. Die Verarbeitung übernimmt der Plattformdienst.",
"speech_to_text_enable_label": "Sprach­eingabe aktivieren",
"speech_to_text_enable_hint": "Tippen funktioniert weiterhin, falls das Mikrofon blockiert ist.",
"speech_to_text_language_label": "Bevorzugte Transkriptionssprache",
"speech_to_text_language_english": "Englisch",
"speech_to_text_language_german": "Deutsch",
"speech_to_text_not_enabled": "Die Sprach­eingabe bleibt deaktiviert, bis du sie einschaltest.",
"speech_to_text_not_enabled_brief": "Sprach­eingabe ist für dein Konto ausgeschaltet.",
"speech_to_text_go_to_settings": "In den Einstellungen verwalten",
"speech_to_text_unsupported": "Sprach­eingabe ist auf diesem Gerät nicht verfügbar.",
"speech_to_text_error_permission": "Bitte erlaube den Mikrofonzugriff, um diktieren zu können.",
"speech_to_text_error_general": "Sprach­eingabe fehlgeschlagen. Bitte erneut versuchen.",
"speech_to_text_error_connection": "Verbindung verloren. Bitte erneut versuchen.",
"speech_to_text_preparing": "Spracherkennung wird vorbereitet…",
"speech_to_text_live_caption_hint": "Live-Transkription",
"speech_to_text_listening": "Es wird zugehört…",
"speech_to_text_press_to_speak": "Zum Sprechen drücken",
"speech_to_text_idle": "Sprach­eingabe starten",
"speech_to_text_stop_listening": "Zuhören stoppen",
"speech_to_text_opt_out_action": "Sprach­eingabe deaktivieren",
"speech_to_text_enable_short_label": "Wieder aktivieren",
"speech_to_text_language_badge": "{language}",
"@speech_to_text_language_badge": {
"placeholders": {
"language": {}
}
}
}
31 changes: 30 additions & 1 deletion app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
}
}
},
"free_text_answer_hint": "Type your answer here...",
"app_outdated_message": "A new version of the StudyU App is available. Please update to get the latest features and improvements. Thank you for your support!",
"update_now": "Update now",

Expand Down Expand Up @@ -451,5 +452,33 @@
"preview_mode_description": "You are currently in preview mode. This allows you to:\n\n• Fast-forward through study days using the \"Next Day\" button\n• Complete tasks multiple times without restrictions\n• Experience the full study flow without affecting real data\n\nImportant: Results and data from preview mode are not stored or mixed with actual participant results from running studies.",
"preview_mode_results_not_saved": "Task completed in preview mode - results are not saved to protect study data integrity.",
"ok": "OK",
"submit" : "Submit"
"submit" : "Submit",
"speech_to_text_title": "Speech to text",
"speech_to_text_description": "Dictate answers with your device's built-in speech recognition. Audio always stays with the platform service.",
"speech_to_text_enable_label": "Enable speech input",
"speech_to_text_enable_hint": "Typing continues to work even if the microphone is unavailable.",
"speech_to_text_language_label": "Preferred transcription language",
"speech_to_text_language_english": "English",
"speech_to_text_language_german": "German",
"speech_to_text_not_enabled": "Speech input stays disabled until you turn it on.",
"speech_to_text_not_enabled_brief": "Speech input is currently turned off for your account.",
"speech_to_text_go_to_settings": "Manage in Settings",
"speech_to_text_unsupported": "Speech input is unavailable on this device.",
"speech_to_text_error_permission": "Microphone permission is required for speech input.",
"speech_to_text_error_general": "Speech input failed. Please try again.",
"speech_to_text_error_connection": "Connection lost. Please try again.",
"speech_to_text_preparing": "Preparing speech recognizer…",
"speech_to_text_live_caption_hint": "Live transcription",
"speech_to_text_listening": "Listening…",
"speech_to_text_press_to_speak": "Press to speak",
"speech_to_text_idle": "Start speech input",
"speech_to_text_stop_listening": "Stop listening",
"speech_to_text_opt_out_action": "Disable speech input for now",
"speech_to_text_enable_short_label": "Enable again",
"speech_to_text_language_badge": "{language}",
"@speech_to_text_language_badge": {
"placeholders": {
"language": {}
}
}
}
144 changes: 144 additions & 0 deletions app/lib/l10n/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,12 @@ abstract class AppLocalizations {
/// **'Please enter only characters matching the pattern {pattern}'**
String free_text_custom_error(String pattern);

/// No description provided for @free_text_answer_hint.
///
/// In en, this message translates to:
/// **'Type your answer here...'**
String get free_text_answer_hint;

/// No description provided for @app_outdated_message.
///
/// In en, this message translates to:
Expand Down Expand Up @@ -2251,6 +2257,144 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Submit'**
String get submit;

/// No description provided for @speech_to_text_title.
///
/// In en, this message translates to:
/// **'Speech to text'**
String get speech_to_text_title;

/// No description provided for @speech_to_text_description.
///
/// In en, this message translates to:
/// **'Dictate answers with your device\'s built-in speech recognition. Audio always stays with the platform service.'**
String get speech_to_text_description;

/// No description provided for @speech_to_text_enable_label.
///
/// In en, this message translates to:
/// **'Enable speech input'**
String get speech_to_text_enable_label;

/// No description provided for @speech_to_text_enable_hint.
///
/// In en, this message translates to:
/// **'Typing continues to work even if the microphone is unavailable.'**
String get speech_to_text_enable_hint;

/// No description provided for @speech_to_text_language_label.
///
/// In en, this message translates to:
/// **'Preferred transcription language'**
String get speech_to_text_language_label;

/// No description provided for @speech_to_text_language_english.
///
/// In en, this message translates to:
/// **'English'**
String get speech_to_text_language_english;

/// No description provided for @speech_to_text_language_german.
///
/// In en, this message translates to:
/// **'German'**
String get speech_to_text_language_german;

/// No description provided for @speech_to_text_not_enabled.
///
/// In en, this message translates to:
/// **'Speech input stays disabled until you turn it on.'**
String get speech_to_text_not_enabled;

/// No description provided for @speech_to_text_not_enabled_brief.
///
/// In en, this message translates to:
/// **'Speech input is currently turned off for your account.'**
String get speech_to_text_not_enabled_brief;

/// No description provided for @speech_to_text_go_to_settings.
///
/// In en, this message translates to:
/// **'Manage in Settings'**
String get speech_to_text_go_to_settings;

/// No description provided for @speech_to_text_unsupported.
///
/// In en, this message translates to:
/// **'Speech input is unavailable on this device.'**
String get speech_to_text_unsupported;

/// No description provided for @speech_to_text_error_permission.
///
/// In en, this message translates to:
/// **'Microphone permission is required for speech input.'**
String get speech_to_text_error_permission;

/// No description provided for @speech_to_text_error_general.
///
/// In en, this message translates to:
/// **'Speech input failed. Please try again.'**
String get speech_to_text_error_general;

/// No description provided for @speech_to_text_error_connection.
///
/// In en, this message translates to:
/// **'Connection lost. Please try again.'**
String get speech_to_text_error_connection;

/// No description provided for @speech_to_text_preparing.
///
/// In en, this message translates to:
/// **'Preparing speech recognizer…'**
String get speech_to_text_preparing;

/// No description provided for @speech_to_text_live_caption_hint.
///
/// In en, this message translates to:
/// **'Live transcription'**
String get speech_to_text_live_caption_hint;

/// No description provided for @speech_to_text_listening.
///
/// In en, this message translates to:
/// **'Listening…'**
String get speech_to_text_listening;

/// No description provided for @speech_to_text_press_to_speak.
///
/// In en, this message translates to:
/// **'Press to speak'**
String get speech_to_text_press_to_speak;

/// No description provided for @speech_to_text_idle.
///
/// In en, this message translates to:
/// **'Start speech input'**
String get speech_to_text_idle;

/// No description provided for @speech_to_text_stop_listening.
///
/// In en, this message translates to:
/// **'Stop listening'**
String get speech_to_text_stop_listening;

/// No description provided for @speech_to_text_opt_out_action.
///
/// In en, this message translates to:
/// **'Disable speech input for now'**
String get speech_to_text_opt_out_action;

/// No description provided for @speech_to_text_enable_short_label.
///
/// In en, this message translates to:
/// **'Enable again'**
String get speech_to_text_enable_short_label;

/// No description provided for @speech_to_text_language_badge.
///
/// In en, this message translates to:
/// **'{language}'**
String speech_to_text_language_badge(Object language);
}

class _AppLocalizationsDelegate
Expand Down
83 changes: 83 additions & 0 deletions app/lib/l10n/app_localizations_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,9 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Bitte geben Sie nur Zeichen ein, die dem Muster $pattern entsprechen';
}

@override
String get free_text_answer_hint => 'Geben Sie Ihre Antwort hier ein...';

@override
String get app_outdated_message =>
'Eine neue Version der StudyU App ist verfügbar. Bitte führen Sie eine Aktualisierung durch, um die neuesten Funktionen und Verbesserungen zu erhalten. Vielen Dank für Ihre Unterstützung!';
Expand Down Expand Up @@ -1166,4 +1169,84 @@ class AppLocalizationsDe extends AppLocalizations {

@override
String get submit => 'Absenden';

@override
String get speech_to_text_title => 'Sprach-zu-Text';

@override
String get speech_to_text_description =>
'Diktiere Antworten mit der integrierten Spracherkennung deines Geräts. Die Verarbeitung übernimmt der Plattformdienst.';

@override
String get speech_to_text_enable_label => 'Sprach­eingabe aktivieren';

@override
String get speech_to_text_enable_hint =>
'Tippen funktioniert weiterhin, falls das Mikrofon blockiert ist.';

@override
String get speech_to_text_language_label =>
'Bevorzugte Transkriptionssprache';

@override
String get speech_to_text_language_english => 'Englisch';

@override
String get speech_to_text_language_german => 'Deutsch';

@override
String get speech_to_text_not_enabled =>
'Die Sprach­eingabe bleibt deaktiviert, bis du sie einschaltest.';

@override
String get speech_to_text_not_enabled_brief =>
'Sprach­eingabe ist für dein Konto ausgeschaltet.';

@override
String get speech_to_text_go_to_settings => 'In den Einstellungen verwalten';

@override
String get speech_to_text_unsupported =>
'Sprach­eingabe ist auf diesem Gerät nicht verfügbar.';

@override
String get speech_to_text_error_permission =>
'Bitte erlaube den Mikrofonzugriff, um diktieren zu können.';

@override
String get speech_to_text_error_general =>
'Sprach­eingabe fehlgeschlagen. Bitte erneut versuchen.';

@override
String get speech_to_text_error_connection =>
'Verbindung verloren. Bitte erneut versuchen.';

@override
String get speech_to_text_preparing => 'Spracherkennung wird vorbereitet…';

@override
String get speech_to_text_live_caption_hint => 'Live-Transkription';

@override
String get speech_to_text_listening => 'Es wird zugehört…';

@override
String get speech_to_text_press_to_speak => 'Zum Sprechen drücken';

@override
String get speech_to_text_idle => 'Sprach­eingabe starten';

@override
String get speech_to_text_stop_listening => 'Zuhören stoppen';

@override
String get speech_to_text_opt_out_action => 'Sprach­eingabe deaktivieren';

@override
String get speech_to_text_enable_short_label => 'Wieder aktivieren';

@override
String speech_to_text_language_badge(Object language) {
return '$language';
}
}
Loading
Loading