From 0e6ad3076c66157880e986b4c7f8595147547d3e Mon Sep 17 00:00:00 2001 From: Karsten Knappe Date: Thu, 29 Jan 2026 12:18:27 +0100 Subject: [PATCH] Fix voice message recording not starting after permission is granted --- .../composer/DefaultVoiceMessageComposerPresenter.kt | 12 ++++++++++++ .../DefaultVoiceMessageComposerPresenterTest.kt | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenter.kt index 56b0e402d2..e50017642c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenter.kt @@ -69,6 +69,7 @@ class DefaultVoiceMessageComposerPresenter( } private val permissionsPresenter = permissionsPresenterFactory.create(Manifest.permission.RECORD_AUDIO) + private var pendingEvent: VoiceMessageRecorderEvent.Start? = null private val mediaSender = mediaSenderFactory.create(timelineMode) @Composable @@ -88,6 +89,15 @@ class DefaultVoiceMessageComposerPresenter( player.setMedia(recording.file.path) } + LaunchedEffect(permissionState.permissionGranted) { + if (permissionState.permissionGranted) { + pendingEvent?.let { + localCoroutineScope.startRecording() + pendingEvent = null + } + } + } + fun handleLifecycleEvent(event: Lifecycle.Event) { when (event) { Lifecycle.Event.ON_PAUSE -> { @@ -102,6 +112,7 @@ class DefaultVoiceMessageComposerPresenter( } fun handleVoiceMessageRecorderEvent(event: VoiceMessageRecorderEvent) { + pendingEvent = null when (event) { VoiceMessageRecorderEvent.Start -> { Timber.v("Voice message record button pressed") @@ -111,6 +122,7 @@ class DefaultVoiceMessageComposerPresenter( } else -> { Timber.i("Voice message permission needed") + pendingEvent = VoiceMessageRecorderEvent.Start permissionState.eventSink(PermissionsEvent.RequestPermissions) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt index 48348f5e9a..7c9cc42c70 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt @@ -551,9 +551,10 @@ class DefaultVoiceMessageComposerPresenterTest { // Dialog is hidden, user accepts permissions assertThat(awaitItem().showPermissionRationaleDialog).isFalse() + // Permission is granted, recording starts automatically permissionsPresenter.setPermissionGranted() - awaitItem().eventSink(VoiceMessageComposerEvent.RecorderEvent(VoiceMessageRecorderEvent.Start)) + skipItems(1) val finalState = awaitItem() assertThat(finalState.voiceMessageState).isEqualTo(RECORDING_STATE) voiceRecorder.assertCalls(started = 1)