refactor(app): the device's speech recognition moves from Learn into halkyon_app, with dictation into a text
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>
This commit is contained in:
parent
86c9f4522a
commit
603218ef96
3 changed files with 405 additions and 16 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_app/testing.dart' show FakeSpeechInput;
|
||||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/device_settings/model/device_settings.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
|
||||
|
|
@ -17,7 +18,6 @@ import 'package:lucide_icons_flutter/lucide_icons.dart';
|
|||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
import '../../support/fake_card_gateway.dart';
|
||||
import '../../support/fake_speech_input.dart';
|
||||
import '../../support/fake_studyset_gateway.dart';
|
||||
import '../../support/memory_device_settings_store.dart';
|
||||
import '../../support/pump_app.dart';
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/assistant/data/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();
|
||||
}
|
||||
|
|
@ -24,7 +24,6 @@ import 'package:halkyon_learn_flutter/src/feature/archive/model/import_archive.d
|
|||
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_files.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_lookups.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/assistant/data/conversation_repository.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/assistant/data/speech_input.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/assistant/data/web_search.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/card/data/card_deletions.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/card/data/card_gateway.dart';
|
||||
|
|
@ -101,7 +100,6 @@ import 'fake_publish_gateway.dart';
|
|||
import 'fake_review_gateway.dart';
|
||||
import 'fake_settings_gateway.dart';
|
||||
import 'fake_sound_player.dart';
|
||||
import 'fake_speech_input.dart';
|
||||
import 'fake_studyset_gateway.dart';
|
||||
import 'fake_tag_gateway.dart';
|
||||
import 'fake_youtube_videos.dart';
|
||||
|
|
|
|||
Loading…
Reference in a new issue