fix: mic permissions

This commit is contained in:
cogwheel0
2025-08-28 19:48:35 +05:30
parent fe7c7758ba
commit b9f41e0d07
3 changed files with 19 additions and 19 deletions

View File

@@ -250,6 +250,20 @@ class VoiceInputService {
return _textStreamController!.stream; return _textStreamController!.stream;
} }
/// Centralized entry point to begin voice recognition.
/// Ensures initialization and microphone permission before starting.
Future<Stream<String>> beginListening() async {
// Ensure service is ready
await initialize();
// Ensure microphone permission (triggers OS prompt if needed)
final hasMic = await checkPermissions();
if (!hasMic) {
throw Exception('Microphone permission not granted');
}
// Start listening and return the transcript stream
return startListening();
}
Future<void> stopListening() async { Future<void> stopListening() async {
await _stopListening(); await _stopListening();
} }

View File

@@ -1998,16 +1998,11 @@ class _VoiceInputSheetState extends ConsumerState<_VoiceInputSheet> {
); );
try { try {
// Ensure service is initialized (local STT will request permissions itself) // Ensure service is initialized
final ok = await _voiceService.initialize(); final ok = await _voiceService.initialize();
if (!ok) { if (!ok) {
throw Exception('Voice service unavailable'); throw Exception('Voice service unavailable');
} }
// Only check mic permission when falling back to recording
if (!_voiceService.hasLocalStt) {
final mic = await _voiceService.checkPermissions();
if (!mic) throw Exception('Microphone permission not granted');
}
// Start elapsed timer for UX // Start elapsed timer for UX
_elapsedTimer?.cancel(); _elapsedTimer?.cancel();
@@ -2019,7 +2014,8 @@ class _VoiceInputSheetState extends ConsumerState<_VoiceInputSheet> {
setState(() => _elapsedSeconds += 1); setState(() => _elapsedSeconds += 1);
}); });
final stream = _voiceService.startListening(); // Centralized permission + start
final stream = await _voiceService.beginListening();
_intensitySub = _voiceService.intensityStream.listen((value) { _intensitySub = _voiceService.intensityStream.listen((value) {
if (!mounted) return; if (!mounted) return;
setState(() => _intensity = value); setState(() => _intensity = value);

View File

@@ -1150,22 +1150,12 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
); );
return; return;
} }
if (!_voiceService.hasLocalStt) { // Centralized permission + start
final mic = await _voiceService.checkPermissions(); final stream = await _voiceService.beginListening();
if (!mic) {
_showVoiceUnavailable(
AppLocalizations.of(context)?.errorMessage ??
'Microphone permission required',
);
return;
}
}
setState(() { setState(() {
_isRecording = true; _isRecording = true;
_baseTextAtStart = _controller.text; _baseTextAtStart = _controller.text;
}); });
final stream = _voiceService.startListening();
_intensitySub?.cancel(); _intensitySub?.cancel();
_intensitySub = _voiceService.intensityStream.listen((value) { _intensitySub = _voiceService.intensityStream.listen((value) {
if (!mounted) return; if (!mounted) return;