From c52bd3d44b28497d56dac066c0b02c4b1032c31a Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Thu, 8 Dec 2022 22:38:36 +0300 Subject: [PATCH] DROID-642 Relations | Feature | Suggest marketplace relations for user input search query + allow installing relation to user workspace (#2750) --- .../di/feature/relations/RelationAddDI.kt | 71 ++++- .../ui/relations/RelationAddBaseFragment.kt | 36 ++- .../anytype/core_models/ObjectTypeIds.kt | 4 + .../anytype/core_models/ObjectWrapper.kt | 2 + .../common/DefaultSectionViewHolder.kt | 8 +- .../features/relations/RelationAddAdapter.kt | 102 +++++-- core-ui/src/main/res/values/strings.xml | 1 + .../anytype/domain/relations/GetRelations.kt | 39 +++ .../objects/ObjectTypeChangeViewModel.kt | 4 +- .../RelationAddToDataViewViewModel.kt | 41 ++- .../relations/RelationAddToObjectViewModel.kt | 36 ++- .../relations/RelationAddViewModelBase.kt | 218 +++++++++++--- .../relations/model/RelationView.kt | 15 +- .../search/ObjectSearchConstants.kt | 38 ++- .../relations/RelationAddViewModelBaseTest.kt | 266 +++++++++++++++--- .../types/ObjectTypeChangeViewModelTest.kt | 34 +-- .../anytypeio/anytype/core_models/Relation.kt | 42 +-- 17 files changed, 766 insertions(+), 191 deletions(-) create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/relations/RelationAddDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/relations/RelationAddDI.kt index 3c0b47714f..b0da71fd98 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/relations/RelationAddDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/relations/RelationAddDI.kt @@ -3,12 +3,15 @@ package com.anytypeio.anytype.di.feature.relations import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.core_utils.di.scope.PerDialog +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.dataview.interactor.AddRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer import com.anytypeio.anytype.domain.objects.StoreOfRelations import com.anytypeio.anytype.domain.relations.AddRelationToObject +import com.anytypeio.anytype.domain.relations.GetRelations import com.anytypeio.anytype.domain.relations.ObjectRelationList +import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace import com.anytypeio.anytype.presentation.relations.RelationAddToDataViewViewModel import com.anytypeio.anytype.presentation.relations.RelationAddToObjectViewModel import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider @@ -21,6 +24,7 @@ import com.anytypeio.anytype.ui.relations.RelationAddToObjectFragment import dagger.Module import dagger.Provides import dagger.Subcomponent +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.StateFlow @Subcomponent(modules = [RelationAddToObjectModule::class]) @@ -48,12 +52,18 @@ object RelationAddToObjectModule { dispatcher: Dispatcher, analytics: Analytics, relationsProvider: ObjectRelationProvider, + getRelations: GetRelations, + appCoroutineDispatchers: AppCoroutineDispatchers, + addObjectToWorkspace: AddObjectToWorkspace ): RelationAddToObjectViewModel.Factory = RelationAddToObjectViewModel.Factory( storeOfRelations = storeOfRelations, addRelationToObject = addRelationToObject, dispatcher = dispatcher, analytics = analytics, relationsProvider = relationsProvider, + getRelations = getRelations, + appCoroutineDispatchers = appCoroutineDispatchers, + addObjectToWorkspace = addObjectToWorkspace ) @JvmStatic @@ -62,6 +72,31 @@ object RelationAddToObjectModule { fun provideObjectRelationListUseCase( repo: BlockRepository ): ObjectRelationList = ObjectRelationList(repo) + + @JvmStatic + @Provides + @PerDialog + fun getRelations(repo: BlockRepository) : GetRelations = GetRelations(repo) + + @JvmStatic + @Provides + @PerDialog + fun appCoroutineDispatchers() : AppCoroutineDispatchers = AppCoroutineDispatchers( + io = Dispatchers.IO, + computation = Dispatchers.Default, + main = Dispatchers.Main + ) + + @JvmStatic + @Provides + @PerDialog + fun addObjectToWorkspace( + repo: BlockRepository, + appCoroutineDispatchers: AppCoroutineDispatchers + ) : AddObjectToWorkspace = AddObjectToWorkspace( + repo = repo, + dispatchers = appCoroutineDispatchers + ) } @Subcomponent(modules = [RelationAddToDataViewModule::class]) @@ -79,27 +114,32 @@ interface RelationAddToDataViewSubComponent { @Module object RelationAddToDataViewModule { + @JvmStatic @Provides @PerDialog fun provideViewModelFactory( addRelationToDataView: AddRelationToDataView, - storeOfRelations: StoreOfRelations, dispatcher: Dispatcher, state: StateFlow, session: ObjectSetSession, updateDataViewViewer: UpdateDataViewViewer, analytics: Analytics, relationsProvider: ObjectRelationProvider, + appCoroutineDispatchers: AppCoroutineDispatchers, + getRelations: GetRelations, + addObjectToWorkspace: AddObjectToWorkspace ): RelationAddToDataViewViewModel.Factory = RelationAddToDataViewViewModel.Factory( - storeOfRelations = storeOfRelations, addRelationToDataView = addRelationToDataView, dispatcher = dispatcher, state = state, session = session, updateDataViewViewer = updateDataViewViewer, analytics = analytics, - relationsProvider = relationsProvider + relationsProvider = relationsProvider, + appCoroutineDispatchers = appCoroutineDispatchers, + getRelations = getRelations, + addObjectToWorkspace = addObjectToWorkspace ) @JvmStatic @@ -115,4 +155,29 @@ object RelationAddToDataViewModule { fun provideAddRelationToDataViewUseCase( repo: BlockRepository ): AddRelationToDataView = AddRelationToDataView(repo) + + @JvmStatic + @Provides + @PerDialog + fun getRelations(repo: BlockRepository) : GetRelations = GetRelations(repo) + + @JvmStatic + @Provides + @PerDialog + fun appCoroutineDispatchers() : AppCoroutineDispatchers = AppCoroutineDispatchers( + io = Dispatchers.IO, + computation = Dispatchers.Default, + main = Dispatchers.Main + ) + + @JvmStatic + @Provides + @PerDialog + fun addObjectToWorkspace( + repo: BlockRepository, + appCoroutineDispatchers: AppCoroutineDispatchers + ) : AddObjectToWorkspace = AddObjectToWorkspace( + repo = repo, + dispatchers = appCoroutineDispatchers + ) } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationAddBaseFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationAddBaseFragment.kt index bd1445d334..8f8da1f65d 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationAddBaseFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationAddBaseFragment.kt @@ -17,6 +17,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.anytypeio.anytype.R import com.anytypeio.anytype.analytics.base.EventsDictionary import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.Key +import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_ui.features.relations.RelationAddAdapter import com.anytypeio.anytype.core_ui.features.relations.RelationAddHeaderAdapter import com.anytypeio.anytype.core_ui.reactive.focusChanges @@ -34,7 +36,7 @@ import com.anytypeio.anytype.di.common.componentManager import com.anytypeio.anytype.presentation.relations.RelationAddToDataViewViewModel import com.anytypeio.anytype.presentation.relations.RelationAddToObjectViewModel import com.anytypeio.anytype.presentation.relations.RelationAddViewModelBase -import com.anytypeio.anytype.presentation.relations.model.RelationView +import com.anytypeio.anytype.presentation.relations.RelationAddViewModelBase.Command import com.google.android.material.bottomsheet.BottomSheetBehavior import java.io.Serializable import javax.inject.Inject @@ -56,7 +58,10 @@ abstract class RelationAddBaseFragment : BaseBottomSheetTextInputFragment - onRelationSelected(ctx = ctx, relation = relation) + vm.onRelationSelected( + ctx = ctx, + relation = relation + ) } private val concatAdapter = ConcatAdapter(createFromScratchAdapter, relationAdapter) @@ -94,6 +99,17 @@ abstract class RelationAddBaseFragment : BaseBottomSheetTextInputFragment + when(command) { + is Command.DispatchSelectedRelation -> { + onRelationSelected( + ctx = command.ctx, + relation = command.relation, + format = command.format + ) + } + } + } } } @@ -108,12 +124,7 @@ abstract class RelationAddBaseFragment : BaseBottomSheetTextInputFragment Unit -) : ListAdapter(Differ) { +) : ListAdapter(Differ) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int - ) = DefaultRelationViewHolder( - binding = ItemRelationFormatBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - ).apply { - itemView.setOnClickListener { - if (bindingAdapterPosition != RecyclerView.NO_POSITION) - onItemClick(getItem(bindingAdapterPosition)) + ) = when(viewType) { + R.layout.item_relation_format -> { + DefaultRelationViewHolder( + binding = ItemRelationFormatBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ).apply { + itemView.setOnClickListener { + if (bindingAdapterPosition != RecyclerView.NO_POSITION) { + val item = getItem(bindingAdapterPosition) + if (item is RelationView.Existing) { onItemClick(item) } + } + } + } + } + R.layout.item_default_list_section -> { + DefaultSectionViewHolder( + binding =ItemDefaultListSectionBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ).apply { + binding.tvSectionName.updateLayoutParams { + marginStart = dimen(R.dimen.dp_20) + } + } + } + else -> throw IllegalStateException("Unexpected view type: $viewType") + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + val item = getItem(position) + when(holder) { + is DefaultRelationViewHolder -> { + check(item is RelationView.Existing) + holder.bind(name = item.name, format = item.format) + } + is DefaultSectionViewHolder -> { + check(item is Section) + when(item) { + Section.Marketplace -> { + holder.bind(holder.itemView.resources.getString(R.string.marketplace)) + } + Section.Library -> { + holder.bind(holder.itemView.resources.getString(R.string.my_relations)) + } + } + } } } - override fun onBindViewHolder(holder: DefaultRelationViewHolder, position: Int) { - getItem(position).apply { holder.bind(name = name, format = format) } + override fun getItemViewType(position: Int): Int = when(val item = getItem(position)) { + is RelationView.Existing -> R.layout.item_relation_format + is Section -> R.layout.item_default_list_section + else -> throw IllegalStateException("Unexpected type: ${item::class.simpleName}") } - override fun getItemViewType(position: Int): Int = R.layout.item_relation_format - - object Differ : DiffUtil.ItemCallback() { + object Differ : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: RelationView.Existing, - newItem: RelationView.Existing - ): Boolean = oldItem.key == newItem.key + oldItem: RelationItemView, + newItem: RelationItemView + ): Boolean { + return if (oldItem is RelationView.Existing && newItem is RelationView.Existing) + oldItem.key == newItem.key + else + oldItem == newItem + } override fun areContentsTheSame( - oldItem: RelationView.Existing, - newItem: RelationView.Existing + oldItem: RelationItemView, + newItem: RelationItemView ): Boolean = oldItem == newItem } } diff --git a/core-ui/src/main/res/values/strings.xml b/core-ui/src/main/res/values/strings.xml index 712cb53910..92fcfec64a 100644 --- a/core-ui/src/main/res/values/strings.xml +++ b/core-ui/src/main/res/values/strings.xml @@ -583,5 +583,6 @@ Type: %1$s Marketplace My types + My relations diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt b/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt new file mode 100644 index 0000000000..85e2dd35e4 --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt @@ -0,0 +1,39 @@ +package com.anytypeio.anytype.domain.relations + +import com.anytypeio.anytype.core_models.DVFilter +import com.anytypeio.anytype.core_models.DVSort +import com.anytypeio.anytype.core_models.Key +import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.domain.base.BaseUseCase +import com.anytypeio.anytype.domain.block.repo.BlockRepository + +class GetRelations( + private val repo: BlockRepository +) : BaseUseCase, GetRelations.Params>() { + + override suspend fun run(params: Params) = safe { proceedWithUseCase(params) } + + suspend fun execute(params: Params) : List { + return proceedWithUseCase(params) + } + + private suspend fun proceedWithUseCase(params: Params) = repo.searchObjects( + keys = params.keys, + filters = params.filters, + sorts = params.sorts, + limit = params.limit, + offset = params.offset, + fulltext = params.query + ).map { struct -> + ObjectWrapper.Relation(struct) + } + + data class Params( + val sorts: List = emptyList(), + val filters: List = emptyList(), + val keys: List = emptyList(), + val offset: Int = 0, + val limit: Int = 0, + val query: String = "" + ) +} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt index b2c9e00c1c..1f6dc2e245 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt @@ -178,7 +178,7 @@ class ObjectTypeChangeViewModel( ) } }, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), query = query, keys = ObjectSearchConstants.defaultKeysObjectType ) @@ -203,7 +203,7 @@ class ObjectTypeChangeViewModel( ) } }, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), query = query, keys = ObjectSearchConstants.defaultKeysObjectType ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToDataViewViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToDataViewViewModel.kt index 20082fbd42..95744d9c8b 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToDataViewViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToDataViewViewModel.kt @@ -7,13 +7,16 @@ import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_models.DV import com.anytypeio.anytype.core_models.DVViewerRelation import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.Payload +import com.anytypeio.anytype.core_models.RelationFormat +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.dataview.interactor.AddRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer -import com.anytypeio.anytype.domain.objects.StoreOfRelations +import com.anytypeio.anytype.domain.relations.GetRelations +import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace import com.anytypeio.anytype.presentation.extension.getPropName import com.anytypeio.anytype.presentation.extension.sendAnalyticsAddRelationEvent -import com.anytypeio.anytype.presentation.relations.model.RelationView import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider import com.anytypeio.anytype.presentation.sets.ObjectSet import com.anytypeio.anytype.presentation.sets.ObjectSetSession @@ -23,25 +26,35 @@ import kotlinx.coroutines.launch import timber.log.Timber class RelationAddToDataViewViewModel( - storeOfRelations: StoreOfRelations, relationsProvider: ObjectRelationProvider, private val state: StateFlow, private val session: ObjectSetSession, private val updateDataViewViewer: UpdateDataViewViewer, private val addRelationToDataView: AddRelationToDataView, + private val getRelations: GetRelations, private val dispatcher: Dispatcher, - private val analytics: Analytics + private val analytics: Analytics, + private val addObjectToWorkspace: AddObjectToWorkspace, + appCoroutineDispatchers: AppCoroutineDispatchers ) : RelationAddViewModelBase( - storeOfRelations = storeOfRelations, - relationsProvider = relationsProvider + relationsProvider = relationsProvider, + appCoroutineDispatchers = appCoroutineDispatchers, + getRelations = getRelations, + addObjectToWorkspace = addObjectToWorkspace ) { - fun onRelationSelected(ctx: Id, relation: RelationView.Existing, dv: Id, screenType: String) { + fun onRelationSelected( + ctx: Id, + relation: Key, + format: RelationFormat, + dv: Id, + screenType: String + ) { viewModelScope.launch { addRelationToDataView( AddRelationToDataView.Params( ctx = ctx, - relation = relation.key, + relation = relation, dv = dv ) ).process( @@ -49,13 +62,13 @@ class RelationAddToDataViewViewModel( dispatcher.send(it).also { proceedWithAddingNewRelationToCurrentViewer( ctx = ctx, - relation = relation.key + relation = relation ) } sendAnalyticsAddRelationEvent( analytics = analytics, type = screenType, - format = relation.format.getPropName() + format = format.getPropName() ) }, failure = { @@ -97,23 +110,27 @@ class RelationAddToDataViewViewModel( private val state: StateFlow, private val session: ObjectSetSession, private val updateDataViewViewer: UpdateDataViewViewer, - private val storeOfRelations: StoreOfRelations, private val addRelationToDataView: AddRelationToDataView, private val dispatcher: Dispatcher, private val analytics: Analytics, private val relationsProvider: ObjectRelationProvider, + private val appCoroutineDispatchers: AppCoroutineDispatchers, + private val getRelations: GetRelations, + private val addObjectToWorkspace: AddObjectToWorkspace ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { return RelationAddToDataViewViewModel( addRelationToDataView = addRelationToDataView, - storeOfRelations = storeOfRelations, dispatcher = dispatcher, session = session, updateDataViewViewer = updateDataViewViewer, state = state, analytics = analytics, relationsProvider = relationsProvider, + appCoroutineDispatchers = appCoroutineDispatchers, + getRelations = getRelations, + addObjectToWorkspace = addObjectToWorkspace ) as T } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToObjectViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToObjectViewModel.kt index aa2edaa5a4..0548bea7a7 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToObjectViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddToObjectViewModel.kt @@ -6,13 +6,17 @@ import androidx.lifecycle.viewModelScope import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.analytics.base.EventsDictionary import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.Payload +import com.anytypeio.anytype.core_models.RelationFormat +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.objects.StoreOfRelations import com.anytypeio.anytype.domain.relations.AddRelationToObject +import com.anytypeio.anytype.domain.relations.GetRelations +import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace import com.anytypeio.anytype.presentation.extension.getPropName import com.anytypeio.anytype.presentation.extension.sendAnalyticsAddRelationEvent import com.anytypeio.anytype.presentation.extension.sendAnalyticsSearchQueryEvent -import com.anytypeio.anytype.presentation.relations.model.RelationView import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider import com.anytypeio.anytype.presentation.util.Dispatcher import kotlinx.coroutines.flow.MutableSharedFlow @@ -24,29 +28,39 @@ class RelationAddToObjectViewModel( private val addRelationToObject: AddRelationToObject, private val dispatcher: Dispatcher, private val analytics: Analytics, - val storeOfRelations: StoreOfRelations + val storeOfRelations: StoreOfRelations, + appCoroutineDispatchers: AppCoroutineDispatchers, + getRelations: GetRelations, + addObjectToWorkspace: AddObjectToWorkspace ) : RelationAddViewModelBase( relationsProvider = relationsProvider, - storeOfRelations = storeOfRelations + appCoroutineDispatchers = appCoroutineDispatchers, + getRelations = getRelations, + addObjectToWorkspace = addObjectToWorkspace ) { val commands = MutableSharedFlow(replay = 0) - fun onRelationSelected(ctx: Id, relation: RelationView.Existing, screenType: String) { + fun onRelationSelected( + ctx: Id, + relation: Key, + format: RelationFormat, + screenType: String + ) { viewModelScope.launch { addRelationToObject( AddRelationToObject.Params( ctx = ctx, - relationKey = relation.key + relationKey = relation ) ).process( success = { dispatcher.send(it).also { - commands.emit(Command.OnRelationAdd(relation = relation.key)) + commands.emit(Command.OnRelationAdd(relation = relation)) sendAnalyticsAddRelationEvent( analytics = analytics, type = screenType, - format = relation.format.getPropName() + format = format.getPropName() ) isDismissed.value = true } @@ -73,6 +87,9 @@ class RelationAddToObjectViewModel( private val dispatcher: Dispatcher, private val analytics: Analytics, private val relationsProvider: ObjectRelationProvider, + private val appCoroutineDispatchers: AppCoroutineDispatchers, + private val getRelations: GetRelations, + private val addObjectToWorkspace: AddObjectToWorkspace ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { @@ -81,7 +98,10 @@ class RelationAddToObjectViewModel( addRelationToObject = addRelationToObject, storeOfRelations = storeOfRelations, dispatcher = dispatcher, - analytics = analytics + analytics = analytics, + appCoroutineDispatchers = appCoroutineDispatchers, + getRelations = getRelations, + addObjectToWorkspace = addObjectToWorkspace ) as T } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt index 221f7c3837..7fd61ae4c3 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt @@ -1,84 +1,230 @@ package com.anytypeio.anytype.presentation.relations import androidx.lifecycle.viewModelScope +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.Key +import com.anytypeio.anytype.core_models.Marketplace import com.anytypeio.anytype.core_models.ObjectWrapper -import com.anytypeio.anytype.core_utils.ext.cancel -import com.anytypeio.anytype.domain.objects.StoreOfRelations +import com.anytypeio.anytype.core_models.RelationFormat +import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.relations.GetRelations +import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace import com.anytypeio.anytype.presentation.common.BaseViewModel +import com.anytypeio.anytype.presentation.relations.model.RelationItemView import com.anytypeio.anytype.presentation.relations.model.RelationView +import com.anytypeio.anytype.presentation.relations.model.Section import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider -import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.Flow +import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultObjectSearchSorts +import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.filterMarketplaceRelations +import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.filterMyRelations +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch +import timber.log.Timber /** * Base view model for adding a relation either to an object or to a set. */ abstract class RelationAddViewModelBase( private val relationsProvider: ObjectRelationProvider, - private val storeOfRelations: StoreOfRelations + private val getRelations: GetRelations, + private val appCoroutineDispatchers: AppCoroutineDispatchers, + private val addObjectToWorkspace: AddObjectToWorkspace ) : BaseViewModel() { - private val jobs = mutableListOf() private val userInput = MutableStateFlow(DEFAULT_INPUT) - private val views = MutableStateFlow>(emptyList()) + private val searchQuery = userInput.take(1).onCompletion { emitAll(userInput.drop(1).debounce(DEBOUNCE_DURATION).distinctUntilChanged()) } + val command = MutableSharedFlow() val isDismissed = MutableStateFlow(false) - val results: Flow> = combine(searchQuery, views) { query, views -> - if (query.isEmpty()) - views - else - views.filter { view -> view.name.contains(query, true) } + val results = MutableStateFlow(emptyList()) + + private val objectRelationKeys = relationsProvider.observeAll().map { relations -> + relations.map { r -> r.key } } - abstract fun sendAnalyticsEvent(length: Int) - - fun onStart() { - jobs += viewModelScope.launch { - val all = storeOfRelations.getAll().filter { it.isValid } - getVisibleRelations(available = all).collect { filtered -> - views.value = filtered + init { + viewModelScope.launch { + combine( + searchQuery, + objectRelationKeys + ) { query, keys -> + val myRelations = proceedWithGettingMyRelations(query = query) + val marketplaceRelations = proceedWithGettingMarketplaceRelations( + query = query, + excluded = myRelations.mapNotNull { it.sourceObject } + ) + buildViews( + myRelations = myRelations, + marketplaceRelations = marketplaceRelations, + objectRelationKeys = keys + ) + }.flowOn(appCoroutineDispatchers.io).catch { + sendToast("An error occured. Please try again later.") + }.collect { views -> + results.value = views } } } - fun onStop() { - jobs.cancel() - } - - private fun getVisibleRelations(available: List): Flow> { - return relationsProvider.observeAll().map { addedRelations -> - val addedRelationKeys = addedRelations.map { it.key }.toSet() - available - .filter { it.isHidden != true } - .filter { relation -> !addedRelationKeys.contains(relation.key) } - .map { - RelationView.Existing( - key = it.key, - name = it.name.orEmpty(), - format = it.format - ) - } + private fun buildViews( + myRelations: List, + marketplaceRelations: List, + objectRelationKeys: List, + ) = buildList { + val my = myRelations.filter { + !objectRelationKeys.contains(it.key) + }.map { wrapper -> + RelationView.Existing( + id = wrapper.id, + key = wrapper.key, + name = wrapper.name.orEmpty(), + format = wrapper.format, + workspace = wrapper.workspaceId + ) + } + val marketplace = marketplaceRelations.filter { + !objectRelationKeys.contains(it.key) + }.map { wrapper -> + RelationView.Existing( + id = wrapper.id, + key = wrapper.key, + name = wrapper.name.orEmpty(), + format = wrapper.format, + workspace = wrapper.workspaceId + ) + } + if (my.isNotEmpty()) { + add(Section.Library) + addAll(my) + } + if (marketplace.isNotEmpty()) { + add(Section.Marketplace) + addAll(marketplace) } } + private suspend fun proceedWithGettingMarketplaceRelations( + excluded: List, + query: String + ) = getRelations.execute( + GetRelations.Params( + sorts = defaultObjectSearchSorts(), + filters = buildList { + addAll(filterMarketplaceRelations()) + if (excluded.isNotEmpty()) { + add( + DVFilter( + relationKey = Relations.ID, + condition = DVFilterCondition.NOT_IN, + value = excluded + ) + ) + } + add( + DVFilter( + relationKey = Relations.IS_HIDDEN, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) + }, + query = query + ) + ) + + private suspend fun proceedWithGettingMyRelations(query: String) = getRelations.execute( + GetRelations.Params( + sorts = defaultObjectSearchSorts(), + filters = buildList { + addAll(filterMyRelations()) + add( + DVFilter( + relationKey = Relations.IS_HIDDEN, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) + }, + query = query + ) + ) + + abstract fun sendAnalyticsEvent(length: Int) + fun onQueryChanged(input: String) { sendAnalyticsEvent(input.length) userInput.value = input } + fun onRelationSelected( + ctx: Id, + relation: RelationView.Existing + ) { + viewModelScope.launch { + if (relation.workspace == Marketplace.MARKETPLACE_ID) { + addObjectToWorkspace( + AddObjectToWorkspace.Params( + objects = listOf(relation.id) + ) + ).proceed( + success = { + sendToast("Relation `${relation.name}` added to your library") + proceedWithDispatchingSelectedRelation( + ctx = ctx, + relation = relation + ) + }, + failure = { + Timber.e(it, "Error while adding relation to workspace.") + sendToast("Something went wrong. Please, try again later.") + } + ) + } + proceedWithDispatchingSelectedRelation( + ctx = ctx, + relation = relation + ) + } + } + + private suspend fun proceedWithDispatchingSelectedRelation( + ctx: Id, + relation: RelationView.Existing + ) { + command.emit( + Command.DispatchSelectedRelation( + ctx = ctx, + relation = relation.key, + format = relation.format + ) + ) + } + + sealed class Command { + data class DispatchSelectedRelation( + val ctx: Id, + val relation: Key, + val format: RelationFormat + ): Command() + } + companion object { const val ERROR_MESSAGE = "Error while adding relation to object" const val DEBOUNCE_DURATION = 300L diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/model/RelationView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/model/RelationView.kt index e636fb5ba4..900e951852 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/model/RelationView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/model/RelationView.kt @@ -1,20 +1,31 @@ package com.anytypeio.anytype.presentation.relations.model +import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.RelationFormat -sealed class RelationView { + +sealed class RelationItemView + +sealed class RelationView : RelationItemView() { abstract val format: RelationFormat data class Existing( + val id: Id, val key: Key, + val workspace: Id?, val name: String, - override val format: RelationFormat + override val format: RelationFormat, ) : RelationView() data class CreateFromScratch( override val format: RelationFormat, val isSelected: Boolean = false ) : RelationView() +} + +sealed class Section : RelationItemView() { + object Library: Section() + object Marketplace : Section() } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt index 6e97753a90..44b63c023b 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt @@ -401,10 +401,46 @@ object ObjectSearchConstants { //endregion - fun defaultObjectTypeSorts() : List = listOf( + fun defaultObjectSearchSorts() : List = listOf( DVSort( relationKey = Relations.NAME, type = DVSortType.ASC ) ) + + fun filterMyRelations() : List = listOf( + DVFilter( + relationKey = Relations.TYPE, + condition = DVFilterCondition.EQUAL, + value = RELATION + ), + DVFilter( + relationKey = Relations.IS_ARCHIVED, + condition = DVFilterCondition.EQUAL, + value = false + ), + DVFilter( + relationKey = Relations.IS_DELETED, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) + + fun filterMarketplaceRelations() : List = listOf( + DVFilter( + relationKey = Relations.TYPE, + condition = DVFilterCondition.EQUAL, + value = MarketplaceObjectTypeIds.RELATION + ), + DVFilter( + relationKey = Relations.IS_ARCHIVED, + condition = DVFilterCondition.EQUAL, + value = false + ), + DVFilter( + relationKey = Relations.IS_DELETED, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) } \ No newline at end of file diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt index d50b09350a..5f13e44303 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt @@ -1,81 +1,275 @@ package com.anytypeio.anytype.presentation.relations import app.cash.turbine.test +import com.anytypeio.anytype.core_models.DVFilter +import com.anytypeio.anytype.core_models.DVFilterCondition +import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.StubRelationObject -import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations -import com.anytypeio.anytype.domain.objects.StoreOfRelations +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.block.repo.BlockRepository +import com.anytypeio.anytype.domain.relations.GetRelations +import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace import com.anytypeio.anytype.presentation.relations.model.RelationView +import com.anytypeio.anytype.presentation.relations.model.Section import com.anytypeio.anytype.presentation.relations.providers.FakeObjectRelationProvider +import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider +import com.anytypeio.anytype.presentation.search.ObjectSearchConstants import com.anytypeio.anytype.presentation.util.CoroutinesTestRule import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import org.junit.Before import org.junit.Rule import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.stub import kotlin.test.assertEquals @ExperimentalCoroutinesApi class RelationAddViewModelBaseTest { @get:Rule - internal val coroutineTestRule = CoroutinesTestRule() + val coroutineTestRule = CoroutinesTestRule() - private val availableHidden = StubRelationObject(isHidden = true) - private val available = StubRelationObject() - private val availableRelations = listOf(available, availableHidden) + private val appCoroutineDispatchers = AppCoroutineDispatchers( + io = coroutineTestRule.testDispatcher, + main = coroutineTestRule.testDispatcher, + computation = coroutineTestRule.testDispatcher + ) + + @Mock + lateinit var repo: BlockRepository private val relationsProvider = FakeObjectRelationProvider() - @Test - fun `no added relations - results are available without hidden`() { - runTest { - // SETUP - val store = DefaultStoreOfRelations() - val vm = createVM(store) + @Before + fun setup() { + MockitoAnnotations.openMocks(this) + } - // TESTING - store.merge(availableRelations) - vm.onStart() - coroutineTestRule.testDispatcher.scheduler.runCurrent() - vm.results.test { - assertEquals( - actual = awaitItem(), - expected = listOf( - RelationView.Existing( - key = available.key, - name = available.name.orEmpty(), - format = available.format + @Test + fun `no added relations - results are available without hidden`() = runTest { + + // SETUP + + val relation = StubRelationObject() + + repo.stub { + onBlocking { + searchObjects( + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), + filters = buildList { + addAll(ObjectSearchConstants.filterMyRelations()) + add( + DVFilter( + relationKey = Relations.IS_HIDDEN, + condition = DVFilterCondition.EQUAL, + value = false + ) ) + }, + limit = 0, + offset = 0, + fulltext = "" + ) + } doReturn listOf(relation.map) + } + + repo.stub { + onBlocking { + searchObjects( + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), + filters = buildList { + addAll(ObjectSearchConstants.filterMarketplaceRelations()) + add( + DVFilter( + relationKey = Relations.ID, + condition = DVFilterCondition.NOT_IN, + value = listOf(relation.sourceObject) + ) + ) + add( + DVFilter( + relationKey = Relations.IS_HIDDEN, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) + }, + limit = 0, + offset = 0, + fulltext = "" + ) + } doReturn emptyList() + } + + val vm = givenViewModel(relationsProvider = relationsProvider) + + // TESTING + + coroutineTestRule.testDispatcher.scheduler.runCurrent() + + vm.results.test { + assertEquals( + actual = awaitItem(), + expected = listOf( + Section.Library, + RelationView.Existing( + key = relation.key, + id = relation.id, + name = relation.name.orEmpty(), + format = relation.format, + workspace = null ) ) - } + ) } } @Test - fun `added relations equal to available - results are empty`() { - relationsProvider.relation = available - runTest { + fun `added relations equal to available - results are empty`() = runTest { // SETUP - val store = DefaultStoreOfRelations() - val vm = createVM(store) + val vm = givenViewModel(relationsProvider) // TESTING - store.merge(availableRelations) - vm.onStart() + vm.results.test { assertEquals( actual = awaitItem(), expected = emptyList() ) } + } + + @Test + fun `should query relations from library and marketplace filtering out already addded relations`() = runTest { + + // SETUP + + val marketplace = listOf( + StubRelationObject(), + StubRelationObject(), + StubRelationObject() + ) + + val library = listOf( + StubRelationObject(sourceObject = marketplace[0].id), + StubRelationObject(), + StubRelationObject() + ) + + repo.stub { + onBlocking { + searchObjects( + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), + filters = buildList { + addAll(ObjectSearchConstants.filterMyRelations()) + add( + DVFilter( + relationKey = Relations.IS_HIDDEN, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) + }, + limit = 0, + offset = 0, + fulltext = "" + ) + } doReturn library.map { it.map } + } + + repo.stub { + onBlocking { + searchObjects( + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), + filters = buildList { + addAll(ObjectSearchConstants.filterMarketplaceRelations()) + add( + DVFilter( + relationKey = Relations.ID, + condition = DVFilterCondition.NOT_IN, + value = library.mapNotNull { it.sourceObject } + ) + ) + add( + DVFilter( + relationKey = Relations.IS_HIDDEN, + condition = DVFilterCondition.EQUAL, + value = false + ) + ) + }, + limit = 0, + offset = 0, + fulltext = "" + ) + } doReturn marketplace.takeLast(2).map { it.map } + } + + val vm = givenViewModel(relationsProvider = relationsProvider) + + // TESTING + + coroutineTestRule.testDispatcher.scheduler.runCurrent() + + vm.results.test { + assertEquals( + actual = awaitItem(), + expected = listOf( + Section.Library, + RelationView.Existing( + key = library[0].key, + id = library[0].id, + name = library[0].name.orEmpty(), + format = library[0].format, + workspace = null + ), + RelationView.Existing( + key = library[1].key, + id = library[1].id, + name = library[1].name.orEmpty(), + format = library[1].format, + workspace = null + ), + RelationView.Existing( + key = library[2].key, + id = library[2].id, + name = library[2].name.orEmpty(), + format = library[2].format, + workspace = null + ), + Section.Marketplace, + RelationView.Existing( + key = marketplace[1].key, + id = marketplace[1].id, + name = marketplace[1].name.orEmpty(), + format = marketplace[1].format, + workspace = null + ), + RelationView.Existing( + key = marketplace[2].key, + id = marketplace[2].id, + name = marketplace[2].name.orEmpty(), + format = marketplace[2].format, + workspace = null + ), + ) + ) } } - private fun createVM( - storeOfRelations: StoreOfRelations + private fun givenViewModel( + relationsProvider: ObjectRelationProvider ) = object : RelationAddViewModelBase( - storeOfRelations = storeOfRelations, - relationsProvider = relationsProvider + relationsProvider = relationsProvider, + getRelations = GetRelations(repo), + appCoroutineDispatchers = appCoroutineDispatchers, + addObjectToWorkspace = AddObjectToWorkspace( + repo = repo, + dispatchers = appCoroutineDispatchers + ) ) { override fun sendAnalyticsEvent(length: Int) {} } diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt index 463f87fd39..1a04f3bc69 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt @@ -99,7 +99,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = ObjectSearchConstants.defaultKeysObjectType, @@ -143,7 +143,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = "", @@ -171,7 +171,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMyTypeKeys, @@ -184,7 +184,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMarketplaceTypeKeys, @@ -230,7 +230,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = "", @@ -245,7 +245,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = "", @@ -258,7 +258,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = query, @@ -273,7 +273,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = query, @@ -299,7 +299,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMyTypeKeys, @@ -312,7 +312,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMarketplaceTypeKeys, @@ -331,7 +331,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMyTypeKeys, @@ -344,7 +344,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMarketplaceTypeKeys, @@ -389,7 +389,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = "", @@ -404,7 +404,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = "", @@ -436,7 +436,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMyTypeKeys, @@ -449,7 +449,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(repo, times(1)) { searchObjects( filters = expectedMarketplaceTypeFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, keys = expectedMarketplaceTypeKeys, @@ -496,7 +496,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { searchObjects( filters = expectedMyTypesFilters, - sorts = ObjectSearchConstants.defaultObjectTypeSorts(), + sorts = ObjectSearchConstants.defaultObjectSearchSorts(), limit = 0, offset = 0, fulltext = "", diff --git a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Relation.kt b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Relation.kt index 37f6625197..fc92815e64 100644 --- a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Relation.kt +++ b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Relation.kt @@ -2,31 +2,6 @@ package com.anytypeio.anytype.core_models import com.anytypeio.anytype.test_utils.MockDataFactory -@Deprecated("To be deleted") -fun StubRelation( - key: String = MockDataFactory.randomString(), - name: String = MockDataFactory.randomString(), - format: Relation.Format = Relation.Format.SHORT_TEXT, - source: Relation.Source = Relation.Source.LOCAL, - isHidden: Boolean = false, - isReadOnly: Boolean = false, - isMulti: Boolean = false, - selections: List = emptyList(), - objectTypes: List = emptyList(), - defaultValue: Any? = null -): Relation = Relation( - key, - name, - format, - source, - isHidden, - isReadOnly, - isMulti, - selections, - objectTypes, - defaultValue -) - fun StubRelationObject( id: String = MockDataFactory.randomString(), key: String = MockDataFactory.randomString(), @@ -35,7 +10,8 @@ fun StubRelationObject( isHidden: Boolean = false, isReadOnly: Boolean = false, objectTypes: List = emptyList(), - relationOptionsDict: List = emptyList() + relationOptionsDict: List = emptyList(), + sourceObject: Id = MockDataFactory.randomUuid() ): ObjectWrapper.Relation = ObjectWrapper.Relation( map = mapOf( Relations.ID to id, @@ -45,21 +21,11 @@ fun StubRelationObject( Relations.IS_READ_ONLY to isReadOnly, Relations.RELATION_FORMAT_OBJECT_TYPES to objectTypes, Relations.RELATION_FORMAT to format.code.toDouble(), - Relations.RELATION_OPTION_DICT to relationOptionsDict + Relations.RELATION_OPTION_DICT to relationOptionsDict, + Relations.SOURCE_OBJECT to sourceObject ) ) -@Deprecated("To be deleted") -fun StubRelationOption( - id: String = MockDataFactory.randomUuid(), - text: String = MockDataFactory.randomString(), - color: String = MockDataFactory.randomString() -): Relation.Option = Relation.Option( - id = id, - text = text, - color = color -) - fun StubRelationOptionObject( id: String = MockDataFactory.randomUuid(), text: String = MockDataFactory.randomString(),