1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-1027 Collections | Object creation, start params (#3042)

* DROID-1027 types widget should be in hidden state on opening

* DROID-1027 update type widget showing logic + tests

* DROID-1027 send event on create object with template

* DROID-1027 delete doubled logic

* DROID-1027 createObject, internal flags + tests

* DROID-1027 fix test
This commit is contained in:
Konstantin Ivanov 2023-03-27 12:59:59 +02:00 committed by GitHub
parent 65fcf56151
commit 65845ec9ab
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 65 additions and 113 deletions

View file

@ -25,16 +25,23 @@ class CreateObject(
val type = params.type ?: getDefaultPageType.run(Unit).type
val template = if (type != null) {
getTemplates.run(GetTemplates.Params(type = type)).singleOrNull()?.id
val objectTemplates = if (type != null) {
getTemplates.run(GetTemplates.Params(type = type))
} else {
null
}
val internalFlags = if (template != null) {
listOf()
} else {
listOf(InternalFlags.ShouldSelectType, InternalFlags.ShouldEmptyDelete)
val template = objectTemplates?.singleOrNull()?.id
val internalFlags = buildList {
if (objectTemplates != null && objectTemplates.size > 1) {
add(InternalFlags.ShouldSelectTemplate)
} else {
if (template == null) {
add(InternalFlags.ShouldSelectType)
}
}
add(InternalFlags.ShouldEmptyDelete)
}
val prefilled = buildMap {

View file

@ -126,7 +126,9 @@ class CreateObjectTest {
val commands = Command.CreateObject(
prefilled = buildMap { put(Relations.TYPE, defaultType) },
template = templateBook,
internalFlags = listOf()
internalFlags = listOf(
InternalFlags.ShouldEmptyDelete
)
)
verifyBlocking(repo, times(1)) { createObject(commands) }
}
@ -180,7 +182,9 @@ class CreateObjectTest {
val commands = Command.CreateObject(
prefilled = buildMap { put(Relations.TYPE, type) },
template = template,
internalFlags = listOf()
internalFlags = listOf(
InternalFlags.ShouldEmptyDelete
)
)
verifyBlocking(repo, times(1)) { createObject(commands) }
}
@ -216,7 +220,7 @@ class CreateObjectTest {
prefilled = buildMap { put(Relations.TYPE, type) },
template = null,
internalFlags = listOf(
InternalFlags.ShouldSelectType,
InternalFlags.ShouldSelectTemplate,
InternalFlags.ShouldEmptyDelete
)
)

View file

@ -16,6 +16,7 @@ import com.anytypeio.anytype.core_models.Block.Prototype
import com.anytypeio.anytype.core_models.Document
import com.anytypeio.anytype.core_models.Event
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.InternalFlags
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
@ -522,8 +523,8 @@ class EditorViewModel(
orchestrator.stores.objectTypes.update(event.objectTypes)
orchestrator.stores.relationLinks.update(event.relationLinks)
orchestrator.stores.objectRestrictions.update(event.objectRestrictions)
val objectType = event.details.details[context]?.type?.firstOrNull()
proceedWithShowingObjectTypesWidget(objectType, event.blocks)
proceedWithShowingObjectTypesWidget()
}
is Event.Command.Details -> {
orchestrator.stores.details.apply { update(current().process(event)) }
@ -5831,8 +5832,6 @@ class EditorViewModel(
fun onObjectTypesWidgetItemClicked(typeId: Id) {
Timber.d("onObjectTypesWidgetItemClicked, type:[$typeId]")
dispatchObjectCreateEvent(typeId)
proceedWithHidingObjectTypeWidget()
proceedWithObjectTypeChange(type = typeId, applyTemplate = true)
}
@ -5852,32 +5851,17 @@ class EditorViewModel(
)
}
private fun proceedWithShowingObjectTypesWidget(objectType: String?, blocks: List<Block>) {
private fun proceedWithShowingObjectTypesWidget() {
val restrictions = orchestrator.stores.objectRestrictions.current()
if (restrictions.contains(ObjectRestriction.TYPE_CHANGE)) {
return
}
when (objectType) {
ObjectTypeIds.NOTE -> {
val root = blocks.find { it.id == context } ?: return
if (root.children.size == 2) {
val lastBlock = blocks.find { it.id == root.children.last() }
if (lastBlock != null && lastBlock.content is Content.Text) {
if (lastBlock.content<Content.Text>().text.isEmpty()) {
proceedWithGettingObjectTypesForObjectTypeWidget()
}
}
}
}
else -> {
val root = blocks.find { it.id == context } ?: return
if (root.children.size == 1) {
val title = blocks.title() ?: return
if (title.content<Content.Text>().text.isEmpty()) {
proceedWithGettingObjectTypesForObjectTypeWidget()
}
}
}
val details = orchestrator.stores.details.current()
val objectDetails = ObjectWrapper.Basic(details.details[context]?.map ?: emptyMap())
val internalFlags = objectDetails.internalFlags
if (internalFlags.contains(InternalFlags.ShouldSelectType)) {
proceedWithGettingObjectTypesForObjectTypeWidget()
}
}

View file

@ -3,6 +3,8 @@ package com.anytypeio.anytype.presentation.home
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Config
import com.anytypeio.anytype.core_models.Event
@ -37,6 +39,7 @@ import com.anytypeio.anytype.domain.page.CreateObject
import com.anytypeio.anytype.domain.widgets.CreateWidget
import com.anytypeio.anytype.domain.widgets.DeleteWidget
import com.anytypeio.anytype.domain.widgets.UpdateWidget
import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectCreateEvent
import com.anytypeio.anytype.presentation.home.Command.ChangeWidgetType.Companion.UNDEFINED_LAYOUT_CODE
import com.anytypeio.anytype.presentation.navigation.NavigationViewModel
import com.anytypeio.anytype.presentation.search.Subscriptions
@ -95,7 +98,8 @@ class HomeScreenViewModel(
private val emptyBin: EmptyBin,
private val unsubscriber: Unsubscriber,
private val getDefaultPageType: GetDefaultPageType,
private val appActionManager: AppActionManager
private val appActionManager: AppActionManager,
private val analytics: Analytics
) : NavigationViewModel<HomeScreenViewModel.Navigation>(),
Reducer<ObjectView, Payload>,
WidgetActiveViewStateHolder by widgetActiveViewStateHolder,
@ -728,10 +732,23 @@ class HomeScreenViewModel(
}
fun onCreateNewObjectClicked() {
val startTime = System.currentTimeMillis()
viewModelScope.launch {
createObject.stream(CreateObject.Param(null)).collect { result ->
result.fold(
onSuccess = { navigate(Navigation.OpenObject(it.objectId)) },
onSuccess = {
if (it.appliedTemplate != null) {
val middleTime = System.currentTimeMillis()
sendAnalyticsObjectCreateEvent(
analytics = analytics,
objType = it.type,
route = EventsDictionary.Routes.objPowerTool,
startTime = startTime,
middleTime = middleTime
)
}
navigate(Navigation.OpenObject(it.objectId))
},
onFailure = {
Timber.e(it, "Error while creating object")
sendToast("Error while creating object. Please, try again later")
@ -818,7 +835,8 @@ class HomeScreenViewModel(
private val emptyBin: EmptyBin,
private val unsubscriber: Unsubscriber,
private val getDefaultPageType: GetDefaultPageType,
private val appActionManager: AppActionManager
private val appActionManager: AppActionManager,
private val analytics: Analytics
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = HomeScreenViewModel(
@ -843,7 +861,8 @@ class HomeScreenViewModel(
emptyBin = emptyBin,
unsubscriber = unsubscriber,
getDefaultPageType = getDefaultPageType,
appActionManager = appActionManager
appActionManager = appActionManager,
analytics = analytics
) as T
}

View file

@ -3,8 +3,10 @@ package com.anytypeio.anytype.presentation.editor.editor
import android.util.Log
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.InternalFlags
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.SmartBlockType
import com.anytypeio.anytype.presentation.editor.EditorViewModel
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
@ -46,7 +48,7 @@ class EditorObjectTypeChangeWidgetTest : EditorPresentationTestSetup() {
}
@Test
fun `should show widget on note object with one empty text block`() {
fun `should show widget on object with select type internal flag`() {
val paragraph = Block(
id = MockDataFactory.randomUuid(),
@ -87,7 +89,8 @@ class EditorObjectTypeChangeWidgetTest : EditorPresentationTestSetup() {
val objectDetails = Block.Fields(
mapOf(
"type" to ObjectTypeIds.NOTE,
"layout" to ObjectType.Layout.NOTE.code.toDouble()
"layout" to ObjectType.Layout.NOTE.code.toDouble(),
Relations.INTERNAL_FLAGS to listOf(1.0)
)
)
@ -116,7 +119,7 @@ class EditorObjectTypeChangeWidgetTest : EditorPresentationTestSetup() {
}
@Test
fun `should not show widget on note object with one not empty text block`() {
fun `should not show widget on note object with empty internal flags`() {
val paragraph = Block(
id = MockDataFactory.randomUuid(),
@ -183,74 +186,4 @@ class EditorObjectTypeChangeWidgetTest : EditorPresentationTestSetup() {
assertNotNull(objectTypesWidget)
assertFalse(objectTypesWidget.isVisible)
}
@Test
fun `should show widget on note object layout with one empty text block and default not note type`() {
val paragraph = Block(
id = MockDataFactory.randomUuid(),
fields = Block.Fields.empty(),
children = emptyList(),
content = Block.Content.Text(
text = "",
marks = emptyList(),
style = Block.Content.Text.Style.P
)
)
val featuredBlock = Block(
id = "featuredRelations",
fields = Block.Fields.empty(),
children = emptyList(),
content = Block.Content.FeaturedRelations
)
val header = Block(
id = "header",
content = Block.Content.Layout(
type = Block.Content.Layout.Type.HEADER
),
fields = Block.Fields.empty(),
children = listOf(featuredBlock.id)
)
val page = Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Smart(SmartBlockType.PAGE),
children = listOf(header.id, paragraph.id)
)
val doc = listOf(page, header, paragraph, featuredBlock)
val objectDetails = Block.Fields(
mapOf(
"type" to ObjectTypeIds.NOTE,
"layout" to ObjectType.Layout.NOTE.code.toDouble()
)
)
val detailsList = Block.Details(details = mapOf(root to objectDetails))
stubInterceptEvents()
stubInterceptThreadStatus()
stubSearchObjects()
stubGetDefaultObjectType(type = ObjectTypeIds.PAGE)
stubOpenDocument(
document = doc,
details = detailsList
)
stubGetObjectTypes(listOf())
val vm = buildViewModel()
vm.onStart(root)
val state = vm.controlPanelViewState.value
val objectTypesWidget = state?.objectTypesToolbar
assertNotNull(objectTypesWidget)
assertTrue(objectTypesWidget.isVisible)
}
}

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.presentation.home
import app.cash.turbine.test
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Event
import com.anytypeio.anytype.core_models.Id
@ -132,6 +133,9 @@ class HomeScreenViewModelTest {
@Mock
lateinit var gateway: Gateway
@Mock
lateinit var analytics: Analytics
private val objectPayloadDispatcher = Dispatcher.Default<Payload>()
private val widgetEventDispatcher = Dispatcher.Default<WidgetDispatchEvent>()
@ -1883,7 +1887,8 @@ class HomeScreenViewModelTest {
emptyBin = emptyBin,
unsubscriber = unsubscriber,
getDefaultPageType = getDefaultPageType,
appActionManager = appActionManager
appActionManager = appActionManager,
analytics = analytics
)
companion object {