mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 13:57:10 +09:00
DROID-496 Sets | Enhancement | Creating object in sets aggregated by relations (#2731)
This commit is contained in:
parent
64e5e8c6dd
commit
ef6eeac53c
23 changed files with 461 additions and 192 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<ObjectRestriction>
|
||||
|
|
|
@ -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 -> {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -579,5 +579,6 @@
|
|||
<string name="error_block_selection">Block selection error</string>
|
||||
<string name="undefined">Undefined</string>
|
||||
<string name="set_by_relations">Relations: %1$s</string>
|
||||
<string name="set_by_type">Type: %1$s</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -385,7 +385,7 @@ class BlockDataRepository(
|
|||
override suspend fun createDataViewObject(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
): Id = remote.createDataViewRecord(
|
||||
template = template,
|
||||
prefilled = prefilled,
|
||||
|
|
|
@ -119,7 +119,7 @@ interface BlockDataStore {
|
|||
suspend fun createDataViewRecord(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
): Id
|
||||
|
||||
suspend fun addDataViewViewer(
|
||||
|
|
|
@ -126,7 +126,7 @@ interface BlockRemote {
|
|||
suspend fun createDataViewObject(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
): Id
|
||||
|
||||
suspend fun addDataViewViewer(
|
||||
|
|
|
@ -284,7 +284,7 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
|
|||
override suspend fun createDataViewRecord(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
): Id = remote.createDataViewObject(
|
||||
template = template,
|
||||
prefilled = prefilled,
|
||||
|
|
|
@ -177,7 +177,7 @@ interface BlockRepository {
|
|||
suspend fun createDataViewObject(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
): Id
|
||||
|
||||
suspend fun addDataViewViewer(
|
||||
|
|
|
@ -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<Id, CreateDataViewObject.Params>() {
|
||||
|
||||
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<Id, Any> = emptyMap()
|
||||
)
|
||||
private suspend fun resolveSetByTypePrefilledObjectData(filters: List<DVFilter>): 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<DVFilter>): 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<DVFilter>
|
||||
) : Params()
|
||||
data class SetByRelation(
|
||||
val filters: List<DVFilter>
|
||||
) : Params()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EMPTY_STRING_VALUE = ""
|
||||
}
|
||||
}
|
|
@ -316,7 +316,7 @@ class BlockMiddleware(
|
|||
override suspend fun createDataViewObject(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
): Id = middleware.objectCreate(
|
||||
template = template,
|
||||
prefilled = prefilled,
|
||||
|
|
|
@ -916,11 +916,11 @@ class Middleware(
|
|||
fun objectCreate(
|
||||
type: Id,
|
||||
template: Id?,
|
||||
prefilled: Map<Id, Any>,
|
||||
prefilled: Struct,
|
||||
shouldSelectType: Boolean = false,
|
||||
shouldEmptyDelete: Boolean = false
|
||||
) : Id {
|
||||
val details: Map<String, Any> = buildMap {
|
||||
val details: Struct = buildMap {
|
||||
put(Relations.TYPE, type)
|
||||
putAll(prefilled)
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ private fun mapFeaturedRelations(
|
|||
Relations.SET_OF -> {
|
||||
val objectSet = ObjectWrapper.Basic(details.details[ctx]?.map.orEmpty())
|
||||
val sources = mutableListOf<ObjectView>()
|
||||
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)
|
||||
|
|
|
@ -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<Id, Any> = 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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -168,7 +168,6 @@ open class ObjectSetViewModelTestSetup {
|
|||
analytics = analytics,
|
||||
downloadUnsplashImage = downloadUnsplashImage,
|
||||
setDocCoverImage = setDocCoverImage,
|
||||
getTemplates = getTemplates,
|
||||
createNewObject = createNewObject,
|
||||
setDataViewSource = setDataViewSource,
|
||||
setObjectDetails = setObjectDetails,
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<DVViewer> = emptyList(),
|
||||
relations: List<RelationLink> = emptyList(),
|
||||
sources: List<Id> = 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<DVFilter> = emptyList(),
|
||||
sorts: List<DVSort> = emptyList(),
|
||||
type: DVViewerType = DVViewerType.GRID,
|
||||
name: String = MockDataFactory.randomString(),
|
||||
viewerRelations: List<DVViewerRelation> = 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
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue