Skip to content

Droid 2826 editor fix cursor jumps back inside bullet list #1578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: release/0-32-0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
onDragListener = dndDelegate.dndListener,
lifecycle = lifecycle,
dragAndDropSelector = DragAndDropAdapterDelegate(),
onCellSelectionChanged = vm::onCellSelectionChanged
onCellSelectionChanged = vm::onCellSelectionChanged,
onCursorConsumed = vm::onCursorConsumed
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<BlockViewHolder>(),
ItemProviderAdapter<BlockView>,
DragAndDropSelector by dragAndDropSelector {
Expand Down Expand Up @@ -274,7 +275,8 @@ class BlockAdapter(
HOLDER_PARAGRAPH -> {
Paragraph(
ItemBlockTextBinding.inflate(inflater, parent, false),
clicked = onClickListener
clicked = onClickListener,
onCursorConsumed = onCursorConsumed
)
}
HOLDER_TITLE -> {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1646,7 +1649,7 @@ class BlockAdapter(

fun updateWithDiffUtil(items: List<BlockView>) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,10 @@ class BlockViewDiffUtil(
}

if (newBlock is BlockView.Cursor && oldBlock is BlockView.Cursor) {
if (newBlock.cursor != oldBlock.cursor)
if (newBlock.cursor != oldBlock.cursor) {
Timber.d("DROID-2826 cursor changed: ${newBlock.cursor}")
changes.add(CURSOR_CHANGED)
}
}

if (newBlock is Indentable && oldBlock is Indentable) {
Expand Down Expand Up @@ -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")
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,7 +19,8 @@ import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class Paragraph(
val binding: ItemBlockTextBinding,
clicked: (ListenerType) -> Unit,
) : Text<BlockView.Text.Paragraph>(binding.root, clicked), SupportNesting, DecoratableViewHolder {
onCursorConsumed: (Id) -> Unit
) : Text<BlockView.Text.Paragraph>(binding.root, clicked, onCursorConsumed), SupportNesting, DecoratableViewHolder {

override val root: View = binding.root
override val content: TextInputWidget = binding.textContent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<BlockTextType : BlockView.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 {

Expand All @@ -28,6 +30,7 @@ abstract class Text<BlockTextType : BlockView.Text>(
open fun bind(
item: BlockTextType,
) {
Timber.d("DROID-2826 binding item in adapter: ${item}")
indentize(item)
select(item)
inputAction(item)
Expand All @@ -53,7 +56,13 @@ abstract class Text<BlockTextType : BlockView.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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ class EditorViewModel(
renderCommand
.stream()
.switchToLatestFrom(orchestrator.stores.views.stream())
.distinctUntilChanged()
.onEach { dispatchToUI(it) }
.launchIn(viewModelScope)

Expand Down Expand Up @@ -795,7 +796,8 @@ class EditorViewModel(

footers.value = getFooterState(root, details)
val flags = mutableListOf<BlockViewRenderer.RenderFlag>()
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<BlockView.Text.Paragraph>().map { it.id to it.cursor }}")
val doc = models.asMap().render(
mode = mode,
root = root,
Expand All @@ -818,6 +820,7 @@ class EditorViewModel(
emit(emptyList())
}
.onEach { views ->
Timber.d("DROID-2826 Rendering finished with view with cursor: ${views.filterIsInstance<BlockView.Text.Paragraph>().map { it.id to it.cursor }}")
orchestrator.stores.views.update(views)
renderCommand.send(Unit)
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -3111,9 +3134,6 @@ class EditorViewModel(
}

private suspend fun refresh() {
if (BuildConfig.DEBUG) {
Timber.d("----------Blocks dispatched to render pipeline----------")
}
renderizePipeline.send(blocks)
}

Expand Down Expand Up @@ -6070,6 +6090,7 @@ class EditorViewModel(
mentionTrigger = mentionTrigger
)

// Replacing text domain-level block
val update = blocks.map { block ->
if (block.id != target.id)
block
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<BlockView>) : ViewState()
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class DefaultBlockViewRenderer @Inject constructor(
private val storeOfObjectTypes: StoreOfObjectTypes
) : BlockViewRenderer, ToggleStateHolder by toggleStateHolder {

var flags = 1

override suspend fun Map<Id, List<Block>>.render(
mode: EditorMode,
root: Block,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -2203,6 +2214,8 @@ class DefaultBlockViewRenderer @Inject constructor(
focus: Focus,
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
Expand Down
Loading