From ccc4d5f66916a3930432e8c703581fc062aa25d3 Mon Sep 17 00:00:00 2001 From: Nikhil Date: Tue, 28 Apr 2026 12:48:40 +0530 Subject: [PATCH] fix: handle missing microphone permission for voice recording --- .../chats/conversation/ui/ChatInputBar.kt | 19 ++++++++++++++----- .../conversation/ui/inputbar/VoiceRecorder.kt | 10 ++++++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/ChatInputBar.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/ChatInputBar.kt index 4b75133e..dadf51ae 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/ChatInputBar.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/ChatInputBar.kt @@ -311,11 +311,16 @@ fun ChatInputBar( } } - val voiceRecorder = rememberVoiceRecorder { path, duration, waveform -> - if (!canSendVoice || isSlowModeActive) return@rememberVoiceRecorder - actions.onSendVoice(path, duration, waveform) - activateSlowModeCooldown() - } + val voiceRecorder = rememberVoiceRecorder( + onRecordingFinished = { path, duration, waveform -> + if (!canSendVoice || isSlowModeActive) return@rememberVoiceRecorder + actions.onSendVoice(path, duration, waveform) + activateSlowModeCooldown() + }, + onPermissionDenied = { + microphonePermissionLauncher.launch(Manifest.permission.RECORD_AUDIO) + } + ) val maxMessageLength by remember( state.pendingMediaPaths, state.pendingDocumentPaths, @@ -614,6 +619,9 @@ fun ChatInputBar( hasCameraPermission.value = granted if (granted) showCamera = true } + val microphonePermissionLauncher = rememberLauncherForActivityResult( + ActivityResultContracts.RequestPermission() + ) { } val documentsPickerLauncher = rememberLauncherForActivityResult( ActivityResultContracts.OpenMultipleDocuments() ) { uris -> @@ -1093,4 +1101,5 @@ fun ChatInputBar( } ) } + } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/inputbar/VoiceRecorder.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/inputbar/VoiceRecorder.kt index a5483332..860a7512 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/inputbar/VoiceRecorder.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/conversation/ui/inputbar/VoiceRecorder.kt @@ -14,7 +14,8 @@ import kotlin.math.log10 @Composable fun rememberVoiceRecorder( - onRecordingFinished: (String, Int, ByteArray) -> Unit + onRecordingFinished: (String, Int, ByteArray) -> Unit, + onPermissionDenied: () -> Unit = {} ): VoiceRecorderState { val context = LocalContext.current val state = remember { VoiceRecorderState(context) } @@ -23,6 +24,10 @@ fun rememberVoiceRecorder( state.onRecordingFinished = onRecordingFinished } + LaunchedEffect(onPermissionDenied) { + state.onPermissionDenied = onPermissionDenied + } + DisposableEffect(Unit) { onDispose { state.stopRecording(cancel = true) @@ -55,6 +60,7 @@ class VoiceRecorderState(private val context: Context) { private var startTime = 0L var onRecordingFinished: ((String, Int, ByteArray) -> Unit)? = null + var onPermissionDenied: (() -> Unit)? = null @Suppress("DEPRECATION") fun startRecording() { @@ -65,7 +71,7 @@ class VoiceRecorderState(private val context: Context) { Manifest.permission.RECORD_AUDIO ) != PackageManager.PERMISSION_GRANTED ) { - // TODO: Request permission + onPermissionDenied?.invoke() return }