summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
author Govinda Wasserman <gwasserman@google.com> 2024-05-24 18:27:16 -0400
committer Govinda Wasserman <gwasserman@google.com> 2024-05-29 09:14:09 -0400
commit971f4321406cc7ae4346f9ecbb220a0095a4151f (patch)
tree425574a53f1e2b5e65f0e6ed5fcc42c093a1d57e /java
parenta5734e47268d2b02e993580a022c4aa0be3a351a (diff)
Cursor continuously fetches new pages as the user scrolls
Whenever the user gets more than half a page away from the center, the cursor will fetch the next page in that direction. Test: manual test with Share Test Test: atest IntentResolver-tests-unit BUG: 341923886 FIX: 341923886 Flag: android.service.chooser.chooser_payload_toggling Change-Id: Ifc9f651ccf028f25af8adfb7bc359977803d540a
Diffstat (limited to 'java')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt16
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt2
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractor.kt4
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewsModel.kt10
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt22
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt13
6 files changed, 60 insertions, 7 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt
index a0fc11c3..fa600c86 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/CursorPreviewsInteractor.kt
@@ -43,6 +43,8 @@ import dagger.hilt.components.SingletonComponent
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import javax.inject.Qualifier
+import kotlin.math.max
+import kotlin.math.min
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
@@ -93,11 +95,14 @@ constructor(
var state = initialState
val startPageNum = state.firstLoadedPageNum
while ((state.hasMoreLeft || state.hasMoreRight) && state.numLoadedPages < maxLoadedPages) {
+ val (leftTriggerIndex, rightTriggerIndex) = state.triggerIndices()
interactor.setPreviews(
previews = state.merged.values.toList(),
startIndex = startPageNum,
hasMoreLeft = state.hasMoreLeft,
hasMoreRight = state.hasMoreRight,
+ leftTriggerIndex = leftTriggerIndex,
+ rightTriggerIndex = rightTriggerIndex,
)
val loadedLeft = startPageNum - state.firstLoadedPageNum
val loadedRight = state.lastLoadedPageNum - startPageNum
@@ -120,6 +125,8 @@ constructor(
) {
var state = initialState
while (true) {
+ val (leftTriggerIndex, rightTriggerIndex) = state.triggerIndices()
+
// Design note: in order to prevent load requests from the UI when it was displaying a
// previously-published dataset being accidentally associated with a recently-published
// one, we generate a new Flow of load requests for each dataset and only listen to
@@ -130,6 +137,8 @@ constructor(
startIndex = 0, // TODO: actually track this as the window changes?
hasMoreLeft = state.hasMoreLeft,
hasMoreRight = state.hasMoreRight,
+ leftTriggerIndex = leftTriggerIndex,
+ rightTriggerIndex = rightTriggerIndex,
)
state = loadingState.handleOneLoadRequest(state, pagedCursor, unclaimedRecords)
}
@@ -238,6 +247,13 @@ constructor(
}
}
+ private fun CursorWindow.triggerIndices(): Pair<Int, Int> {
+ val totalIndices = numLoadedPages * pageSize
+ val midIndex = totalIndices / 2
+ val halfPage = pageSize / 2
+ return max(midIndex - halfPage, 0) to min(midIndex + halfPage, totalIndices - 1)
+ }
+
private suspend fun readPage(
state: CursorWindow,
pagedCursor: PagedCursor<CursorRow?>,
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt
index 388cbc7e..c9c9a9b3 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/FetchPreviewsInteractor.kt
@@ -51,6 +51,8 @@ constructor(
startIndex = focusedItemIdx,
hasMoreLeft = false,
hasMoreRight = false,
+ leftTriggerIndex = initialPreviewMap.indices.first(),
+ rightTriggerIndex = initialPreviewMap.indices.last(),
)
cursorInteractor.launch(cursor.await() ?: return@coroutineScope, initialPreviewMap)
}
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractor.kt
index 437bc942..124e2a3d 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/SetCursorPreviewsInteractor.kt
@@ -35,6 +35,8 @@ constructor(private val previewsRepo: CursorPreviewsRepository) {
startIndex: Int,
hasMoreLeft: Boolean,
hasMoreRight: Boolean,
+ leftTriggerIndex: Int,
+ rightTriggerIndex: Int
): Flow<LoadDirection?> {
val loadingState = MutableStateFlow<LoadDirection?>(null)
previewsRepo.previewsModel.value =
@@ -53,6 +55,8 @@ constructor(private val previewsRepo: CursorPreviewsRepository) {
} else {
null
},
+ leftTriggerIndex = leftTriggerIndex,
+ rightTriggerIndex = rightTriggerIndex,
)
return loadingState.asStateFlow()
}
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewsModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewsModel.kt
index 1d3eb4b4..ae8bd1eb 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewsModel.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/shared/model/PreviewsModel.kt
@@ -32,4 +32,14 @@ data class PreviewsModel(
* indicates that there is no more data to load in that direction.
*/
val loadMoreRight: (() -> Unit)?,
+ /**
+ * Index into [previewModels] where any attempted access less than or equal to it should trigger
+ * a window shift left.
+ */
+ val leftTriggerIndex: Int,
+ /**
+ * Index into [previewModels] where any attempted access greater than or equal to it should
+ * trigger a window shift right.
+ */
+ val rightTriggerIndex: Int,
)
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 02d997ae..8e2626bf 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
@@ -41,7 +41,9 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -59,6 +61,7 @@ import com.android.intentresolver.contentpreview.payloadtoggle.shared.ContentTyp
import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewsModel
import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.ShareouselPreviewViewModel
import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.ShareouselViewModel
+import kotlin.math.abs
import kotlinx.coroutines.launch
@Composable
@@ -104,7 +107,24 @@ private fun PreviewCarousel(
.systemGestureExclusion()
) {
itemsIndexed(previews.previewModels, key = { _, model -> model.uri }) { index, model ->
- ShareouselCard(viewModel.preview(index, model))
+
+ // Index if this is the element in the center of the viewing area, otherwise null
+ val previewIndex by remember {
+ derivedStateOf {
+ carouselState.layoutInfo.visibleItemsInfo
+ .firstOrNull { it.index == index }
+ ?.let {
+ val viewportCenter = carouselState.layoutInfo.viewportEndOffset / 2
+ val halfPreviewWidth = it.size / 2
+ val previewCenter = it.offset + halfPreviewWidth
+ val previewDistanceToViewportCenter =
+ abs(previewCenter - viewportCenter)
+ if (previewDistanceToViewportCenter <= halfPreviewWidth) index else null
+ }
+ }
+ }
+
+ ShareouselCard(viewModel.preview(model, previewIndex))
}
}
}
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 9d53b92a..c3ad7b6c 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
@@ -55,7 +55,7 @@ data class ShareouselViewModel(
/** List of action chips presented underneath Shareousel. */
val actions: Flow<List<ActionChipViewModel>>,
/** Creates a [ShareouselPreviewViewModel] for a [PreviewModel] present in [previews]. */
- val preview: (index: Int, key: PreviewModel) -> ShareouselPreviewViewModel,
+ val preview: (key: PreviewModel, index: Int?) -> ShareouselPreviewViewModel,
)
@Module
@@ -112,7 +112,7 @@ interface ShareouselViewModelModule {
}
}
},
- preview = { index, key ->
+ preview = { key, index ->
keySet.value?.maybeLoad(index)
val previewInteractor = interactor.preview(key)
val contentType =
@@ -134,9 +134,10 @@ interface ShareouselViewModelModule {
}
}
-private fun PreviewsModel.maybeLoad(index: Int) {
- when (index) {
- previewModels.indices.firstOrNull() -> loadMoreLeft?.invoke()
- previewModels.indices.lastOrNull() -> loadMoreRight?.invoke()
+private fun PreviewsModel.maybeLoad(index: Int?) {
+ when {
+ index == null -> {}
+ index <= leftTriggerIndex -> loadMoreLeft?.invoke()
+ index >= rightTriggerIndex -> loadMoreRight?.invoke()
}
}