mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-1593 Editor | Feature | InternalFlags, selectTemplate, selectType (#261)
This commit is contained in:
parent
25ec3e9a0e
commit
a1a3b4f965
18 changed files with 442 additions and 79 deletions
|
@ -60,6 +60,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultPageType
|
|||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations
|
||||
|
@ -269,6 +270,9 @@ open class EditorTestSetup {
|
|||
@Mock
|
||||
lateinit var fileLimitsEventChannel: FileLimitsEventChannel
|
||||
|
||||
@Mock
|
||||
lateinit var setObjectInternalFlags: SetObjectInternalFlags
|
||||
|
||||
lateinit var interceptFileLimitEvents: InterceptFileLimitEvents
|
||||
|
||||
lateinit var addRelationToObject: AddRelationToObject
|
||||
|
@ -466,7 +470,8 @@ open class EditorTestSetup {
|
|||
getObjectTypes = getObjectTypes,
|
||||
objectToCollection = objectToCollection,
|
||||
interceptFileLimitEvents = interceptFileLimitEvents,
|
||||
addRelationToObject = addRelationToObject
|
||||
addRelationToObject = addRelationToObject,
|
||||
setObjectInternalFlags = setObjectInternalFlags
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
|
|||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
|
||||
import com.anytypeio.anytype.domain.`object`.DuplicateObject
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
|
@ -233,6 +234,14 @@ object EditorSessionModule {
|
|||
dispatchers: AppCoroutineDispatchers
|
||||
) : InterceptFileLimitEvents = InterceptFileLimitEvents(channel, dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideSetObjectInternalFlags(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : SetObjectInternalFlags = SetObjectInternalFlags(repo, dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
fun providePageViewModelFactory(
|
||||
|
@ -271,7 +280,8 @@ object EditorSessionModule {
|
|||
getObjectTypes: GetObjectTypes,
|
||||
objectToCollection: ConvertObjectToCollection,
|
||||
interceptFileLimitEvents: InterceptFileLimitEvents,
|
||||
addRelationToObject: AddRelationToObject
|
||||
addRelationToObject: AddRelationToObject,
|
||||
setObjectInternalFlags: SetObjectInternalFlags
|
||||
): EditorViewModelFactory = EditorViewModelFactory(
|
||||
openPage = openPage,
|
||||
closeObject = closePage,
|
||||
|
@ -308,7 +318,8 @@ object EditorSessionModule {
|
|||
getObjectTypes = getObjectTypes,
|
||||
objectToCollection = objectToCollection,
|
||||
interceptFileLimitEvents = interceptFileLimitEvents,
|
||||
addRelationToObject = addRelationToObject
|
||||
addRelationToObject = addRelationToObject,
|
||||
setObjectInternalFlags = setObjectInternalFlags
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -5,9 +5,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
|
@ -20,7 +18,6 @@ import com.anytypeio.anytype.databinding.FragmentTemplateSelectBinding
|
|||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateSelectViewModel
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class TemplateSelectFragment :
|
||||
|
@ -40,9 +37,15 @@ class TemplateSelectFragment :
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupViewPagerAndTabs()
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
setupClickEventHandlers()
|
||||
with(lifecycleScope) {
|
||||
subscribe(binding.btnCancel.clicks()) {
|
||||
vm.onCancelButtonClicked()
|
||||
}
|
||||
subscribe(binding.btnUseTemplate.clicks()) {
|
||||
vm.onUseTemplateButtonPressed(
|
||||
currentItem = binding.templateViewPager.currentItem,
|
||||
ctx = ctx
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,11 +56,6 @@ class TemplateSelectFragment :
|
|||
TabLayoutMediator(binding.tabs, binding.templateViewPager) { _, _ -> }.attach()
|
||||
}
|
||||
|
||||
private suspend fun setupClickEventHandlers() {
|
||||
setupUseTemplateClicks()
|
||||
setupCancelClicks()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
jobs += lifecycleScope.subscribe(vm.viewState) { render(it) }
|
||||
jobs += lifecycleScope.subscribe(vm.isDismissed) { if (it) exit() }
|
||||
|
@ -67,7 +65,6 @@ class TemplateSelectFragment :
|
|||
|
||||
private fun render(viewState: TemplateSelectViewModel.ViewState) {
|
||||
when (viewState) {
|
||||
TemplateSelectViewModel.ViewState.ErrorGettingType -> TODO()
|
||||
TemplateSelectViewModel.ViewState.Init -> {
|
||||
binding.tvTemplateCountOrTutorial.text = null
|
||||
binding.btnCancel.isEnabled = true
|
||||
|
@ -86,19 +83,6 @@ class TemplateSelectFragment :
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun setupUseTemplateClicks() {
|
||||
binding.btnUseTemplate.clicks().collect {
|
||||
vm.onUseTemplateButtonPressed(
|
||||
currentItem = binding.templateViewPager.currentItem,
|
||||
ctx = ctx
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setupCancelClicks() {
|
||||
binding.btnCancel.clicks().collect { exit() }
|
||||
}
|
||||
|
||||
private fun exit() {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
|
|
|
@ -421,4 +421,6 @@ sealed class Command {
|
|||
|
||||
data class AddObjectToCollection(val ctx: Id, val afterId: Id, val ids: List<Id>)
|
||||
data class SetQueryToSet(val ctx: Id, val query: String)
|
||||
|
||||
data class SetInternalFlags(val ctx: Id, val flags: List<InternalFlags>)
|
||||
}
|
|
@ -841,4 +841,8 @@ class BlockDataRepository(
|
|||
override suspend fun fileSpaceUsage(): FileLimits {
|
||||
return remote.fileSpaceUsage()
|
||||
}
|
||||
|
||||
override suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload {
|
||||
return remote.setInternalFlags(command)
|
||||
}
|
||||
}
|
|
@ -360,4 +360,6 @@ interface BlockRemote {
|
|||
suspend fun addObjectToCollection(command: Command.AddObjectToCollection): Payload
|
||||
suspend fun setQueryToSet(command: Command.SetQueryToSet): Payload
|
||||
suspend fun fileSpaceUsage(): FileLimits
|
||||
|
||||
suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload
|
||||
}
|
|
@ -412,4 +412,5 @@ interface BlockRepository {
|
|||
suspend fun addObjectToCollection(command: Command.AddObjectToCollection): Payload
|
||||
suspend fun setQueryToSet(command: Command.SetQueryToSet): Payload
|
||||
suspend fun fileSpaceUsage(): FileLimits
|
||||
suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.anytypeio.anytype.domain.`object`
|
||||
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.InternalFlags
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
||||
class SetObjectInternalFlags(
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<SetObjectInternalFlags.Params, Payload>(dispatchers.io) {
|
||||
|
||||
override suspend fun doWork(params: Params): Payload {
|
||||
val command = Command.SetInternalFlags(
|
||||
ctx = params.ctx,
|
||||
flags = params.flags
|
||||
)
|
||||
return repo.setInternalFlags(command)
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val ctx: Id,
|
||||
val flags: List<InternalFlags>
|
||||
)
|
||||
}
|
|
@ -792,4 +792,8 @@ class BlockMiddleware(
|
|||
override suspend fun fileSpaceUsage(): FileLimits {
|
||||
return middleware.fileSpaceUsage()
|
||||
}
|
||||
|
||||
override suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload {
|
||||
return middleware.setInternalFlags(command)
|
||||
}
|
||||
}
|
|
@ -2185,6 +2185,20 @@ class Middleware @Inject constructor(
|
|||
return response.event.toPayload()
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun setInternalFlags(
|
||||
command: Command.SetInternalFlags
|
||||
): Payload {
|
||||
val request = Rpc.Object.SetInternalFlags.Request(
|
||||
contextId = command.ctx,
|
||||
internalFlags = command.flags.toMiddlewareModel()
|
||||
)
|
||||
if (BuildConfig.DEBUG) logRequest(request)
|
||||
val response = service.setInternalFlags(request)
|
||||
if (BuildConfig.DEBUG) logResponse(response)
|
||||
return response.event.toPayload()
|
||||
}
|
||||
|
||||
fun addObjectToCollection(command: Command.AddObjectToCollection): Payload {
|
||||
val request = Rpc.ObjectCollection.Add.Request(
|
||||
contextId = command.ctx,
|
||||
|
|
|
@ -143,6 +143,9 @@ interface MiddlewareService {
|
|||
@Throws(Exception::class)
|
||||
fun setObjectSource(request: Rpc.Object.SetSource.Request): Rpc.Object.SetSource.Response
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun setInternalFlags(request: Rpc.Object.SetInternalFlags.Request): Rpc.Object.SetInternalFlags.Response
|
||||
|
||||
//endregion
|
||||
|
||||
//region OBJECT'S RELATIONS command
|
||||
|
|
|
@ -1611,4 +1611,17 @@ class MiddlewareServiceImplementation @Inject constructor(
|
|||
return response
|
||||
}
|
||||
}
|
||||
|
||||
override fun setInternalFlags(request: Rpc.Object.SetInternalFlags.Request): Rpc.Object.SetInternalFlags.Response {
|
||||
val encoded = Service.objectSetInternalFlags(
|
||||
Rpc.Object.SetInternalFlags.Request.ADAPTER.encode(request)
|
||||
)
|
||||
val response = Rpc.Object.SetInternalFlags.Response.ADAPTER.decode(encoded)
|
||||
val error = response.error
|
||||
if (error != null && error.code != Rpc.Object.SetInternalFlags.Response.Error.Code.NULL) {
|
||||
throw Exception(error.description)
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,6 +73,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultPageType
|
|||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfRelations
|
||||
|
@ -94,6 +95,7 @@ import com.anytypeio.anytype.presentation.common.Delegator
|
|||
import com.anytypeio.anytype.presentation.common.StateReducer
|
||||
import com.anytypeio.anytype.presentation.common.SupportCommand
|
||||
import com.anytypeio.anytype.presentation.editor.ControlPanelMachine.Interactor
|
||||
import com.anytypeio.anytype.presentation.editor.ControlPanelMachine.Event.ObjectTypesWidgetEvent
|
||||
import com.anytypeio.anytype.presentation.editor.Editor.Restore
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Command
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Intent
|
||||
|
@ -286,7 +288,8 @@ class EditorViewModel(
|
|||
private val workspaceManager: WorkspaceManager,
|
||||
private val getObjectTypes: GetObjectTypes,
|
||||
private val interceptFileLimitEvents: InterceptFileLimitEvents,
|
||||
private val addRelationToObject: AddRelationToObject
|
||||
private val addRelationToObject: AddRelationToObject,
|
||||
private val setObjectInternalFlags: SetObjectInternalFlags
|
||||
) : ViewStateViewModel<ViewState>(),
|
||||
PickerListener,
|
||||
SupportNavigation<EventWrapper<AppNavigation.Command>>,
|
||||
|
@ -1212,9 +1215,7 @@ class EditorViewModel(
|
|||
)
|
||||
viewModelScope.launch { orchestrator.stores.views.update(new) }
|
||||
viewModelScope.launch { orchestrator.proxies.changes.send(update) }
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
}
|
||||
|
||||
fun onDescriptionBlockTextChanged(view: BlockView.Description) {
|
||||
|
@ -1229,9 +1230,7 @@ class EditorViewModel(
|
|||
)
|
||||
viewModelScope.launch { orchestrator.stores.views.update(new) }
|
||||
viewModelScope.launch { orchestrator.proxies.changes.send(update) }
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
}
|
||||
|
||||
fun onTextBlockTextChanged(view: BlockView.Text) {
|
||||
|
@ -1257,9 +1256,7 @@ class EditorViewModel(
|
|||
}
|
||||
|
||||
viewModelScope.launch { orchestrator.proxies.changes.send(update) }
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
}
|
||||
|
||||
fun onSelectionChanged(id: String, selection: IntRange) {
|
||||
|
@ -1438,9 +1435,7 @@ class EditorViewModel(
|
|||
) {
|
||||
Timber.d("onEndLineEnterClicked, id:[$id] text:[$text] marks:[$marks]")
|
||||
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
|
||||
val target = blocks.first { it.id == id }
|
||||
|
||||
|
@ -2908,9 +2903,7 @@ class EditorViewModel(
|
|||
fun onOutsideClicked() {
|
||||
Timber.d("onOutsideClicked, ")
|
||||
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
|
||||
if (mode is EditorMode.Styling) {
|
||||
onExitBlockStyleToolbarClicked()
|
||||
|
@ -4289,11 +4282,9 @@ class EditorViewModel(
|
|||
analytics = analytics,
|
||||
objType = storeOfObjectTypes.get(type)
|
||||
)
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
if (applyTemplate) {
|
||||
proceedWithTemplateSelection(type)
|
||||
proceedWithCheckingInternalFlagShouldSelectTemplate(objTypeId = type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5353,9 +5344,7 @@ class EditorViewModel(
|
|||
Timber.d("onKeyPressedEvent, event:[$event]")
|
||||
when (event) {
|
||||
is KeyPressedEvent.OnTitleBlockEnterKeyEvent -> {
|
||||
if (isObjectTypesWidgetVisible) {
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
proceedWithTitleEnterClicked(
|
||||
title = event.target,
|
||||
text = event.text,
|
||||
|
@ -5883,28 +5872,17 @@ class EditorViewModel(
|
|||
|
||||
fun onObjectTypesWidgetDoneClicked() {
|
||||
Timber.d("onObjectTypesWidgetDoneClicked, ")
|
||||
proceedWithHidingObjectTypeWidget()
|
||||
val details = orchestrator.stores.details.current()
|
||||
val wrapper = ObjectWrapper.Basic(details.details[context]?.map ?: emptyMap())
|
||||
if (wrapper.internalFlags.contains(InternalFlags.ShouldSelectTemplate)) {
|
||||
if (wrapper.type.isNotEmpty()) {
|
||||
proceedWithTemplateSelection(typeId = wrapper.type.first())
|
||||
}
|
||||
}
|
||||
sendHideObjectTypeWidgetEvent()
|
||||
proceedWithCheckingInternalFlagShouldSelectTemplate()
|
||||
}
|
||||
|
||||
private fun proceedWithShowingObjectTypesWidget() {
|
||||
val restrictions = orchestrator.stores.objectRestrictions.current()
|
||||
if (restrictions.contains(ObjectRestriction.TYPE_CHANGE)) {
|
||||
Timber.d("proceedWithShowingObjectTypesWidget, type change is restricted")
|
||||
return
|
||||
}
|
||||
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()
|
||||
}
|
||||
proceedWithCheckingInternalFlagShouldSelectType()
|
||||
}
|
||||
|
||||
private fun proceedWithGettingObjectTypesForObjectTypeWidget() {
|
||||
|
@ -5959,10 +5937,6 @@ class EditorViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
private fun proceedWithHidingObjectTypeWidget() {
|
||||
controlPanelInteractor.onEvent(ControlPanelMachine.Event.ObjectTypesWidgetEvent.Hide)
|
||||
}
|
||||
|
||||
private fun proceedWithOpeningSelectingObjectTypeScreen() {
|
||||
val excludeTypes = orchestrator.stores.details.current().details[context]?.type
|
||||
val command = if (isObjectTypesWidgetVisible) {
|
||||
|
@ -5976,6 +5950,10 @@ class EditorViewModel(
|
|||
}
|
||||
dispatch(command)
|
||||
}
|
||||
|
||||
private fun sendHideObjectTypeWidgetEvent() {
|
||||
if (isObjectTypesWidgetVisible) controlPanelInteractor.onEvent(ObjectTypesWidgetEvent.Hide)
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region OBJECT APPEARANCE SETTING
|
||||
|
@ -6186,23 +6164,28 @@ class EditorViewModel(
|
|||
viewModelScope.launch { onEvent(SelectTemplateEvent.OnSkipped) }
|
||||
}
|
||||
|
||||
private fun proceedWithTemplateSelection(typeId: Id) {
|
||||
private fun proceedWithStartTemplateEvent(objTypeId: Id) {
|
||||
viewModelScope.launch {
|
||||
val objType = storeOfObjectTypes.get(typeId)
|
||||
val objType = storeOfObjectTypes.get(objTypeId)
|
||||
if (objType != null) {
|
||||
onEvent(
|
||||
SelectTemplateEvent.OnStart(
|
||||
ctx = context,
|
||||
type = typeId,
|
||||
type = objTypeId,
|
||||
typeName = objType.name.orEmpty()
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Timber.e("Error while getting object type from storeOfObjectTypes by id: $typeId")
|
||||
Timber.e("Error while getting object type from storeOfObjectTypes by id: $objTypeId")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getObjectTypeFromDetails(): Id? {
|
||||
val details = orchestrator.stores.details.current()
|
||||
val wrapper = ObjectWrapper.Basic(details.details[context]?.map ?: emptyMap())
|
||||
return wrapper.getProperType()
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region SIMPLE TABLES
|
||||
|
@ -6892,6 +6875,84 @@ class EditorViewModel(
|
|||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region INTERNAL FLAGS
|
||||
private fun proceedWithCheckingInternalFlagShouldSelectType() {
|
||||
val internalFlags = getInternalFlagsFromDetails()
|
||||
if (internalFlags.contains(InternalFlags.ShouldSelectType)) {
|
||||
//We use this flag to show object type widget and then we don't need it anymore
|
||||
proceedWithGettingObjectTypesForObjectTypeWidget()
|
||||
proceedWithOptOutTypeInternalFlag()
|
||||
} else {
|
||||
Timber.d("Object doesn't have internal flag: ShouldSelectType")
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCheckingInternalFlagShouldSelectTemplate(objTypeId: Id? = null) {
|
||||
val internalFlags = getInternalFlagsFromDetails()
|
||||
if (internalFlags.contains(InternalFlags.ShouldSelectTemplate)) {
|
||||
//We use this flag to show template widget and then we don't need it anymore
|
||||
val properObjTypeId = objTypeId ?: getObjectTypeFromDetails() ?: return
|
||||
proceedWithStartTemplateEvent(objTypeId = properObjTypeId)
|
||||
proceedWithOptOutTemplateInternalFlag()
|
||||
} else {
|
||||
Timber.d("Object doesn't have internal flag: ShouldSelectTemplate")
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithOptOutTypeInternalFlag() {
|
||||
val internalFlags = getInternalFlagsFromDetails()
|
||||
if (!internalFlags.contains(InternalFlags.ShouldSelectType)) return
|
||||
val flagsWithoutType = filterOutInternalFlags(
|
||||
flags = internalFlags,
|
||||
out = InternalFlags.ShouldSelectType
|
||||
)
|
||||
updateFlagsAndProceed(
|
||||
flags = flagsWithoutType,
|
||||
action = this::sendHideObjectTypeWidgetEvent
|
||||
)
|
||||
}
|
||||
|
||||
private fun proceedWithOptOutTemplateInternalFlag() {
|
||||
val internalFlags = getInternalFlagsFromDetails()
|
||||
if (!internalFlags.contains(InternalFlags.ShouldSelectTemplate)) return
|
||||
val flagsWithoutTemplate = filterOutInternalFlags(
|
||||
flags = internalFlags,
|
||||
out = InternalFlags.ShouldSelectTemplate
|
||||
)
|
||||
updateFlagsAndProceed(flags = flagsWithoutTemplate)
|
||||
}
|
||||
|
||||
private fun getInternalFlagsFromDetails(): List<InternalFlags> {
|
||||
val details = orchestrator.stores.details.current()
|
||||
val obj = ObjectWrapper.Basic(details.details[context]?.map ?: emptyMap())
|
||||
return obj.internalFlags
|
||||
}
|
||||
|
||||
private fun filterOutInternalFlags(flags: List<InternalFlags>, out: InternalFlags): List<InternalFlags> {
|
||||
return flags.filter { it != out }
|
||||
}
|
||||
|
||||
private fun updateFlagsAndProceed(flags: List<InternalFlags>, action: () -> Unit = {}) {
|
||||
viewModelScope.launch {
|
||||
val params = SetObjectInternalFlags.Params(
|
||||
ctx = context,
|
||||
flags = flags
|
||||
)
|
||||
setObjectInternalFlags.async(params).fold(
|
||||
onSuccess = {
|
||||
dispatcher.send(it)
|
||||
Timber.d("Internal flags updated")
|
||||
action.invoke()
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while updating internal flags")
|
||||
action.invoke()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
|
||||
private const val NO_POSITION = -1
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultPageType
|
|||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfRelations
|
||||
|
@ -79,7 +80,8 @@ open class EditorViewModelFactory(
|
|||
private val getObjectTypes: GetObjectTypes,
|
||||
private val objectToCollection: ConvertObjectToCollection,
|
||||
private val interceptFileLimitEvents: InterceptFileLimitEvents,
|
||||
private val addRelationToObject: AddRelationToObject
|
||||
private val addRelationToObject: AddRelationToObject,
|
||||
private val setObjectInternalFlags: SetObjectInternalFlags
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -120,7 +122,8 @@ open class EditorViewModelFactory(
|
|||
workspaceManager = workspaceManager,
|
||||
getObjectTypes = getObjectTypes,
|
||||
interceptFileLimitEvents = interceptFileLimitEvents,
|
||||
addRelationToObject = addRelationToObject
|
||||
addRelationToObject = addRelationToObject,
|
||||
setObjectInternalFlags = setObjectInternalFlags
|
||||
) as T
|
||||
}
|
||||
}
|
|
@ -127,6 +127,10 @@ class TemplateSelectViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onCancelButtonClicked() {
|
||||
isDismissed.value = true
|
||||
}
|
||||
|
||||
class Factory @Inject constructor(
|
||||
private val applyTemplate: ApplyTemplate,
|
||||
private val getTemplates: GetTemplates,
|
||||
|
@ -149,7 +153,6 @@ class TemplateSelectViewModel(
|
|||
) : ViewState()
|
||||
|
||||
object Init : ViewState()
|
||||
object ErrorGettingType : ViewState()
|
||||
}
|
||||
|
||||
}
|
|
@ -61,6 +61,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultPageType
|
|||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations
|
||||
|
@ -352,6 +353,7 @@ open class EditorViewModelTest {
|
|||
private lateinit var objectToSet: ConvertObjectToSet
|
||||
private lateinit var clearBlockContent: ClearBlockContent
|
||||
private lateinit var clearBlockStyle: ClearBlockStyle
|
||||
private lateinit var setObjectInternalFlags: SetObjectInternalFlags
|
||||
|
||||
val root = MockDataFactory.randomUuid()
|
||||
|
||||
|
@ -3812,6 +3814,7 @@ open class EditorViewModelTest {
|
|||
clearBlockContent = ClearBlockContent(repo)
|
||||
clearBlockStyle = ClearBlockStyle(repo)
|
||||
interceptFileLimitEvents = InterceptFileLimitEvents(fileLimitsEventChannel, dispatchers)
|
||||
setObjectInternalFlags = SetObjectInternalFlags(repo, dispatchers)
|
||||
|
||||
workspaceManager = WorkspaceManager.DefaultWorkspaceManager()
|
||||
runBlocking {
|
||||
|
@ -3904,7 +3907,8 @@ open class EditorViewModelTest {
|
|||
workspaceManager = workspaceManager,
|
||||
getObjectTypes = getObjectTypes,
|
||||
interceptFileLimitEvents = interceptFileLimitEvents,
|
||||
addRelationToObject = addRelationToObject
|
||||
addRelationToObject = addRelationToObject,
|
||||
setObjectInternalFlags = setObjectInternalFlags
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.anytypeio.anytype.core_models.Relations
|
|||
import com.anytypeio.anytype.core_models.StubHeader
|
||||
import com.anytypeio.anytype.core_models.StubSmartBlock
|
||||
import com.anytypeio.anytype.core_models.StubTitle
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.presentation.util.DefaultCoroutineTestRule
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
@ -19,6 +20,10 @@ 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
|
||||
import org.mockito.kotlin.verifyNoInteractions
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class EditorInternalFlagsTest : EditorPresentationTestSetup() {
|
||||
|
@ -99,4 +104,203 @@ class EditorInternalFlagsTest : EditorPresentationTestSetup() {
|
|||
|
||||
assertEquals(expected = expectedFlags, actual = actualFlags)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should remove type flag on show object event with type flag in details`() = runTest {
|
||||
val title = StubTitle()
|
||||
val header = StubHeader(children = listOf(title.id))
|
||||
val page = StubSmartBlock(id = root, children = listOf(header.id))
|
||||
val document = listOf(page, header, title)
|
||||
stubInterceptEvents()
|
||||
|
||||
val detailsList = Block.Details(
|
||||
details = mapOf(
|
||||
root to Block.Fields(
|
||||
mapOf(
|
||||
Relations.TYPE to ObjectTypeIds.PAGE,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.INTERNAL_FLAGS to listOf(
|
||||
InternalFlags.ShouldSelectTemplate.code.toDouble(),
|
||||
InternalFlags.ShouldEmptyDelete.code.toDouble(),
|
||||
InternalFlags.ShouldSelectType.code.toDouble(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
stubOpenDocument(document = document, details = detailsList)
|
||||
stubGetObjectTypes(types = emptyList())
|
||||
stubGetDefaultObjectType()
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
||||
stubFileLimitEvents()
|
||||
stubSetInternalFlags()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
verifyBlocking(setObjectInternalFlags, times(1)) {
|
||||
async(
|
||||
params = SetObjectInternalFlags.Params(
|
||||
ctx = root,
|
||||
flags = listOf(
|
||||
InternalFlags.ShouldSelectTemplate,
|
||||
InternalFlags.ShouldEmptyDelete
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
coroutineTestRule.advanceTime(100)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not remove type flag on show object event without type flag in details`() = runTest {
|
||||
val title = StubTitle()
|
||||
val header = StubHeader(children = listOf(title.id))
|
||||
val page = StubSmartBlock(id = root, children = listOf(header.id))
|
||||
val document = listOf(page, header, title)
|
||||
stubInterceptEvents()
|
||||
|
||||
val detailsList = Block.Details(
|
||||
details = mapOf(
|
||||
root to Block.Fields(
|
||||
mapOf(
|
||||
Relations.TYPE to ObjectTypeIds.PAGE,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.INTERNAL_FLAGS to listOf(
|
||||
InternalFlags.ShouldSelectTemplate.code.toDouble(),
|
||||
InternalFlags.ShouldEmptyDelete.code.toDouble()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
stubOpenDocument(document = document, details = detailsList)
|
||||
stubGetObjectTypes(types = emptyList())
|
||||
stubGetDefaultObjectType()
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
||||
stubFileLimitEvents()
|
||||
stubSetInternalFlags()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
verifyNoInteractions(setObjectInternalFlags)
|
||||
|
||||
coroutineTestRule.advanceTime(100)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should remove template flag on start template selection widget`() = runTest {
|
||||
val title = StubTitle()
|
||||
val header = StubHeader(children = listOf(title.id))
|
||||
val page = StubSmartBlock(id = root, children = listOf(header.id))
|
||||
val document = listOf(page, header, title)
|
||||
stubInterceptEvents()
|
||||
|
||||
val detailsList = Block.Details(
|
||||
details = mapOf(
|
||||
root to Block.Fields(
|
||||
mapOf(
|
||||
Relations.TYPE to ObjectTypeIds.PAGE,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.INTERNAL_FLAGS to listOf(
|
||||
InternalFlags.ShouldSelectTemplate.code.toDouble(),
|
||||
InternalFlags.ShouldEmptyDelete.code.toDouble(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
stubOpenDocument(document = document, details = detailsList)
|
||||
stubGetObjectTypes(types = emptyList())
|
||||
stubGetDefaultObjectType()
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
||||
stubFileLimitEvents()
|
||||
stubSetInternalFlags()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
advanceUntilIdle()
|
||||
vm.onObjectTypesWidgetDoneClicked()
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
verifyBlocking(setObjectInternalFlags, times(1)) {
|
||||
async(
|
||||
params = SetObjectInternalFlags.Params(
|
||||
ctx = root,
|
||||
flags = listOf(
|
||||
InternalFlags.ShouldEmptyDelete
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
coroutineTestRule.advanceTime(100)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not remove template flag on start template selection widget when flag isn't present`() = runTest {
|
||||
val title = StubTitle()
|
||||
val header = StubHeader(children = listOf(title.id))
|
||||
val page = StubSmartBlock(id = root, children = listOf(header.id))
|
||||
val document = listOf(page, header, title)
|
||||
stubInterceptEvents()
|
||||
|
||||
val detailsList = Block.Details(
|
||||
details = mapOf(
|
||||
root to Block.Fields(
|
||||
mapOf(
|
||||
Relations.TYPE to ObjectTypeIds.PAGE,
|
||||
Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
|
||||
Relations.INTERNAL_FLAGS to listOf(
|
||||
InternalFlags.ShouldSelectType.code.toDouble(),
|
||||
InternalFlags.ShouldEmptyDelete.code.toDouble(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
stubOpenDocument(document = document, details = detailsList)
|
||||
stubGetObjectTypes(types = emptyList())
|
||||
stubGetDefaultObjectType()
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
||||
stubFileLimitEvents()
|
||||
stubSetInternalFlags()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
advanceUntilIdle()
|
||||
vm.onObjectTypesWidgetDoneClicked()
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
verifyBlocking(setObjectInternalFlags, times(1)) {
|
||||
async(
|
||||
params = SetObjectInternalFlags.Params(
|
||||
ctx = root,
|
||||
flags = listOf(
|
||||
InternalFlags.ShouldEmptyDelete
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
verifyNoMoreInteractions(setObjectInternalFlags)
|
||||
|
||||
coroutineTestRule.advanceTime(100)
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultPageType
|
|||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToCollection
|
||||
import com.anytypeio.anytype.domain.`object`.ConvertObjectToSet
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectInternalFlags
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations
|
||||
|
@ -346,6 +347,9 @@ open class EditorPresentationTestSetup {
|
|||
lateinit var fileLimitsEventChannel: FileLimitsEventChannel
|
||||
lateinit var interceptFileLimitEvents: InterceptFileLimitEvents
|
||||
|
||||
@Mock
|
||||
lateinit var setObjectInternalFlags: SetObjectInternalFlags
|
||||
|
||||
open fun buildViewModel(urlBuilder: UrlBuilder = builder): EditorViewModel {
|
||||
|
||||
val storage = Editor.Storage()
|
||||
|
@ -467,7 +471,8 @@ open class EditorPresentationTestSetup {
|
|||
workspaceManager = workspaceManager,
|
||||
getObjectTypes = getObjectTypes,
|
||||
interceptFileLimitEvents = interceptFileLimitEvents,
|
||||
addRelationToObject = addRelationToObject
|
||||
addRelationToObject = addRelationToObject,
|
||||
setObjectInternalFlags = setObjectInternalFlags
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -746,4 +751,16 @@ open class EditorPresentationTestSetup {
|
|||
} doReturn Resultat.success(types)
|
||||
}
|
||||
}
|
||||
|
||||
fun stubFileLimitEvents() {
|
||||
interceptFileLimitEvents.stub {
|
||||
onBlocking { run(Unit) } doReturn emptyFlow()
|
||||
}
|
||||
}
|
||||
|
||||
fun stubSetInternalFlags() {
|
||||
setObjectInternalFlags.stub {
|
||||
onBlocking { async(any()) } doReturn Resultat.success(Payload(root, emptyList()))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue