added local implementation of speech_to_text_dialog
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025 Fabian Freund.
|
||||
*
|
||||
* This file is part of WebLibre
|
||||
* (see https://weblibre.eu).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter/services.dart' show BinaryMessenger;
|
||||
import 'src/pigeons/speech_to_text.g.dart';
|
||||
|
||||
/// Speech recognition dialog using Android's RecognizerIntent.
|
||||
///
|
||||
/// This class provides a Flutter interface to Android's speech recognition
|
||||
/// dialog, allowing users to dictate text that is then returned to the app.
|
||||
///
|
||||
/// Example usage:
|
||||
/// ```dart
|
||||
/// final speechDialog = SpeechToTextDialog();
|
||||
///
|
||||
/// // Listen for results
|
||||
/// final subscription = speechDialog.textStream.listen((text) {
|
||||
/// print('Recognized: $text');
|
||||
/// });
|
||||
///
|
||||
/// // Show the dialog
|
||||
/// final success = await speechDialog.showDialog(locale: 'en-US');
|
||||
///
|
||||
/// // Clean up when done
|
||||
/// await subscription.cancel();
|
||||
/// speechDialog.dispose();
|
||||
/// ```
|
||||
class SpeechToTextDialog implements SpeechToTextEvents {
|
||||
/// Creates a new [SpeechToTextDialog] instance.
|
||||
///
|
||||
/// Optionally provide a custom [api] for testing or dependency injection.
|
||||
/// If [binaryMessenger] is provided, it will be used for Pigeon communication.
|
||||
SpeechToTextDialog({
|
||||
SpeechToTextApi? api,
|
||||
BinaryMessenger? binaryMessenger,
|
||||
}) : _api = api ?? SpeechToTextApi(binaryMessenger: binaryMessenger),
|
||||
_binaryMessenger = binaryMessenger {
|
||||
// Set up the event handler
|
||||
SpeechToTextEvents.setUp(this, binaryMessenger: binaryMessenger);
|
||||
}
|
||||
|
||||
final SpeechToTextApi _api;
|
||||
final BinaryMessenger? _binaryMessenger;
|
||||
final _textStreamController = StreamController<String>.broadcast();
|
||||
bool _disposed = false;
|
||||
|
||||
/// Stream of recognized speech text.
|
||||
///
|
||||
/// This stream emits the recognized text when the user completes
|
||||
/// speech input. An empty string may be emitted if recognition failed
|
||||
/// or the user cancelled.
|
||||
Stream<String> get textStream => _textStreamController.stream;
|
||||
|
||||
/// Show the speech recognition dialog.
|
||||
///
|
||||
/// Returns [true] if the dialog was shown successfully.
|
||||
/// Returns [false] if the speech recognition service is not available.
|
||||
///
|
||||
/// The [locale] parameter specifies the language locale for recognition
|
||||
/// (e.g., 'en-US', 'de-DE', 'es-ES'). If null, uses the device default locale.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// final success = await speechDialog.showDialog(locale: 'en-US');
|
||||
/// if (!success) {
|
||||
/// print('Speech recognition not available');
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> showDialog({String? locale}) async {
|
||||
return _api.showDialog(locale: locale);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTextReceived(String text) {
|
||||
if (!_disposed) {
|
||||
_textStreamController.add(text);
|
||||
}
|
||||
}
|
||||
|
||||
/// Release resources used by this instance.
|
||||
///
|
||||
/// Call this when the speech dialog is no longer needed to avoid memory leaks.
|
||||
/// After calling [dispose], this instance cannot be used again.
|
||||
void dispose() {
|
||||
if (!_disposed) {
|
||||
_disposed = true;
|
||||
SpeechToTextEvents.setUp(null, binaryMessenger: _binaryMessenger);
|
||||
_textStreamController.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// Autogenerated from Pigeon (v26.1.5), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||
|
||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
PlatformException _createConnectionError(String channelName) {
|
||||
return PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel: "$channelName".',
|
||||
);
|
||||
}
|
||||
|
||||
List<Object?> wrapResponse({Object? result, PlatformException? error, bool empty = false}) {
|
||||
if (empty) {
|
||||
return <Object?>[];
|
||||
}
|
||||
if (error == null) {
|
||||
return <Object?>[result];
|
||||
}
|
||||
return <Object?>[error.code, error.message, error.details];
|
||||
}
|
||||
|
||||
|
||||
class _PigeonCodec extends StandardMessageCodec {
|
||||
const _PigeonCodec();
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is int) {
|
||||
buffer.putUint8(4);
|
||||
buffer.putInt64(value);
|
||||
} else {
|
||||
super.writeValue(buffer, value);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Host API - methods called from Flutter to native Android.
|
||||
class SpeechToTextApi {
|
||||
/// Constructor for [SpeechToTextApi]. The [binaryMessenger] named argument is
|
||||
/// available for dependency injection. If it is left null, the default
|
||||
/// BinaryMessenger will be used which routes to the host platform.
|
||||
SpeechToTextApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
|
||||
: pigeonVar_binaryMessenger = binaryMessenger,
|
||||
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
final BinaryMessenger? pigeonVar_binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
|
||||
final String pigeonVar_messageChannelSuffix;
|
||||
|
||||
/// Show the speech recognition dialog.
|
||||
///
|
||||
/// Returns [true] if the dialog was shown successfully.
|
||||
/// Returns [false] if the speech recognition service is not available.
|
||||
///
|
||||
/// The [locale] parameter specifies the language locale for recognition
|
||||
/// (e.g., 'en-US', 'de-DE'). If null, uses the device default.
|
||||
Future<bool> showDialog({String? locale}) async {
|
||||
final pigeonVar_channelName = 'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextApi.showDialog$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[locale]);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else if (pigeonVar_replyList[0] == null) {
|
||||
throw PlatformException(
|
||||
code: 'null-error',
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} else {
|
||||
return (pigeonVar_replyList[0] as bool?)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Flutter API - callbacks from native Android to Flutter.
|
||||
abstract class SpeechToTextEvents {
|
||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
||||
|
||||
/// Called when speech recognition completes with the recognized text.
|
||||
///
|
||||
/// [text] contains the recognized speech text. May be empty if
|
||||
/// recognition failed or was cancelled.
|
||||
void onTextReceived(String text);
|
||||
|
||||
static void setUp(SpeechToTextEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) {
|
||||
messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
|
||||
{
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived$messageChannelSuffix', pigeonChannelCodec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
pigeonVar_channel.setMessageHandler(null);
|
||||
} else {
|
||||
pigeonVar_channel.setMessageHandler((Object? message) async {
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final String? arg_text = (args[0] as String?);
|
||||
assert(arg_text != null,
|
||||
'Argument for dev.flutter.pigeon.speech_to_text_dialog.SpeechToTextEvents.onTextReceived was null, expected non-null String.');
|
||||
try {
|
||||
api.onTextReceived(arg_text!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user