Merge branch 'develop' into feat/variable-playback-speed

This commit is contained in:
Florian 2025-12-30 21:29:18 +01:00 committed by GitHub
commit 0c004d933c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8020 changed files with 56825 additions and 29988 deletions

View file

@ -1,14 +1,14 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* 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.voiceplayer.impl
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
@ -21,7 +21,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlin.time.Duration
@ContributesBinding(RoomScope::class)
@Inject
class DefaultVoiceMessagePresenterFactory(
private val analyticsService: AnalyticsService,
@SessionCoroutineScope

View file

@ -1,7 +1,8 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/

View file

@ -1,14 +1,14 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* 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.voiceplayer.impl
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.core.extensions.mapCatchingExceptions
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.RoomScope
@ -124,8 +124,7 @@ class DefaultVoiceMessagePlayer(
filename: String?,
) : VoiceMessagePlayer {
@ContributesBinding(RoomScope::class) // Scoped types can't use @Inject.
@Inject
class Factory(
class Factory(
private val mediaPlayer: MediaPlayer,
private val voiceMessageMediaRepoFactory: VoiceMessageMediaRepo.Factory,
) : VoiceMessagePlayer.Factory {

View file

@ -1,7 +1,8 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
@ -87,7 +88,7 @@ class VoiceMessagePresenter(
}
}
fun eventSink(event: VoiceMessageEvents) {
fun handleEvent(event: VoiceMessageEvents) {
when (event) {
is VoiceMessageEvents.PlayPause -> {
if (playerState.isPlaying) {
@ -130,7 +131,7 @@ class VoiceMessagePresenter(
time = time,
showCursor = showCursor,
playbackSpeed = playbackSpeed.value,
eventSink = { eventSink(it) },
eventSink = ::handleEvent,
)
}
}

View file

@ -1,7 +1,8 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
@ -11,8 +12,8 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.mxc.MxcTools
import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
import io.element.android.libraries.matrix.test.mxc.FakeMxcTools
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@ -130,7 +131,7 @@ private fun createDefaultVoiceMessageMediaRepo(
mxcUri: String = MXC_URI,
) = DefaultVoiceMessageMediaRepo(
cacheDir = temporaryFolder.root,
mxcTools = MxcTools(),
mxcTools = FakeMxcTools(),
matrixMediaLoader = matrixMediaLoader,
mediaSource = MediaSource(
url = mxcUri,

View file

@ -1,7 +1,8 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
@ -114,7 +115,8 @@ class DefaultVoiceMessagePlayerTest {
assertThat(player1.prepare().isSuccess).isTrue()
matchReadyState(1_000L)
player1.play()
awaitItem().let { // it plays until the end.
awaitItem().let {
// it plays until the end.
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isTrue()
@ -127,14 +129,16 @@ class DefaultVoiceMessagePlayerTest {
player2.state.test {
matchInitialState()
assertThat(player2.prepare().isSuccess).isTrue()
awaitItem().let { // Additional spurious state due to MediaPlayer owner change.
awaitItem().let {
// Additional spurious state due to MediaPlayer owner change.
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isTrue()
assertThat(it.currentPosition).isEqualTo(1000)
assertThat(it.duration).isEqualTo(1000)
}
awaitItem().let { // Additional spurious state due to MediaPlayer owner change.
awaitItem().let {
// Additional spurious state due to MediaPlayer owner change.
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isFalse()
@ -143,7 +147,8 @@ class DefaultVoiceMessagePlayerTest {
}
matchReadyState(1_000L)
player2.play()
awaitItem().let { // it plays until the end.
awaitItem().let {
// it plays until the end.
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isTrue()
@ -154,7 +159,8 @@ class DefaultVoiceMessagePlayerTest {
// Play player1 again.
player1.state.test {
awaitItem().let { // Last previous state/
awaitItem().let {
// Last previous state/
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isTrue()
@ -162,7 +168,8 @@ class DefaultVoiceMessagePlayerTest {
assertThat(it.duration).isEqualTo(1000)
}
assertThat(player1.prepare().isSuccess).isTrue()
awaitItem().let { // Additional spurious state due to MediaPlayer owner change.
awaitItem().let {
// Additional spurious state due to MediaPlayer owner change.
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isFalse()
@ -171,7 +178,8 @@ class DefaultVoiceMessagePlayerTest {
}
matchReadyState(1_000L)
player1.play()
awaitItem().let { // it played again until the end.
awaitItem().let {
// it played again until the end.
assertThat(it.isReady).isFalse()
assertThat(it.isPlaying).isFalse()
assertThat(it.isEnded).isTrue()
@ -189,7 +197,8 @@ class DefaultVoiceMessagePlayerTest {
assertThat(player.prepare().isSuccess).isTrue()
matchReadyState()
player.play()
skipItems(1) // skip play state
// skip play state
skipItems(1)
player.pause()
awaitItem().let {
assertThat(it.isPlaying).isFalse()
@ -206,9 +215,11 @@ class DefaultVoiceMessagePlayerTest {
assertThat(player.prepare().isSuccess).isTrue()
matchReadyState()
player.play()
skipItems(1) // skip play state
// skip play state
skipItems(1)
player.pause()
skipItems(1) // skip pause state
// skip pause state
skipItems(1)
player.play()
awaitItem().let {
assertThat(it.isPlaying).isTrue()

View file

@ -1,7 +1,8 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/

View file

@ -1,7 +1,8 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/