mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3438 Widgets | Enhancement | Creating widgets with suggest object type (#2216)
This commit is contained in:
parent
37c4327fa0
commit
7bec1556cb
12 changed files with 273 additions and 152 deletions
|
@ -10,6 +10,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
|
|||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.primitives.FieldParser
|
||||
import com.anytypeio.anytype.domain.search.SearchObjects
|
||||
import com.anytypeio.anytype.domain.widgets.GetSuggestedWidgetTypes
|
||||
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
|
@ -67,7 +68,8 @@ object SelectWidgetSourceModule {
|
|||
dispatcher: Dispatcher<WidgetDispatchEvent>,
|
||||
analyticsHelper: AnalyticSpaceHelperDelegate,
|
||||
fieldParser: FieldParser,
|
||||
storeOfObjectTypes: StoreOfObjectTypes
|
||||
storeOfObjectTypes: StoreOfObjectTypes,
|
||||
getSuggestedWidgetTypes: GetSuggestedWidgetTypes
|
||||
): SelectWidgetSourceViewModel.Factory = SelectWidgetSourceViewModel.Factory(
|
||||
vmParams = vmParams,
|
||||
urlBuilder = urlBuilder,
|
||||
|
@ -77,6 +79,7 @@ object SelectWidgetSourceModule {
|
|||
dispatcher = dispatcher,
|
||||
analyticSpaceHelperDelegate = analyticsHelper,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
getSuggestedWidgetTypes = getSuggestedWidgetTypes
|
||||
)
|
||||
}
|
|
@ -276,6 +276,7 @@ class HomeScreenFragment : BaseComposeFragment(),
|
|||
findNavController().navigate(
|
||||
R.id.selectWidgetSourceScreen,
|
||||
args = SelectWidgetSourceFragment.args(
|
||||
ctx = command.ctx,
|
||||
target = command.target,
|
||||
isInEditMode = command.isInEditMode,
|
||||
spaceId = command.space
|
||||
|
|
|
@ -66,7 +66,8 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
DefaultObjectViewAdapter(
|
||||
onDefaultObjectClicked = vm::onObjectClicked,
|
||||
onBundledWidgetSourceClicked = vm::onBundledWidgetSourceClicked,
|
||||
onCreateNewObject = vm::onCreateNewObjectClicked
|
||||
onCreateNewObject = vm::onCreateNewObjectClicked,
|
||||
onSuggestedWidgetObjectTypeClicked = vm::onSuggestedWidgetObjectTypeClicked
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -80,7 +81,9 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
dialogCancelListener = this
|
||||
).apply()
|
||||
|
||||
vm.state.observe(viewLifecycleOwner) { observe(it) }
|
||||
|
||||
subscribe(vm.viewState) { setViewState(it) }
|
||||
|
||||
clearSearchText = binding.searchView.root.findViewById(R.id.clearSearchText)
|
||||
filterInputField = binding.searchView.root.findViewById(R.id.filterInputField)
|
||||
filterInputField.setHint(R.string.search)
|
||||
|
@ -110,6 +113,7 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
)
|
||||
} else {
|
||||
vm.onStartWithNewWidget(
|
||||
ctx = ctx,
|
||||
target = target,
|
||||
isInEditMode = isInEditMode
|
||||
)
|
||||
|
@ -128,7 +132,7 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
vm.onStop()
|
||||
}
|
||||
|
||||
private fun observe(state: ObjectSearchView) {
|
||||
private fun setViewState(state: ObjectSearchView) {
|
||||
when (state) {
|
||||
ObjectSearchView.Loading -> {
|
||||
with(binding) {
|
||||
|
@ -284,10 +288,12 @@ class SelectWidgetSourceFragment : BaseBottomSheetTextInputFragment<FragmentObje
|
|||
* Flow for selecting source for new widget.
|
||||
*/
|
||||
fun args(
|
||||
ctx: Id,
|
||||
target: Id?,
|
||||
isInEditMode: Boolean,
|
||||
spaceId: Id
|
||||
) = bundleOf(
|
||||
CTX_KEY to ctx,
|
||||
TARGET_KEY to target,
|
||||
IS_IN_EDIT_MODE_KEY to isInEditMode,
|
||||
SPACE_KEY to spaceId
|
||||
|
|
|
@ -21,12 +21,14 @@ import com.anytypeio.anytype.presentation.navigation.NewObject
|
|||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchSection
|
||||
import com.anytypeio.anytype.presentation.widgets.source.BundledWidgetSourceView
|
||||
import com.anytypeio.anytype.presentation.widgets.source.SuggestWidgetObjectType
|
||||
|
||||
class DefaultObjectViewAdapter(
|
||||
private val onDefaultObjectClicked: (DefaultObjectView) -> Unit,
|
||||
private val onBundledWidgetSourceClicked: (BundledWidgetSourceView) -> Unit = {},
|
||||
private val onCurrentListChanged: (Int, Int) -> Unit = { prevSize, newSize -> },
|
||||
private val onCreateNewObject: () -> Unit = {}
|
||||
private val onCreateNewObject: () -> Unit = {},
|
||||
private val onSuggestedWidgetObjectTypeClicked: (SuggestWidgetObjectType) -> Unit = {}
|
||||
) : ListAdapter<DefaultSearchItem, DefaultObjectViewAdapter.ObjectViewHolder>(Differ) {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
|
@ -69,6 +71,21 @@ class DefaultObjectViewAdapter(
|
|||
onCreateNewObject()
|
||||
}
|
||||
}
|
||||
TYPE_SUGGESTED_WIDGET_OBJECT_TYPE -> SuggestWidgetObjectTypeViewHolder(
|
||||
ItemListObjectBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
).apply {
|
||||
itemView.setOnThrottleClickListener {
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
val item = getItem(pos)
|
||||
if (item is SuggestWidgetObjectType) {
|
||||
onSuggestedWidgetObjectTypeClicked(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected view type: $viewType")
|
||||
}
|
||||
|
||||
|
@ -103,6 +120,10 @@ class DefaultObjectViewAdapter(
|
|||
check(item is BundledWidgetSourceView)
|
||||
holder.bind(item)
|
||||
}
|
||||
is SuggestWidgetObjectTypeViewHolder -> {
|
||||
check(item is SuggestWidgetObjectType)
|
||||
holder.bind(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,6 +132,7 @@ class DefaultObjectViewAdapter(
|
|||
is ObjectSearchSection -> TYPE_SECTION
|
||||
is BundledWidgetSourceView -> TYPE_BUNDLED_WIDGET_SOURCE
|
||||
is NewObject -> TYPE_NEW_OBJECT
|
||||
is SuggestWidgetObjectType -> TYPE_SUGGESTED_WIDGET_OBJECT_TYPE
|
||||
else -> throw IllegalStateException("Unexpected item type: ${item.javaClass.name}")
|
||||
}
|
||||
|
||||
|
@ -216,36 +238,25 @@ class BundledWidgetSourceHolder(
|
|||
ivIcon.setBackgroundResource(R.drawable.ic_widget_system_bin)
|
||||
}
|
||||
}
|
||||
// TODO remove this
|
||||
BundledWidgetSourceView.Sets -> {
|
||||
with(binding) {
|
||||
tvTitle.setText(R.string.sets)
|
||||
tvSubtitle.gone()
|
||||
ivIcon.setImageDrawable(
|
||||
drawable = binding.root.context.resources.getDrawable(
|
||||
R.drawable.ic_widget_bundled_source_sets,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
// TODO remove this
|
||||
BundledWidgetSourceView.Collections -> {
|
||||
with(binding) {
|
||||
tvTitle.setText(R.string.collections)
|
||||
tvSubtitle.gone()
|
||||
ivIcon.setImageDrawable(
|
||||
drawable = binding.root.context.resources.getDrawable(
|
||||
R.drawable.ic_widget_bundled_source_collection,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SuggestWidgetObjectTypeViewHolder(
|
||||
private val binding: ItemListObjectBinding
|
||||
) : DefaultObjectViewAdapter.ObjectViewHolder(binding.root) {
|
||||
|
||||
init {
|
||||
binding.ivIcon.binding.emojiContainer.invisible()
|
||||
binding.tvSubtitle.gone()
|
||||
}
|
||||
|
||||
fun bind(source: SuggestWidgetObjectType) {
|
||||
binding.tvTitle.text = source.name
|
||||
binding.ivIcon.setIcon(source.objectIcon)
|
||||
}
|
||||
}
|
||||
|
||||
class NewObjectViewHolder(
|
||||
binding: ItemSearchNewObjectBinding
|
||||
) : DefaultObjectViewAdapter.ObjectViewHolder(binding.root)
|
||||
|
@ -253,4 +264,5 @@ class NewObjectViewHolder(
|
|||
private const val TYPE_ITEM = 0
|
||||
private const val TYPE_SECTION = 1
|
||||
private const val TYPE_BUNDLED_WIDGET_SOURCE = 2
|
||||
private const val TYPE_NEW_OBJECT = 3
|
||||
private const val TYPE_NEW_OBJECT = 3
|
||||
private const val TYPE_SUGGESTED_WIDGET_OBJECT_TYPE = 4
|
|
@ -1,22 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="30dp"
|
||||
android:height="30dp"
|
||||
android:viewportWidth="30"
|
||||
android:viewportHeight="30">
|
||||
<path
|
||||
android:pathData="M3.5,3C2.672,3 2,3.672 2,4.5V6H9V4.5C9,3.672 8.328,3 7.5,3H3.5ZM11.5,6C11.5,5.172 12.172,4.5 13,4.5H17C17.828,4.5 18.5,5.172 18.5,6V7.5H11.5V6ZM22.5,6C21.672,6 21,6.672 21,7.5V9H2V25.5C2,26.328 2.672,27 3.5,27H26.5C27.328,27 28,26.328 28,25.5V10.5V9V7.5C28,6.672 27.328,6 26.5,6H22.5Z"
|
||||
android:fillType="evenOdd">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="15"
|
||||
android:startY="3"
|
||||
android:endX="15"
|
||||
android:endY="27"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="@color/collection_grey_gradient_start"/>
|
||||
<item android:offset="1" android:color="@color/collection_grey_gradient_end"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
|
@ -1,22 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="30dp"
|
||||
android:height="30dp"
|
||||
android:viewportWidth="30"
|
||||
android:viewportHeight="30">
|
||||
<path
|
||||
android:pathData="M18.5,11C18.5,15.142 15.142,18.5 11,18.5C6.858,18.5 3.5,15.142 3.5,11C3.5,6.858 6.858,3.5 11,3.5C15.142,3.5 18.5,6.858 18.5,11ZM20,11C20,15.971 15.971,20 11,20C6.029,20 2,15.971 2,11C2,6.029 6.029,2 11,2C15.971,2 20,6.029 20,11ZM18.165,18.866C17.579,19.452 17.579,20.402 18.165,20.987L23.738,26.56C24.324,27.146 25.274,27.146 25.86,26.56L26.567,25.853C27.152,25.267 27.152,24.318 26.567,23.732L20.994,18.159C20.408,17.573 19.458,17.573 18.872,18.159L18.165,18.866Z"
|
||||
android:fillType="evenOdd">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="15.125"
|
||||
android:startY="2"
|
||||
android:endX="15.063"
|
||||
android:endY="27"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="@color/collection_grey_gradient_start"/>
|
||||
<item android:offset="1" android:color="@color/loading_end"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
|
@ -0,0 +1,42 @@
|
|||
package com.anytypeio.anytype.domain.widgets
|
||||
|
||||
import com.anytypeio.anytype.core_models.DVFilter
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.primitives.Space
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetSuggestedWidgetTypes @Inject constructor(
|
||||
dispatchers: AppCoroutineDispatchers,
|
||||
private val repo: BlockRepository,
|
||||
) : ResultInteractor<GetSuggestedWidgetTypes.Params, List<ObjectWrapper.Type>>(dispatchers.io) {
|
||||
|
||||
override suspend fun doWork(params: Params): List<ObjectWrapper.Type> {
|
||||
|
||||
// TODO DROID-3438 open widget object preview and filter out existing object types
|
||||
|
||||
val types = repo.searchObjects(
|
||||
space = params.space,
|
||||
limit = DEFAULT_LIMIT,
|
||||
filters = params.objectTypeFilters,
|
||||
keys = params.objectTypeKeys
|
||||
).map { result ->
|
||||
ObjectWrapper.Type(result)
|
||||
}
|
||||
|
||||
return types
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val space: Space,
|
||||
val objectTypeFilters: List<DVFilter>,
|
||||
val objectTypeKeys: List<Id>
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_LIMIT = 5
|
||||
}
|
||||
}
|
|
@ -1544,10 +1544,6 @@ fun CoroutineScope.sendChangeWidgetSourceEvent(
|
|||
props = Props(
|
||||
buildMap {
|
||||
when (view) {
|
||||
BundledWidgetSourceView.Collections -> {
|
||||
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_COLLECTIONS)
|
||||
}
|
||||
|
||||
BundledWidgetSourceView.Favorites -> {
|
||||
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_FAVORITES)
|
||||
}
|
||||
|
@ -1560,11 +1556,8 @@ fun CoroutineScope.sendChangeWidgetSourceEvent(
|
|||
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_RECENT_LOCAL)
|
||||
}
|
||||
|
||||
BundledWidgetSourceView.Sets -> {
|
||||
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_SETS)
|
||||
}
|
||||
BundledWidgetSourceView.Bin -> {
|
||||
// TODO add analytics
|
||||
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_BIN)
|
||||
}
|
||||
}
|
||||
if (isForNewWidget)
|
||||
|
|
|
@ -898,16 +898,20 @@ class HomeScreenViewModel(
|
|||
|
||||
fun onCreateWidgetClicked() {
|
||||
viewModelScope.launch {
|
||||
sendAddWidgetEvent(
|
||||
analytics = analytics,
|
||||
isInEditMode = isInEditMode()
|
||||
)
|
||||
commands.emit(
|
||||
Command.SelectWidgetSource(
|
||||
isInEditMode = isInEditMode(),
|
||||
space = spaceManager.get()
|
||||
val config = spaceManager.getConfig()
|
||||
if (config != null) {
|
||||
sendAddWidgetEvent(
|
||||
analytics = analytics,
|
||||
isInEditMode = isInEditMode()
|
||||
)
|
||||
)
|
||||
commands.emit(
|
||||
Command.SelectWidgetSource(
|
||||
ctx = config.widgets,
|
||||
isInEditMode = isInEditMode(),
|
||||
space = spaceManager.get()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1171,17 +1175,21 @@ class HomeScreenViewModel(
|
|||
|
||||
private fun proceedWithAddingWidgetBelow(widget: Id) {
|
||||
viewModelScope.launch {
|
||||
sendAddWidgetEvent(
|
||||
analytics = analytics,
|
||||
isInEditMode = isInEditMode()
|
||||
)
|
||||
commands.emit(
|
||||
Command.SelectWidgetSource(
|
||||
target = widget,
|
||||
isInEditMode = isInEditMode(),
|
||||
space = spaceManager.get()
|
||||
val config = spaceManager.getConfig()
|
||||
if (config != null) {
|
||||
sendAddWidgetEvent(
|
||||
analytics = analytics,
|
||||
isInEditMode = isInEditMode()
|
||||
)
|
||||
)
|
||||
commands.emit(
|
||||
Command.SelectWidgetSource(
|
||||
ctx = config.widgets,
|
||||
target = widget,
|
||||
isInEditMode = isInEditMode(),
|
||||
space = spaceManager.get()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2514,6 +2522,7 @@ sealed class Command {
|
|||
* [target] optional target, below which new widget will be created
|
||||
*/
|
||||
data class SelectWidgetSource(
|
||||
val ctx: Id,
|
||||
val target: Id? = null,
|
||||
val isInEditMode: Boolean,
|
||||
val space: Id
|
||||
|
|
|
@ -2,27 +2,39 @@ package com.anytypeio.anytype.presentation.widgets
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.Block.Content.DataView.Filter
|
||||
import com.anytypeio.anytype.core_models.DVFilter
|
||||
import com.anytypeio.anytype.core_models.DVFilterCondition
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.domain.base.Resultat
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.base.getOrDefault
|
||||
import com.anytypeio.anytype.domain.base.onSuccess
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.primitives.FieldParser
|
||||
import com.anytypeio.anytype.domain.search.SearchObjects
|
||||
import com.anytypeio.anytype.domain.widgets.GetSuggestedWidgetTypes
|
||||
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
||||
import com.anytypeio.anytype.presentation.extension.sendChangeWidgetSourceEvent
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.navigation.DefaultObjectView
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchSection
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchView
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.presentation.widgets.source.BundledWidgetSourceView
|
||||
import com.anytypeio.anytype.presentation.widgets.source.SuggestWidgetObjectType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -37,6 +49,7 @@ class SelectWidgetSourceViewModel(
|
|||
private val dispatcher: Dispatcher<WidgetDispatchEvent>,
|
||||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
|
||||
private val storeOfObjectTypes: StoreOfObjectTypes,
|
||||
private val getSuggestedWidgetTypes: GetSuggestedWidgetTypes,
|
||||
fieldParser: FieldParser
|
||||
) : ObjectSearchViewModel(
|
||||
vmParams = vmParams,
|
||||
|
@ -49,9 +62,48 @@ class SelectWidgetSourceViewModel(
|
|||
storeOfObjectTypes = storeOfObjectTypes
|
||||
) {
|
||||
|
||||
val suggested = MutableStateFlow<List<SuggestWidgetObjectType>>(emptyList())
|
||||
|
||||
val isDismissed = MutableStateFlow(false)
|
||||
var config : Config = Config.None
|
||||
|
||||
val viewState = combine(
|
||||
stateData
|
||||
.asFlow(),
|
||||
suggested
|
||||
) { state, suggested ->
|
||||
if (suggested.isNotEmpty()) {
|
||||
when(state) {
|
||||
is ObjectSearchView.Success -> {
|
||||
state.copy(
|
||||
objects = buildList {
|
||||
|
||||
// System widgets
|
||||
add(ObjectSearchSection.SelectWidgetSource.System)
|
||||
add(BundledWidgetSourceView.Favorites)
|
||||
add(BundledWidgetSourceView.Recent)
|
||||
add(BundledWidgetSourceView.RecentLocal)
|
||||
add(BundledWidgetSourceView.Bin)
|
||||
|
||||
// Suggested widgets (aka object type widgets)
|
||||
if (suggested.isNotEmpty()) {
|
||||
add(ObjectSearchSection.SelectWidgetSource.Suggested)
|
||||
addAll(suggested)
|
||||
}
|
||||
|
||||
// Widgets from existing objects
|
||||
add(ObjectSearchSection.SelectWidgetSource.FromMyObjects)
|
||||
addAll(state.objects)
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> state
|
||||
}
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
dispatcher.flow()
|
||||
|
@ -64,52 +116,33 @@ class SelectWidgetSourceViewModel(
|
|||
}
|
||||
|
||||
override fun resolveViews(result: Resultat<List<DefaultObjectView>>) {
|
||||
result.fold(
|
||||
onSuccess = { views ->
|
||||
if (views.isEmpty()) {
|
||||
stateData.postValue(ObjectSearchView.NoResults(userInput.value))
|
||||
} else {
|
||||
if (userInput.value.isEmpty()) {
|
||||
stateData.postValue(
|
||||
ObjectSearchView.Success(
|
||||
buildList {
|
||||
add(ObjectSearchSection.SelectWidgetSource.System)
|
||||
addAll(
|
||||
listOf(
|
||||
BundledWidgetSourceView.Favorites,
|
||||
BundledWidgetSourceView.Recent,
|
||||
BundledWidgetSourceView.RecentLocal,
|
||||
BundledWidgetSourceView.Bin
|
||||
)
|
||||
)
|
||||
|
||||
// TODO in the next PR: add suggested types
|
||||
|
||||
add(ObjectSearchSection.SelectWidgetSource.FromMyObjects)
|
||||
addAll(views)
|
||||
}
|
||||
)
|
||||
)
|
||||
viewModelScope.launch {
|
||||
result.fold(
|
||||
onSuccess = { views ->
|
||||
if (views.isEmpty()) {
|
||||
stateData.postValue(ObjectSearchView.NoResults(userInput.value))
|
||||
} else {
|
||||
stateData.postValue(ObjectSearchView.Success(views))
|
||||
}
|
||||
},
|
||||
onLoading = {
|
||||
stateData.postValue(ObjectSearchView.Loading)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while selecting source for widget")
|
||||
}
|
||||
},
|
||||
onLoading = {
|
||||
stateData.postValue(ObjectSearchView.Loading)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while selecting source for widget")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onStartWithNewWidget(
|
||||
ctx: Id,
|
||||
target: Id?,
|
||||
isInEditMode: Boolean
|
||||
) {
|
||||
Timber.d("onStart with picking source for new widget")
|
||||
config = Config.NewWidget(
|
||||
ctx = ctx,
|
||||
target = target,
|
||||
isInEditMode = isInEditMode
|
||||
)
|
||||
|
@ -135,6 +168,32 @@ class SelectWidgetSourceViewModel(
|
|||
}
|
||||
|
||||
private fun proceedWithSearchQuery() {
|
||||
viewModelScope.launch {
|
||||
getSuggestedWidgetTypes.async(
|
||||
params = GetSuggestedWidgetTypes.Params(
|
||||
space = vmParams.space,
|
||||
objectTypeFilters = buildList {
|
||||
add(
|
||||
DVFilter(
|
||||
relation = Relations.SPACE_ID,
|
||||
condition = DVFilterCondition.EQUAL,
|
||||
value = vmParams.space.id
|
||||
)
|
||||
)
|
||||
addAll(ObjectSearchConstants.filterTypes())
|
||||
},
|
||||
objectTypeKeys = ObjectSearchConstants.defaultKeysObjectType
|
||||
)
|
||||
).onSuccess { types ->
|
||||
suggested.value = types.map { type ->
|
||||
SuggestWidgetObjectType(
|
||||
id = type.id,
|
||||
name = type.name.orEmpty(),
|
||||
objectIcon = type.objectIcon()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
getObjectTypes()
|
||||
startProcessingSearchQuery(null)
|
||||
}
|
||||
|
@ -185,6 +244,43 @@ class SelectWidgetSourceViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onSuggestedWidgetObjectTypeClicked(view: SuggestWidgetObjectType) {
|
||||
Timber.d("onSuggestedWidgetObjectTypeClicked, view:[$view]")
|
||||
when (val curr = config) {
|
||||
is Config.NewWidget -> {
|
||||
viewModelScope.launch {
|
||||
dispatcher.send(
|
||||
WidgetDispatchEvent.SourcePicked.Default(
|
||||
source = view.id,
|
||||
target = curr.target,
|
||||
sourceLayout = ObjectType.Layout.OBJECT_TYPE.code
|
||||
)
|
||||
).also {
|
||||
// TODO send analytics
|
||||
}
|
||||
}
|
||||
}
|
||||
is Config.ExistingWidget -> {
|
||||
viewModelScope.launch {
|
||||
dispatcher.send(
|
||||
WidgetDispatchEvent.SourceChanged(
|
||||
ctx = curr.ctx,
|
||||
widget = curr.widget,
|
||||
source = view.id,
|
||||
type = curr.type
|
||||
)
|
||||
).also {
|
||||
// TODO send analytics
|
||||
}
|
||||
isDismissed.value = true
|
||||
}
|
||||
}
|
||||
Config.None -> {
|
||||
Timber.w("Missing config for widget source")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onCreateNewObjectClicked() {
|
||||
viewModelScope.launch {
|
||||
dispatcher.send(WidgetDispatchEvent.NewWithWidgetWithNewSource)
|
||||
|
@ -271,6 +367,7 @@ class SelectWidgetSourceViewModel(
|
|||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
|
||||
private val fieldParser: FieldParser,
|
||||
private val storeOfObjectTypes: StoreOfObjectTypes,
|
||||
private val getSuggestedWidgetTypes: GetSuggestedWidgetTypes
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -284,7 +381,8 @@ class SelectWidgetSourceViewModel(
|
|||
dispatcher = dispatcher,
|
||||
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
getSuggestedWidgetTypes = getSuggestedWidgetTypes
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +390,7 @@ class SelectWidgetSourceViewModel(
|
|||
sealed class Config {
|
||||
data object None : Config()
|
||||
data class NewWidget(
|
||||
val ctx: Id,
|
||||
val target: Id?,
|
||||
val isInEditMode: Boolean
|
||||
) : Config()
|
||||
|
|
|
@ -76,8 +76,12 @@ object BundledWidgetSourceIds {
|
|||
const val FAVORITE = "favorite"
|
||||
const val RECENT = "recent"
|
||||
const val RECENT_LOCAL = "recentOpen"
|
||||
const val SETS = "set"
|
||||
const val BIN = "bin"
|
||||
|
||||
@Deprecated("DROID-3438 To be deleted")
|
||||
const val SETS = "set"
|
||||
@Deprecated("DROID-3438 To be deleted")
|
||||
const val COLLECTIONS = "collection"
|
||||
|
||||
val ids = listOf(FAVORITE, RECENT, RECENT_LOCAL, SETS, COLLECTIONS, BIN)
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.presentation.widgets.source
|
|||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.presentation.navigation.DefaultSearchItem
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.widgets.BundledWidgetSourceIds
|
||||
|
||||
/**
|
||||
|
@ -13,17 +14,6 @@ sealed class BundledWidgetSourceView : DefaultSearchItem {
|
|||
data object Favorites : BundledWidgetSourceView() {
|
||||
override val id: Id get() = BundledWidgetSourceIds.FAVORITE
|
||||
}
|
||||
|
||||
@Deprecated("To be deleted. Migrating to widget source by suggested types")
|
||||
data object Sets : BundledWidgetSourceView() {
|
||||
override val id: Id get() = BundledWidgetSourceIds.SETS
|
||||
}
|
||||
|
||||
@Deprecated("To be deleted. Migrating to widget source by suggested types")
|
||||
data object Collections : BundledWidgetSourceView() {
|
||||
override val id: Id get() = BundledWidgetSourceIds.COLLECTIONS
|
||||
}
|
||||
|
||||
data object Recent : BundledWidgetSourceView() {
|
||||
override val id: Id get() = BundledWidgetSourceIds.RECENT
|
||||
}
|
||||
|
@ -35,4 +25,10 @@ sealed class BundledWidgetSourceView : DefaultSearchItem {
|
|||
data object Bin : BundledWidgetSourceView() {
|
||||
override val id: Id get() = BundledWidgetSourceIds.BIN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class SuggestWidgetObjectType(
|
||||
val id: Id,
|
||||
val name: String,
|
||||
val objectIcon: ObjectIcon
|
||||
) : DefaultSearchItem
|
Loading…
Add table
Add a link
Reference in a new issue