From 428b65318c7b0228bb7bfa08267b2cfe95e91a4b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 13:33:26 +0000 Subject: [PATCH 1/9] fix(deps): update dependency org.matrix.rustcomponents:sdk-android to v25.10.13 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e2826d792c..74045eda92 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -167,7 +167,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.10.7" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.10.13" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } From a83630169eddeb650f93b4af19e958e0b57d66e3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 15:52:06 +0200 Subject: [PATCH 2/9] Fix API break in QrCodeLoginStep. --- .../android/libraries/matrix/api/auth/qrlogin/QrCodeLoginStep.kt | 1 + .../matrix/impl/auth/qrlogin/QrLoginProgressExtensions.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrCodeLoginStep.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrCodeLoginStep.kt index 20b57d2c71..f20ebc5dc8 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrCodeLoginStep.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrCodeLoginStep.kt @@ -12,6 +12,7 @@ sealed interface QrCodeLoginStep { data class EstablishingSecureChannel(val checkCode: String) : QrCodeLoginStep data object Starting : QrCodeLoginStep data class WaitingForToken(val userCode: String) : QrCodeLoginStep + data object SyncingSecrets : QrCodeLoginStep data class Failed(val error: QrLoginException) : QrCodeLoginStep data object Finished : QrCodeLoginStep } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrLoginProgressExtensions.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrLoginProgressExtensions.kt index 6c95f31a9f..0e9d60629f 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrLoginProgressExtensions.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrLoginProgressExtensions.kt @@ -15,6 +15,7 @@ fun QrLoginProgress.toStep(): QrCodeLoginStep { is QrLoginProgress.EstablishingSecureChannel -> QrCodeLoginStep.EstablishingSecureChannel(checkCodeString) is QrLoginProgress.Starting -> QrCodeLoginStep.Starting is QrLoginProgress.WaitingForToken -> QrCodeLoginStep.WaitingForToken(userCode) + is QrLoginProgress.SyncingSecrets -> QrCodeLoginStep.SyncingSecrets is QrLoginProgress.Done -> QrCodeLoginStep.Finished } } From 5320bd06c21bef597baa0de3d9d1933e3fd86067 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 16:06:08 +0200 Subject: [PATCH 3/9] Add some comment --- .../libraries/textcomposer/model/VoiceMessageState.kt | 2 ++ .../libraries/voicerecorder/api/VoiceRecorderState.kt | 9 ++++++--- .../libraries/voicerecorder/impl/DefaultVoiceRecorder.kt | 2 ++ .../voicerecorder/impl/audio/AudioLevelCalculator.kt | 3 +++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/VoiceMessageState.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/VoiceMessageState.kt index 8fa0ffbe55..46622ec59f 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/VoiceMessageState.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/VoiceMessageState.kt @@ -21,11 +21,13 @@ sealed interface VoiceMessageState { val showCursor: Boolean, val playbackProgress: Float, val time: Duration, + // Values are between 0 and 1 val waveform: ImmutableList, ) : VoiceMessageState data class Recording( val duration: Duration, + // Values are between 0 and 1 val levels: ImmutableList, ) : VoiceMessageState } diff --git a/libraries/voicerecorder/api/src/main/kotlin/io/element/android/libraries/voicerecorder/api/VoiceRecorderState.kt b/libraries/voicerecorder/api/src/main/kotlin/io/element/android/libraries/voicerecorder/api/VoiceRecorderState.kt index cc4dc0238c..2765e8e832 100644 --- a/libraries/voicerecorder/api/src/main/kotlin/io/element/android/libraries/voicerecorder/api/VoiceRecorderState.kt +++ b/libraries/voicerecorder/api/src/main/kotlin/io/element/android/libraries/voicerecorder/api/VoiceRecorderState.kt @@ -22,16 +22,19 @@ sealed interface VoiceRecorderState { * The recorder is currently recording. * * @property elapsedTime The elapsed time since the recording started. - * @property levels The current audio levels of the recording as a fraction of 1. + * @property levels The current audio levels of the recording as a fraction of 1. All values are between 0 and 1. */ - data class Recording(val elapsedTime: Duration, val levels: List) : VoiceRecorderState + data class Recording( + val elapsedTime: Duration, + val levels: List, + ) : VoiceRecorderState /** * The recorder has finished recording. * * @property file The recorded file. * @property mimeType The mime type of the file. - * @property waveform The waveform of the recording. + * @property waveform The waveform of the recording. All values are between 0 and 1. * @property duration The total time spent recording. */ data class Finished( diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt index 624282edef..b4d48e1d14 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt @@ -63,6 +63,8 @@ class DefaultVoiceRecorder( private var outputFile: File? = null private var audioReader: AudioReader? = null private var recordingJob: Job? = null + + // List of Float between 0 and 1 representing the audio levels private val levels: MutableList = mutableListOf() private val lock = Mutex() diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/audio/AudioLevelCalculator.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/audio/AudioLevelCalculator.kt index d58ca3e4e2..64c0fc9ddb 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/audio/AudioLevelCalculator.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/audio/AudioLevelCalculator.kt @@ -7,6 +7,8 @@ package io.element.android.libraries.voicerecorder.impl.audio +import androidx.annotation.FloatRange + interface AudioLevelCalculator { /** * Calculate the audio level of the audio buffer. @@ -14,5 +16,6 @@ interface AudioLevelCalculator { * @param buffer The audio buffer containing 16bit PCM audio data. * @return A float value between 0 and 1 proportional to the audio level. */ + @FloatRange(from = 0.0, to = 1.0) fun calculateAudioLevel(buffer: ShortArray): Float } From 58dc3c7aedc84c01275bba1375b86289cf584575 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 16:09:46 +0200 Subject: [PATCH 4/9] Fix API break on voice messages. --- .../android/libraries/matrix/impl/timeline/RustTimeline.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index 4c52e78205..ba63cd2ef0 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -29,7 +29,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransa import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl import io.element.android.libraries.matrix.impl.media.map -import io.element.android.libraries.matrix.impl.media.toMSC3246range import io.element.android.libraries.matrix.impl.poll.toInner import io.element.android.libraries.matrix.impl.room.RoomContentForwarder import io.element.android.libraries.matrix.impl.room.location.toInner @@ -484,7 +483,7 @@ class RustTimeline( inReplyTo = inReplyToEventId?.value, ), audioInfo = audioInfo.map(), - waveform = waveform.toMSC3246range(), + waveform = waveform, ) } } From e9f80d917a987aabbacd424da0117f715448ab5d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 16:21:17 +0200 Subject: [PATCH 5/9] Centralize WaveForm samples. --- .../VoiceMessageComposerStateProvider.kt | 6 +-- .../components/media/WaveFormSamples.kt | 26 +++++++++++ .../components/media/WaveformPlaybackView.kt | 46 +------------------ .../impl/gallery/MediaGalleryStateProvider.kt | 4 +- .../local/audio/MediaInfoAudioProvider.kt | 4 +- .../impl/model/MediaItemFactories.kt | 4 +- .../impl/viewer/MediaViewerStateProvider.kt | 4 +- 7 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt diff --git a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt index b418b08726..aaba414b79 100644 --- a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt +++ b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt @@ -8,15 +8,15 @@ package io.element.android.features.messages.api.timeline.voicemessages.composer import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.designsystem.components.media.WaveFormSamples import io.element.android.libraries.designsystem.components.media.createFakeWaveform import io.element.android.libraries.textcomposer.model.VoiceMessageState -import kotlinx.collections.immutable.toImmutableList import kotlin.time.Duration.Companion.seconds open class VoiceMessageComposerStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aVoiceMessageComposerState(voiceMessageState = VoiceMessageState.Recording(duration = 61.seconds, levels = aWaveformLevels)), + aVoiceMessageComposerState(voiceMessageState = VoiceMessageState.Recording(duration = 61.seconds, levels = WaveFormSamples.allRangeWaveForm)), ) } @@ -41,5 +41,3 @@ fun aVoiceMessagePreviewState() = VoiceMessageState.Preview( time = 10.seconds, waveform = createFakeWaveform(), ) - -internal var aWaveformLevels = List(100) { it.toFloat() / 100 }.toImmutableList() diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt new file mode 100644 index 0000000000..7185dba072 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.components.media + +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +object WaveFormSamples { + val allRangeWaveForm = List(100) { it.toFloat() / 100 }.toImmutableList() + + val realisticWaveForm = persistentListOf( + 0.000f, 0.000f, 0.000f, 0.003f, 0.354f, + 0.353f, 0.365f, 0.790f, 0.787f, 0.167f, + 0.333f, 0.975f, 0.000f, 0.102f, 0.003f, + 0.531f, 0.584f, 0.317f, 0.140f, 0.475f, + 0.496f, 0.561f, 0.042f, 0.263f, 0.169f, + 0.829f, 0.349f, 0.010f, 0.000f, 0.000f, + 1.000f, 0.334f, 0.321f, 0.011f, 0.000f, + 0.000f, 0.003f, + ) +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt index 5fe722d447..7a3c273084 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt @@ -187,14 +187,14 @@ internal fun WaveformPlaybackViewPreview() = ElementPreview { showCursor = false, playbackProgress = 0.5f, onSeek = {}, - waveform = aWaveForm().toImmutableList(), + waveform = WaveFormSamples.realisticWaveForm, ) WaveformPlaybackView( modifier = Modifier.height(34.dp), showCursor = true, playbackProgress = 0.5f, onSeek = {}, - waveform = List(1024) { it / 1024f }.toImmutableList(), + waveform = WaveFormSamples.allRangeWaveForm, ) } } @@ -217,45 +217,3 @@ private fun ImmutableList.normalisedData(maxSamplesCount: Int): Immutable return result.toImmutableList() } - -fun aWaveForm(): List { - return listOf( - 0.000f, - 0.000f, - 0.000f, - 0.003f, - 0.354f, - 0.353f, - 0.365f, - 0.790f, - 0.787f, - 0.167f, - 0.333f, - 0.975f, - 0.000f, - 0.102f, - 0.003f, - 0.531f, - 0.584f, - 0.317f, - 0.140f, - 0.475f, - 0.496f, - 0.561f, - 0.042f, - 0.263f, - 0.169f, - 0.829f, - 0.349f, - 0.010f, - 0.000f, - 0.000f, - 1.000f, - 0.334f, - 0.321f, - 0.011f, - 0.000f, - 0.000f, - 0.003f, - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt index aedea1eb75..22a312bb05 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.designsystem.components.media.aWaveForm +import io.element.android.libraries.designsystem.components.media.WaveFormSamples import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState import io.element.android.libraries.mediaviewer.impl.details.aMediaDetailsBottomSheetState @@ -71,7 +71,7 @@ open class MediaGalleryStateProvider : PreviewParameterProvider { get() = sequenceOf( anAudioMediaInfo(), anAudioMediaInfo( - waveForm = aWaveForm(), + waveForm = WaveFormSamples.realisticWaveForm, ), ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt index b04973322a..6854954601 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt @@ -7,7 +7,7 @@ package io.element.android.libraries.mediaviewer.impl.model -import io.element.android.libraries.designsystem.components.media.aWaveForm +import io.element.android.libraries.designsystem.components.media.WaveFormSamples import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.core.UserId @@ -91,7 +91,7 @@ fun aMediaItemVoice( filename: String = "filename.ogg", caption: String? = null, duration: String? = "1:23", - waveform: List = aWaveForm(), + waveform: List = WaveFormSamples.realisticWaveForm, ): MediaItem.Voice { return MediaItem.Voice( id = id, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt index 05a55b4e5f..09e71c7fc4 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt @@ -11,7 +11,7 @@ import android.net.Uri import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.designsystem.components.media.aWaveForm +import io.element.android.libraries.designsystem.components.media.WaveFormSamples import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.timeline.Timeline @@ -138,7 +138,7 @@ open class MediaViewerStateProvider : PreviewParameterProvider mediaBottomSheetState = aMediaDeleteConfirmationState(), ), anAudioMediaInfo( - waveForm = aWaveForm(), + waveForm = WaveFormSamples.realisticWaveForm, ).let { aMediaViewerState( listOf( From 93ae7941a4e639f06acc561bfbfb12e05cc49219 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 16:24:16 +0200 Subject: [PATCH 6/9] Update comment. `createFakeWaveform` will be removed. --- .../designsystem/components/media/WaveformPlaybackView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt index 7a3c273084..496286fffa 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveformPlaybackView.kt @@ -49,7 +49,7 @@ private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F * * @param playbackProgress The current playback progress, between 0 and 1. * @param showCursor Whether to show the cursor or not. - * @param waveform The waveform to display. Use [createFakeWaveform] to generate a fake waveform. + * @param waveform The waveform to display. * @param onSeek Callback when the user seeks the waveform. Called with a value between 0 and 1. * @param modifier The modifier to be applied to the view. * @param seekEnabled Whether the user can seek the waveform or not. From 90cd52b5d53790c4da5efa292edb60fed17eaa76 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 16:28:20 +0200 Subject: [PATCH 7/9] Let the preview provider use stable data. I do not get why the generated screenshot was always similar. --- .../VoiceMessageComposerStateProvider.kt | 3 +- .../components/media/WaveFormSamples.kt | 3 ++ .../libraries/textcomposer/TextComposer.kt | 30 +++++++++++-------- .../components/VoiceMessagePreview.kt | 16 ++++++---- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt index aaba414b79..f089af2dd3 100644 --- a/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt +++ b/features/messages/api/src/main/kotlin/io/element/android/features/messages/api/timeline/voicemessages/composer/VoiceMessageComposerStateProvider.kt @@ -9,7 +9,6 @@ package io.element.android.features.messages.api.timeline.voicemessages.composer import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.designsystem.components.media.WaveFormSamples -import io.element.android.libraries.designsystem.components.media.createFakeWaveform import io.element.android.libraries.textcomposer.model.VoiceMessageState import kotlin.time.Duration.Companion.seconds @@ -39,5 +38,5 @@ fun aVoiceMessagePreviewState() = VoiceMessageState.Preview( showCursor = false, playbackProgress = 0f, time = 10.seconds, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, ) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt index 7185dba072..6fbb217392 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/WaveFormSamples.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.designsystem.components.media import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toPersistentList object WaveFormSamples { val allRangeWaveForm = List(100) { it.toFloat() / 100 }.toImmutableList() @@ -23,4 +24,6 @@ object WaveFormSamples { 1.000f, 0.334f, 0.321f, 0.011f, 0.000f, 0.000f, 0.003f, ) + + val longRealisticWaveForm = List(4) { realisticWaveForm }.flatten().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 1126a39466..e1a72e04ca 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 @@ -52,7 +52,7 @@ import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.androidutils.ui.showKeyboard -import io.element.android.libraries.designsystem.components.media.createFakeWaveform +import io.element.android.libraries.designsystem.components.media.WaveFormSamples import io.element.android.libraries.designsystem.preview.DAY_MODE_NAME import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.NIGHT_MODE_NAME @@ -808,30 +808,33 @@ internal fun TextComposerCaptionPreview() = ElementPreview { internal fun TextComposerVoicePreview() = ElementPreview { PreviewColumn( items = persistentListOf( - VoiceMessageState.Recording(61.seconds, createFakeWaveform()), + VoiceMessageState.Recording( + duration = 61.seconds, + levels = WaveFormSamples.realisticWaveForm, + ), VoiceMessageState.Preview( isSending = false, isPlaying = false, showCursor = false, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, time = 0.seconds, - playbackProgress = 0.0f + playbackProgress = 0.0f, ), VoiceMessageState.Preview( isSending = false, isPlaying = true, showCursor = true, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, time = 3.seconds, - playbackProgress = 0.2f + playbackProgress = 0.2f, ), VoiceMessageState.Preview( isSending = true, isPlaying = false, showCursor = false, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, time = 61.seconds, - playbackProgress = 0.0f + playbackProgress = 0.0f, ), ) ) { voiceMessageState -> @@ -848,12 +851,15 @@ internal fun TextComposerVoicePreview() = ElementPreview { internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview { PreviewColumn( items = persistentListOf( - VoiceMessageState.Recording(61.seconds, createFakeWaveform()), + VoiceMessageState.Recording( + duration = 61.seconds, + levels = WaveFormSamples.realisticWaveForm, + ), VoiceMessageState.Preview( isSending = false, isPlaying = false, showCursor = false, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, time = 0.seconds, playbackProgress = 0.0f ), @@ -861,7 +867,7 @@ internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview { isSending = false, isPlaying = true, showCursor = true, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, time = 3.seconds, playbackProgress = 0.2f ), @@ -869,7 +875,7 @@ internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview { isSending = true, isPlaying = false, showCursor = false, - waveform = createFakeWaveform(), + waveform = WaveFormSamples.realisticWaveForm, time = 61.seconds, playbackProgress = 0.0f ), 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 d965a3d0d6..fbe45866c9 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 @@ -29,8 +29,8 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.libraries.designsystem.components.media.WaveFormSamples 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.theme.components.Icon @@ -138,14 +138,18 @@ private fun PlayerButton( private fun PauseIcon() = Icon( imageVector = CompoundIcons.PauseSolid(), contentDescription = stringResource(id = CommonStrings.a11y_pause), - modifier = Modifier.size(20.dp).padding(2.dp), + modifier = Modifier + .size(20.dp) + .padding(2.dp), ) @Composable private fun PlayIcon() = Icon( imageVector = CompoundIcons.PlaySolid(), contentDescription = stringResource(id = CommonStrings.a11y_play), - modifier = Modifier.size(20.dp).padding(2.dp), + modifier = Modifier + .size(20.dp) + .padding(2.dp), ) @PreviewsDayNight @@ -160,7 +164,7 @@ internal fun VoiceMessagePreviewPreview() = ElementPreview { time = 2.seconds, playbackProgress = 0.2f, showCursor = true, - waveform = createFakeWaveform() + waveform = WaveFormSamples.longRealisticWaveForm, ) AVoiceMessagePreview( isInteractive = true, @@ -168,7 +172,7 @@ internal fun VoiceMessagePreviewPreview() = ElementPreview { time = 0.seconds, playbackProgress = 0.0f, showCursor = true, - waveform = createFakeWaveform() + waveform = WaveFormSamples.longRealisticWaveForm, ) AVoiceMessagePreview( isInteractive = false, @@ -176,7 +180,7 @@ internal fun VoiceMessagePreviewPreview() = ElementPreview { time = 789.seconds, playbackProgress = 0.0f, showCursor = false, - waveform = createFakeWaveform() + waveform = WaveFormSamples.longRealisticWaveForm, ) } } From 901685471cd98c87643444ce6a10fd295eacb2a8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Oct 2025 16:42:54 +0200 Subject: [PATCH 8/9] Let the test use sample data. --- .../components/media/FakeWaveformFactory.kt | 25 ------------------- .../SingleMediaGalleryDataSourceTest.kt | 4 +-- 2 files changed, 2 insertions(+), 27 deletions(-) delete mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/FakeWaveformFactory.kt 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 deleted file mode 100644 index 3264f55754..0000000000 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/FakeWaveformFactory.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.designsystem.components.media - -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList -import kotlin.random.Random - -/** - * 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() } - .toImmutableList() -} diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt index c80aa15428..1b70d8b6ce 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.mediaviewer.impl.viewer import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.designsystem.components.media.createFakeWaveform +import io.element.android.libraries.designsystem.components.media.WaveFormSamples import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.AN_EVENT_ID @@ -128,7 +128,7 @@ class SingleMediaGalleryDataSourceTest { fun `createFrom should create a SingleMediaGalleryDataSource with a voice item`() { testFactory( mediaInfo = aVoiceMediaInfo( - waveForm = createFakeWaveform(), + waveForm = WaveFormSamples.longRealisticWaveForm, duration = "12:34", ), expectedResult = { params -> From 5dcae950511e07d60118e89c4e613378e33994cc Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 13 Oct 2025 15:31:09 +0000 Subject: [PATCH 9/9] Update screenshots --- .../images/features.messages.impl_MessagesView_Day_7_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_7_en.png | 4 ++-- ...nsystem.components.media_WaveformPlaybackView_Day_0_en.png | 4 ++-- ...ystem.components.media_WaveformPlaybackView_Night_0_en.png | 4 ++-- ...ibraries.textcomposer.components_VoiceMessage_Day_0_en.png | 4 ++-- ...raries.textcomposer.components_VoiceMessage_Night_0_en.png | 4 ++-- ...es.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png | 4 ++-- ....textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png | 4 ++-- .../libraries.textcomposer_TextComposerVoice_Day_0_en.png | 4 ++-- .../libraries.textcomposer_TextComposerVoice_Night_0_en.png | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png index 571a7c532a..e2c39da845 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d80066ecad50390fbd0529d4e0f25462ac91d9e168817ecfdbf472129b95410 -size 50641 +oid sha256:ac595ce33affb3eec6c465fd68ab1fa57eb942f58944cc16e5e01892a21ba4a7 +size 50323 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png index a564e03041..4db80abcb1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d90b319d5b4fd3ec77fdfe15bed786e5acbc66b86da83f24efce313eb8d178b -size 44750 +oid sha256:72023d9b9eaade788d33ef6c123a89edc079c4cc543421c256676b75fba6adc1 +size 44505 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Day_0_en.png index b54f89bef8..7d68bb0570 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f162675e687af3aa9c352cdf7ae177f4760d1ce008cd217641b6722a71d34d49 -size 10271 +oid sha256:837bb03b66cccdfebb039b36da1096589da31e898de36975e413782349896ba0 +size 10167 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Night_0_en.png index 6690e37706..3a689c5959 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.components.media_WaveformPlaybackView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30328b9c5a43508d135d086fcbafe5ad5cf9989e208f8f25b1450e61df08994e -size 9549 +oid sha256:091bd502d78b80633e267670e2cfdde1696f22d26b9b729d8e33d6d33b8e6d58 +size 9469 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Day_0_en.png index 8bf9395609..600ad51b94 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ed72cd85cc94390214b721b26229c8784174c54fb2a58eb1cc01431e6c57898 -size 20699 +oid sha256:45422a841a79f4236a56a72773cfe8485e267f345abb03c2b376b3307e430fab +size 18537 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Night_0_en.png index f584255fa6..4b14520d95 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer.components_VoiceMessage_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea8534fe10a038e86e9c9c572391f29c1241fc77a1ce93c549bf6350f48c01bb -size 19500 +oid sha256:dedaa24fb05db78c0b9d4c2357c5c76ac181365c09f6e6b666387112f7962a4a +size 17424 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png index be74924cc6..186753469b 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2429482b11d6a507830a38c9bf483687d2d6b4c9e33ee2ad063d2fb6199e0f44 -size 37673 +oid sha256:98dbb0ac81d2079ac41f107b78e6fb7ccbf1f53fcd9e95e8716fb05ca1b14ea3 +size 36091 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png index 8f6d149a61..bb102c7bcb 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoiceNotEncrypted_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2fdc8ba783be4355b0a436473082151225811652c2b03cb11c19c26bca0e2ac7 -size 35756 +oid sha256:c454bf724b6875610870eec156f0c544e84baf9c6e9a755b965f692f498a1b1e +size 34222 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png index 0dda2f3ca1..24be8a7dbc 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9477cd51e70796a6e3d1eeaad1270db5c37ae40f0cfffea38f8d09f8f743b266 -size 26488 +oid sha256:274f54991bbd79c4220d945964caf7fc523ce99a70b748ef992cc15ee030fdf5 +size 25124 diff --git a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png index 1f50879399..433550b84b 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.textcomposer_TextComposerVoice_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f891e663e2d8649629ef9fe5c4f79a71ad5304fdc1b450946ddd6975237eb329 -size 25502 +oid sha256:258643d514aeb7a53788ba2addc53fe46f888193ced2970c73887f9eb1584753 +size 24039