From 7ebea4acf13fb7acb63f7f4a29d0515764837599 Mon Sep 17 00:00:00 2001 From: jonnyandrew Date: Fri, 27 Oct 2023 15:07:02 +0100 Subject: [PATCH 1/3] Refactor waveform factory function --- .../components/media/FakeWaveformFactory.kt | 24 +++++++++---------- .../libraries/textcomposer/TextComposer.kt | 2 +- .../components/VoiceMessagePreview.kt | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/FakeWaveformFactory.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/FakeWaveformFactory.kt index 19b2d4e8b5..4273d95e2c 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/FakeWaveformFactory.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/FakeWaveformFactory.kt @@ -20,17 +20,15 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList import kotlin.random.Random -object FakeWaveformFactory { - /** - * Generate a waveform for testing purposes. - * - * The waveform is a list of floats between 0 and 1. - * - * @param length The length of the waveform. - */ - fun createFakeWaveform(length: Int = 1000): ImmutableList { - val random = Random(seed = 2) - return List(length) { random.nextFloat() } - .toPersistentList() - } +/** + * Generate a waveform for testing purposes. + * + * The waveform is a list of floats between 0 and 1. + * + * @param length The length of the waveform. + */ +fun createFakeWaveform(length: Int = 1000): ImmutableList { + val random = Random(seed = 2) + return List(length) { random.nextFloat() } + .toPersistentList() } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 3116f79ba0..5c55dbb517 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -48,7 +48,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import io.element.android.libraries.designsystem.components.media.FakeWaveformFactory.createFakeWaveform +import io.element.android.libraries.designsystem.components.media.createFakeWaveform import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.applyScaleUp diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt index be06f853f8..baee7d1be5 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessagePreview.kt @@ -34,8 +34,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import io.element.android.libraries.designsystem.components.media.FakeWaveformFactory.createFakeWaveform import io.element.android.libraries.designsystem.components.media.WaveformPlaybackView +import io.element.android.libraries.designsystem.components.media.createFakeWaveform import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.text.applyScaleUp From 71644910e8d02a3265055fcc30af6fc060047be8 Mon Sep 17 00:00:00 2001 From: jonnyandrew Date: Fri, 27 Oct 2023 15:14:01 +0100 Subject: [PATCH 2/3] Ensure deleting pauses audio --- .../composer/VoiceMessageComposerPresenter.kt | 5 ++++- .../VoiceMessageComposerPresenterTest.kt | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt index 0fae36f1ec..3ea8bde6ca 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt @@ -165,7 +165,10 @@ class VoiceMessageComposerPresenter @Inject constructor( is VoiceMessageComposerEvents.SendVoiceMessage -> localCoroutineScope.launch { onSendButtonPress() } - VoiceMessageComposerEvents.DeleteVoiceMessage -> localCoroutineScope.deleteRecording() + VoiceMessageComposerEvents.DeleteVoiceMessage -> { + player.pause() + localCoroutineScope.deleteRecording() + } VoiceMessageComposerEvents.DismissPermissionsRationale -> onDismissPermissionsRationale() VoiceMessageComposerEvents.AcceptPermissionRationale -> onAcceptPermissionsRationale() is VoiceMessageComposerEvents.LifecycleEvent -> onLifecycleEvent(event.event) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt index d3cb53fb49..67cf2123be 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt @@ -209,6 +209,28 @@ class VoiceMessageComposerPresenterTest { } } + @Test + fun `present - delete while playing`() = runTest { + val presenter = createVoiceMessageComposerPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().eventSink(VoiceMessageComposerEvents.RecordButtonEvent(PressEvent.PressStart)) + awaitItem().eventSink(VoiceMessageComposerEvents.RecordButtonEvent(PressEvent.LongPressEnd)) + awaitItem().eventSink(VoiceMessageComposerEvents.PlayerEvent(VoiceMessagePlayerEvent.Play)) + awaitItem().eventSink(VoiceMessageComposerEvents.DeleteVoiceMessage) + awaitItem().apply { + assertThat(voiceMessageState).isEqualTo(aPreviewState(isPlaying = false)) + } + + val finalState = awaitItem() + assertThat(finalState.voiceMessageState).isEqualTo(VoiceMessageState.Idle) + voiceRecorder.assertCalls(started = 1, stopped = 1, deleted = 1) + + testPauseAndDestroy(finalState) + } + } + @Test fun `present - send recording`() = runTest { val presenter = createVoiceMessageComposerPresenter() From 08ba8e182a0cebe5a783f3fa88e29ea06f30c3e4 Mon Sep 17 00:00:00 2001 From: jonnyandrew Date: Fri, 27 Oct 2023 15:16:58 +0100 Subject: [PATCH 3/3] Ensure sending pauses audio --- .../composer/VoiceMessageComposerPresenter.kt | 1 + .../VoiceMessageComposerPresenterTest.kt | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt index 3ea8bde6ca..ff3e2df722 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt @@ -149,6 +149,7 @@ class VoiceMessageComposerPresenter @Inject constructor( return@lambda } isSending = true + player.pause() appCoroutineScope.sendMessage( file = finishedState.file, mimeType = finishedState.mimeType, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt index 67cf2123be..4cffe65036 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/voicemessages/composer/VoiceMessageComposerPresenterTest.kt @@ -251,6 +251,29 @@ class VoiceMessageComposerPresenterTest { } } + @Test + fun `present - send while playing`() = runTest { + val presenter = createVoiceMessageComposerPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().eventSink(VoiceMessageComposerEvents.RecordButtonEvent(PressEvent.PressStart)) + awaitItem().eventSink(VoiceMessageComposerEvents.RecordButtonEvent(PressEvent.LongPressEnd)) + awaitItem().eventSink(VoiceMessageComposerEvents.PlayerEvent(VoiceMessagePlayerEvent.Play)) + awaitItem().eventSink(VoiceMessageComposerEvents.SendVoiceMessage) + assertThat(awaitItem().voiceMessageState).isEqualTo(aPreviewState( + isSending = true, isPlaying = false, + )) + + val finalState = awaitItem() + assertThat(finalState.voiceMessageState).isEqualTo(VoiceMessageState.Idle) + assertThat(matrixRoom.sendMediaCount).isEqualTo(1) + voiceRecorder.assertCalls(started = 1, stopped = 1, deleted = 1) + + testPauseAndDestroy(finalState) + } + } + @Test fun `present - send recording before previous completed, waits`() = runTest { val presenter = createVoiceMessageComposerPresenter()