From 827edecda401c8649f4270b77594cd1a9ba3a4d5 Mon Sep 17 00:00:00 2001 From: David Langley Date: Thu, 26 Oct 2023 08:58:03 +0100 Subject: [PATCH] Remove WaveformProgressIndicator and waveform library and lint. -Remove WaveformProgressIndicator - Remove waveform library - lint. --- features/messages/impl/build.gradle.kts | 1 - .../components/event/TimelineItemVoiceView.kt | 1 - .../impl/voicemessages/timeline/Waveform.kt | 50 ++++++++++ .../timeline/WaveformPlaybackView.kt | 43 ++------- .../timeline/WaveformProgressIndicator.kt | 96 ------------------- gradle/libs.versions.toml | 1 - settings.gradle.kts | 1 - 7 files changed, 57 insertions(+), 136 deletions(-) create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/Waveform.kt delete mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformProgressIndicator.kt diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts index db625e5b74..814262321c 100644 --- a/features/messages/impl/build.gradle.kts +++ b/features/messages/impl/build.gradle.kts @@ -65,7 +65,6 @@ dependencies { implementation(libs.vanniktech.blurhash) implementation(libs.telephoto.zoomableimage) implementation(libs.matrix.emojibase.bindings) - implementation(libs.audiowaveform) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt index b0b287f9dc..e6259e291c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt @@ -46,7 +46,6 @@ import io.element.android.features.messages.impl.voicemessages.timeline.VoiceMes import io.element.android.features.messages.impl.voicemessages.timeline.VoiceMessageStateProvider import io.element.android.features.messages.impl.voicemessages.timeline.Waveform import io.element.android.features.messages.impl.voicemessages.timeline.WaveformPlaybackView -import io.element.android.features.messages.impl.voicemessages.timeline.WaveformProgressIndicator import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/Waveform.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/Waveform.kt new file mode 100644 index 0000000000..708aee8b8e --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/Waveform.kt @@ -0,0 +1,50 @@ +/* + * 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.features.messages.impl.voicemessages.timeline + +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList +import kotlin.math.roundToInt + +data class Waveform ( + val data: ImmutableList +) { + companion object { + private val dataRange = 0..1024 + } + + fun normalisedData(maxSamplesCount: Int): ImmutableList { + if(maxSamplesCount <= 0) { + return persistentListOf() + } + + // Filter the data to keep only the expected number of samples + val result = if (data.size > maxSamplesCount) { + (0.. + val targetIndex = (index.toDouble() * (data.count().toDouble() / maxSamplesCount.toDouble())).roundToInt() + data[targetIndex] + } + } else { + data + } + + // Normalize the sample in the allowed range + return result.map { it.toFloat() / dataRange.last.toFloat() }.toPersistentList() + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformPlaybackView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformPlaybackView.kt index eeaf34490d..4759a58ef9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformPlaybackView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformPlaybackView.kt @@ -45,39 +45,10 @@ import androidx.compose.ui.unit.dp 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.persistentListOf import kotlinx.collections.immutable.toPersistentList import kotlin.math.max -import kotlin.math.roundToInt -data class Waveform ( - val data: ImmutableList -) { - companion object { - private val dataRange = 0..1024 - } - - fun normalisedData(maxSamplesCount: Int): ImmutableList { - if(maxSamplesCount <= 0) { - return persistentListOf() - } - - // Filter the data to keep only the expected number of samples - val result = if (data.size > maxSamplesCount) { - (0.. - val targetIndex = (index.toDouble() * (data.count().toDouble() / maxSamplesCount.toDouble())).roundToInt() - data[targetIndex] - } - } else { - data - } - - // Normalize the sample in the allowed range - return result.map { it.toFloat() / dataRange.last.toFloat() }.toPersistentList() - } -} private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -94,7 +65,7 @@ fun WaveformPlaybackView( linePadding: Dp = 2.dp, minimumGraphAmplitude: Float = 2F, ) { - var seekProgress = remember { mutableStateOf(null) } + val seekProgress = remember { mutableStateOf(null) } var canvasSize by remember { mutableStateOf(DpSize(0.dp, 0.dp)) } var canvasSizePx by remember { mutableStateOf(Size(0f, 0f)) } val progress by remember(playbackProgress, seekProgress.value) { @@ -105,7 +76,7 @@ fun WaveformPlaybackView( val progressAnimated = animateFloatAsState(targetValue = progress, label = "progressAnimation") val amplitudeDisplayCount by remember(canvasSize) { derivedStateOf { - ((canvasSize.width.value) / (lineWidth.value + linePadding.value)).toInt() + (canvasSize.width.value / (lineWidth.value + linePadding.value)).toInt() } } val normalizedWaveformData by remember(amplitudeDisplayCount) { @@ -124,13 +95,13 @@ fun WaveformPlaybackView( MotionEvent.ACTION_DOWN -> { if (it.x in 0F..canvasSizePx.width) { requestDisallowInterceptTouchEvent.invoke(true) - seekProgress.value = (it.x / canvasSizePx.width) + seekProgress.value = it.x / canvasSizePx.width true } else false } MotionEvent.ACTION_MOVE -> { if (it.x in 0F..canvasSizePx.width) { - seekProgress.value = (it.x / canvasSizePx.width) + seekProgress.value = it.x / canvasSizePx.width } true } @@ -155,7 +126,7 @@ fun WaveformPlaybackView( brush = brush, topLeft = Offset( x = index * (linePadding + lineWidth).toPx(), - y = centerY - (drawingAmplitude / 2) + y = centerY - drawingAmplitude / 2 ), size = Size( width = lineWidth.toPx(), @@ -168,7 +139,7 @@ fun WaveformPlaybackView( drawRect( brush = progressBrush, size = Size( - width = (progressAnimated.value) * canvasSize.width.toPx(), + width = progressAnimated.value * canvasSize.width.toPx(), height = canvasSize.height.toPx() ), blendMode = BlendMode.SrcAtop @@ -178,7 +149,7 @@ fun WaveformPlaybackView( brush = cursorBrush, topLeft = Offset( x = progressAnimated.value * canvasSize.width.toPx(), - y = centerY - ((canvasSize.height.toPx() - 2) / 2) + y = centerY - (canvasSize.height.toPx() - 2) / 2 ), size = Size( width = lineWidth.toPx(), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformProgressIndicator.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformProgressIndicator.kt deleted file mode 100644 index 94731ef0c8..0000000000 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/WaveformProgressIndicator.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.features.messages.impl.voicemessages.timeline - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.unit.dp -import com.linc.audiowaveform.AudioWaveform -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.persistentListOf -import kotlinx.collections.immutable.toPersistentList - -@Composable -fun WaveformProgressIndicator( - progress: Float, - amplitudes: ImmutableList, - modifier: Modifier = Modifier, - onSeek: (progress: Float) -> Unit = {}, -) { - var seekProgress: Float? by remember { mutableStateOf(null) } - val scaledAmplitudes = remember(amplitudes) { amplitudes.scaleAmplitudes() } - AudioWaveform( - modifier = modifier, - waveformBrush = SolidColor(ElementTheme.colors.iconQuaternary), - progressBrush = SolidColor(ElementTheme.colors.iconSecondary), - onProgressChangeFinished = { - // This is to send just one onSeek callback after the user has finished seeking. - // Otherwise the AudioWaveform library would send multiple callbacks while the user is seeking. - val p = seekProgress!! - seekProgress = null - onSeek(p) - }, - spikeWidth = 1.6.dp, - spikeRadius = 0.8.dp, - spikePadding = 3.dp, - progress = seekProgress ?: progress, - amplitudes = scaledAmplitudes, - onProgressChange = { seekProgress = it }, - ) -} - -@PreviewsDayNight -@Composable -internal fun WaveformProgressIndicatorPreview() = ElementPreview { - Column { - WaveformProgressIndicator( - progress = 0.5f, - amplitudes = persistentListOf(), - ) - WaveformProgressIndicator( - progress = 0.5f, - amplitudes = persistentListOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), - ) - WaveformProgressIndicator( - progress = 0.5f, - amplitudes = List(1024) { it }.toPersistentList() - ) - } -} - -/** - * Scale amplitudes to fit in the waveform view. - * - * It seems amplitudes > 128 are clipped by the waveform library. - * Workaround for https://github.com/lincollincol/compose-audiowaveform/issues/22 - * - * TODO Voice messages: Remove this workaround when the waveform library is fixed. - */ -private fun ImmutableList.scaleAmplitudes(): List { - val maxAmplitude = if (isEmpty()) 1 else maxOf { it } - val scalingFactor = 128 / maxAmplitude.toFloat() - return map { (it * scalingFactor).toInt() } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a9499d81ee..831fae272e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -166,7 +166,6 @@ maplibre = "org.maplibre.gl:android-sdk:10.2.0" maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:2.0.1" maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:2.0.1" opusencoder = "io.element.android:opusencoder:1.1.0" -audiowaveform = "com.github.lincollincol:compose-audiowaveform:1.1.1" # Analytics posthog = "com.posthog.android:posthog:2.0.3" diff --git a/settings.gradle.kts b/settings.gradle.kts index 3da4e5efe9..9ac2c96dde 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,7 +35,6 @@ dependencyResolutionManagement { content { includeModule("com.github.UnifiedPush", "android-connector") includeModule("com.github.matrix-org", "matrix-analytics-events") - includeModule("com.github.lincollincol", "compose-audiowaveform") } } // To have immediate access to Rust SDK versions