summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java2
-rw-r--r--java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt4
-rw-r--r--java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt63
-rw-r--r--java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt29
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt83
-rw-r--r--java/src/com/android/intentresolver/contentpreview/shareousel/ui/viewmodel/ShareouselViewModel.kt23
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivity.java2
-rw-r--r--tests/shared/src/com/android/intentresolver/TestContentPreviewViewModel.kt23
8 files changed, 203 insertions, 26 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 820fa3b2..c3b13527 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -307,7 +307,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
getCoroutineScope(getLifecycle()),
previewViewModel.createOrReuseProvider(mChooserRequest.getTargetIntent()),
mChooserRequest.getTargetIntent(),
- previewViewModel.createOrReuseImageLoader(),
+ previewViewModel.getImageLoader(),
createChooserActionFactory(),
mEnterTransitionAnimationDelegate,
new HeadlineGeneratorImpl(this));
diff --git a/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt
index 4c781a46..3b20a45c 100644
--- a/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt
+++ b/java/src/com/android/intentresolver/contentpreview/BasePreviewViewModel.kt
@@ -24,5 +24,7 @@ import androidx.lifecycle.ViewModel
abstract class BasePreviewViewModel : ViewModel() {
@MainThread abstract fun createOrReuseProvider(targetIntent: Intent): PreviewDataProvider
- @MainThread abstract fun createOrReuseImageLoader(): ImageLoader
+ abstract val imageLoader: ImageLoader
+
+ abstract val payloadToggleInteractor: PayloadToggleInteractor?
}
diff --git a/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt b/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt
new file mode 100644
index 00000000..0e6d3869
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/PayloadToggleInteractor.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 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
+
+import android.net.Uri
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.update
+
+class PayloadToggleInteractor {
+
+ private val storage = MutableStateFlow<Map<Any, Item>>(emptyMap()) // TODO: implement
+ private val selectedKeys = MutableStateFlow<Set<Any>>(emptySet())
+
+ val targetPosition: Flow<Int> = flowOf(0) // TODO: implement
+ val previewKeys: Flow<List<Any>> = flowOf(emptyList()) // TODO: implement
+
+ fun setSelected(key: Any, isSelected: Boolean) {
+ if (isSelected) {
+ selectedKeys.update { it + key }
+ } else {
+ selectedKeys.update { it - key }
+ }
+ }
+
+ fun selected(key: Any): Flow<Boolean> = previewKeys.map { key in it }
+
+ fun previewInteractor(key: Any) = PayloadTogglePreviewInteractor(key, this)
+
+ fun previewUri(key: Any): Flow<Uri?> = storage.map { it[key]?.previewUri }
+
+ private data class Item(
+ val previewUri: Uri?,
+ )
+}
+
+class PayloadTogglePreviewInteractor(
+ private val key: Any,
+ private val interactor: PayloadToggleInteractor,
+) {
+ fun setSelected(selected: Boolean) {
+ interactor.setSelected(key, selected)
+ }
+
+ val previewUri: Flow<Uri?> = interactor.previewUri(key)
+ val selected: Flow<Boolean> = interactor.selected(key)
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt
index 9acc4689..d855ea16 100644
--- a/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt
+++ b/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt
@@ -41,7 +41,6 @@ constructor(
@Background private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
) : BasePreviewViewModel() {
private var previewDataProvider: PreviewDataProvider? = null
- private var imageLoader: ImagePreviewImageLoader? = null
@MainThread
override fun createOrReuseProvider(targetIntent: Intent): PreviewDataProvider =
@@ -53,19 +52,21 @@ constructor(
)
.also { previewDataProvider = it }
- @MainThread
- override fun createOrReuseImageLoader(): ImageLoader =
- imageLoader
- ?: ImagePreviewImageLoader(
- viewModelScope + dispatcher,
- thumbnailSize =
- application.resources.getDimensionPixelSize(
- R.dimen.chooser_preview_image_max_dimen
- ),
- application.contentResolver,
- cacheSize = 16
- )
- .also { imageLoader = it }
+ override val imageLoader by lazy {
+ ImagePreviewImageLoader(
+ viewModelScope + dispatcher,
+ thumbnailSize =
+ application.resources.getDimensionPixelSize(
+ R.dimen.chooser_preview_image_max_dimen
+ ),
+ application.contentResolver,
+ cacheSize = 16
+ )
+ }
+
+ override val payloadToggleInteractor: PayloadToggleInteractor? by lazy {
+ PayloadToggleInteractor()
+ }
companion object {
val Factory: ViewModelProvider.Factory =
diff --git a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt
new file mode 100644
index 00000000..a10d3272
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt
@@ -0,0 +1,83 @@
+/*
+ * 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
+
+import android.content.res.Resources
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.platform.ComposeView
+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.toShareouselViewModel
+
+internal class ShareouselContentPreviewUi(
+ private val actionFactory: ActionFactory,
+) : ContentPreviewUi() {
+
+ override fun getType(): Int = ContentPreviewType.CONTENT_PREVIEW_IMAGE
+
+ override fun display(
+ resources: Resources,
+ layoutInflater: LayoutInflater,
+ parent: ViewGroup,
+ headlineViewParent: View?,
+ ): ViewGroup {
+ return displayInternal(parent, headlineViewParent).also { layout ->
+ displayModifyShareAction(headlineViewParent ?: layout, actionFactory)
+ }
+ }
+
+ private fun displayInternal(
+ parent: ViewGroup,
+ headlineViewParent: View?,
+ ): ViewGroup {
+ if (headlineViewParent != null) {
+ inflateHeadline(headlineViewParent)
+ }
+ val composeView =
+ ComposeView(parent.context).apply {
+ setContent {
+ val vm: BasePreviewViewModel = viewModel()
+ val interactor =
+ requireNotNull(vm.payloadToggleInteractor) { "Should not be null" }
+ val viewModel = interactor.toShareouselViewModel(vm.imageLoader)
+
+ 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
+ }
+ }
+ }
+ }
+ }
+
+ Shareousel(viewModel = viewModel)
+ }
+ }
+ return composeView
+ }
+}
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 39f2040b..4592ea6d 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
@@ -16,8 +16,12 @@
package com.android.intentresolver.contentpreview.shareousel.ui.viewmodel
import android.graphics.Bitmap
+import com.android.intentresolver.contentpreview.ImageLoader
+import com.android.intentresolver.contentpreview.PayloadToggleInteractor
import com.android.intentresolver.icon.ComposeIcon
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
data class ShareouselViewModel(
val headline: Flow<String>,
@@ -36,3 +40,22 @@ data class ShareouselImageViewModel(
val setSelected: (Boolean) -> Unit,
val onActionClick: () -> Unit,
)
+
+fun PayloadToggleInteractor.toShareouselViewModel(imageLoader: ImageLoader): ShareouselViewModel {
+ return ShareouselViewModel(
+ headline = MutableStateFlow("Shareousel"),
+ previewKeys = previewKeys,
+ actions = MutableStateFlow(emptyList()),
+ centerIndex = targetPosition,
+ previewForKey = { key ->
+ val previewInteractor = previewInteractor(key)
+ ShareouselImageViewModel(
+ bitmap = previewInteractor.previewUri.map { uri -> uri?.let { imageLoader(uri) } },
+ contentDescription = MutableStateFlow(""),
+ isSelected = previewInteractor.selected,
+ setSelected = { isSelected -> previewInteractor.setSelected(isSelected) },
+ onActionClick = {},
+ )
+ }
+ )
+}
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index 64c5881c..b9cf53b6 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -474,7 +474,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
getCoroutineScope(getLifecycle()),
previewViewModel.createOrReuseProvider(chooserRequest.getTargetIntent()),
chooserRequest.getTargetIntent(),
- previewViewModel.createOrReuseImageLoader(),
+ previewViewModel.getImageLoader(),
createChooserActionFactory(),
mEnterTransitionAnimationDelegate,
new HeadlineGeneratorImpl(this));
diff --git a/tests/shared/src/com/android/intentresolver/TestContentPreviewViewModel.kt b/tests/shared/src/com/android/intentresolver/TestContentPreviewViewModel.kt
index 888fc161..998c0802 100644
--- a/tests/shared/src/com/android/intentresolver/TestContentPreviewViewModel.kt
+++ b/tests/shared/src/com/android/intentresolver/TestContentPreviewViewModel.kt
@@ -22,19 +22,22 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import com.android.intentresolver.contentpreview.BasePreviewViewModel
import com.android.intentresolver.contentpreview.ImageLoader
+import com.android.intentresolver.contentpreview.PayloadToggleInteractor
import com.android.intentresolver.contentpreview.PreviewDataProvider
/** A test content preview model that supports image loader override. */
class TestContentPreviewViewModel(
private val viewModel: BasePreviewViewModel,
- private val imageLoader: ImageLoader? = null,
+ private val imageLoaderDelegate: ImageLoader?,
) : BasePreviewViewModel() {
- override fun createOrReuseProvider(
- targetIntent: Intent
- ): PreviewDataProvider = viewModel.createOrReuseProvider(targetIntent)
+ override fun createOrReuseProvider(targetIntent: Intent): PreviewDataProvider =
+ viewModel.createOrReuseProvider(targetIntent)
- override fun createOrReuseImageLoader(): ImageLoader =
- imageLoader ?: viewModel.createOrReuseImageLoader()
+ override val imageLoader: ImageLoader
+ get() = imageLoaderDelegate ?: viewModel.imageLoader
+
+ override val payloadToggleInteractor: PayloadToggleInteractor?
+ get() = viewModel.payloadToggleInteractor
companion object {
fun wrap(
@@ -47,10 +50,12 @@ class TestContentPreviewViewModel(
modelClass: Class<T>,
extras: CreationExtras
): T {
+ val wrapped = factory.create(modelClass, extras) as BasePreviewViewModel
return TestContentPreviewViewModel(
- factory.create(modelClass, extras) as BasePreviewViewModel,
- imageLoader,
- ) as T
+ wrapped,
+ imageLoader ?: wrapped.imageLoader,
+ )
+ as T
}
}
}