diff options
4 files changed, 67 insertions, 59 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt b/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt index 8a34e6a9..003f6884 100644 --- a/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt +++ b/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt @@ -118,7 +118,6 @@ class PayloadToggleInteractor( fun start() { scope.launch { - publishInitialState() val cursorReader = cursorReaderProvider() val selectedItems = initiallySharedUris.map { uri -> @@ -148,31 +147,6 @@ class PayloadToggleInteractor( } } - private suspend fun publishInitialState() { - stateFlowSource.emit( - State( - if (0 <= focusedUriIdx && focusedUriIdx < initiallySharedUris.size) { - val fileInfo = uriMetadataReader(initiallySharedUris[focusedUriIdx]) - listOf( - Record( - // a unique key that won't appear anywhere after more items are loaded - -initiallySharedUris.size - 1, - initiallySharedUris[focusedUriIdx], - fileInfo.previewUri, - fileInfo.mimeType, - fileInfo.mimeType?.mimeTypeToItemType() ?: ItemType.File, - ), - ) - } else { - emptyList() - }, - hasMoreItemsBefore = true, - hasMoreItemsAfter = true, - allowSelectionChange = false, - ) - ) - } - fun loadMorePreviousItems() { invokeAsyncIfNotRunning(prevPageLoadingGate) { doLoadMorePreviousItems() @@ -194,7 +168,6 @@ class PayloadToggleInteractor( val (_, selectionTracker) = waitForCursorData() ?: return@launch selectionTracker.setItemSelection(record.key, record, isSelected) val targetIntent = targetIntentModifier(selectionTracker.getSelection()) - val newJob = scope.launch { notifySelectionChanged(targetIntent) } notifySelectionJobRef.getAndSet(newJob)?.cancel() } @@ -390,8 +363,10 @@ class PayloadTogglePreviewInteractor( val previewUri: Flow<Uri?> get() = interactor.previewUri(item) + val selected: Flow<Boolean> get() = interactor.selected(item) + val key get() = item.key } diff --git a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt index 4dd0d3f5..cc89f5bf 100644 --- a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt +++ b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt @@ -21,16 +21,26 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.material3.MaterialTheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import com.android.intentresolver.R import com.android.intentresolver.contentpreview.ChooserContentPreviewUi.ActionFactory import com.android.intentresolver.contentpreview.shareousel.ui.composable.Shareousel +import com.android.intentresolver.contentpreview.shareousel.ui.viewmodel.ShareouselViewModel import com.android.intentresolver.contentpreview.shareousel.ui.viewmodel.toShareouselViewModel internal class ShareouselContentPreviewUi( @@ -63,33 +73,55 @@ internal class ShareouselContentPreviewUi( val vm: BasePreviewViewModel = viewModel() val interactor = requireNotNull(vm.payloadToggleInteractor) { "Should not be null" } - val viewModel = interactor.toShareouselViewModel(vm.imageLoader, actionFactory) - if (headlineViewParent != null) { - LaunchedEffect(Unit) { - viewModel.headline.collect { headline -> - headlineViewParent.findViewById<TextView>(R.id.headline)?.apply { - if (headline.isNotBlank()) { - text = headline - visibility = View.VISIBLE - } else { - visibility = View.GONE - } + var viewModel by remember { mutableStateOf<ShareouselViewModel?>(null) } + LaunchedEffect(Unit) { + viewModel = + interactor.toShareouselViewModel( + vm.imageLoader, + actionFactory, + vm.viewModelScope + ) + } + + headlineViewParent?.let { + viewModel?.let { viewModel -> + LaunchedEffect(viewModel) { + viewModel.headline.collect { headline -> + headlineViewParent + .findViewById<TextView>(R.id.headline) + ?.apply { + if (headline.isNotBlank()) { + text = headline + visibility = View.VISIBLE + } else { + visibility = View.GONE + } + } } } } } - MaterialTheme( - colorScheme = - if (isSystemInDarkTheme()) { - dynamicDarkColorScheme(LocalContext.current) - } else { - dynamicLightColorScheme(LocalContext.current) - }, - ) { - Shareousel(viewModel = viewModel) + viewModel?.let { viewModel -> + MaterialTheme( + colorScheme = + if (isSystemInDarkTheme()) { + dynamicDarkColorScheme(LocalContext.current) + } else { + dynamicLightColorScheme(LocalContext.current) + }, + ) { + Shareousel(viewModel = viewModel) + } } + ?: run { + Spacer( + Modifier.height( + dimensionResource(R.dimen.chooser_preview_image_height_tall) + ) + ) + } } } return composeView diff --git a/java/src/com/android/intentresolver/contentpreview/shareousel/ui/composable/ShareouselComposable.kt b/java/src/com/android/intentresolver/contentpreview/shareousel/ui/composable/ShareouselComposable.kt index 0e6e9d7e..5cf35297 100644 --- a/java/src/com/android/intentresolver/contentpreview/shareousel/ui/composable/ShareouselComposable.kt +++ b/java/src/com/android/intentresolver/contentpreview/shareousel/ui/composable/ShareouselComposable.kt @@ -47,15 +47,12 @@ import com.android.intentresolver.contentpreview.shareousel.ui.viewmodel.Shareou @Composable fun Shareousel(viewModel: ShareouselViewModel) { - val previewKeys by viewModel.previewKeys.collectAsStateWithLifecycle(initialValue = emptyList()) - val centerIdx by viewModel.centerIndex.collectAsStateWithLifecycle(initialValue = 0) + val centerIdx = viewModel.centerIndex.value + val carouselState = rememberLazyListState(initialFirstVisibleItemIndex = centerIdx) + val previewKeys by viewModel.previewKeys.collectAsStateWithLifecycle() Column { // TODO: item needs to be centered, check out ScalingLazyColumn impl or see if // HorizontalPager works for our use-case - val carouselState = - rememberLazyListState( - initialFirstVisibleItemIndex = centerIdx, - ) LazyRow( state = carouselState, horizontalArrangement = Arrangement.spacedBy(4.dp), diff --git a/java/src/com/android/intentresolver/contentpreview/shareousel/ui/viewmodel/ShareouselViewModel.kt b/java/src/com/android/intentresolver/contentpreview/shareousel/ui/viewmodel/ShareouselViewModel.kt index fae439e5..18ee2539 100644 --- a/java/src/com/android/intentresolver/contentpreview/shareousel/ui/viewmodel/ShareouselViewModel.kt +++ b/java/src/com/android/intentresolver/contentpreview/shareousel/ui/viewmodel/ShareouselViewModel.kt @@ -24,16 +24,19 @@ import com.android.intentresolver.contentpreview.PayloadToggleInteractor import com.android.intentresolver.icon.BitmapIcon import com.android.intentresolver.icon.ComposeIcon import com.android.intentresolver.widget.ActionRow.Action +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn data class ShareouselViewModel( val headline: Flow<String>, - val previewKeys: Flow<List<Any>>, + val previewKeys: StateFlow<List<Any>>, val actions: Flow<List<ActionChipViewModel>>, - val centerIndex: Flow<Int>, + val centerIndex: StateFlow<Int>, val previewForKey: (key: Any) -> ShareouselImageViewModel, val previewRowKey: (Any) -> Any ) @@ -47,13 +50,14 @@ data class ShareouselImageViewModel( val setSelected: (Boolean) -> Unit, ) -fun PayloadToggleInteractor.toShareouselViewModel( +suspend fun PayloadToggleInteractor.toShareouselViewModel( imageLoader: ImageLoader, - actionFactory: ActionFactory + actionFactory: ActionFactory, + scope: CoroutineScope, ): ShareouselViewModel { return ShareouselViewModel( headline = MutableStateFlow("Shareousel"), - previewKeys = previewKeys, + previewKeys = previewKeys.stateIn(scope), actions = if (actionFactory is MutableActionFactory) { actionFactory.customActionsFlow.map { actions -> @@ -64,7 +68,7 @@ fun PayloadToggleInteractor.toShareouselViewModel( emit(actionFactory.createCustomActions().map { it.toActionChipViewModel() }) } }, - centerIndex = targetPosition, + centerIndex = targetPosition.stateIn(scope), previewForKey = { key -> val previewInteractor = previewInteractor(key) ShareouselImageViewModel( |