diff options
Diffstat (limited to 'java/src')
6 files changed, 74 insertions, 18 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractor.kt index 802e58a2..e99aa50c 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractor.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SelectionInteractor.kt @@ -16,8 +16,10 @@ package com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor +import com.android.intentresolver.contentpreview.MimeTypeClassifier import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.PreviewSelectionsRepository import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.TargetIntentModifier +import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentType import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -31,6 +33,7 @@ constructor( private val selectionsRepo: PreviewSelectionsRepository, private val targetIntentModifier: TargetIntentModifier<PreviewModel>, private val updateTargetIntentInteractor: UpdateTargetIntentInteractor, + private val mimeTypeClassifier: MimeTypeClassifier, ) { /** Set of selected previews. */ val selections: StateFlow<Set<PreviewModel>> @@ -39,6 +42,8 @@ constructor( /** Amount of selected previews. */ val amountSelected: Flow<Int> = selectionsRepo.selections.map { it.size } + val aggregateContentType: Flow<ContentType> = selections.map { aggregateContentType(it) } + fun select(model: PreviewModel) { updateChooserRequest(selectionsRepo.selections.updateAndGet { it + model }) } @@ -53,4 +58,29 @@ constructor( val intent = targetIntentModifier.intentFromSelection(selections) updateTargetIntentInteractor.updateTargetIntent(intent) } + + private fun aggregateContentType( + items: Set<PreviewModel>, + ): ContentType { + if (items.isEmpty()) { + return ContentType.Other + } + + var allImages = true + var allVideos = true + for (item in items) { + allImages = allImages && mimeTypeClassifier.isImageType(item.mimeType) + allVideos = allVideos && mimeTypeClassifier.isVideoType(item.mimeType) + + if (!allImages && !allVideos) { + break + } + } + + return when { + allImages -> ContentType.Image + allVideos -> ContentType.Video + else -> ContentType.Other + } + } } diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/ContentType.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/ContentType.kt new file mode 100644 index 00000000..3ef6d98f --- /dev/null +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/ContentType.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * 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 com.android.intentresolver.contentpreview.payloadtoggle.shared + +/** Type of the content being previewed. */ +enum class ContentType { + Image, + Video, + Other +} diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselCardComposable.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselCardComposable.kt index c2330ad8..a0be1a9b 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselCardComposable.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselCardComposable.kt @@ -33,7 +33,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.android.intentresolver.R -import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.ContentType +import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentType @Composable fun ShareouselCard( diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt index 36c94b59..c25b0154 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt @@ -56,8 +56,8 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.intentresolver.R +import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentType import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewsModel -import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.ContentType import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.ShareouselPreviewViewModel import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.ShareouselViewModel import kotlinx.coroutines.launch @@ -114,12 +114,10 @@ private fun PreviewCarousel( private fun ShareouselCard(viewModel: ShareouselPreviewViewModel) { val bitmap by viewModel.bitmap.collectAsStateWithLifecycle(initialValue = null) val selected by viewModel.isSelected.collectAsStateWithLifecycle(initialValue = false) - val contentType by - viewModel.contentType.collectAsStateWithLifecycle(initialValue = ContentType.Image) val borderColor = MaterialTheme.colorScheme.primary val scope = rememberCoroutineScope() val contentDescription = - when (contentType) { + when (viewModel.contentType) { ContentType.Image -> stringResource(R.string.selectable_image) ContentType.Video -> stringResource(R.string.selectable_video) else -> stringResource(R.string.selectable_item) @@ -141,7 +139,7 @@ private fun ShareouselCard(viewModel: ShareouselPreviewViewModel) { Box(modifier = Modifier.fillMaxHeight().aspectRatio(aspectRatio)) } }, - contentType = contentType, + contentType = viewModel.contentType, selected = selected, modifier = Modifier.thenIf(selected) { diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt index 9827fcd4..540229c9 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselPreviewViewModel.kt @@ -17,6 +17,7 @@ package com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel import android.graphics.Bitmap +import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentType import kotlinx.coroutines.flow.Flow /** An individual preview within Shareousel. */ @@ -24,17 +25,10 @@ data class ShareouselPreviewViewModel( /** Image to be shared. */ val bitmap: Flow<Bitmap?>, /** Type of data to be shared. */ - val contentType: Flow<ContentType>, + val contentType: ContentType, /** Whether this preview has been selected by the user. */ val isSelected: Flow<Boolean>, /** Sets whether this preview has been selected by the user. */ val setSelected: suspend (Boolean) -> Unit, val aspectRatio: Float, ) - -/** Type of the content being previewed. */ -enum class ContentType { - Image, - Video, - Other -} diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt index 1b9c231b..4eda3fa9 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt @@ -18,11 +18,13 @@ package com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel import com.android.intentresolver.contentpreview.CachingImagePreviewImageLoader import com.android.intentresolver.contentpreview.HeadlineGenerator import com.android.intentresolver.contentpreview.ImageLoader +import com.android.intentresolver.contentpreview.MimeTypeClassifier import com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor.PayloadToggle import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.ChooserRequestInteractor import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.CustomActionsInteractor import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.SelectablePreviewsInteractor import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.SelectionInteractor +import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentType import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewsModel import com.android.intentresolver.inject.ViewModelOwned @@ -35,9 +37,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.zip /** A dynamic carousel of selectable previews within share sheet. */ data class ShareouselViewModel( @@ -71,6 +73,7 @@ interface ShareouselViewModelModule { headlineGenerator: HeadlineGenerator, selectionInteractor: SelectionInteractor, chooserRequestInteractor: ChooserRequestInteractor, + mimeTypeClassifier: MimeTypeClassifier, // TODO: remove if possible @ViewModelOwned scope: CoroutineScope, ): ShareouselViewModel { @@ -82,8 +85,9 @@ interface ShareouselViewModelModule { ) return ShareouselViewModel( headline = - selectionInteractor.amountSelected.map { numItems -> - val contentType = ContentType.Image // TODO: convert from metadata + selectionInteractor.aggregateContentType.zip( + selectionInteractor.amountSelected + ) { contentType, numItems -> when (contentType) { ContentType.Other -> headlineGenerator.getFilesHeadline(numItems) ContentType.Image -> headlineGenerator.getImagesHeadline(numItems) @@ -111,9 +115,15 @@ interface ShareouselViewModelModule { preview = { key -> keySet.value?.maybeLoad(key) val previewInteractor = interactor.preview(key) + val contentType = + when { + mimeTypeClassifier.isImageType(key.mimeType) -> ContentType.Image + mimeTypeClassifier.isVideoType(key.mimeType) -> ContentType.Video + else -> ContentType.Other + } ShareouselPreviewViewModel( bitmap = flow { emit(key.previewUri?.let { imageLoader(it) }) }, - contentType = flowOf(ContentType.Image), // TODO: convert from metadata + contentType = contentType, isSelected = previewInteractor.isSelected, setSelected = previewInteractor::setSelected, aspectRatio = key.aspectRatio, |