Use the right video preset when sharing videos (#5892)
This commit is contained in:
parent
028741d81c
commit
d298200934
6 changed files with 30 additions and 17 deletions
|
|
@ -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.permalink.PermalinkBuilder
|
||||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfig
|
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.MediaSenderFactory
|
||||||
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
|
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
|
||||||
import io.element.android.libraries.mediaupload.api.allFiles
|
import io.element.android.libraries.mediaupload.api.allFiles
|
||||||
|
|
@ -62,6 +63,7 @@ class AttachmentsPreviewPresenter(
|
||||||
private val mediaOptimizationSelectorPresenterFactory: MediaOptimizationSelectorPresenter.Factory,
|
private val mediaOptimizationSelectorPresenterFactory: MediaOptimizationSelectorPresenter.Factory,
|
||||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
|
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
|
||||||
) : Presenter<AttachmentsPreviewState> {
|
) : Presenter<AttachmentsPreviewState> {
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
|
@ -107,13 +109,9 @@ class AttachmentsPreviewPresenter(
|
||||||
// to prepare it for sending. This is done to avoid blocking the UI thread when the
|
// to prepare it for sending. This is done to avoid blocking the UI thread when the
|
||||||
// user clicks on the send button.
|
// user clicks on the send button.
|
||||||
if (mediaOptimizationSelectorState.displayMediaSelectorViews == false) {
|
if (mediaOptimizationSelectorState.displayMediaSelectorViews == false) {
|
||||||
val mediaOptimizationConfig = MediaOptimizationConfig(
|
|
||||||
compressImages = mediaOptimizationSelectorState.isImageOptimizationEnabled == true,
|
|
||||||
videoCompressionPreset = mediaOptimizationSelectorState.selectedVideoPreset ?: VideoCompressionPreset.STANDARD,
|
|
||||||
)
|
|
||||||
preprocessMediaJob = preProcessAttachment(
|
preprocessMediaJob = preProcessAttachment(
|
||||||
attachment = attachment,
|
attachment = attachment,
|
||||||
mediaOptimizationConfig = mediaOptimizationConfig,
|
mediaOptimizationConfig = mediaOptimizationConfigProvider.get(),
|
||||||
displayProgress = false,
|
displayProgress = false,
|
||||||
sendActionState = sendActionState,
|
sendActionState = sendActionState,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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.FeatureFlagService
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.mediaupload.api.MaxUploadSizeProvider
|
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.mediaupload.api.compressorHelper
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
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 io.element.android.libraries.preferences.api.store.VideoCompressionPreset
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
|
|
@ -39,8 +38,8 @@ import kotlin.math.roundToLong
|
||||||
class DefaultMediaOptimizationSelectorPresenter(
|
class DefaultMediaOptimizationSelectorPresenter(
|
||||||
@Assisted private val localMedia: LocalMedia,
|
@Assisted private val localMedia: LocalMedia,
|
||||||
private val maxUploadSizeProvider: MaxUploadSizeProvider,
|
private val maxUploadSizeProvider: MaxUploadSizeProvider,
|
||||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
|
||||||
private val featureFlagService: FeatureFlagService,
|
private val featureFlagService: FeatureFlagService,
|
||||||
|
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
|
||||||
mediaExtractorFactory: VideoMetadataExtractor.Factory,
|
mediaExtractorFactory: VideoMetadataExtractor.Factory,
|
||||||
) : MediaOptimizationSelectorPresenter {
|
) : MediaOptimizationSelectorPresenter {
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
|
|
@ -124,11 +123,12 @@ class DefaultMediaOptimizationSelectorPresenter(
|
||||||
var selectedVideoOptimizationPreset by remember { mutableStateOf<AsyncData<VideoCompressionPreset>>(AsyncData.Loading()) }
|
var selectedVideoOptimizationPreset by remember { mutableStateOf<AsyncData<VideoCompressionPreset>>(AsyncData.Loading()) }
|
||||||
|
|
||||||
LaunchedEffect(videoSizeEstimations.dataOrNull()) {
|
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
|
// 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
|
// 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(
|
selectedVideoOptimizationPreset = findBestVideoPreset(
|
||||||
defaultVideoPreset = sessionPreferencesStore.getVideoCompressionPreset().first(),
|
defaultVideoPreset = mediaOptimizationConfig.videoCompressionPreset,
|
||||||
videoSizeEstimations = videoSizeEstimations,
|
videoSizeEstimations = videoSizeEstimations,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.MediaSenderFactory
|
||||||
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
|
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
|
||||||
import io.element.android.libraries.mediaupload.impl.DefaultMediaSender
|
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.mediaupload.test.FakeMediaPreProcessor
|
||||||
import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo
|
import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo
|
||||||
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
|
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
|
||||||
|
|
@ -598,6 +599,7 @@ class AttachmentsPreviewPresenterTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
|
||||||
): AttachmentsPreviewPresenter {
|
): AttachmentsPreviewPresenter {
|
||||||
return AttachmentsPreviewPresenter(
|
return AttachmentsPreviewPresenter(
|
||||||
attachment = aMediaAttachment(localMedia),
|
attachment = aMediaAttachment(localMedia),
|
||||||
|
|
@ -619,6 +621,7 @@ class AttachmentsPreviewPresenterTest {
|
||||||
mediaOptimizationSelectorPresenterFactory = mediaOptimizationSelectorPresenterFactory,
|
mediaOptimizationSelectorPresenterFactory = mediaOptimizationSelectorPresenterFactory,
|
||||||
timelineMode = timelineMode,
|
timelineMode = timelineMode,
|
||||||
inReplyToEventId = null,
|
inReplyToEventId = null,
|
||||||
|
mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.featureflag.test.FakeFeatureFlagService
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
import io.element.android.libraries.mediaupload.api.MaxUploadSizeProvider
|
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.aVideoMediaInfo
|
||||||
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
|
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||||
import io.element.android.libraries.mediaviewer.test.viewer.aLocalMedia
|
import io.element.android.libraries.mediaviewer.test.viewer.aLocalMedia
|
||||||
import io.element.android.libraries.preferences.api.store.VideoCompressionPreset
|
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.element.android.tests.testutils.WarmUpRule
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -233,16 +233,16 @@ class DefaultMediaOptimizationSelectorPresenterTest {
|
||||||
private fun createDefaultMediaOptimizationSelectorPresenter(
|
private fun createDefaultMediaOptimizationSelectorPresenter(
|
||||||
localMedia: LocalMedia = aLocalMedia(mockMediaUrl, aVideoMediaInfo()),
|
localMedia: LocalMedia = aLocalMedia(mockMediaUrl, aVideoMediaInfo()),
|
||||||
maxUploadSizeProvider: MaxUploadSizeProvider = MaxUploadSizeProvider { Result.success(1_000L) },
|
maxUploadSizeProvider: MaxUploadSizeProvider = MaxUploadSizeProvider { Result.success(1_000L) },
|
||||||
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
|
|
||||||
featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SelectableMediaQuality.key to true)),
|
featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SelectableMediaQuality.key to true)),
|
||||||
mediaExtractorFactory: FakeVideoMetadataExtractorFactory = FakeVideoMetadataExtractorFactory(),
|
mediaExtractorFactory: FakeVideoMetadataExtractorFactory = FakeVideoMetadataExtractorFactory(),
|
||||||
|
mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
|
||||||
): DefaultMediaOptimizationSelectorPresenter {
|
): DefaultMediaOptimizationSelectorPresenter {
|
||||||
return DefaultMediaOptimizationSelectorPresenter(
|
return DefaultMediaOptimizationSelectorPresenter(
|
||||||
localMedia = localMedia,
|
localMedia = localMedia,
|
||||||
maxUploadSizeProvider = maxUploadSizeProvider,
|
maxUploadSizeProvider = maxUploadSizeProvider,
|
||||||
sessionPreferencesStore = sessionPreferencesStore,
|
|
||||||
featureFlagService = featureFlagService,
|
featureFlagService = featureFlagService,
|
||||||
mediaExtractorFactory = mediaExtractorFactory,
|
mediaExtractorFactory = mediaExtractorFactory,
|
||||||
|
mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ dependencies {
|
||||||
implementation(projects.libraries.androidutils)
|
implementation(projects.libraries.androidutils)
|
||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
implementation(projects.libraries.di)
|
implementation(projects.libraries.di)
|
||||||
|
implementation(projects.libraries.featureflag.api)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
implementation(projects.services.toolbox.api)
|
implementation(projects.services.toolbox.api)
|
||||||
implementation(libs.androidx.exifinterface)
|
implementation(libs.androidx.exifinterface)
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,28 @@ package io.element.android.libraries.mediaupload.impl
|
||||||
|
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.di.SessionScope
|
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.MediaOptimizationConfig
|
||||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
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.SessionPreferencesStore
|
||||||
|
import io.element.android.libraries.preferences.api.store.VideoCompressionPreset
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
class DefaultMediaOptimizationConfigProvider(
|
class DefaultMediaOptimizationConfigProvider(
|
||||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
private val sessionPreferencesStore: SessionPreferencesStore,
|
||||||
|
private val featureFlagsService: FeatureFlagService,
|
||||||
) : MediaOptimizationConfigProvider {
|
) : MediaOptimizationConfigProvider {
|
||||||
override suspend fun get(): MediaOptimizationConfig = MediaOptimizationConfig(
|
override suspend fun get(): MediaOptimizationConfig {
|
||||||
compressImages = sessionPreferencesStore.doesOptimizeImages().first(),
|
val compressImages = sessionPreferencesStore.doesOptimizeImages().first()
|
||||||
videoCompressionPreset = sessionPreferencesStore.getVideoCompressionPreset().first(),
|
return MediaOptimizationConfig(
|
||||||
)
|
compressImages = compressImages,
|
||||||
|
videoCompressionPreset = if (featureFlagsService.isFeatureEnabled(FeatureFlags.SelectableMediaQuality)) {
|
||||||
|
sessionPreferencesStore.getVideoCompressionPreset().first()
|
||||||
|
} else {
|
||||||
|
if (compressImages) VideoCompressionPreset.STANDARD else VideoCompressionPreset.HIGH
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue