diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt index 24b25bd97b..3dca304cd7 100644 --- a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt +++ b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt @@ -20,11 +20,13 @@ import com.anytypeio.anytype.domain.base.Result import com.anytypeio.anytype.domain.block.interactor.UpdateText import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.Gateway +import com.anytypeio.anytype.domain.config.UserSettingsRepository import com.anytypeio.anytype.domain.cover.SetDocCoverImage import com.anytypeio.anytype.domain.dataview.SetDataViewSource import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer import com.anytypeio.anytype.domain.event.interactor.InterceptEvents +import com.anytypeio.anytype.domain.launch.GetDefaultEditorType import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.objects.DefaultObjectStore import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations @@ -88,6 +90,9 @@ abstract class TestObjectSetSetup { @Mock lateinit var auth: AuthRepository + @Mock + lateinit var userSettingsRepository: UserSettingsRepository + @Mock lateinit var gateway: Gateway @Mock @@ -105,6 +110,7 @@ abstract class TestObjectSetSetup { lateinit var createNewObject: CreateNewObject private lateinit var getTemplates: GetTemplates + private lateinit var getDefaultEditorType: GetDefaultEditorType private val session = ObjectSetSession() private val reducer = ObjectSetReducer() @@ -147,7 +153,15 @@ abstract class TestObjectSetSetup { setDataViewSource = SetDataViewSource(repo) updateText = UpdateText(repo) openObjectSet = OpenObjectSet(repo, auth) - createDataViewObject = CreateDataViewObject(repo) + getDefaultEditorType = GetDefaultEditorType( + userSettingsRepository = userSettingsRepository + ) + createDataViewObject = CreateDataViewObject( + getTemplates = getTemplates, + repo = repo, + storeOfRelations = storeOfRelations, + getDefaultEditorType = getDefaultEditorType + ) setObjectDetails = UpdateDetail(repo) updateDataViewViewer = UpdateDataViewViewer(repo) interceptThreadStatus = InterceptThreadStatus(channel = threadStatusChannel) @@ -192,7 +206,6 @@ abstract class TestObjectSetSetup { downloadUnsplashImage = downloadUnsplashImage, setDocCoverImage = setDocCoverImage, delegator = delegator, - getTemplates = getTemplates, createNewObject = createNewObject, setDataViewSource = setDataViewSource, cancelSearchSubscription = cancelSearchSubscription, diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt index f9d8f2cd2b..ec90304d99 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt @@ -151,7 +151,6 @@ object ObjectSetModule { analytics: Analytics, downloadUnsplashImage: DownloadUnsplashImage, setDocCoverImage: SetDocCoverImage, - getTemplates: GetTemplates, dataViewSubscriptionContainer: DataViewSubscriptionContainer, cancelSearchSubscription: CancelSearchSubscription, setDataViewSource: SetDataViewSource, @@ -176,7 +175,6 @@ object ObjectSetModule { analytics = analytics, downloadUnsplashImage = downloadUnsplashImage, setDocCoverImage = setDocCoverImage, - getTemplates = getTemplates, createNewObject = createNewObject, dataViewSubscriptionContainer = dataViewSubscriptionContainer, cancelSearchSubscription = cancelSearchSubscription, @@ -240,8 +238,16 @@ object ObjectSetModule { @Provides @PerScreen fun provideCreateDataViewRecordUseCase( - repo: BlockRepository - ): CreateDataViewObject = CreateDataViewObject(repo = repo) + repo: BlockRepository, + storeOfRelations: StoreOfRelations, + getDefaultEditorType: GetDefaultEditorType, + getTemplates: GetTemplates + ): CreateDataViewObject = CreateDataViewObject( + repo = repo, + getDefaultEditorType = getDefaultEditorType, + getTemplates = getTemplates, + storeOfRelations = storeOfRelations + ) @JvmStatic @Provides diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/ObjectWrapper.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/ObjectWrapper.kt index 0ca9d5786e..3e888c2314 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/ObjectWrapper.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/ObjectWrapper.kt @@ -194,7 +194,6 @@ sealed class ObjectWrapper { val isReadOnly: Boolean? by default val isArchived: Boolean? by default val isDeleted: Boolean? by default - val isReadonly: Boolean? by default val isReadonlyValue: Boolean = relationReadonlyValue ?: false val restrictions: List diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt index ba58f34827..5f59a6a653 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt @@ -318,8 +318,10 @@ class FeaturedRelationGroupWidget : ConstraintLayout { setTextColor(context.color(R.color.text_secondary)) setTextSize(context.dimen(R.dimen.featured_relations_text_size)) setup( - name = obj.name, - icon = obj.icon + name = resources.getString( + R.string.set_by_type, + obj.name + ) ) } is ObjectView.Deleted -> { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt index ec2df1bdeb..7a703d3e13 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt @@ -45,7 +45,10 @@ class ObjectIconTextWidget @JvmOverloads constructor( binding.objectName.setTextColor(textColor) } - fun setup(name: String?, icon: ObjectIcon) { + fun setup( + name: String?, + icon: ObjectIcon = ObjectIcon.None + ) { binding.objectName.text = name binding.objectIcon.setIcon(icon) if (icon is ObjectIcon.None) { diff --git a/core-ui/src/main/res/values/strings.xml b/core-ui/src/main/res/values/strings.xml index 9f3ed9afc7..1b2f7e75c0 100644 --- a/core-ui/src/main/res/values/strings.xml +++ b/core-ui/src/main/res/values/strings.xml @@ -579,5 +579,6 @@ Block selection error Undefined Relations: %1$s + Type: %1$s diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt index fb68b94e41..053b64885c 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt @@ -385,7 +385,7 @@ class BlockDataRepository( override suspend fun createDataViewObject( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, ): Id = remote.createDataViewRecord( template = template, prefilled = prefilled, diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt index 2b008bb381..d6dd47c017 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt @@ -119,7 +119,7 @@ interface BlockDataStore { suspend fun createDataViewRecord( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, ): Id suspend fun addDataViewViewer( diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt index c1d49dee10..1bd6b9e986 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt @@ -126,7 +126,7 @@ interface BlockRemote { suspend fun createDataViewObject( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, ): Id suspend fun addDataViewViewer( diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt index 156ac11177..8e3095881e 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt @@ -284,7 +284,7 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore { override suspend fun createDataViewRecord( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, ): Id = remote.createDataViewObject( template = template, prefilled = prefilled, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt index 9938fc640e..95215e5dda 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt @@ -177,7 +177,7 @@ interface BlockRepository { suspend fun createDataViewObject( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, ): Id suspend fun addDataViewViewer( diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/dataview/interactor/CreateDataViewObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/dataview/interactor/CreateDataViewObject.kt index c16b648e0a..cd46769f9d 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/dataview/interactor/CreateDataViewObject.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/dataview/interactor/CreateDataViewObject.kt @@ -1,32 +1,128 @@ package com.anytypeio.anytype.domain.dataview.interactor +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.ObjectTypeIds +import com.anytypeio.anytype.core_models.Relation +import com.anytypeio.anytype.core_models.Struct import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.block.repo.BlockRepository +import com.anytypeio.anytype.domain.launch.GetDefaultEditorType +import com.anytypeio.anytype.domain.objects.StoreOfRelations +import com.anytypeio.anytype.domain.templates.GetTemplates /** * Use-case for creating a new record inside data view's database. */ class CreateDataViewObject( - private val repo: BlockRepository + private val repo: BlockRepository, + private val getTemplates: GetTemplates, + private val getDefaultEditorType: GetDefaultEditorType, + private val storeOfRelations: StoreOfRelations ) : BaseUseCase() { override suspend fun run(params: Params) = safe { - repo.createDataViewObject( - template = params.template, - prefilled = params.prefilled, - type = params.type - ) + when(params) { + is Params.SetByType -> { + repo.createDataViewObject( + template = resolveTemplateForNewObject(type = params.type), + prefilled = resolveSetByTypePrefilledObjectData( + filters = params.filters + ), + type = params.type + ) + } + is Params.SetByRelation -> { + val type = resolveDefaultObjectType() + repo.createDataViewObject( + template = resolveTemplateForNewObject(type = type), + prefilled = resolveSetByRelationPrefilledObjectData( + filters = params.filters + ), + type = type + ) + } + } } - /** - * @property [type] type of the new object - * @property [template] optional template for dv record - * @property [prefilled] prefilled or pre-populated data for dv record - */ - data class Params( - val type: Id, - val template: Id?, - val prefilled: Map = emptyMap() - ) + private suspend fun resolveSetByTypePrefilledObjectData(filters: List): Struct = buildMap { + filters.forEach { filter -> + val relation = storeOfRelations.getByKey(filter.relationKey) + if (relation != null && relation.isReadOnly == false) { + if (filter.condition == DVFilterCondition.ALL_IN || filter.condition == DVFilterCondition.IN || filter.condition == DVFilterCondition.EQUAL) { + filter.value?.let { put(filter.relationKey, it) } + } + } + } + } + + private suspend fun resolveTemplateForNewObject(type: Id): Id? { + val templates = try { + getTemplates.run(GetTemplates.Params(type)) + } catch (e: Exception) { + emptyList() + } + return templates.singleOrNull()?.id + } + + private suspend fun resolveSetByRelationPrefilledObjectData(filters: List): Struct = try { + buildMap { + filters.forEach { filter -> + val relation = storeOfRelations.getByKey(filter.relationKey) + if (relation != null && !relation.isReadonlyValue) { + if (filter.condition == DVFilterCondition.ALL_IN || filter.condition == DVFilterCondition.IN || filter.condition == DVFilterCondition.EQUAL) { + val value = filter.value + if (value != null) { + put(filter.relationKey, value) + } + } else { + when(relation.format) { + Relation.Format.LONG_TEXT, + Relation.Format.SHORT_TEXT, + Relation.Format.URL, + Relation.Format.EMAIL, + Relation.Format.PHONE, + Relation.Format.EMOJI -> { + put(filter.relationKey, EMPTY_STRING_VALUE) + } + Relation.Format.NUMBER -> { + put(filter.relationKey, null) + } + Relation.Format.CHECKBOX -> { + put(filter.relationKey, false) + } + else -> { + put(filter.relationKey, null) + } + } + } + } + } + } + } catch (e: Exception) { + emptyMap() + } + + private suspend fun resolveDefaultObjectType() : Id { + return try { + getDefaultEditorType.run(Unit).type ?: ObjectTypeIds.NOTE + } catch (e: Exception) { + ObjectTypeIds.NOTE + } + } + + sealed class Params { + data class SetByType( + val type: Id, + val filters: List + ) : Params() + data class SetByRelation( + val filters: List + ) : Params() + } + + companion object { + const val EMPTY_STRING_VALUE = "" + } } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt index 0074f35e75..4f5fcaf186 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt @@ -316,7 +316,7 @@ class BlockMiddleware( override suspend fun createDataViewObject( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, ): Id = middleware.objectCreate( template = template, prefilled = prefilled, diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index 8a0db1d906..79c55a8bc6 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -916,11 +916,11 @@ class Middleware( fun objectCreate( type: Id, template: Id?, - prefilled: Map, + prefilled: Struct, shouldSelectType: Boolean = false, shouldEmptyDelete: Boolean = false ) : Id { - val details: Map = buildMap { + val details: Struct = buildMap { put(Relations.TYPE, type) putAll(prefilled) } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt index d44b59fe1b..3dcc81c656 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt @@ -71,8 +71,8 @@ private fun mapFeaturedRelations( Relations.SET_OF -> { val objectSet = ObjectWrapper.Basic(details.details[ctx]?.map.orEmpty()) val sources = mutableListOf() - objectSet.setOf.forEach { objectTypeId -> - val wrapper = ObjectWrapper.Basic(details.details[objectTypeId]?.map.orEmpty()) + objectSet.setOf.forEach { sourceId -> + val wrapper = ObjectWrapper.Basic(details.details[sourceId]?.map.orEmpty()) if (!wrapper.isEmpty()) { sources.add( wrapper.toObjectView(urlBuilder = urlBuilder) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt index 5af95aa2f1..e10cb3eb23 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt @@ -10,7 +10,6 @@ import com.anytypeio.anytype.analytics.base.sendEvent import com.anytypeio.anytype.analytics.props.Props import com.anytypeio.anytype.core_models.DV import com.anytypeio.anytype.core_models.DVFilter -import com.anytypeio.anytype.core_models.DVFilterCondition import com.anytypeio.anytype.core_models.Event import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectType @@ -44,7 +43,6 @@ import com.anytypeio.anytype.domain.search.CancelSearchSubscription import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer import com.anytypeio.anytype.domain.sets.OpenObjectSet import com.anytypeio.anytype.domain.status.InterceptThreadStatus -import com.anytypeio.anytype.domain.templates.GetTemplates import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage import com.anytypeio.anytype.presentation.common.Action import com.anytypeio.anytype.presentation.common.Delegator @@ -94,7 +92,6 @@ class ObjectSetViewModel( private val closeBlock: CloseBlock, private val updateDataViewViewer: UpdateDataViewViewer, private val setObjectDetails: UpdateDetail, - private val createDataViewObject: CreateDataViewObject, private val downloadUnsplashImage: DownloadUnsplashImage, private val setDocCoverImage: SetDocCoverImage, private val updateText: UpdateText, @@ -106,7 +103,7 @@ class ObjectSetViewModel( private val coverImageHashProvider: CoverImageHashProvider, private val session: ObjectSetSession, private val analytics: Analytics, - private val getTemplates: GetTemplates, + private val createDataViewObject: CreateDataViewObject, private val createNewObject: CreateNewObject, private val dataViewSubscriptionContainer: DataViewSubscriptionContainer, private val cancelSearchSubscription: CancelSearchSubscription, @@ -746,35 +743,41 @@ class ObjectSetViewModel( val setObject = ObjectWrapper.Basic( currentState.details[context]?.map ?: emptyMap() ) - val setOfTypeId = setObject.setOf.singleOrNull() - if (setOfTypeId == ObjectTypeIds.BOOKMARK) { - dispatch( - ObjectSetCommand.Modal.CreateBookmark( - ctx = context - ) - ) - } else if (!setOfTypeId.isNullOrEmpty()) { - viewModelScope.launch { - createDataViewObject( - CreateDataViewObject.Params( - template = resolveTemplateForNewRecord(), - prefilled = resolvePrefilledRecordData(currentState), - type = setOfTypeId - ) - ).process( - failure = { Timber.e(it, "Error while creating new record") }, - success = { record -> - dispatch( - ObjectSetCommand.Modal.SetNameForCreatedObject( - ctx = context, - target = record + val viewer = currentState.viewerById(session.currentViewerId.value) + val sourceId = setObject.setOf.singleOrNull() + if (sourceId == null) { + toast("Unabled to define source for new object") + } else { + val sourceDetails = currentState.details[sourceId] + if (sourceDetails != null && sourceDetails.map.isNotEmpty()) { + when(sourceDetails.type.firstOrNull()) { + ObjectTypeIds.OBJECT_TYPE -> { + if (sourceId == ObjectTypeIds.BOOKMARK) { + dispatch( + ObjectSetCommand.Modal.CreateBookmark( + ctx = context + ) + ) + } else { + proceedWithCreatingDataViewObject( + CreateDataViewObject.Params.SetByType( + type = sourceId, + filters = viewer.filters + ) + ) + } + } + ObjectTypeIds.RELATION -> { + proceedWithCreatingDataViewObject( + CreateDataViewObject.Params.SetByRelation( + filters = viewer.filters ) ) } - ) + } + } else { + toast("Unabled to define source for new object") } - } else { - toast("Unabled to define type for new object") } } } else { @@ -782,32 +785,19 @@ class ObjectSetViewModel( } } - private fun resolvePrefilledRecordData(setOfObjects: ObjectSet): Map = buildMap { - val viewer = setOfObjects.viewerById(session.currentViewerId.value) - val block = setOfObjects.dataview - val dv = block.content as DV - viewer.filters.forEach { filter -> - val relation = dv.relations.find { it.key == filter.relationKey } - if (relation != null && !relation.isReadOnly) { - if (filter.condition == DVFilterCondition.ALL_IN || filter.condition == DVFilterCondition.IN || filter.condition == DVFilterCondition.EQUAL) { - filter.value?.let { put(filter.relationKey, it) } + private fun proceedWithCreatingDataViewObject(params: CreateDataViewObject.Params) { + viewModelScope.launch { + createDataViewObject(params).process( + failure = { Timber.e(it, "Error while creating new record") }, + success = { record -> + dispatch( + ObjectSetCommand.Modal.SetNameForCreatedObject( + ctx = context, + target = record + ) + ) } - } - } - } - - private suspend fun resolveTemplateForNewRecord(): Id? { - val obj = ObjectWrapper.Basic(reducer.state.value.details[context]?.map ?: emptyMap()) - val type = obj.setOf.singleOrNull() - return if (type != null) { - val templates = try { - getTemplates.run(GetTemplates.Params(type)) - } catch (e: Exception) { - emptyList() - } - templates.singleOrNull()?.id - } else { - null + ) } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt index 2a6e424a1c..7744370055 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt @@ -19,7 +19,6 @@ import com.anytypeio.anytype.domain.search.CancelSearchSubscription import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer import com.anytypeio.anytype.domain.sets.OpenObjectSet import com.anytypeio.anytype.domain.status.InterceptThreadStatus -import com.anytypeio.anytype.domain.templates.GetTemplates import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage import com.anytypeio.anytype.presentation.common.Action import com.anytypeio.anytype.presentation.common.Delegator @@ -44,7 +43,6 @@ class ObjectSetViewModelFactory( private val urlBuilder: UrlBuilder, private val session: ObjectSetSession, private val analytics: Analytics, - private val getTemplates: GetTemplates, private val createNewObject: CreateNewObject, private val dataViewSubscriptionContainer: DataViewSubscriptionContainer, private val cancelSearchSubscription: CancelSearchSubscription, @@ -73,7 +71,6 @@ class ObjectSetViewModelFactory( urlBuilder = urlBuilder, session = session, analytics = analytics, - getTemplates = getTemplates, createNewObject = createNewObject, dataViewSubscriptionContainer = dataViewSubscriptionContainer, cancelSearchSubscription = cancelSearchSubscription, diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetDataViewObjectCreateTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetDataViewObjectCreateTest.kt index 8952bb7ebd..ade7a3fc27 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetDataViewObjectCreateTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetDataViewObjectCreateTest.kt @@ -8,8 +8,13 @@ import com.anytypeio.anytype.core_models.DVFilterCondition import com.anytypeio.anytype.core_models.DVFilterOperator import com.anytypeio.anytype.core_models.DVViewer import com.anytypeio.anytype.core_models.DVViewerRelation +import com.anytypeio.anytype.core_models.ObjectTypeIds import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.StubDataView +import com.anytypeio.anytype.core_models.StubDataViewView +import com.anytypeio.anytype.core_models.StubHeader +import com.anytypeio.anytype.core_models.StubTitle import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject import com.anytypeio.anytype.presentation.util.CoroutinesTestRule import com.anytypeio.anytype.test_utils.MockDataFactory @@ -28,25 +33,8 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { @get:Rule val coroutineTestRule = CoroutinesTestRule() - private val title = Block( - id = MockDataFactory.randomUuid(), - content = Block.Content.Text( - style = Block.Content.Text.Style.TITLE, - text = MockDataFactory.randomString(), - marks = emptyList() - ), - children = emptyList(), - fields = Block.Fields.empty() - ) - - private val header = Block( - id = MockDataFactory.randomUuid(), - content = Block.Content.Layout( - type = Block.Content.Layout.Type.HEADER - ), - fields = Block.Fields.empty(), - children = listOf(title.id) - ) + private val title = StubTitle() + private val header = StubHeader(children = listOf(title.id)) @Before fun setup() { @@ -59,27 +47,17 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { // SETUP - val viewer = DVViewer( - id = MockDataFactory.randomUuid(), - filters = emptyList(), - sorts = emptyList(), - type = Block.Content.DataView.Viewer.Type.GRID, - name = MockDataFactory.randomString(), - viewerRelations = emptyList() + val viewer = StubDataViewView( + type = Block.Content.DataView.Viewer.Type.GRID ) - val dv = Block( + val dv = StubDataView( id = MockDataFactory.randomUuid(), - content = DV( - sources = listOf(MockDataFactory.randomString()), - relations = emptyList(), - viewers = listOf(viewer) - ), - children = emptyList(), - fields = Block.Fields.empty() + views = listOf(viewer), + sources = listOf(MockDataFactory.randomString()) ) - val type = MockDataFactory.randomUuid() + val givenType = MockDataFactory.randomUuid() val newObjectId = MockDataFactory.randomUuid() stubInterceptEvents() @@ -87,7 +65,7 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { stubInterceptThreadStatus() stubSearchWithSubscription() stubSubscriptionEventChannel() - stubGetTemplates(type = type) + stubGetTemplates(type = givenType) stubOpenObjectSet( doc = listOf( header, @@ -97,7 +75,10 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { details = Block.Details( mapOf( root to Block.Fields( - map = mapOf(Relations.SET_OF to listOf(type)) + map = mapOf(Relations.SET_OF to listOf(givenType)) + ), + givenType to Block.Fields( + map = mapOf(Relations.TYPE to ObjectTypeIds.OBJECT_TYPE) ) ) ) @@ -113,9 +94,9 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { verifyBlocking(createDataViewObject, times(1)) { invoke( - CreateDataViewObject.Params( - template = null, - type = type + CreateDataViewObject.Params.SetByType( + type = givenType, + filters = viewer.filters ) ) } @@ -133,24 +114,14 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { MockDataFactory.randomUuid() ) - val viewer = DVViewer( - id = MockDataFactory.randomUuid(), - filters = emptyList(), - sorts = emptyList(), - type = Block.Content.DataView.Viewer.Type.GRID, - name = MockDataFactory.randomString(), - viewerRelations = emptyList() + val viewer = StubDataViewView( + type = Block.Content.DataView.Viewer.Type.GRID ) - val dv = Block( + val dv = StubDataView( id = MockDataFactory.randomUuid(), - content = DV( - sources = listOf(MockDataFactory.randomString()), - relations = emptyList(), - viewers = listOf(viewer) - ), - children = emptyList(), - fields = Block.Fields.empty() + views = listOf(viewer), + sources = listOf(MockDataFactory.randomString()) ) val newObjectId = MockDataFactory.randomUuid() @@ -176,6 +147,9 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { map = mapOf( Relations.SET_OF to listOf(givenType) ) + ), + givenType to Block.Fields( + map = mapOf(Relations.TYPE to ObjectTypeIds.OBJECT_TYPE) ) ) ) @@ -191,9 +165,9 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { verifyBlocking(createDataViewObject, times(1)) { invoke( - CreateDataViewObject.Params( - template = null, - type = givenType + CreateDataViewObject.Params.SetByType( + type = givenType, + filters = viewer.filters ) ) } @@ -250,6 +224,9 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { map = mapOf( Relations.SET_OF to listOf(givenType) ) + ), + givenType to Block.Fields( + map = mapOf(Relations.TYPE to ObjectTypeIds.OBJECT_TYPE) ) ) ) @@ -265,9 +242,9 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { verifyBlocking(createDataViewObject, times(1)) { invoke( - CreateDataViewObject.Params( - template = givenTemplate, - type = givenType + CreateDataViewObject.Params.SetByType( + type = givenType, + filters = viewer.filters ) ) } @@ -309,7 +286,7 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { val givenTemplate = MockDataFactory.randomUuid() - val source = MockDataFactory.randomString() + val givenType = MockDataFactory.randomString() val filter = DVFilter( relationKey = relationStakeholderKey, @@ -340,7 +317,7 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { val dv = Block( id = MockDataFactory.randomUuid(), content = DV( - sources = listOf(source), + sources = listOf(givenType), relations = listOf(relationStakeHolders), viewers = listOf(viewer) ), @@ -356,7 +333,7 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { stubSearchWithSubscription() stubSubscriptionEventChannel() stubGetTemplates( - type = source, + type = givenType, templates = listOf(givenTemplate) ) stubOpenObjectSet( @@ -369,8 +346,11 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { mapOf( root to Block.Fields( map = mapOf( - Relations.SET_OF to listOf(source) + Relations.SET_OF to listOf(givenType) ) + ), + givenType to Block.Fields( + map = mapOf(Relations.TYPE to ObjectTypeIds.OBJECT_TYPE) ) ) ) @@ -386,10 +366,9 @@ class ObjectSetDataViewObjectCreateTest : ObjectSetViewModelTestSetup() { verifyBlocking(createDataViewObject, times(1)) { invoke( - CreateDataViewObject.Params( - template = givenTemplate, - prefilled = mapOf(relationStakeholderKey to relationStakeholderValue), - type = source + CreateDataViewObject.Params.SetByType( + type = givenType, + filters = viewer.filters ) ) } diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetInitializationTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetInitializationTest.kt index 734dc4f0e3..13efbb0c58 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetInitializationTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetInitializationTest.kt @@ -1,8 +1,9 @@ package com.anytypeio.anytype.presentation.sets.main import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import com.anytypeio.anytype.core_models.Block import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.StubHeader +import com.anytypeio.anytype.core_models.StubTitle import com.anytypeio.anytype.domain.base.Either import com.anytypeio.anytype.presentation.util.CoroutinesTestRule import com.anytypeio.anytype.test_utils.MockDataFactory @@ -17,25 +18,8 @@ import org.mockito.kotlin.verifyNoInteractions class ObjectSetInitializationTest : ObjectSetViewModelTestSetup() { - private val title = Block( - id = MockDataFactory.randomUuid(), - content = Block.Content.Text( - style = Block.Content.Text.Style.TITLE, - text = MockDataFactory.randomString(), - marks = emptyList() - ), - children = emptyList(), - fields = Block.Fields.empty() - ) - - private val header = Block( - id = MockDataFactory.randomUuid(), - content = Block.Content.Layout( - type = Block.Content.Layout.Type.HEADER - ), - fields = Block.Fields.empty(), - children = listOf(title.id) - ) + private val title = StubTitle() + private val header = StubHeader(children = listOf(title.id)) private val ctx: Id = MockDataFactory.randomUuid() diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetNavigationTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetNavigationTest.kt index 9e9d62e18f..8f53c29400 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetNavigationTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetNavigationTest.kt @@ -12,6 +12,7 @@ import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_models.RelationLink import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.SearchResult +import com.anytypeio.anytype.core_models.StubHeader import com.anytypeio.anytype.core_models.StubRelationObject import com.anytypeio.anytype.core_models.StubTitle import com.anytypeio.anytype.core_models.ext.content @@ -61,15 +62,7 @@ class ObjectSetNavigationTest : ObjectSetViewModelTestSetup() { } private val title = StubTitle() - - private val header = Block( - id = MockDataFactory.randomUuid(), - content = Block.Content.Layout( - type = Block.Content.Layout.Type.HEADER - ), - fields = Block.Fields.empty(), - children = listOf(title.id) - ) + private val header = StubHeader(children = listOf(title.id)) private val linkedProjectRelation = StubRelationObject( key = MockDataFactory.randomString(), diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt index 891bdcdea6..86015560f6 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt @@ -168,7 +168,6 @@ open class ObjectSetViewModelTestSetup { analytics = analytics, downloadUnsplashImage = downloadUnsplashImage, setDocCoverImage = setDocCoverImage, - getTemplates = getTemplates, createNewObject = createNewObject, setDataViewSource = setDataViewSource, setObjectDetails = setObjectDetails, diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/SetByRelationTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/SetByRelationTest.kt new file mode 100644 index 0000000000..457c899fab --- /dev/null +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/SetByRelationTest.kt @@ -0,0 +1,163 @@ +package com.anytypeio.anytype.presentation.sets.main + +import com.anytypeio.anytype.core_models.Block +import com.anytypeio.anytype.core_models.ObjectTypeIds +import com.anytypeio.anytype.core_models.RelationLink +import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.StubDataView +import com.anytypeio.anytype.core_models.StubDataViewView +import com.anytypeio.anytype.core_models.StubDataViewViewRelation +import com.anytypeio.anytype.core_models.StubHeader +import com.anytypeio.anytype.core_models.StubRelationObject +import com.anytypeio.anytype.core_models.StubTitle +import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject +import com.anytypeio.anytype.presentation.util.CoroutinesTestRule +import com.anytypeio.anytype.test_utils.MockDataFactory +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.times +import org.mockito.kotlin.verifyBlocking + +class SetByRelationTest : ObjectSetViewModelTestSetup() { + + private val title = StubTitle() + private val header = StubHeader(children = listOf(title.id)) + + private val relations = listOf( + StubRelationObject(), + StubRelationObject(), + StubRelationObject() + ) + + private val viewer = StubDataViewView( + viewerRelations = relations.map { + StubDataViewViewRelation( + key = it.key + ) + } + ) + + private val dv = StubDataView( + views = listOf(viewer), + relations = relations.map { + RelationLink( + key = it.key, + format = it.relationFormat + ) + } + ) + + @get:Rule + val coroutineTestRule = CoroutinesTestRule() + + @Before + fun setup() { + MockitoAnnotations.openMocks(this) + initDataViewSubscriptionContainer() + } + + @Test + fun `should create new object with source object type if given set is aggregated by specific object type`() { + + // SETUP + + val givenSourceType = MockDataFactory.randomUuid() + + stubInterceptEvents() + stubInterceptThreadStatus() + stubSearchWithSubscription() + stubSubscriptionEventChannel() + stubOpenObjectSet( + doc = listOf( + header, + title, + dv + ), + details = Block.Details( + mapOf( + root to Block.Fields( + map = mapOf(Relations.SET_OF to listOf(givenSourceType)) + ), + givenSourceType to Block.Fields( + map = mapOf(Relations.TYPE to ObjectTypeIds.OBJECT_TYPE) + ) + ) + ) + ) + stubGetTemplates(type = givenSourceType) + + val vm = givenViewModel() + + + // TESTING + + with(vm) { + onStart(root) + onCreateNewDataViewObject() + } + + verifyBlocking(createDataViewObject, times(1)) { + invoke( + CreateDataViewObject.Params.SetByType( + type = givenSourceType, + filters = viewer.filters + ) + ) + } + } + + @Test + fun `should create new object with default object type if given set is aggregated by relations`() { + + // SETUP + + val givenSourceRelation = relations.random() + + stubInterceptEvents() + stubInterceptThreadStatus() + stubSearchWithSubscription() + stubSubscriptionEventChannel() + stubOpenObjectSet( + doc = listOf( + header, + title, + dv + ), + details = Block.Details( + mapOf( + root to Block.Fields( + map = mapOf( + Relations.SET_OF to listOf(givenSourceRelation.id) + ) + ), + givenSourceRelation.id to Block.Fields( + map = mapOf( + Relations.ID to givenSourceRelation.id, + Relations.RELATION_KEY to givenSourceRelation.key, + Relations.TYPE to ObjectTypeIds.RELATION + ) + ) + ) + ) + ) + + val vm = givenViewModel() + + // TESTING + + with(vm) { + onStart(root) + onCreateNewDataViewObject() + } + + verifyBlocking(createDataViewObject, times(1)) { + invoke( + CreateDataViewObject.Params.SetByRelation( + filters = viewer.filters + ) + ) + } + } +} \ No newline at end of file diff --git a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/DataView.kt b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/DataView.kt new file mode 100644 index 0000000000..521bd84a1c --- /dev/null +++ b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/DataView.kt @@ -0,0 +1,44 @@ +package com.anytypeio.anytype.core_models + +import com.anytypeio.anytype.test_utils.MockDataFactory + +fun StubDataView( + id : Id = MockDataFactory.randomUuid(), + views: List = emptyList(), + relations: List = emptyList(), + sources: List = emptyList() +) : Block = Block( + id = id, + content = DV( + sources = sources, + relations = emptyList(), + relationsIndex= relations, + viewers = views + ), + children = emptyList(), + fields = Block.Fields.empty() +) + +fun StubDataViewView( + id : Id = MockDataFactory.randomUuid(), + filters: List = emptyList(), + sorts: List = emptyList(), + type: DVViewerType = DVViewerType.GRID, + name: String = MockDataFactory.randomString(), + viewerRelations: List = emptyList() +) : DVViewer = DVViewer( + id = id, + filters = filters, + sorts = sorts, + type = type, + name = name, + viewerRelations = viewerRelations +) + +fun StubDataViewViewRelation( + key: Key = MockDataFactory.randomUuid(), + isVisible: Boolean = MockDataFactory.randomBoolean() +) : DVViewerRelation = DVViewerRelation( + key = key, + isVisible = isVisible +) \ No newline at end of file