From 8e3e0951e7c290a4f875efb26824c299016da05f Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 16 Dec 2025 16:40:44 +0100 Subject: [PATCH] Use the right video preset when sharing videos (#5892) --- .../preview/AttachmentsPreviewPresenter.kt | 8 +++----- ...faultMediaOptimizationSelectorPresenter.kt | 10 +++++----- .../AttachmentsPreviewPresenterTest.kt | 3 +++ ...tMediaOptimizationSelectorPresenterTest.kt | 6 +++--- libraries/mediaupload/impl/build.gradle.kts | 1 + .../DefaultMediaOptimizationConfigProvider.kt | 19 +++++++++++++++---- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt index d7e0332bd4..f7641ec21b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt @@ -37,6 +37,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.mediaupload.api.MediaOptimizationConfig +import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider import io.element.android.libraries.mediaupload.api.MediaSenderFactory import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.api.allFiles @@ -62,6 +63,7 @@ class AttachmentsPreviewPresenter( private val mediaOptimizationSelectorPresenterFactory: MediaOptimizationSelectorPresenter.Factory, @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, private val dispatchers: CoroutineDispatchers, + private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider, ) : Presenter { @AssistedFactory interface Factory { @@ -107,13 +109,9 @@ class AttachmentsPreviewPresenter( // to prepare it for sending. This is done to avoid blocking the UI thread when the // user clicks on the send button. if (mediaOptimizationSelectorState.displayMediaSelectorViews == false) { - val mediaOptimizationConfig = MediaOptimizationConfig( - compressImages = mediaOptimizationSelectorState.isImageOptimizationEnabled == true, - videoCompressionPreset = mediaOptimizationSelectorState.selectedVideoPreset ?: VideoCompressionPreset.STANDARD, - ) preprocessMediaJob = preProcessAttachment( attachment = attachment, - mediaOptimizationConfig = mediaOptimizationConfig, + mediaOptimizationConfig = mediaOptimizationConfigProvider.get(), displayProgress = false, sendActionState = sendActionState, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt index d0716abe83..c81c306f90 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenter.kt @@ -25,13 +25,12 @@ import io.element.android.libraries.di.SessionScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.mediaupload.api.MaxUploadSizeProvider +import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider import io.element.android.libraries.mediaupload.api.compressorHelper import io.element.android.libraries.mediaviewer.api.local.LocalMedia -import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.flow.first import timber.log.Timber import kotlin.math.roundToLong @@ -39,8 +38,8 @@ import kotlin.math.roundToLong class DefaultMediaOptimizationSelectorPresenter( @Assisted private val localMedia: LocalMedia, private val maxUploadSizeProvider: MaxUploadSizeProvider, - private val sessionPreferencesStore: SessionPreferencesStore, private val featureFlagService: FeatureFlagService, + private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider, mediaExtractorFactory: VideoMetadataExtractor.Factory, ) : MediaOptimizationSelectorPresenter { @ContributesBinding(SessionScope::class) @@ -124,11 +123,12 @@ class DefaultMediaOptimizationSelectorPresenter( var selectedVideoOptimizationPreset by remember { mutableStateOf>(AsyncData.Loading()) } LaunchedEffect(videoSizeEstimations.dataOrNull()) { - selectedImageOptimization = AsyncData.Success(sessionPreferencesStore.doesOptimizeImages().first()) + val mediaOptimizationConfig = mediaOptimizationConfigProvider.get() + selectedImageOptimization = AsyncData.Success(mediaOptimizationConfig.compressImages) // Find the best video preset based on the default preset and the video size estimations // Since the estimation for the current preset may be way too large to upload, we check the ones that provide lower file sizes selectedVideoOptimizationPreset = findBestVideoPreset( - defaultVideoPreset = sessionPreferencesStore.getVideoCompressionPreset().first(), + defaultVideoPreset = mediaOptimizationConfig.videoCompressionPreset, videoSizeEstimations = videoSizeEstimations, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index 5263182fa0..fe462fc988 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -44,6 +44,7 @@ import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaSenderFactory import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.impl.DefaultMediaSender +import io.element.android.libraries.mediaupload.test.FakeMediaOptimizationConfigProvider import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo import io.element.android.libraries.mediaviewer.api.anApkMediaInfo @@ -598,6 +599,7 @@ class AttachmentsPreviewPresenterTest { ) } ), + mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), ): AttachmentsPreviewPresenter { return AttachmentsPreviewPresenter( attachment = aMediaAttachment(localMedia), @@ -619,6 +621,7 @@ class AttachmentsPreviewPresenterTest { mediaOptimizationSelectorPresenterFactory = mediaOptimizationSelectorPresenterFactory, timelineMode = timelineMode, inReplyToEventId = null, + mediaOptimizationConfigProvider = mediaOptimizationConfigProvider, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt index aad3e0b885..96cc93ea3d 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/video/DefaultMediaOptimizationSelectorPresenterTest.kt @@ -22,12 +22,12 @@ import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.mediaupload.api.MaxUploadSizeProvider +import io.element.android.libraries.mediaupload.test.FakeMediaOptimizationConfigProvider import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.test.viewer.aLocalMedia import io.element.android.libraries.preferences.api.store.VideoCompressionPreset -import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore import io.element.android.tests.testutils.WarmUpRule import io.mockk.mockk import kotlinx.coroutines.test.runTest @@ -233,16 +233,16 @@ class DefaultMediaOptimizationSelectorPresenterTest { private fun createDefaultMediaOptimizationSelectorPresenter( localMedia: LocalMedia = aLocalMedia(mockMediaUrl, aVideoMediaInfo()), maxUploadSizeProvider: MaxUploadSizeProvider = MaxUploadSizeProvider { Result.success(1_000L) }, - sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(), featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SelectableMediaQuality.key to true)), mediaExtractorFactory: FakeVideoMetadataExtractorFactory = FakeVideoMetadataExtractorFactory(), + mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), ): DefaultMediaOptimizationSelectorPresenter { return DefaultMediaOptimizationSelectorPresenter( localMedia = localMedia, maxUploadSizeProvider = maxUploadSizeProvider, - sessionPreferencesStore = sessionPreferencesStore, featureFlagService = featureFlagService, mediaExtractorFactory = mediaExtractorFactory, + mediaOptimizationConfigProvider = mediaOptimizationConfigProvider, ) } } diff --git a/libraries/mediaupload/impl/build.gradle.kts b/libraries/mediaupload/impl/build.gradle.kts index dd73164eb1..827366f556 100644 --- a/libraries/mediaupload/impl/build.gradle.kts +++ b/libraries/mediaupload/impl/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.di) + implementation(projects.libraries.featureflag.api) implementation(projects.libraries.matrix.api) implementation(projects.services.toolbox.api) implementation(libs.androidx.exifinterface) diff --git a/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaOptimizationConfigProvider.kt b/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaOptimizationConfigProvider.kt index 4b6d298666..363263e5bf 100644 --- a/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaOptimizationConfigProvider.kt +++ b/libraries/mediaupload/impl/src/main/kotlin/io/element/android/libraries/mediaupload/impl/DefaultMediaOptimizationConfigProvider.kt @@ -10,17 +10,28 @@ package io.element.android.libraries.mediaupload.impl import dev.zacsweers.metro.ContributesBinding import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.mediaupload.api.MediaOptimizationConfig import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider import io.element.android.libraries.preferences.api.store.SessionPreferencesStore +import io.element.android.libraries.preferences.api.store.VideoCompressionPreset import kotlinx.coroutines.flow.first @ContributesBinding(SessionScope::class) class DefaultMediaOptimizationConfigProvider( private val sessionPreferencesStore: SessionPreferencesStore, + private val featureFlagsService: FeatureFlagService, ) : MediaOptimizationConfigProvider { - override suspend fun get(): MediaOptimizationConfig = MediaOptimizationConfig( - compressImages = sessionPreferencesStore.doesOptimizeImages().first(), - videoCompressionPreset = sessionPreferencesStore.getVideoCompressionPreset().first(), - ) + override suspend fun get(): MediaOptimizationConfig { + val compressImages = sessionPreferencesStore.doesOptimizeImages().first() + return MediaOptimizationConfig( + compressImages = compressImages, + videoCompressionPreset = if (featureFlagsService.isFeatureEnabled(FeatureFlags.SelectableMediaQuality)) { + sessionPreferencesStore.getVideoCompressionPreset().first() + } else { + if (compressImages) VideoCompressionPreset.STANDARD else VideoCompressionPreset.HIGH + }, + ) + } }