diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt index 9fda8b8548..803bc260d7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt @@ -47,8 +47,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageT import io.element.android.libraries.matrix.ui.messages.toHtmlDocument import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList -import java.time.Duration import javax.inject.Inject +import kotlin.time.Duration class TimelineItemContentMessageFactory @Inject constructor( private val fileSizeFormatter: FileSizeFormatter, @@ -104,7 +104,7 @@ class TimelineItemContentMessageFactory @Inject constructor( mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream, width = messageType.info?.width?.toInt(), height = messageType.info?.height?.toInt(), - duration = messageType.info?.duration?.toMillis() ?: 0L, + duration = messageType.info?.duration ?: Duration.ZERO, blurHash = messageType.info?.blurhash, aspectRatio = aspectRatio, formattedFileSize = fileSizeFormatter.format(messageType.info?.size ?: 0), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt index 9d9a41e0e3..454bc581dc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt @@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.timeline.model.event import io.element.android.features.messages.impl.media.helper.formatFileExtensionAndSize import io.element.android.libraries.matrix.api.media.MediaSource -import java.time.Duration +import kotlin.time.Duration data class TimelineItemAudioContent( val body: String, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt index 06cb53b6fe..09c553730d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt @@ -19,7 +19,7 @@ package io.element.android.features.messages.impl.timeline.model.event import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MediaSource -import java.time.Duration +import kotlin.time.Duration.Companion.milliseconds open class TimelineItemAudioContentProvider : PreviewParameterProvider { override val values: Sequence @@ -35,6 +35,6 @@ fun aTimelineItemAudioContent(fileName: String = "A sound.mp3") = TimelineItemAu mimeType = MimeTypes.Pdf, formattedFileSize = "100kB", fileExtension = "mp3", - duration = Duration.ofMillis(100), + duration = 100.milliseconds, mediaSource = MediaSource(""), ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt index 14ec0a972d..5519fbc7f1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt @@ -17,10 +17,11 @@ package io.element.android.features.messages.impl.timeline.model.event import io.element.android.libraries.matrix.api.media.MediaSource +import kotlin.time.Duration data class TimelineItemVideoContent( val body: String, - val duration: Long, + val duration: Duration, val videoSource: MediaSource, val thumbnailSource: MediaSource?, val aspectRatio: Float?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt index adff01bdc8..939636fadc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH +import kotlin.time.Duration.Companion.milliseconds open class TimelineItemVideoContentProvider : PreviewParameterProvider { override val values: Sequence @@ -35,7 +36,7 @@ fun aTimelineItemVideoContent() = TimelineItemVideoContent( thumbnailSource = null, blurHash = A_BLUR_HASH, aspectRatio = 0.5f, - duration = 100, + duration = 100.milliseconds, videoSource = MediaSource(""), height = 300, width = 150, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt index 0d3bb903de..395b5dd2b3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContent.kt @@ -19,7 +19,7 @@ package io.element.android.features.messages.impl.timeline.model.event import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource import kotlinx.collections.immutable.ImmutableList -import java.time.Duration +import kotlin.time.Duration data class TimelineItemVoiceContent( val eventId: EventId?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt index 830255f06e..f27922a4dd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVoiceContentProvider.kt @@ -21,21 +21,23 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource import kotlinx.collections.immutable.toPersistentList -import java.time.Duration +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes open class TimelineItemVoiceContentProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aTimelineItemVoiceContent( - durationMs = 1, + duration = 1.milliseconds, waveform = listOf(), ), aTimelineItemVoiceContent( - durationMs = 10_000, + duration = 10_000.milliseconds, waveform = listOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 8f, 7f, 6f, 5f, 4f, 3f, 2f, 1f, 0f), ), aTimelineItemVoiceContent( - durationMs = 1_800_000, // 30 minutes + duration = 30.minutes, waveform = List(1024) { it / 1024f }, ), ) @@ -44,14 +46,14 @@ open class TimelineItemVoiceContentProvider : PreviewParameterProvider = listOf(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 8f, 7f, 6f, 5f, 4f, 3f, 2f, 1f, 0f), ) = TimelineItemVoiceContent( eventId = eventId?.let { EventId(it) }, body = body, - duration = Duration.ofMillis(durationMs), + duration = duration, mediaSource = MediaSource(contentUri), mimeType = mimeType, waveform = waveform.toPersistentList(), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt index 584ec96f2a..0e1b960ecc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt @@ -16,6 +16,7 @@ package io.element.android.features.messages.impl.voicemessages.composer +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.mediaplayer.api.MediaPlayer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -41,7 +42,7 @@ class VoiceMessageComposerPlayer @Inject constructor( private val coroutineScope: CoroutineScope, ) { companion object { - const val MIME_TYPE = "audio/ogg" + const val MIME_TYPE = MimeTypes.Ogg } private var mediaPath: String? = null @@ -201,6 +202,7 @@ class VoiceMessageComposerPlayer @Inject constructor( progress = 0f, ) } + /** * Whether this player is currently playing. */ @@ -212,7 +214,6 @@ class VoiceMessageComposerPlayer @Inject constructor( val isStopped get() = this.playState == PlayState.Stopped } - enum class PlayState { /** * The player is stopped, i.e. it has just been initialised. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePlayer.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePlayer.kt index a6f002c38a..76180397f4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePlayer.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePlayer.kt @@ -17,6 +17,7 @@ package io.element.android.features.messages.impl.voicemessages.timeline import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource @@ -196,7 +197,7 @@ class DefaultVoiceMessagePlayer( mediaPlayer.setMedia( uri = mediaFile.path, mediaId = eventId.value, - mimeType = "audio/ogg", // Files in the voice cache have no extension so we need to set the mime type manually. + mimeType = MimeTypes.Ogg, // Files in the voice cache have no extension so we need to set the mime type manually. startPositionMs = if (state.isEnded) 0L else state.currentPosition, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenter.kt index aebed9dd57..fa6632308a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenter.kt @@ -98,7 +98,7 @@ class VoiceMessagePresenter @AssistedInject constructor( } } val duration by remember { - derivedStateOf { playerState.duration ?: content.duration.toMillis() } + derivedStateOf { playerState.duration ?: content.duration.inWholeMilliseconds } } val progress by remember { derivedStateOf { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 5410ac0695..4c5bafa1c6 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -264,7 +264,7 @@ class MessagesPresenterTest { val mediaMessage = aMessageEvent( content = TimelineItemVideoContent( body = "video.mp4", - duration = 10L, + duration = 10.milliseconds, videoSource = MediaSource(AN_AVATAR_URL), thumbnailSource = MediaSource(AN_AVATAR_URL), mimeType = MimeTypes.Mp4, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index e695107e10..8c8af4589b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -58,8 +58,8 @@ import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.test.runTest import org.junit.Test -import java.time.Duration -import java.time.Duration.ofMinutes +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes class TimelineItemContentMessageFactoryTest { @@ -140,14 +140,14 @@ class TimelineItemContentMessageFactoryTest { ) val expected = TimelineItemVideoContent( body = "body", - duration = 0, + duration = Duration.ZERO, videoSource = MediaSource(url = "url", json = null), thumbnailSource = null, aspectRatio = null, blurHash = null, height = null, width = null, - mimeType = "application/octet-stream", + mimeType = MimeTypes.OctetStream, formattedFileSize = "0 Bytes", fileExtension = "", ) @@ -163,7 +163,7 @@ class TimelineItemContentMessageFactoryTest { body = "body.mp4", source = MediaSource("url"), info = VideoInfo( - duration = ofMinutes(1), + duration = 1.minutes, height = 100, width = 300, mimetype = MimeTypes.Mp4, @@ -184,7 +184,7 @@ class TimelineItemContentMessageFactoryTest { ) val expected = TimelineItemVideoContent( body = "body.mp4", - duration = 60_000, + duration = 1.minutes, videoSource = MediaSource(url = "url", json = null), thumbnailSource = MediaSource("url_thumbnail"), aspectRatio = 3f, @@ -210,7 +210,7 @@ class TimelineItemContentMessageFactoryTest { body = "body", duration = Duration.ZERO, mediaSource = MediaSource(url = "url", json = null), - mimeType = "application/octet-stream", + mimeType = MimeTypes.OctetStream, formattedFileSize = "0 Bytes", fileExtension = "", ) @@ -226,7 +226,7 @@ class TimelineItemContentMessageFactoryTest { body = "body.mp3", source = MediaSource("url"), info = AudioInfo( - duration = ofMinutes(1), + duration = 1.minutes, size = 123L, mimetype = MimeTypes.Mp3, ) @@ -237,7 +237,7 @@ class TimelineItemContentMessageFactoryTest { ) val expected = TimelineItemAudioContent( body = "body.mp3", - duration = ofMinutes(1), + duration = 1.minutes, mediaSource = MediaSource(url = "url", json = null), mimeType = MimeTypes.Mp3, formattedFileSize = "123 Bytes", @@ -259,7 +259,7 @@ class TimelineItemContentMessageFactoryTest { body = "body", duration = Duration.ZERO, mediaSource = MediaSource(url = "url", json = null), - mimeType = "application/octet-stream", + mimeType = MimeTypes.OctetStream, waveform = emptyList().toImmutableList() ) assertThat(result).isEqualTo(expected) @@ -274,12 +274,13 @@ class TimelineItemContentMessageFactoryTest { body = "body.ogg", source = MediaSource("url"), info = AudioInfo( - duration = ofMinutes(1), + duration = 1.minutes, size = 123L, mimetype = MimeTypes.Ogg, ), details = AudioDetails( - duration = ofMinutes(1), waveform = listOf(1f, 2f) + duration = 1.minutes, + waveform = listOf(1f, 2f), ), ) ), @@ -289,7 +290,7 @@ class TimelineItemContentMessageFactoryTest { val expected = TimelineItemVoiceContent( eventId = AN_EVENT_ID, body = "body.ogg", - duration = ofMinutes(1), + duration = 1.minutes, mediaSource = MediaSource(url = "url", json = null), mimeType = MimeTypes.Ogg, waveform = listOf(1f, 2f).toImmutableList() @@ -315,7 +316,7 @@ class TimelineItemContentMessageFactoryTest { body = "body", duration = Duration.ZERO, mediaSource = MediaSource(url = "url", json = null), - mimeType = "application/octet-stream", + mimeType = MimeTypes.OctetStream, formattedFileSize = "0 Bytes", fileExtension = "" ) @@ -336,7 +337,7 @@ class TimelineItemContentMessageFactoryTest { thumbnailSource = null, formattedFileSize = "0 Bytes", fileExtension = "", - mimeType = "application/octet-stream", + mimeType = MimeTypes.OctetStream, blurhash = null, width = null, height = null, @@ -401,7 +402,7 @@ class TimelineItemContentMessageFactoryTest { thumbnailSource = null, formattedFileSize = "0 Bytes", fileExtension = "", - mimeType = "application/octet-stream" + mimeType = MimeTypes.OctetStream ) assertThat(result).isEqualTo(expected) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt index d9587b5e9b..e562d66815 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt @@ -17,6 +17,7 @@ package io.element.android.features.messages.impl.voicemessages.timeline import com.google.common.truth.Truth +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.test.media.FakeMediaLoader @@ -143,7 +144,7 @@ private fun createDefaultVoiceMessageMediaRepo( url = mxcUri, json = null ), - mimeType = "audio/ogg", + mimeType = MimeTypes.Ogg, body = "someBody.ogg" ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessagePlayerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessagePlayerTest.kt index 23830fdf39..c84487da1d 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessagePlayerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessagePlayerTest.kt @@ -19,6 +19,7 @@ package io.element.android.features.messages.impl.voicemessages.timeline import app.cash.turbine.TurbineTestContext import app.cash.turbine.test import com.google.common.truth.Truth +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.test.AN_EVENT_ID @@ -287,7 +288,7 @@ private fun createDefaultVoiceMessagePlayer( url = MXC_URI, json = null ), - mimeType = "audio/ogg", + mimeType = MimeTypes.Ogg, body = "someBody.ogg" ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt index 644f1fe231..8e776d1eea 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/RedactedVoiceMessageManagerTest.kt @@ -17,6 +17,7 @@ package io.element.android.features.messages.impl.voicemessages.timeline import com.google.common.truth.Truth +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo @@ -37,7 +38,7 @@ class RedactedVoiceMessageManagerTest { @Test fun `redacted event - no playing related media`() = runTest { val mediaPlayer = FakeMediaPlayer().apply { - setMedia(uri = "someUri", mediaId = AN_EVENT_ID.value, mimeType = "audio/ogg") + setMedia(uri = "someUri", mediaId = AN_EVENT_ID.value, mimeType = MimeTypes.Ogg) play() } val manager = aDefaultRedactedVoiceMessageManager(mediaPlayer = mediaPlayer) @@ -54,7 +55,7 @@ class RedactedVoiceMessageManagerTest { @Test fun `redacted event - playing related media is paused`() = runTest { val mediaPlayer = FakeMediaPlayer().apply { - setMedia(uri = "someUri", mediaId = AN_EVENT_ID.value, mimeType = "audio/ogg") + setMedia(uri = "someUri", mediaId = AN_EVENT_ID.value, mimeType = MimeTypes.Ogg) play() } val manager = aDefaultRedactedVoiceMessageManager(mediaPlayer = mediaPlayer) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenterTest.kt index 299e27ced2..9d885016d8 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessagePresenterTest.kt @@ -29,6 +29,7 @@ import io.element.android.services.analytics.test.FakeAnalyticsService import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test +import kotlin.time.Duration.Companion.milliseconds class VoiceMessagePresenterTest { @Test @@ -49,7 +50,7 @@ class VoiceMessagePresenterTest { fun `pressing play downloads and plays`() = runTest { val presenter = createVoiceMessagePresenter( mediaPlayer = FakeMediaPlayer(fakeTotalDurationMs = 2_000), - content = aTimelineItemVoiceContent(durationMs = 2_000), + content = aTimelineItemVoiceContent(duration = 2_000.milliseconds), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -87,7 +88,7 @@ class VoiceMessagePresenterTest { mediaPlayer = FakeMediaPlayer(fakeTotalDurationMs = 2_000), voiceMessageMediaRepo = FakeVoiceMessageMediaRepo().apply { shouldFail = true }, analyticsService = analyticsService, - content = aTimelineItemVoiceContent(durationMs = 2_000), + content = aTimelineItemVoiceContent(duration = 2_000.milliseconds), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -123,7 +124,7 @@ class VoiceMessagePresenterTest { fun `pressing pause while playing pauses`() = runTest { val presenter = createVoiceMessagePresenter( mediaPlayer = FakeMediaPlayer(fakeTotalDurationMs = 2_000), - content = aTimelineItemVoiceContent(durationMs = 2_000), + content = aTimelineItemVoiceContent(duration = 2_000.milliseconds), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -172,7 +173,7 @@ class VoiceMessagePresenterTest { fun `seeking before play`() = runTest { val presenter = createVoiceMessagePresenter( mediaPlayer = FakeMediaPlayer(fakeTotalDurationMs = 2_000), - content = aTimelineItemVoiceContent(durationMs = 10_000), + content = aTimelineItemVoiceContent(duration = 10_000.milliseconds), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -196,7 +197,7 @@ class VoiceMessagePresenterTest { @Test fun `seeking after play`() = runTest { val presenter = createVoiceMessagePresenter( - content = aTimelineItemVoiceContent(durationMs = 10_000), + content = aTimelineItemVoiceContent(duration = 10_000.milliseconds), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt index 42eb81d4a7..422307ffd9 100644 --- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt @@ -29,6 +29,7 @@ import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.RequiresApi import io.element.android.libraries.androidutils.R import io.element.android.libraries.androidutils.compat.getApplicationInfoCompat +import io.element.android.libraries.core.mimetype.MimeTypes @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O) fun supportNotificationChannels() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O @@ -125,7 +126,7 @@ fun Context.startSharePlainTextIntent( noActivityFoundMessage: String = getString(R.string.error_no_compatible_app_found), ) { val share = Intent(Intent.ACTION_SEND) - share.type = "text/plain" + share.type = MimeTypes.PlainText share.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) // Add data to the intent, the receiving app will decide what to do with it. share.putExtra(Intent.EXTRA_SUBJECT, subject) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt index 059369c5da..d8ddca14e7 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt @@ -16,7 +16,7 @@ package io.element.android.libraries.matrix.api.media -import java.time.Duration +import kotlin.time.Duration data class AudioDetails( val duration: Duration, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioInfo.kt index bd4539bced..542c13f75c 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioInfo.kt @@ -16,7 +16,7 @@ package io.element.android.libraries.matrix.api.media -import java.time.Duration +import kotlin.time.Duration data class AudioInfo( val duration: Duration?, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/VideoInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/VideoInfo.kt index b7af54c6b2..53cb2564e1 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/VideoInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/VideoInfo.kt @@ -16,7 +16,7 @@ package io.element.android.libraries.matrix.api.media -import java.time.Duration +import kotlin.time.Duration data class VideoInfo( val duration: Duration?, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt index 5bca137a85..2540372260 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt @@ -17,15 +17,17 @@ package io.element.android.libraries.matrix.impl.media import io.element.android.libraries.matrix.api.media.AudioDetails +import kotlin.time.toJavaDuration +import kotlin.time.toKotlinDuration import org.matrix.rustcomponents.sdk.UnstableAudioDetailsContent as RustAudioDetails fun RustAudioDetails.map(): AudioDetails = AudioDetails( - duration = duration, + duration = duration.toKotlinDuration(), waveform = waveform.fromMSC3246range(), ) fun AudioDetails.map(): RustAudioDetails = RustAudioDetails( - duration = duration, + duration = duration.toJavaDuration(), waveform = waveform.toMSC3246range() ) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioInfo.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioInfo.kt index 70c3bac6ed..b7cff173be 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioInfo.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioInfo.kt @@ -17,16 +17,18 @@ package io.element.android.libraries.matrix.impl.media import io.element.android.libraries.matrix.api.media.AudioInfo +import kotlin.time.toJavaDuration +import kotlin.time.toKotlinDuration import org.matrix.rustcomponents.sdk.AudioInfo as RustAudioInfo fun RustAudioInfo.map(): AudioInfo = AudioInfo( - duration = duration, + duration = duration?.toKotlinDuration(), size = size?.toLong(), mimetype = mimetype ) fun AudioInfo.map(): RustAudioInfo = RustAudioInfo( - duration = duration, + duration = duration?.toJavaDuration(), size = size?.toULong(), mimetype = mimetype, ) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/VideoInfo.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/VideoInfo.kt index 661d1b9b33..bfdb328bc9 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/VideoInfo.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/VideoInfo.kt @@ -17,10 +17,12 @@ package io.element.android.libraries.matrix.impl.media import io.element.android.libraries.matrix.api.media.VideoInfo +import kotlin.time.toJavaDuration +import kotlin.time.toKotlinDuration import org.matrix.rustcomponents.sdk.VideoInfo as RustVideoInfo fun RustVideoInfo.map(): VideoInfo = VideoInfo( - duration = duration, + duration = duration?.toKotlinDuration(), height = height?.toLong(), width = width?.toLong(), mimetype = mimetype, @@ -31,7 +33,7 @@ fun RustVideoInfo.map(): VideoInfo = VideoInfo( ) fun VideoInfo.map(): RustVideoInfo = RustVideoInfo( - duration = duration, + duration = duration?.toJavaDuration(), height = height?.toULong(), width = width?.toULong(), mimetype = mimetype, diff --git a/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTests.kt b/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTests.kt index 480cf8065f..35aee8b2d5 100644 --- a/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTests.kt +++ b/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTests.kt @@ -18,6 +18,7 @@ package io.element.android.libraries.mediaupload.api import android.net.Uri import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor @@ -39,7 +40,7 @@ class MediaSenderTests { val sender = aMediaSender(preProcessor) val uri = Uri.parse("content://image.jpg") - sender.sendMedia(uri = uri, mimeType = "image/jpeg", compressIfPossible = true) + sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg, compressIfPossible = true) assertThat(preProcessor.processCallCount).isEqualTo(1) } @@ -50,7 +51,7 @@ class MediaSenderTests { val sender = aMediaSender(room = room) val uri = Uri.parse("content://image.jpg") - sender.sendMedia(uri = uri, mimeType = "image/jpeg", compressIfPossible = true) + sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg, compressIfPossible = true) assertThat(room.sendMediaCount).isEqualTo(1) } @@ -63,7 +64,7 @@ class MediaSenderTests { val sender = aMediaSender(preProcessor) val uri = Uri.parse("content://image.jpg") - val result = sender.sendMedia(uri = uri, mimeType = "image/jpeg", compressIfPossible = true) + val result = sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg, compressIfPossible = true) assertThat(result.exceptionOrNull()).isNotNull() } @@ -76,7 +77,7 @@ class MediaSenderTests { val sender = aMediaSender(room = room) val uri = Uri.parse("content://image.jpg") - val result = sender.sendMedia(uri = uri, mimeType = "image/jpeg", compressIfPossible = true) + val result = sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg, compressIfPossible = true) assertThat(result.exceptionOrNull()).isNotNull() } @@ -88,7 +89,7 @@ class MediaSenderTests { val sender = aMediaSender(room = room) val sendJob = launch { val uri = Uri.parse("content://image.jpg") - sender.sendMedia(uri = uri, mimeType = "image/jpeg", compressIfPossible = true) + sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg, compressIfPossible = true) } // Wait until several internal tasks run and the file is being uploaded advanceTimeBy(3L) diff --git a/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/AndroidMediaPreProcessor.kt b/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/AndroidMediaPreProcessor.kt index 205be3b241..f05fe5bdc3 100644 --- a/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/AndroidMediaPreProcessor.kt +++ b/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/AndroidMediaPreProcessor.kt @@ -47,8 +47,9 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.withContext import java.io.File import java.io.InputStream -import java.time.Duration import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds @ContributesBinding(AppScope::class) class AndroidMediaPreProcessor @Inject constructor( @@ -269,6 +270,6 @@ fun ImageCompressionResult.toImageInfo(mimeType: String, thumbnailResult: Thumbn private fun MediaMetadataRetriever.extractDuration(): Duration { val durationInMs = extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L - return Duration.ofMillis(durationInMs) + return durationInMs.milliseconds } diff --git a/libraries/mediaupload/test/build.gradle.kts b/libraries/mediaupload/test/build.gradle.kts index 956afffbe0..a0d3ed35cc 100644 --- a/libraries/mediaupload/test/build.gradle.kts +++ b/libraries/mediaupload/test/build.gradle.kts @@ -24,5 +24,6 @@ android { dependencies { api(projects.libraries.mediaupload.api) + implementation(projects.libraries.core) implementation(projects.tests.testutils) } diff --git a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt index 8e7e71e8fb..0c612c8d1c 100644 --- a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt +++ b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt @@ -17,6 +17,7 @@ package io.element.android.libraries.mediaupload.test import android.net.Uri +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.mediaupload.api.MediaPreProcessor @@ -24,7 +25,6 @@ import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.tests.testutils.simulateLongTask import java.io.File import kotlin.time.Duration.Companion.seconds -import kotlin.time.toJavaDuration class FakeMediaPreProcessor : MediaPreProcessor { @@ -35,7 +35,7 @@ class FakeMediaPreProcessor : MediaPreProcessor { MediaUploadInfo.AnyFile( File("test"), FileInfo( - mimetype = "*/*", + mimetype = MimeTypes.Any, size = 999L, thumbnailInfo = null, thumbnailSource = null, @@ -63,9 +63,9 @@ class FakeMediaPreProcessor : MediaPreProcessor { MediaUploadInfo.Audio( file = File("audio.ogg"), audioInfo = AudioInfo( - duration = 1000.seconds.toJavaDuration(), + duration = 1000.seconds, size = 1000, - mimetype = "audio/ogg", + mimetype = MimeTypes.Ogg, ), ) ) diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/di/VoiceRecorderModule.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/di/VoiceRecorderModule.kt index b21ab48ac3..29071a9879 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/di/VoiceRecorderModule.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/di/VoiceRecorderModule.kt @@ -21,6 +21,7 @@ import android.media.MediaRecorder import com.squareup.anvil.annotations.ContributesTo import dagger.Module import dagger.Provides +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.di.RoomScope import io.element.android.libraries.voicerecorder.impl.audio.AudioConfig import io.element.android.libraries.voicerecorder.impl.audio.SampleRate @@ -50,7 +51,7 @@ object VoiceRecorderModule { VoiceFileConfig( cacheSubdir = "voice_recordings", fileExt = "ogg", - mimeType = "audio/ogg", + mimeType = MimeTypes.Ogg, ) @Provides 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 d67a44f6f3..030545a3bc 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 @@ -21,6 +21,7 @@ import android.media.MediaRecorder import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.appconfig.VoiceMessageConfig +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.voicerecorder.api.VoiceRecorderState import io.element.android.libraries.voicerecorder.impl.audio.Audio import io.element.android.libraries.voicerecorder.impl.audio.AudioConfig @@ -85,7 +86,7 @@ class VoiceRecorderImplTest { assertThat(awaitItem()).isEqualTo( VoiceRecorderState.Finished( file = File(FILE_PATH), - mimeType = "audio/ogg", + mimeType = MimeTypes.Ogg, waveform = List(100) { 1f }, duration = VoiceMessageConfig.maxVoiceMessageDuration, ) @@ -107,7 +108,7 @@ class VoiceRecorderImplTest { assertThat(awaitItem()).isEqualTo( VoiceRecorderState.Finished( file = File(FILE_PATH), - mimeType = "audio/ogg", + mimeType = MimeTypes.Ogg, waveform = List(100) { 1f }, duration = 5.seconds, ) diff --git a/libraries/voicerecorder/test/build.gradle.kts b/libraries/voicerecorder/test/build.gradle.kts index 9628825380..1dc91ab108 100644 --- a/libraries/voicerecorder/test/build.gradle.kts +++ b/libraries/voicerecorder/test/build.gradle.kts @@ -28,4 +28,5 @@ dependencies { implementation(libs.coroutines.test) implementation(libs.test.truth) + implementation(projects.libraries.core) } 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 bc8bda59d1..c4cc1da0ae 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 @@ -17,6 +17,7 @@ package io.element.android.libraries.voicerecorder.test import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.voicerecorder.api.VoiceRecorder import io.element.android.libraries.voicerecorder.api.VoiceRecorderState import kotlinx.coroutines.flow.MutableStateFlow @@ -73,7 +74,7 @@ class FakeVoiceRecorder( null -> VoiceRecorderState.Idle else -> VoiceRecorderState.Finished( file = curRecording!!, - mimeType = "audio/ogg", + mimeType = MimeTypes.Ogg, duration = recordingDuration, waveform = waveform, )