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:
parent
65fcf56151
commit
65845ec9ab
6 changed files with 65 additions and 113 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue