Learn's `SpeechInput` and `DeviceSpeechInput` (ADR 0021, D67) are halkyon_app's now, and its `FakeSpeechInput` is in `testing.dart`, so Meditate's dream journal (ADR 0038, D15) listens through the same code. Learn imports them from there and behaves as before: its composer and its tests are unchanged but for the imports, and `DeviceSpeechInput()` asks for what it asked before. `DeviceSpeechInput` takes three options, off by default: - `preferOnDevice`: on Android, recognition on the device where it can (Android 12 on), else offline; should that fail before a word is heard (not a pause), it listens as Android otherwise does from then on. - `pauseFor`: how long a pause may last before the recogniser stops. - `listenFor`: how long one listen may last at most. `Dictation` writes what is heard where the cursor stands (`DictationInsertion`: in place of a selection, set apart by a space), shows the words so far, and listens again after each pause while it is on, stopping by itself after three listens running heard nothing. speech_to_text moves from Learn's pubspec to halkyon_app's, the lock unchanged. Todo, Train and Meditate link the plugin now; their generated plugin registrants (macOS, Windows) say so. An app declares the microphone itself, and Todo and Train declare none, so nothing there can listen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
51 lines
1.2 KiB
Dart
51 lines
1.2 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:halkyon_app/src/speech/speech_input.dart';
|
|
|
|
/// A [SpeechInput] the test speaks into: [say] hands words on, [finish]
|
|
/// ends the listen.
|
|
class FakeSpeechInput() implements SpeechInput {
|
|
@override
|
|
bool supported = true;
|
|
|
|
/// Whether the device can listen when asked: false as if the microphone
|
|
/// were refused.
|
|
bool listens = true;
|
|
|
|
/// The languages asked to listen in, in order.
|
|
final languages = <String?>[];
|
|
|
|
ValueChanged<String>? _onWords;
|
|
VoidCallback? _onDone;
|
|
|
|
/// Whether a listen is under way.
|
|
bool get listening => _onWords != null;
|
|
|
|
/// Hands on [words], as all heard so far.
|
|
void say(String words) => _onWords?.call(words);
|
|
|
|
/// Ends the listen, as the recogniser does after a pause.
|
|
void finish() {
|
|
final done = _onDone;
|
|
_onWords = null;
|
|
_onDone = null;
|
|
done?.call();
|
|
}
|
|
|
|
@override
|
|
Future<bool> listen({
|
|
required String? language,
|
|
required ValueChanged<String> onWords,
|
|
required VoidCallback onDone,
|
|
}) async {
|
|
languages.add(language);
|
|
if (!listens) {
|
|
return false;
|
|
}
|
|
_onWords = onWords;
|
|
_onDone = onDone;
|
|
return true;
|
|
}
|
|
|
|
@override
|
|
Future<void> stop() async => finish();
|
|
}
|