From 74a15a4a37849960aa1221ca0f8952b309de478b Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Thu, 19 Sep 2024 18:43:19 +0200 Subject: [PATCH 1/4] DROID-2826 fix --- .../main/java/com/anytypeio/anytype/domain/editor/Editor.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt index c860f016cb..43c1128d48 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt @@ -41,8 +41,8 @@ interface Editor { } sealed class Target { - object None: Target() - object FirstTextBlock : Target() + data object None: Target() + data object FirstTextBlock : Target() data class Block(val id: Id) : Target() } } From 28b705618856fca3888e6f4eb02ac2c9eff161c4 Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Fri, 20 Sep 2024 12:05:31 +0200 Subject: [PATCH 2/4] DROID-2826 logging + experiments --- .../anytype/ui/editor/EditorFragment.kt | 3 +- .../core_ui/features/editor/BlockAdapter.kt | 7 +++-- .../features/editor/BlockViewDiffUtil.kt | 13 +++++--- .../editor/holders/interface/TextHolder.kt | 12 +++++--- .../features/editor/holders/text/Paragraph.kt | 4 ++- .../features/editor/holders/text/Text.kt | 15 ++++++++-- .../anytypeio/anytype/domain/editor/Editor.kt | 4 +-- .../editor/DocumentExternalEventReducer.kt | 8 ++--- .../presentation/editor/EditorViewModel.kt | 30 ++++++++++++++++--- .../presentation/editor/editor/ViewState.kt | 4 +-- .../editor/render/DefaultBlockViewRenderer.kt | 14 ++++++++- 11 files changed, 86 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt index 1fbdba9976..29dcf731fb 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt @@ -335,7 +335,8 @@ open class EditorFragment : NavigationFragment(R.layout.f onDragListener = dndDelegate.dndListener, lifecycle = lifecycle, dragAndDropSelector = DragAndDropAdapterDelegate(), - onCellSelectionChanged = vm::onCellSelectionChanged + onCellSelectionChanged = vm::onCellSelectionChanged, + onCursorConsumed = vm::onCursorConsumed ) } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt index 1075be912a..7d0dc49e36 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt @@ -231,6 +231,7 @@ class BlockAdapter( private val onDragListener: View.OnDragListener, private val lifecycle: Lifecycle, private val dragAndDropSelector: DragAndDropSelector, + private val onCursorConsumed: (Id) -> Unit = {} ) : RecyclerView.Adapter(), ItemProviderAdapter, DragAndDropSelector by dragAndDropSelector { @@ -274,7 +275,8 @@ class BlockAdapter( HOLDER_PARAGRAPH -> { Paragraph( ItemBlockTextBinding.inflate(inflater, parent, false), - clicked = onClickListener + clicked = onClickListener, + onCursorConsumed = onCursorConsumed ) } HOLDER_TITLE -> { @@ -851,6 +853,7 @@ class BlockAdapter( if (pos != RecyclerView.NO_POSITION) { val view = views[pos] if (view is BlockView.Text) { + Timber.d("DROID-2826 selectionWatcher callback, changing view cursor to: ${selection.last}") view.cursor = selection.last } onSelectionChanged(view.id, selection) @@ -1646,7 +1649,7 @@ class BlockAdapter( fun updateWithDiffUtil(items: List) { if (BuildConfig.DEBUG) { - Timber.d("----------Blocks dispatched to adapter---------------------") + Timber.d("DROID-2826 ----------Blocks dispatched to adapter---------------------") } val result = DiffUtil.calculateDiff(BlockViewDiffUtil(old = blocks, new = items)) blocks = items diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt index 718a99015e..da28118ba6 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt @@ -93,8 +93,10 @@ class BlockViewDiffUtil( } if (newBlock is BlockView.Cursor && oldBlock is BlockView.Cursor) { - if (newBlock.cursor != oldBlock.cursor) + if (newBlock.cursor != null && newBlock.cursor != oldBlock.cursor) { + Timber.d("DROID-2826 cursor changed: ${newBlock.cursor}") changes.add(CURSOR_CHANGED) + } } if (newBlock is Indentable && oldBlock is Indentable) { @@ -275,9 +277,12 @@ class BlockViewDiffUtil( } return if (changes.isNotEmpty()) - Payload(changes).also { Timber.d("Returning payload: $it") } - else - super.getChangePayload(oldItemPosition, newItemPosition) + Payload(changes).also { Timber.d("DROID-2826 DIFF UTIL Returning payload: $it") } + else { + super.getChangePayload(oldItemPosition, newItemPosition).also { + Timber.d("DROID-2826 DIFF UTIL found no changes. onBindViewHolder will be called") + } + } } /** diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/interface/TextHolder.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/interface/TextHolder.kt index 09d44a996a..d873fd20f7 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/interface/TextHolder.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/interface/TextHolder.kt @@ -30,14 +30,18 @@ interface TextHolder { val selectionView: View - fun setCursor(item: BlockView.Cursor) { - Timber.d("Setting cursor: $item") - item.cursor?.let { + fun setCursor(item: BlockView.Cursor) : Boolean { + Timber.d("DROID-2826 Trying to set cursor: $item") + return item.cursor?.let { val length = content.text?.length ?: 0 if (it in 0..length) { + Timber.d("DROID-2826 Setting cursor: $it") content.setSelection(it) + true + } else { + false } - } + } ?: false } fun setAlignment(alignment: Alignment) { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt index f0559f6b57..259ed5139b 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt @@ -5,6 +5,7 @@ import android.view.View import android.widget.FrameLayout import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams +import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.ItemBlockTextBinding import com.anytypeio.anytype.core_ui.features.editor.SupportNesting @@ -18,7 +19,8 @@ import com.anytypeio.anytype.presentation.editor.editor.model.BlockView class Paragraph( val binding: ItemBlockTextBinding, clicked: (ListenerType) -> Unit, -) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder { + onCursorConsumed: (Id) -> Unit +) : Text(binding.root, clicked, onCursorConsumed), SupportNesting, DecoratableViewHolder { override val root: View = binding.root override val content: TextInputWidget = binding.textContent diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Text.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Text.kt index 8c1f2a9e14..63e10364f9 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Text.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Text.kt @@ -3,23 +3,25 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.text import android.text.Editable import android.view.View import androidx.annotation.CallSuper +import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.extensions.applyMovementMethod import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder import com.anytypeio.anytype.core_ui.features.editor.TextBlockHolder import com.anytypeio.anytype.core_ui.features.editor.performInEditMode import com.anytypeio.anytype.core_ui.features.editor.provide -import com.anytypeio.anytype.core_ui.features.editor.withBlock import com.anytypeio.anytype.core_ui.tools.DefaultTextWatcher import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.mention.MentionEvent import com.anytypeio.anytype.presentation.editor.editor.model.BlockView import com.anytypeio.anytype.presentation.editor.editor.model.Checkable import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent +import timber.log.Timber abstract class Text( view: View, - protected val clicked: (ListenerType) -> Unit + protected val clicked: (ListenerType) -> Unit, + private val onCursorConsumed: (Id) -> Unit = {} ) : BlockViewHolder(view), TextBlockHolder, BlockViewHolder.IndentableHolder, BlockViewHolder.DragAndDropHolder { @@ -28,6 +30,7 @@ abstract class Text( open fun bind( item: BlockTextType, ) { + Timber.d("DROID-2826 binding item in adapter: ${item}") indentize(item) select(item) inputAction(item) @@ -53,7 +56,13 @@ abstract class Text( ) setStyle(item) - if (item.isFocused) setCursor(item) + if (item.isFocused) { + val isConsumed = setCursor(item) + if (isConsumed) { + Timber.d("DROID-2826 Cursor consumed for block ${item.id}") + onCursorConsumed(item.id) + } + } setFocus(item) } diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt index 43c1128d48..5e9c1854ad 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/editor/Editor.kt @@ -7,13 +7,13 @@ interface Editor { /** * @property id id of the focused block - * @property cursor optional cursor/carriage associated with this focus + * @property cursor pending (!) cursor/carriage associated with this focus * @property isEmpty defines whether focus has target or not * @property isPending focus is pending if we do not know whether the target widget has gained focus. */ data class Focus( var target: Target, - val cursor: Cursor?, + var cursor: Cursor?, val isPending: Boolean = true ) : Editor { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/DocumentExternalEventReducer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/DocumentExternalEventReducer.kt index 7457531a8d..ef5862f837 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/DocumentExternalEventReducer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/DocumentExternalEventReducer.kt @@ -168,10 +168,10 @@ object Flags { val skipRefreshKeys = listOf( Relations.NAME, Relations.LAST_MODIFIED_DATE, - Relations.SNIPPET, - Relations.SYNC_DATE, - Relations.SYNC_STATUS, - Relations.INTERNAL_FLAGS +// Relations.SNIPPET, +// Relations.SYNC_DATE, +// Relations.SYNC_STATUS, +// Relations.INTERNAL_FLAGS ) } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt index ee792c8ab9..c36137c60b 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt @@ -754,6 +754,7 @@ class EditorViewModel( renderCommand .stream() .switchToLatestFrom(orchestrator.stores.views.stream()) + .distinctUntilChanged() .onEach { dispatchToUI(it) } .launchIn(viewModelScope) @@ -795,7 +796,8 @@ class EditorViewModel( footers.value = getFooterState(root, details) val flags = mutableListOf() - Timber.d("Rendering starting...") + Timber.d("DROID-2826 Rendering starting... with focus: ${focus}") + Timber.d("DROID-2826 Cursor in vm views before rendering: ${views.filterIsInstance().map { it.id to it.cursor }}") val doc = models.asMap().render( mode = mode, root = root, @@ -818,6 +820,7 @@ class EditorViewModel( emit(emptyList()) } .onEach { views -> + Timber.d("DROID-2826 Rendering finished with view with cursor: ${views.filterIsInstance().map { it.id to it.cursor }}") orchestrator.stores.views.update(views) renderCommand.send(Unit) } @@ -2204,6 +2207,26 @@ class EditorViewModel( viewModelScope.launch { refresh() } } + fun onCursorConsumed( + target: Id + ) { + viewModelScope.launch { + Timber.d("DROID-2826 vm.onCursorConsumed: $target") + val focus = orchestrator.stores.focus.current() + if (focus.targetOrNull() == target) { + orchestrator.stores.focus.update( + Editor.Focus( + target = Editor.Focus.Target.Block(target), + cursor = null, + isPending = false + ) + ) + } else { + TODO() + } + } + } + fun onDocRelationsClicked() { Timber.d("onDocRelationsClicked, ") dispatch( @@ -3111,9 +3134,6 @@ class EditorViewModel( } private suspend fun refresh() { - if (BuildConfig.DEBUG) { - Timber.d("----------Blocks dispatched to render pipeline----------") - } renderizePipeline.send(blocks) } @@ -6070,6 +6090,7 @@ class EditorViewModel( mentionTrigger = mentionTrigger ) + // Replacing text domain-level block val update = blocks.map { block -> if (block.id != target.id) block @@ -6080,6 +6101,7 @@ class EditorViewModel( orchestrator.stores.document.update(update) viewModelScope.launch { + // Desired position. val position = mentionFrom + name.length + 1 orchestrator.stores.focus.update( t = Editor.Focus( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ViewState.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ViewState.kt index 499fb4d02b..7dd514488f 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ViewState.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ViewState.kt @@ -3,7 +3,7 @@ package com.anytypeio.anytype.presentation.editor.editor import com.anytypeio.anytype.presentation.editor.editor.model.BlockView sealed class ViewState { - object Loading : ViewState() - object NotExist : ViewState() + data object Loading : ViewState() + data object NotExist : ViewState() data class Success(val blocks: List) : ViewState() } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt index d906c2ca00..49bfbb562e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt @@ -52,6 +52,8 @@ class DefaultBlockViewRenderer @Inject constructor( private val storeOfObjectTypes: StoreOfObjectTypes ) : BlockViewRenderer, ToggleStateHolder by toggleStateHolder { + var flags = 1 + override suspend fun Map>.render( mode: EditorMode, root: Block, @@ -801,6 +803,15 @@ class DefaultBlockViewRenderer @Inject constructor( ) val isFocused = resolveIsFocused(focus, block) + val cursor = if (isFocused) + setCursor(focus, content) + else + null + + if (isFocused) { + Timber.d("DROID-2826 focused block in renderer, setting cursor: $cursor") + } + return BlockView.Text.Paragraph( mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ, id = block.id, @@ -811,7 +822,7 @@ class DefaultBlockViewRenderer @Inject constructor( background = block.parseThemeBackgroundColor(), indent = indent, alignment = content.align?.toView(), - cursor = if (isFocused) setCursor(focus, content) else null, + cursor = cursor, isSelected = checkIfSelected( mode = mode, block = block, @@ -2203,6 +2214,7 @@ class DefaultBlockViewRenderer @Inject constructor( focus: Focus, content: Content.Text ): Int? = focus.cursor?.let { cursor -> + Timber.d("DROID-2826 BLOCK-RENDERER setting cursor: $cursor") when (cursor) { is Cursor.Start -> 0 is Cursor.End -> content.text.length From 73702eee44b4f4d3dbd8aa8b046558bb7e46a803 Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Fri, 20 Sep 2024 12:16:10 +0200 Subject: [PATCH 3/4] DROID-2826 fix --- .../anytype/core_ui/features/editor/BlockViewDiffUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt index da28118ba6..4d2db2ae26 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockViewDiffUtil.kt @@ -93,7 +93,7 @@ class BlockViewDiffUtil( } if (newBlock is BlockView.Cursor && oldBlock is BlockView.Cursor) { - if (newBlock.cursor != null && newBlock.cursor != oldBlock.cursor) { + if (newBlock.cursor != oldBlock.cursor) { Timber.d("DROID-2826 cursor changed: ${newBlock.cursor}") changes.add(CURSOR_CHANGED) } From a1e292efa682b41a0e9b2972b0a391effe60200d Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Fri, 20 Sep 2024 12:57:24 +0200 Subject: [PATCH 4/4] DROID-2826 fix --- .../presentation/editor/render/DefaultBlockViewRenderer.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt index 49bfbb562e..d1a8bf4dce 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt @@ -2215,6 +2215,7 @@ class DefaultBlockViewRenderer @Inject constructor( content: Content.Text ): Int? = focus.cursor?.let { cursor -> Timber.d("DROID-2826 BLOCK-RENDERER setting cursor: $cursor") + focus.cursor = null when (cursor) { is Cursor.Start -> 0 is Cursor.End -> content.text.length