From 1389c9ed245000921bf96832653cb7a4e1f6b243 Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 26 Oct 2023 23:46:03 +0100 Subject: [PATCH 1/9] Simple live waveform implementation. --- .../composer/VoiceMessageComposerPresenter.kt | 3 +- .../VoiceMessageComposerStateProvider.kt | 7 +- .../media/DrawScopeWaveformExtensions.kt | 57 ++++++++++ .../components/media/WaveformPlaybackView.kt | 25 ++--- .../libraries/textcomposer/TextComposer.kt | 5 +- .../components/LiveWaveformView.kt | 106 ++++++++++++++++++ .../components/VoiceMessageRecording.kt | 32 ++---- .../textcomposer/model/VoiceMessageState.kt | 3 +- .../voicerecorder/api/VoiceRecorderState.kt | 4 +- .../voicerecorder/impl/VoiceRecorderImpl.kt | 4 +- 10 files changed, 195 insertions(+), 51 deletions(-) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/DrawScopeWaveformExtensions.kt create mode 100644 libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt 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 5e0d9bcada..6500176e73 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 @@ -40,6 +40,7 @@ import io.element.android.libraries.textcomposer.model.VoiceMessageState import io.element.android.libraries.voicerecorder.api.VoiceRecorder import io.element.android.libraries.voicerecorder.api.VoiceRecorderState import io.element.android.services.analytics.api.AnalyticsService +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import timber.log.Timber @@ -172,7 +173,7 @@ class VoiceMessageComposerPresenter @Inject constructor( voiceMessageState = when (val state = recorderState) { is VoiceRecorderState.Recording -> VoiceMessageState.Recording( duration = state.elapsedTime, - level = state.level + levels = state.levels.toPersistentList() ) is VoiceRecorderState.Finished -> if (isSending) { VoiceMessageState.Sending diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt index c448ca1a84..f7e3263287 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt @@ -18,12 +18,13 @@ package io.element.android.features.messages.impl.voicemessages.composer import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.textcomposer.model.VoiceMessageState +import kotlinx.collections.immutable.toPersistentList import kotlin.time.Duration.Companion.seconds internal open class VoiceMessageComposerStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aVoiceMessageComposerState(voiceMessageState = VoiceMessageState.Recording(duration = 61.seconds, level = 0.5f)), + aVoiceMessageComposerState(voiceMessageState = VoiceMessageState.Recording(duration = 61.seconds, levels = aWaveformLevels)), ) } @@ -35,3 +36,7 @@ internal fun aVoiceMessageComposerState( showPermissionRationaleDialog = showPermissionRationaleDialog, eventSink = {}, ) + +internal var aWaveformLevels = List(100) { it.toFloat() / 200 }.toPersistentList() + + diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/DrawScopeWaveformExtensions.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/DrawScopeWaveformExtensions.kt new file mode 100644 index 0000000000..9e09d97471 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/media/DrawScopeWaveformExtensions.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.designsystem.components.media + +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.Fill +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import kotlinx.collections.immutable.ImmutableList +import kotlin.math.max + +fun DrawScope.drawWaveform( + waveformData: ImmutableList, + canvasSize: DpSize, + brush: Brush, + minimumGraphAmplitude: Float = 2F, + lineWidth: Dp = 2.dp, + linePadding: Dp = 2.dp, +) { + val centerY = canvasSize.height.toPx() / 2 + val cornerRadius = lineWidth / 2 + waveformData.forEachIndexed { index, amplitude -> + val drawingAmplitude = max(minimumGraphAmplitude, amplitude * (canvasSize.height.toPx() - 2)) + drawRoundRect( + brush = brush, + topLeft = Offset( + x = index * (linePadding + lineWidth).toPx(), + y = centerY - drawingAmplitude / 2 + ), + size = Size( + width = lineWidth.toPx(), + height = drawingAmplitude + ), + cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx()), + style = Fill + ) + } +} 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 d9d15c1c3b..5cf92bf28a 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 @@ -48,7 +48,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.theme.ElementTheme import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList -import kotlin.math.max private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F @OptIn(ExperimentalComposeUiApi::class) @@ -64,7 +63,6 @@ fun WaveformPlaybackView( cursorBrush: Brush = SolidColor(ElementTheme.colors.iconAccentTertiary), lineWidth: Dp = 2.dp, linePadding: Dp = 2.dp, - minimumGraphAmplitude: Float = 2F, ) { val seekProgress = remember { mutableStateOf(null) } var canvasSize by remember { mutableStateOf(DpSize(0.dp, 0.dp)) } @@ -121,22 +119,13 @@ fun WaveformPlaybackView( canvasSizePx = size val centerY = canvasSize.height.toPx() / 2 val cornerRadius = lineWidth / 2 - normalizedWaveformData.forEachIndexed { index, amplitude -> - val drawingAmplitude = max(minimumGraphAmplitude, amplitude * (canvasSize.height.toPx() - 2)) - drawRoundRect( - brush = brush, - topLeft = Offset( - x = index * (linePadding + lineWidth).toPx(), - y = centerY - drawingAmplitude / 2 - ), - size = Size( - width = lineWidth.toPx(), - height = drawingAmplitude - ), - cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx()), - style = Fill - ) - } + drawWaveform( + waveformData = normalizedWaveformData, + canvasSize = canvasSize, + brush = brush, + lineWidth = lineWidth, + linePadding = linePadding + ) drawRect( brush = progressBrush, size = Size( 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 73c1764de2..8432700f3d 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 @@ -82,6 +82,7 @@ import io.element.android.wysiwyg.compose.RichTextEditor import io.element.android.wysiwyg.compose.RichTextEditorState import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import kotlin.time.Duration.Companion.seconds @Composable @@ -204,7 +205,7 @@ fun TextComposer( onPauseClick = onPauseVoiceMessageClicked ) is VoiceMessageState.Recording -> - VoiceMessageRecording(voiceMessageState.level, voiceMessageState.duration) + VoiceMessageRecording(voiceMessageState.levels, voiceMessageState.duration) VoiceMessageState.Idle -> {} } } @@ -798,7 +799,7 @@ internal fun TextComposerVoicePreview() = ElementPreview { enableVoiceMessages = true, ) PreviewColumn(items = persistentListOf({ - VoicePreview(voiceMessageState = VoiceMessageState.Recording(61.seconds, 0.5f)) + VoicePreview(voiceMessageState = VoiceMessageState.Recording(61.seconds, List(100) { it.toFloat() / 200 }.toPersistentList())) }, { VoicePreview(voiceMessageState = VoiceMessageState.Preview(isPlaying = false)) }, { diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt new file mode 100644 index 0000000000..aa4a6cc749 --- /dev/null +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.textcomposer.components + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import io.element.android.libraries.designsystem.components.media.drawWaveform +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.theme.ElementTheme +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toPersistentList + +private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F +private val waveFormHeight = 26.dp +@Composable +fun LiveWaveformView( + levels: ImmutableList, + modifier: Modifier = Modifier, + brush: Brush = SolidColor(ElementTheme.colors.iconQuaternary), + lineWidth: Dp = 2.dp, + linePadding: Dp = 2.dp, +) { + var canvasSize by remember { mutableStateOf(DpSize(0.dp, 0.dp)) } + + val canvasWidth by remember(levels, lineWidth, linePadding) { + derivedStateOf { + levels.size * (lineWidth.value + linePadding.value) + } + } + var width by remember { mutableIntStateOf(0) } + + Box(contentAlignment = Alignment.CenterEnd, + modifier = modifier + .fillMaxWidth() + .height(waveFormHeight) + .onSizeChanged { width = it.width } + ) { + Canvas( + modifier = Modifier + .width(Dp(canvasWidth)) + .graphicsLayer(alpha = DEFAULT_GRAPHICS_LAYER_ALPHA) + .then(modifier) + ) { + canvasSize = DpSize(Dp(canvasWidth), size.height.toDp()) + val countThatFitsWidth = (width.toFloat() / (lineWidth.toPx() + linePadding.toPx())).toInt() + drawWaveform( + waveformData = levels.takeLast(countThatFitsWidth).toPersistentList(), + canvasSize = canvasSize, + brush = brush, + lineWidth = lineWidth, + linePadding = linePadding, + ) + } + } +} + +@PreviewsDayNight +@Composable +internal fun LiveWaveformViewPreview() = ElementPreview { + Column { + + LiveWaveformView( + levels = List(100) { it.toFloat() / 200 }.toPersistentList(), + modifier = Modifier.height(34.dp), + ) + LiveWaveformView( + levels = List(40) { it.toFloat() / 40 }.toPersistentList(), + modifier = Modifier.height(34.dp), + ) + } +} diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt index 22244cd58b..29993a0ec6 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt @@ -20,7 +20,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn @@ -37,12 +36,14 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.theme.ElementTheme import io.element.android.libraries.ui.utils.time.formatShort +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toPersistentList import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @Composable internal fun VoiceMessageRecording( - level: Float, + levels: ImmutableList, duration: Duration, modifier: Modifier = Modifier, ) { @@ -70,28 +71,11 @@ internal fun VoiceMessageRecording( Spacer(Modifier.size(20.dp)) - // TODO Replace with waveform UI - DebugAudioLevel( - modifier = Modifier.weight(1f), level = level - ) - } -} - -@Composable -private fun DebugAudioLevel( - level: Float, - modifier: Modifier = Modifier, -) { - Box( - modifier = modifier - .height(26.dp) - ) { - Box( + LiveWaveformView( modifier = Modifier - .align(Alignment.CenterEnd) - .fillMaxWidth(level) - .background(ElementTheme.colors.iconQuaternary, shape = MaterialTheme.shapes.small) - .fillMaxHeight() + .height(34.dp) + .weight(1f), + levels = levels ) } } @@ -108,5 +92,5 @@ private fun RedRecordingDot( @PreviewsDayNight @Composable internal fun VoiceMessageRecordingPreview() = ElementPreview { - VoiceMessageRecording(0.5f, 0.seconds) + VoiceMessageRecording(List(100) { it.toFloat() / 200 }.toPersistentList(), 0.seconds) } 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 012f655ad2..e5edd2c760 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 @@ -16,6 +16,7 @@ package io.element.android.libraries.textcomposer.model +import kotlinx.collections.immutable.ImmutableList import kotlin.time.Duration sealed class VoiceMessageState { @@ -27,6 +28,6 @@ sealed class VoiceMessageState { data object Sending: VoiceMessageState() data class Recording( val duration: Duration, - val level: Float, + 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 c168e3d5fe..6f7ac54f5e 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 @@ -29,9 +29,9 @@ sealed class VoiceRecorderState { * The recorder is currently recording. * * @property elapsedTime The elapsed time since the recording started. - * @property level The current audio level of the recording as a fraction of 1. + * @property levels The current audio levels of the recording as a fraction of 1. */ - data class Recording(val elapsedTime: Duration, val level: Float) : VoiceRecorderState() + data class Recording(val elapsedTime: Duration, val levels: List) : VoiceRecorderState() /** * The recorder has finished recording. diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt index e1481083f9..2590cf64e0 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt @@ -96,13 +96,13 @@ class VoiceRecorderImpl @Inject constructor( when (audio) { is Audio.Data -> { val audioLevel = audioLevelCalculator.calculateAudioLevel(audio.buffer) - _state.emit(VoiceRecorderState.Recording(elapsedTime, audioLevel)) levels.add(audioLevel) + _state.emit(VoiceRecorderState.Recording(elapsedTime, levels)) encoder.encode(audio.buffer, audio.readSize) } is Audio.Error -> { Timber.e("Voice message error: code=${audio.audioRecordErrorCode}") - _state.emit(VoiceRecorderState.Recording(elapsedTime, 0.0f)) + _state.emit(VoiceRecorderState.Recording(elapsedTime, listOf())) } } } From 416aa3b64a6754abde1fea59e5c82c8f0cef220a Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 27 Oct 2023 08:41:08 +0100 Subject: [PATCH 2/9] FIx height and concurrent exception - Fix live waveform hight - Fix concurrent modification exception when sharing levels - Tidy up width of live waveform --- .../components/LiveWaveformView.kt | 7 +-- .../components/VoiceMessageRecording.kt | 2 +- .../voicerecorder/impl/VoiceRecorderImpl.kt | 45 ++++++++++++------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt index aa4a6cc749..0d083fe3e2 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt @@ -44,6 +44,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.theme.ElementTheme import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList +import java.lang.Float.min private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F private val waveFormHeight = 26.dp @@ -57,7 +58,7 @@ fun LiveWaveformView( ) { var canvasSize by remember { mutableStateOf(DpSize(0.dp, 0.dp)) } - val canvasWidth by remember(levels, lineWidth, linePadding) { + val waveformWidth by remember(levels, lineWidth, linePadding) { derivedStateOf { levels.size * (lineWidth.value + linePadding.value) } @@ -72,11 +73,11 @@ fun LiveWaveformView( ) { Canvas( modifier = Modifier - .width(Dp(canvasWidth)) + .width(canvasSize.width) .graphicsLayer(alpha = DEFAULT_GRAPHICS_LAYER_ALPHA) .then(modifier) ) { - canvasSize = DpSize(Dp(canvasWidth), size.height.toDp()) + canvasSize = DpSize(Dp(min(waveformWidth, width.toFloat())), size.height.toDp()) val countThatFitsWidth = (width.toFloat() / (lineWidth.toPx() + linePadding.toPx())).toInt() drawWaveform( waveformData = levels.takeLast(countThatFitsWidth).toPersistentList(), diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt index 29993a0ec6..038864d4da 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt @@ -73,7 +73,7 @@ internal fun VoiceMessageRecording( LiveWaveformView( modifier = Modifier - .height(34.dp) + .height(26.dp) .weight(1f), levels = levels ) diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt index 2590cf64e0..0dcd085a81 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.voicerecorder.api.VoiceRecorder import io.element.android.libraries.voicerecorder.api.VoiceRecorderState import io.element.android.libraries.voicerecorder.impl.audio.Audio @@ -38,6 +39,8 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.yield import timber.log.Timber import java.io.File @@ -67,6 +70,7 @@ class VoiceRecorderImpl @Inject constructor( private var audioReader: AudioReader? = null private var recordingJob: Job? = null private val levels: MutableList = mutableListOf() + private val lock = Mutex() private val _state = MutableStateFlow(VoiceRecorderState.Idle) override val state: StateFlow = _state @@ -76,7 +80,10 @@ class VoiceRecorderImpl @Inject constructor( Timber.i("Voice recorder started recording") outputFile = fileManager.createFile() .also(encoder::init) - levels.clear() + + lock.withLock { + levels.clear() + } val audioRecorder = audioReaderFactory.create(config, dispatchers).also { audioReader = it } @@ -96,8 +103,11 @@ class VoiceRecorderImpl @Inject constructor( when (audio) { is Audio.Data -> { val audioLevel = audioLevelCalculator.calculateAudioLevel(audio.buffer) - levels.add(audioLevel) - _state.emit(VoiceRecorderState.Recording(elapsedTime, levels)) + + lock.withLock{ + levels.add(audioLevel) + _state.emit(VoiceRecorderState.Recording(elapsedTime, levels.toList())) + } encoder.encode(audio.buffer, audio.readSize) } is Audio.Error -> { @@ -126,21 +136,24 @@ class VoiceRecorderImpl @Inject constructor( audioReader = null encoder.release() - if (cancelled) { - deleteRecording() - levels.clear() - } - _state.emit( - when (val file = outputFile) { - null -> VoiceRecorderState.Idle - else -> VoiceRecorderState.Finished( - file = file, - mimeType = fileConfig.mimeType, - waveform = levels.resample(100), - ) + lock.withLock { + if (cancelled) { + deleteRecording() + levels.clear() } - ) + + _state.emit( + when (val file = outputFile) { + null -> VoiceRecorderState.Idle + else -> VoiceRecorderState.Finished( + file = file, + mimeType = fileConfig.mimeType, + waveform = levels.resample(100), + ) + } + ) + } } /** From 1a2b728361c23580e18f2aebaeecfcdfdcc5a63b Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 27 Oct 2023 08:45:20 +0100 Subject: [PATCH 3/9] lint --- .../android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt index 0dcd085a81..89e6f9186b 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImpl.kt @@ -23,7 +23,6 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn -import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.voicerecorder.api.VoiceRecorder import io.element.android.libraries.voicerecorder.api.VoiceRecorderState import io.element.android.libraries.voicerecorder.impl.audio.Audio From 1cb27661c8cdc9419ed956c3629178458033194b Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 27 Oct 2023 09:32:05 +0100 Subject: [PATCH 4/9] Fix tests --- .../composer/VoiceMessageComposerPresenterTest.kt | 5 +++-- .../libraries/voicerecorder/test/FakeVoiceRecorder.kt | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) 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 90ab3ae16e..27828446e7 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 @@ -44,6 +44,7 @@ import io.element.android.libraries.textcomposer.model.VoiceMessageState import io.element.android.libraries.voicerecorder.test.FakeVoiceRecorder import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest @@ -66,7 +67,7 @@ class VoiceMessageComposerPresenterTest { companion object { private val RECORDING_DURATION = 1.seconds - private val RECORDING_STATE = VoiceMessageState.Recording(RECORDING_DURATION, 0.2f) + private val RECORDING_STATE = VoiceMessageState.Recording(RECORDING_DURATION, listOf(0.1f, 0.2f).toPersistentList()) } @Test @@ -145,7 +146,7 @@ class VoiceMessageComposerPresenterTest { } // Nothing should happen - assertThat(finalState.voiceMessageState).isEqualTo(VoiceMessageState.Recording(RECORDING_DURATION, 0.2f)) + assertThat(finalState.voiceMessageState).isEqualTo(VoiceMessageState.Recording(RECORDING_DURATION, RECORDING_STATE.levels)) voiceRecorder.assertCalls(started = 1, stopped = 0, deleted = 0) testPauseAndDestroy(finalState) diff --git a/libraries/voicerecorder/test/src/main/kotlin/io/element/android/libraries/voicerecorder/test/FakeVoiceRecorder.kt b/libraries/voicerecorder/test/src/main/kotlin/io/element/android/libraries/voicerecorder/test/FakeVoiceRecorder.kt index 7d3f140529..e55d206594 100644 --- a/libraries/voicerecorder/test/src/main/kotlin/io/element/android/libraries/voicerecorder/test/FakeVoiceRecorder.kt +++ b/libraries/voicerecorder/test/src/main/kotlin/io/element/android/libraries/voicerecorder/test/FakeVoiceRecorder.kt @@ -53,8 +53,8 @@ class FakeVoiceRecorder( curRecording = File("file.ogg") timeSource += recordingDuration - levels.forEach { - _state.emit(VoiceRecorderState.Recording(startedAt.elapsedNow(), it)) + for(i in 1..levels.size) { + _state.emit(VoiceRecorderState.Recording(startedAt.elapsedNow(), levels.take(i))) } } From 1d1b97babdbc462436de0cd66cfb154e3bf84969 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 27 Oct 2023 08:51:51 +0000 Subject: [PATCH 5/9] Update screenshots --- ..._MessageComposerViewVoice-D-5_5_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._MessageComposerViewVoice-N-5_6_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...nts_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png | 3 +++ ...nts_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png | 3 +++ ...onents_null_RecordButton-D-12_12_null,NEXUS_5,1.0,en].png} | 0 ...onents_null_RecordButton-N-12_13_null,NEXUS_5,1.0,en].png} | 0 ...mponents_null_SendButton-D-13_13_null,NEXUS_5,1.0,en].png} | 0 ...mponents_null_SendButton-N-13_14_null,NEXUS_5,1.0,en].png} | 0 ...ents_null_TextFormatting-D-14_14_null,NEXUS_5,1.0,en].png} | 0 ...ents_null_TextFormatting-N-14_15_null,NEXUS_5,1.0,en].png} | 0 ...VoiceMessageDeleteButton-D-15_15_null,NEXUS_5,1.0,en].png} | 0 ...VoiceMessageDeleteButton-N-15_16_null,NEXUS_5,1.0,en].png} | 0 ...null_VoiceMessagePreview-D-16_16_null,NEXUS_5,1.0,en].png} | 0 ...null_VoiceMessagePreview-N-16_17_null,NEXUS_5,1.0,en].png} | 0 ...ull_VoiceMessageRecording-D-16_16_null,NEXUS_5,1.0,en].png | 3 --- ...ull_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png | 3 +++ ...ull_VoiceMessageRecording-N-16_17_null,NEXUS_5,1.0,en].png | 3 --- ...ull_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png | 3 +++ ...oser_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png | 4 ++-- 20 files changed, 20 insertions(+), 14 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_RecordButton-D-11_11_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_RecordButton-D-12_12_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_RecordButton-N-11_12_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_RecordButton-N-12_13_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_SendButton-D-12_12_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_SendButton-D-13_13_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_SendButton-N-12_13_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_SendButton-N-13_14_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_TextFormatting-D-13_13_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_TextFormatting-D-14_14_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_TextFormatting-N-13_14_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_TextFormatting-N-14_15_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-D-14_14_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-D-15_15_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-N-14_15_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-N-15_16_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-D-15_15_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-D-16_16_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-N-15_16_null,NEXUS_5,1.0,en].png => ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-N-16_17_null,NEXUS_5,1.0,en].png} (100%) delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-16_16_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-16_17_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-5_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-5_5_null_0,NEXUS_5,1.0,en].png index 9b798ded60..f860d06dd2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-5_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-5_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c25252b8d43f4ffb58673f375709b4811901a78676580a7dd0288b8624615d7 -size 7787 +oid sha256:0e250201e94c17c9907721753edf95250626511e20287a16576f0a7388a28bae +size 8123 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-5_6_null_0,NEXUS_5,1.0,en].png index 26978d7efe..946624ce1b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-5_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-5_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55fa9c5633d3776a3401db72e2e53d9eacedd745e0db7f259f6ada5d7a8d584a -size 7473 +oid sha256:5e566ef57e3db6e25d86dab61492d6acd2712a063f0c70d76b049af6d0b84b41 +size 7750 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..665c8811ac --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb0d3bfcfd75cbd75fd9270ff1dc27090e5dbac79ca8db8a46d91a4c12bc966b +size 4457 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..fae8a6fca3 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c89ac73df77c2bccb0c2aa80cee1420f78e7d07f0eda89a90bffef55e8cf753 +size 4464 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-D-11_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-D-12_12_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-D-11_11_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-D-12_12_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-N-11_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-N-12_13_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-N-11_12_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_RecordButton-N-12_13_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-D-12_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-D-13_13_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-D-12_12_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-D-13_13_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-N-12_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-N-13_14_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-N-12_13_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_SendButton-N-13_14_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-D-13_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-D-14_14_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-D-13_13_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-D-14_14_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-N-13_14_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-N-14_15_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-N-13_14_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_TextFormatting-N-14_15_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-D-14_14_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-D-15_15_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-D-14_14_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-D-15_15_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-N-14_15_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-N-15_16_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-N-14_15_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageDeleteButton-N-15_16_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-D-15_15_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-D-16_16_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-D-15_15_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-D-16_16_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-N-15_16_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-N-16_17_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-N-15_16_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessagePreview-N-16_17_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-16_16_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-16_16_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 1436eea3f5..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-16_16_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:208ad62e23efd6f07e2cce08c1d1511af4c4fc2ae6bc3299134fed9efb1c55d3 -size 7238 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d4f45d7af7 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0db8293a289a2566aa6929bdf2217bde9b73e80accc0a4e396366d4baeab097 +size 6834 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-16_17_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-16_17_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 4b2b719498..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-16_17_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8cf7662c33de6ad1b58785674cbfce1d6323fe84e35c8398b563ea65e5ff9fa7 -size 6919 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..14940aaaca --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92937df3d489e3c475d61c2ae6c5169a5fc8284607ff5e39c4e7cc6c82bb607b +size 6533 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png index 1fc392e02d..2c2555bf7c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8eed5b8511637961df60be133688df984560cb84b333a9377e859446dfac2e04 -size 18036 +oid sha256:ed064889becfca73443372cd8508d26735f8f73413a3b400699a88dffd7f5380 +size 18383 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png index 19603922a0..7177c6e8d0 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14bcc3395316251b2e25a23f95b53030bf2e2ebe0623ef7e113330a5fd2f853d -size 15852 +oid sha256:21c3c1e7225f2f7c0b2aab809fe2bfa3c9327fcfeb35362a70485b66964bbc2a +size 16143 From 8321eaf19de5322d3fa815f83e01330c292077b6 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 27 Oct 2023 10:56:45 +0100 Subject: [PATCH 6/9] Fix tests --- .../voicerecorder/impl/VoiceRecorderImplTest.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImplTest.kt b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImplTest.kt index cb9881087e..b764dc92f7 100644 --- a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImplTest.kt +++ b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/VoiceRecorderImplTest.kt @@ -60,11 +60,11 @@ class VoiceRecorderImplTest { assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Idle) voiceRecorder.startRecord() - assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.seconds, 1.0f)) + assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.seconds, listOf(1.0f))) timeSource += 1.seconds - assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(1.seconds, 0.0f)) + assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(1.seconds, listOf())) timeSource += 1.seconds - assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(2.seconds, 1.0f)) + assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(2.seconds, listOf(1.0f, 1.0f))) } } @@ -75,9 +75,9 @@ class VoiceRecorderImplTest { assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Idle) voiceRecorder.startRecord() - assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.minutes, 1.0f)) + assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.minutes, listOf(1.0f))) timeSource += 29.minutes - assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(29.minutes, 0.0f)) + assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(29.minutes, listOf())) timeSource += 1.minutes assertThat(awaitItem()).isEqualTo( From 977c7e265a8170e203654c6e336a15ba8f2be897 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 27 Oct 2023 13:06:33 +0100 Subject: [PATCH 7/9] Fix naming and waveform previews --- .../composer/VoiceMessageComposerStateProvider.kt | 2 +- .../android/libraries/textcomposer/TextComposer.kt | 2 +- .../textcomposer/components/LiveWaveformView.kt | 14 ++++++++------ .../components/VoiceMessageRecording.kt | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt index f7e3263287..150381461b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerStateProvider.kt @@ -37,6 +37,6 @@ internal fun aVoiceMessageComposerState( eventSink = {}, ) -internal var aWaveformLevels = List(100) { it.toFloat() / 200 }.toPersistentList() +internal var aWaveformLevels = List(100) { it.toFloat() / 100 }.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 fca12fcf48..d601629baa 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 @@ -817,7 +817,7 @@ internal fun TextComposerVoicePreview() = ElementPreview { enableVoiceMessages = true, ) PreviewColumn(items = persistentListOf({ - VoicePreview(voiceMessageState = VoiceMessageState.Recording(61.seconds, List(100) { it.toFloat() / 200 }.toPersistentList())) + VoicePreview(voiceMessageState = VoiceMessageState.Recording(61.seconds, List(100) { it.toFloat() / 100 }.toPersistentList())) }, { VoicePreview(voiceMessageState = VoiceMessageState.Preview(isPlaying = false)) }, { diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt index 0d083fe3e2..d92851c378 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/LiveWaveformView.kt @@ -58,27 +58,29 @@ fun LiveWaveformView( ) { var canvasSize by remember { mutableStateOf(DpSize(0.dp, 0.dp)) } + var parentWidth by remember { mutableIntStateOf(0) } + val waveformWidth by remember(levels, lineWidth, linePadding) { derivedStateOf { levels.size * (lineWidth.value + linePadding.value) } } - var width by remember { mutableIntStateOf(0) } + Box(contentAlignment = Alignment.CenterEnd, modifier = modifier .fillMaxWidth() .height(waveFormHeight) - .onSizeChanged { width = it.width } + .onSizeChanged { parentWidth = it.width } ) { Canvas( modifier = Modifier - .width(canvasSize.width) + .width(Dp(waveformWidth)) .graphicsLayer(alpha = DEFAULT_GRAPHICS_LAYER_ALPHA) .then(modifier) ) { - canvasSize = DpSize(Dp(min(waveformWidth, width.toFloat())), size.height.toDp()) - val countThatFitsWidth = (width.toFloat() / (lineWidth.toPx() + linePadding.toPx())).toInt() + canvasSize = DpSize(Dp(min(waveformWidth, parentWidth.toFloat())), size.height.toDp()) + val countThatFitsWidth = (parentWidth.toFloat() / (lineWidth.toPx() + linePadding.toPx())).toInt() drawWaveform( waveformData = levels.takeLast(countThatFitsWidth).toPersistentList(), canvasSize = canvasSize, @@ -96,7 +98,7 @@ internal fun LiveWaveformViewPreview() = ElementPreview { Column { LiveWaveformView( - levels = List(100) { it.toFloat() / 200 }.toPersistentList(), + levels = List(100) { it.toFloat() / 100 }.toPersistentList(), modifier = Modifier.height(34.dp), ) LiveWaveformView( diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt index 038864d4da..6930441e4b 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/VoiceMessageRecording.kt @@ -92,5 +92,5 @@ private fun RedRecordingDot( @PreviewsDayNight @Composable internal fun VoiceMessageRecordingPreview() = ElementPreview { - VoiceMessageRecording(List(100) { it.toFloat() / 200 }.toPersistentList(), 0.seconds) + VoiceMessageRecording(List(100) { it.toFloat() / 100 }.toPersistentList(), 0.seconds) } From cb5b463c9b39a58ec72476f7d78f0f163c19d120 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 27 Oct 2023 12:23:14 +0000 Subject: [PATCH 8/9] Update screenshots --- ..._MessageComposerViewVoice-D-6_6_null_0,NEXUS_5,1.0,en].png | 4 ++-- ..._MessageComposerViewVoice-N-6_7_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...nts_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png | 4 ++-- ...nts_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png | 4 ++-- ...ull_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png | 4 ++-- ...ull_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-6_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-6_6_null_0,NEXUS_5,1.0,en].png index f860d06dd2..3ec6004b6d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-6_6_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-D-6_6_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e250201e94c17c9907721753edf95250626511e20287a16576f0a7388a28bae -size 8123 +oid sha256:3d5209087d7841a80f7213f26aaf8322cc5fee03466b9059e06b0daf5f489c1b +size 10012 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-6_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-6_7_null_0,NEXUS_5,1.0,en].png index 946624ce1b..dcddb1ae01 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-6_7_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewVoice-N-6_7_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e566ef57e3db6e25d86dab61492d6acd2712a063f0c70d76b049af6d0b84b41 -size 7750 +oid sha256:5b8fca1de81e424f01a518e3a2547b58c0e9eb7249327f3fcdb1cf62ab655972 +size 9429 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png index 665c8811ac..43f40eb21b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-D-11_11_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb0d3bfcfd75cbd75fd9270ff1dc27090e5dbac79ca8db8a46d91a4c12bc966b -size 4457 +oid sha256:c8ab81200d74af2e45390223484cf17c6bb488eedf3cb10a425e3e2b7546e1b0 +size 11422 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png index fae8a6fca3..b3d851ea36 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_LiveWaveformView-N-11_12_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c89ac73df77c2bccb0c2aa80cee1420f78e7d07f0eda89a90bffef55e8cf753 -size 4464 +oid sha256:47fc7fcebbe8c3f8ad745eac3e9687c7722a898e55e1f11f2903cffa2af00636 +size 11059 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png index d4f45d7af7..14ace59009 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-D-17_17_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0db8293a289a2566aa6929bdf2217bde9b73e80accc0a4e396366d4baeab097 -size 6834 +oid sha256:8ee23864465d4f6cd09f4d9c187916793ce4c8fce2ad77a29e2321e1caa57b7d +size 10135 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png index 14940aaaca..91de915f81 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer.components_null_VoiceMessageRecording-N-17_18_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92937df3d489e3c475d61c2ae6c5169a5fc8284607ff5e39c4e7cc6c82bb607b -size 6533 +oid sha256:408ee43f0955bcb120f7e3fbbc51b6276ae139863e1691e6d768a35005d3fa1b +size 9498 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png index e3dbc7572c..825b42e9b2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-D-4_4_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04d22483f11bc6ce290c874b285a36e55144b9ea733b82b0c7fabc1fe9d86772 -size 287 +oid sha256:5abbadadbc4b0943be47d269cddecfe42e8a7ae43e4dd618eb2a8d5aefc7c1b1 +size 27291 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png index 949231be20..e32acc4666 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerVoice-N-4_5_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b680969cf395ca6c2626339699c233133aa281ad6275c1d48fbbe03d770a20e2 -size 287 +oid sha256:f73f8eed6746a54bd0bf706acda638155ea99e7aba8b78fc809b9f26b0a5986f +size 24901 From af513a80236e742026039f511cecfc8a26660d65 Mon Sep 17 00:00:00 2001 From: David Langley Date: Fri, 27 Oct 2023 13:55:42 +0100 Subject: [PATCH 9/9] Fix documentation --- .../designsystem/components/media/WaveformPlaybackView.kt | 1 - 1 file changed, 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 f856c0414e..70a506cffa 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 @@ -66,7 +66,6 @@ private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F * @param cursorBrush The brush to use to draw the cursor. * @param lineWidth The width of the waveform lines. * @param linePadding The padding between waveform lines. - * @param minimumGraphAmplitude The minimum amplitude to display, regardless of waveform data. */ @OptIn(ExperimentalComposeUiApi::class) @Composable