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

DROID-50 Editor | Tech | Create text watchers in oncreate (#2620)

This commit is contained in:
Mikhail 2022-10-03 20:45:50 +03:00 committed by GitHub
parent 12707c651d
commit 7cf46865b2
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 863 additions and 1270 deletions

View file

@ -139,7 +139,7 @@ class DragAndDropDelegate {
)
val shadow = when (vh) {
is Text -> TextInputDragShadow(vh.content.id, vh.itemView, event)
is Text<*> -> TextInputDragShadow(vh.content.id, vh.itemView, event)
is Code -> TextInputDragShadow(vh.content.id, vh.itemView, event)
else -> DefaultEditorDragShadow(vh.itemView, event)
}

View file

@ -106,10 +106,10 @@ import com.anytypeio.anytype.core_ui.features.editor.holders.text.Numbered
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Paragraph
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Text
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Toggle
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.BookmarkUpload
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.FileUpload
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.PictureUpload
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.VideoUpload
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.BookmarkUpload
import com.anytypeio.anytype.core_ui.features.table.holders.TableBlockHolder
import com.anytypeio.anytype.core_ui.tools.ClipboardInterceptor
import com.anytypeio.anytype.core_ui.tools.DefaultTextWatcher
@ -173,7 +173,6 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_PLACEHOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_UPLOAD
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
import com.anytypeio.anytype.presentation.relations.DocumentRelationView
import timber.log.Timber
import java.util.*
@ -215,7 +214,9 @@ class BlockAdapter(
private val onDragListener: View.OnDragListener,
private val lifecycle: Lifecycle,
private val dragAndDropSelector: DragAndDropSelector,
) : RecyclerView.Adapter<BlockViewHolder>(), DragAndDropSelector by dragAndDropSelector {
) : RecyclerView.Adapter<BlockViewHolder>(),
ItemProviderAdapter<BlockView>,
DragAndDropSelector by dragAndDropSelector {
private var blocks: List<BlockView> = initialBlock
val views: List<BlockView> get() = blocks
@ -417,8 +418,11 @@ class BlockAdapter(
Checkbox(
binding = ItemBlockCheckboxBinding.inflate(
inflater, parent, false
), clicked = onClickListener
)
),
clicked = onClickListener
).apply {
setCheckboxClickListener(onCheckboxClicked)
}
}
HOLDER_BULLET -> {
Bulleted(
@ -438,8 +442,11 @@ class BlockAdapter(
Toggle(
binding = ItemBlockToggleBinding.inflate(
inflater, parent, false
), clicked = onClickListener
)
),
clicked = onClickListener
).apply {
setupToggle(onToggleClicked, onTogglePlaceholderClicked)
}
}
HOLDER_DESCRIPTION -> {
Description(
@ -590,7 +597,7 @@ class BlockAdapter(
}
HOLDER_BOOKMARK_UPLOAD -> {
BookmarkUpload(
ItemBlockBookmarkUploadingBinding.inflate(inflater, parent, false)
ItemBlockBookmarkUploadingBinding.inflate(inflater, parent, false)
)
}
HOLDER_PICTURE -> {
@ -710,7 +717,7 @@ class BlockAdapter(
else -> throw IllegalStateException("Unexpected view type: $viewType")
}
if (holder is Text) {
if (holder is Text<*>) {
holder.content.setOnDragListener(onDragListener)
holder.content.editorTouchProcessor.onLongClick = {
val pos = holder.bindingAdapterPosition
@ -747,6 +754,23 @@ class BlockAdapter(
onSelectionChanged(view.id, selection)
}
}
holder.setupViewHolder(
onTextChanged = { editable ->
holder.withBlock<BlockView.Text> { item ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
}
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onBackPressedCallback = onBackPressedCallback,
)
} else {
if (holder !is SupportCustomTouchProcessor) {
when (holder) {
@ -823,33 +847,21 @@ class BlockAdapter(
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is Bulleted -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is Checkbox -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is Title.Document -> {
@ -874,77 +886,49 @@ class BlockAdapter(
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
)
}
is HeaderOne -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is HeaderTwo -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
)
}
is HeaderThree -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
)
}
is Toggle -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is Highlight -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is Callout -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
item = blocks[position],
onTextChanged = onTextBlockTextChanged,
onSelectionChanged = onSelectionChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
clicked = onClickListener
)
}
is File -> {
@ -1140,130 +1124,16 @@ class BlockAdapter(
override fun onBindViewHolder(holder: BlockViewHolder, position: Int) {
if (isInDragAndDropMode) trySetDesiredAppearanceForDraggedItem(holder, position)
when (holder) {
is Paragraph -> {
holder.bind(
item = blocks[position] as BlockView.Text.Paragraph,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is HeaderOne -> {
holder.bind(
block = blocks[position] as BlockView.Text.Header.One,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is HeaderTwo -> {
holder.bind(
block = blocks[position] as BlockView.Text.Header.Two,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is HeaderThree -> {
holder.bind(
block = blocks[position] as BlockView.Text.Header.Three,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Checkbox -> {
holder.bind(
item = blocks[position] as BlockView.Text.Checkbox,
onTextBlockTextChanged = onTextBlockTextChanged,
onCheckboxClicked = onCheckboxClicked,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Bulleted -> {
holder.bind(
item = blocks[position] as BlockView.Text.Bulleted,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Numbered -> {
holder.bind(
item = blocks[position] as BlockView.Text.Numbered,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Toggle -> {
holder.bind(
item = blocks[position] as BlockView.Text.Toggle,
onTextBlockTextChanged = onTextBlockTextChanged,
onTogglePlaceholderClicked = onTogglePlaceholderClicked,
onToggleClicked = onToggleClicked,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Highlight -> {
holder.bind(
item = blocks[position] as BlockView.Text.Highlight,
onTextBlockTextChanged = onTextBlockTextChanged,
clicked = onClickListener,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Callout -> {
holder.bind(
item = blocks[position] as BlockView.Text.Callout,
onTextBlockTextChanged = onTextBlockTextChanged,
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
)
}
is Paragraph -> holder.bind(blocks[position] as BlockView.Text.Paragraph)
is HeaderOne -> holder.bind(blocks[position] as BlockView.Text.Header.One)
is HeaderTwo -> holder.bind(blocks[position] as BlockView.Text.Header.Two)
is HeaderThree -> holder.bind(blocks[position] as BlockView.Text.Header.Three)
is Checkbox -> holder.bind(blocks[position] as BlockView.Text.Checkbox )
is Bulleted -> holder.bind(blocks[position] as BlockView.Text.Bulleted)
is Numbered -> holder.bind(blocks[position] as BlockView.Text.Numbered)
is Toggle -> holder.bind(item = blocks[position] as BlockView.Text.Toggle)
is Highlight -> holder.bind(blocks[position] as BlockView.Text.Highlight)
is Callout -> holder.bind(blocks[position] as BlockView.Text.Callout)
is Title.Document -> {
holder.apply {
bind(
@ -1542,7 +1412,7 @@ class BlockAdapter(
}
}
if (holder is Text) {
if (holder is Text<*>) {
val block = blocks[position]
@ -1592,4 +1462,8 @@ class BlockAdapter(
holder.onDecorationsChanged(decorations = block.decorations)
}
}
override fun provide(pos: Int): BlockView {
return blocks[pos]
}
}

View file

@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_utils.ext.PopupExtensions
import com.anytypeio.anytype.presentation.editor.editor.BlockDimensions
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import timber.log.Timber
/**
* Viewholder for rendering different type of blocks (i.e its UI-models).
@ -50,3 +51,33 @@ open class BlockViewHolder(view: View) : RecyclerView.ViewHolder(view) {
clicked(ListenerType.LongClick(target, dimensions))
}
}
inline fun <reified R : BlockView> BlockViewHolder.withBlock(block: (R) -> Unit) {
val pos = bindingAdapterPosition
val adapter = bindingAdapter
if (pos != RecyclerView.NO_POSITION && adapter is ItemProviderAdapter<*>) {
val view = adapter.provide(pos)
if (view is R) {
block(view)
} else {
if (view != null) {
Timber.w("Unexpected type: ${view::class.simpleName}")
}
}
}
}
inline fun <reified R : BlockView> BlockViewHolder.provide() : R? {
val pos = bindingAdapterPosition
val adapter = bindingAdapter
return if (pos != RecyclerView.NO_POSITION && adapter is ItemProviderAdapter<*>) {
val view = adapter.provide(pos)
if (view is R) {
view
} else {
null
}
} else {
null
}
}

View file

@ -0,0 +1,5 @@
package com.anytypeio.anytype.core_ui.features.editor
interface ItemProviderAdapter<T> {
fun provide(pos: Int): T
}

View file

@ -2,7 +2,6 @@ package com.anytypeio.anytype.core_ui.features.editor
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.Editable
import android.text.Spannable
import android.view.ActionMode
import android.view.Menu
@ -26,7 +25,6 @@ import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewH
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
import com.anytypeio.anytype.core_ui.features.editor.holders.`interface`.TextHolder
import com.anytypeio.anytype.core_ui.tools.DefaultSpannableFactory
import com.anytypeio.anytype.core_ui.tools.DefaultTextWatcher
import com.anytypeio.anytype.core_ui.tools.MentionTextWatcher
import com.anytypeio.anytype.core_ui.tools.SlashTextWatcher
import com.anytypeio.anytype.core_ui.tools.SlashTextWatcherState
@ -219,41 +217,29 @@ interface TextBlockHolder : TextHolder {
}
}
fun setupTextWatcher(
item: BlockView,
onMentionEvent: ((MentionEvent) -> Unit),
onSlashEvent: (SlashEvent) -> Unit,
onTextChanged: (String, Editable) -> Unit,
) {
content.addTextChangedListener(
DefaultTextWatcher { text ->
onTextChanged(item.id, text)
}
)
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
fun setupMentionWatcher(
onMentionEvent: ((MentionEvent) -> Unit)
onMentionEvent: ((MentionEvent) -> Unit),
itemProvider: () -> BlockView.Text?
) {
content.addTextChangedListener(
MentionTextWatcher { state ->
when (state) {
is MentionTextWatcher.MentionTextWatcherState.Start -> {
onMentionEvent.invoke(
MentionEvent.MentionSuggestStart(
cursorCoordinate = content.cursorYBottomCoordinate(),
mentionStart = state.start
itemProvider().performInEditMode { item ->
when (state) {
is MentionTextWatcher.MentionTextWatcherState.Start -> {
onMentionEvent.invoke(
MentionEvent.MentionSuggestStart(
cursorCoordinate = content.cursorYBottomCoordinate(),
mentionStart = state.start
)
)
)
}
MentionTextWatcher.MentionTextWatcherState.Stop -> {
onMentionEvent.invoke(MentionEvent.MentionSuggestStop)
}
}
MentionTextWatcher.MentionTextWatcherState.Stop -> {
onMentionEvent.invoke(MentionEvent.MentionSuggestStop)
}
is MentionTextWatcher.MentionTextWatcherState.Text -> {
onMentionEvent.invoke(MentionEvent.MentionSuggestText(state.text))
is MentionTextWatcher.MentionTextWatcherState.Text -> {
onMentionEvent.invoke(MentionEvent.MentionSuggestText(state.text))
}
}
}
}
@ -262,24 +248,26 @@ interface TextBlockHolder : TextHolder {
fun setupSlashWatcher(
onSlashEvent: (SlashEvent) -> Unit,
viewType: Int
itemProvider: () -> BlockView.Text?
) {
content.addTextChangedListener(
SlashTextWatcher { state ->
when (state) {
is SlashTextWatcherState.Start -> onSlashEvent(
SlashEvent.Start(
slashStart = state.start,
cursorCoordinate = content.cursorYBottomCoordinate()
itemProvider().performInEditMode { item ->
when (state) {
is SlashTextWatcherState.Start -> onSlashEvent(
SlashEvent.Start(
slashStart = state.start,
cursorCoordinate = content.cursorYBottomCoordinate()
)
)
)
SlashTextWatcherState.Stop -> onSlashEvent(SlashEvent.Stop)
is SlashTextWatcherState.Filter -> onSlashEvent(
SlashEvent.Filter(
filter = state.text,
viewType = viewType
SlashTextWatcherState.Stop -> onSlashEvent(SlashEvent.Stop)
is SlashTextWatcherState.Filter -> onSlashEvent(
SlashEvent.Filter(
filter = state.text,
viewType = item.getViewType()
)
)
)
}
}
}
)
@ -289,11 +277,7 @@ interface TextBlockHolder : TextHolder {
fun processChangePayload(
payloads: List<BlockViewDiffUtil.Payload>,
item: BlockView,
onTextChanged: (BlockView.Text) -> Unit,
onSelectionChanged: (String, IntRange) -> Unit,
clicked: (ListenerType) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit
) = payloads.forEach { payload ->
check(item is BlockView.Text)
@ -347,19 +331,6 @@ interface TextBlockHolder : TextHolder {
if (payload.readWriteModeChanged()) {
content.pauseTextWatchers {
if (item.mode == BlockView.Mode.EDIT) {
content.clearTextWatchers()
setupTextWatcher(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextChanged(item)
},
onMentionEvent = onMentionEvent,
onSlashEvent = onSlashEvent
)
//content.selectionWatcher = { onSelectionChanged(item.id, it) }
content.pauseTextWatchers {
enableEditMode()
@ -392,10 +363,6 @@ interface TextBlockHolder : TextHolder {
}
}
fun clearTextWatchers() {
content.clearTextWatchers()
}
fun resolveTextBlockThemedColor(color: ThemeColor): Int {
return content.context.resolveThemedTextColor(color, getDefaultTextColor())
}
@ -500,4 +467,12 @@ interface TextBlockHolder : TextHolder {
}
//endregion
}
fun BlockView.Text?.performInEditMode(block: (BlockView.Text) -> Unit) {
this?.let { item ->
if (item.mode == BlockView.Mode.EDIT) {
block(item)
}
}
}

View file

@ -1,7 +1,6 @@
package com.anytypeio.anytype.core_ui.features.editor.holders.text
import android.graphics.drawable.Drawable
import android.text.Editable
import android.view.View
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
@ -17,18 +16,15 @@ import com.anytypeio.anytype.core_ui.extensions.dark
import com.anytypeio.anytype.core_ui.features.editor.SupportNesting
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
import com.anytypeio.anytype.core_ui.features.editor.marks
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.dimen
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.slash.SlashEvent
class Bulleted(
val binding: ItemBlockBulletedBinding,
clicked: (ListenerType) -> Unit,
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
) : Text<BlockView.Text.Bulleted>(binding.root, clicked), SupportNesting, DecoratableViewHolder {
val indent: View = binding.bulletIndent
val bullet = binding.bullet
@ -75,33 +71,6 @@ class Bulleted(
}
}
fun bind(
item: BlockView.Text.Bulleted,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
override fun getMentionIconSize(): Int = mentionIconSize
override fun getMentionIconPadding(): Int = mentionIconPadding
override fun getMentionCheckedIcon(): Drawable? = mentionCheckedIcon

View file

@ -30,7 +30,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
class Callout(
val binding: ItemBlockCalloutBinding,
clicked: (ListenerType) -> Unit,
) : Text(
) : Text <BlockView.Text.Callout>(
view = binding.root,
clicked = clicked
), BlockViewHolder.IndentableHolder, SupportNesting, DecoratableViewHolder {
@ -63,45 +63,21 @@ class Callout(
}
}
fun bind(
item: BlockView.Text.Callout,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
override fun bind(
item: BlockView.Text.Callout
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
item = item
).also {
icon.setIcon(item.icon)
icon.setOnClickListener {
clicked(ListenerType.Callout.Icon(item.id))
}
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
override fun processChangePayload(
payloads: List<BlockViewDiffUtil.Payload>,
item: BlockView,
onTextChanged: (BlockView.Text) -> Unit,
onSelectionChanged: (String, IntRange) -> Unit,
clicked: (ListenerType) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit
) {
val callout = requireNotNull(item as? BlockView.Text.Callout) {
"Failed to processChangePayload. $item must be Callout"
@ -114,11 +90,7 @@ class Callout(
super.processChangePayload(
payloads,
item,
onTextChanged,
onSelectionChanged,
clicked,
onMentionEvent,
onSlashEvent
)
}

View file

@ -1,7 +1,6 @@
package com.anytypeio.anytype.core_ui.features.editor.holders.text
import android.graphics.drawable.Drawable
import android.text.Editable
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
@ -15,20 +14,18 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockCheckboxBinding
import com.anytypeio.anytype.core_ui.features.editor.SupportNesting
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
import com.anytypeio.anytype.core_ui.features.editor.marks
import com.anytypeio.anytype.core_ui.features.editor.performInEditMode
import com.anytypeio.anytype.core_ui.features.editor.provide
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.dimen
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.slash.SlashEvent
class Checkbox(
val binding: ItemBlockCheckboxBinding,
clicked: (ListenerType) -> Unit,
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
var mode = BlockView.Mode.EDIT
clicked: (ListenerType) -> Unit
) : Text<BlockView.Text.Checkbox>(binding.root, clicked), SupportNesting,
DecoratableViewHolder {
val checkbox: ImageView = binding.checkboxIcon
private val container = binding.graphicPlusTextContainer
@ -74,42 +71,18 @@ class Checkbox(
}
}
fun bind(
override fun bind(
item: BlockView.Text.Checkbox,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onCheckboxClicked: (BlockView.Text.Checkbox) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
) = super.bind(item = item).also {
checkbox.isActivated = item.isChecked
setCheckboxClickListener(item, onCheckboxClicked)
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
private fun setCheckboxClickListener(
item: BlockView.Text.Checkbox,
fun setCheckboxClickListener(
onCheckboxClicked: (BlockView.Text.Checkbox) -> Unit
) {
checkbox.setOnClickListener {
if (mode == BlockView.Mode.EDIT) {
val item = provide<BlockView.Text.Checkbox>() ?: return@setOnClickListener
item.performInEditMode {
item.isChecked = !item.isChecked
checkbox.isActivated = !checkbox.isActivated
applyCheckedCheckboxColorSpan(item.isChecked)
@ -130,16 +103,6 @@ class Checkbox(
}
}
override fun enableEditMode() {
super.enableEditMode()
mode = BlockView.Mode.EDIT
}
override fun enableReadMode() {
super.enableReadMode()
mode = BlockView.Mode.READ
}
override fun select(item: BlockView.Selectable) {
container.isSelected = item.isSelected
}

View file

@ -1,6 +1,5 @@
package com.anytypeio.anytype.core_ui.features.editor.holders.text
import android.text.Editable
import android.view.View
import androidx.core.view.updatePadding
import com.anytypeio.anytype.core_ui.BuildConfig
@ -8,52 +7,21 @@ import com.anytypeio.anytype.core_ui.R
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.decoration.DecoratableViewHolder
import com.anytypeio.anytype.core_ui.features.editor.marks
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.dimen
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.slash.SlashEvent
abstract class Header(
abstract class Header<T : BlockView.Text.Header>(
view: View,
clicked: (ListenerType) -> Unit,
) : Text(view, clicked),
) : Text<T>(view, clicked),
TextBlockHolder,
BlockViewHolder.IndentableHolder,
DecoratableViewHolder
{
DecoratableViewHolder {
abstract val header: TextInputWidget
fun bind(
block: BlockView.Text.Header,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = block,
onTextChanged = { _, editable ->
block.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(block)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, block.getViewType())
}
override fun indentize(item: BlockView.Indentable) {
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
header.updatePadding(

View file

@ -16,7 +16,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HeaderOne(
val binding: ItemBlockHeaderOneBinding,
clicked: (ListenerType) -> Unit,
) : Header(binding.root, clicked) {
) : Header<BlockView.Text.Header.One>(binding.root, clicked) {
override val header: TextInputWidget = binding.headerOne
override val content: TextInputWidget get() = header

View file

@ -16,7 +16,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HeaderThree(
val binding: ItemBlockHeaderThreeBinding,
clicked: (ListenerType) -> Unit,
) : Header(binding.root, clicked) {
) : Header<BlockView.Text.Header.Three>(binding.root, clicked) {
override val header: TextInputWidget = binding.headerThree
override val content: TextInputWidget get() = header

View file

@ -16,7 +16,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HeaderTwo(
val binding: ItemBlockHeaderTwoBinding,
clicked: (ListenerType) -> Unit,
) : Header(binding.root, clicked) {
) : Header<BlockView.Text.Header.Two>(binding.root, clicked) {
override val header: TextInputWidget = binding.headerTwo
override val content: TextInputWidget get() = header

View file

@ -27,7 +27,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
class Highlight(
val binding: ItemBlockHighlightBinding,
clicked: (ListenerType) -> Unit,
) : Text(binding.root, clicked), BlockViewHolder.IndentableHolder, SupportNesting, DecoratableViewHolder {
) : Text<BlockView.Text.Highlight>(binding.root, clicked), BlockViewHolder.IndentableHolder, SupportNesting, DecoratableViewHolder {
override val content: TextInputWidget = binding.highlightContent
override val root: View = itemView
@ -75,34 +75,6 @@ class Highlight(
}
}
fun bind(
item: BlockView.Text.Highlight,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
clicked: (ListenerType) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
override fun select(item: BlockView.Selectable) {
container.isSelected = item.isSelected
}

View file

@ -1,7 +1,6 @@
package com.anytypeio.anytype.core_ui.features.editor.holders.text
import android.graphics.drawable.Drawable
import android.text.Editable
import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
@ -19,7 +18,6 @@ import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
import com.anytypeio.anytype.core_ui.features.editor.SupportNesting
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
import com.anytypeio.anytype.core_ui.features.editor.marks
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.addDot
import com.anytypeio.anytype.core_utils.ext.dimen
@ -31,7 +29,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
class Numbered(
val binding: ItemBlockNumberedBinding,
clicked: (ListenerType) -> Unit,
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
) : Text<BlockView.Text.Numbered>(binding.root, clicked), SupportNesting, DecoratableViewHolder {
private val container = binding.graphicPlusTextContainer
val number = binding.number
@ -77,32 +75,10 @@ class Numbered(
}
}
fun bind(
item: BlockView.Text.Numbered,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
override fun bind(
item: BlockView.Text.Numbered
) = super.bind(item = item).also {
setNumber(item)
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
private fun setNumber(item: BlockView.Text.Numbered) {
@ -122,20 +98,12 @@ class Numbered(
override fun processChangePayload(
payloads: List<BlockViewDiffUtil.Payload>,
item: BlockView,
onTextChanged: (BlockView.Text) -> Unit,
onSelectionChanged: (String, IntRange) -> Unit,
clicked: (ListenerType) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit
clicked: (ListenerType) -> Unit
) {
super.processChangePayload(
payloads,
item,
onTextChanged,
onSelectionChanged,
clicked,
onMentionEvent,
onSlashEvent
clicked
)
payloads.forEach { payload ->
if (payload.changes.contains(BlockViewDiffUtil.NUMBER_CHANGED))

View file

@ -25,7 +25,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
class Paragraph(
val binding: ItemBlockTextBinding,
clicked: (ListenerType) -> Unit,
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
) : Text<BlockView.Text.Paragraph>(binding.root, clicked), SupportNesting, DecoratableViewHolder {
override val root: View = binding.root
override val content: TextInputWidget = binding.textContent
@ -64,33 +64,6 @@ class Paragraph(
}
}
fun bind(
item: BlockView.Text.Paragraph,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
override fun getMentionIconSize(): Int = mentionIconSize
override fun getMentionIconPadding(): Int = mentionIconPadding
override fun getMentionCheckedIcon(): Drawable? = mentionCheckedIcon

View file

@ -2,31 +2,31 @@ 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_ui.R
import com.anytypeio.anytype.core_ui.extensions.applyMovementMethod
import com.anytypeio.anytype.core_ui.extensions.color
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
abstract class Text(
abstract class Text<BlockTextType : BlockView.Text>(
view: View,
protected val clicked: (ListenerType) -> Unit,
protected val clicked: (ListenerType) -> Unit
) : BlockViewHolder(view), TextBlockHolder, BlockViewHolder.IndentableHolder,
BlockViewHolder.DragAndDropHolder {
private val defTextColor: Int = itemView.context.resources.getColor(R.color.text_primary, null)
fun bind(
item: BlockView.TextBlockProps,
onTextChanged: (String, Editable) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: (() -> Boolean)? = null
open fun bind(
item: BlockTextType,
) {
indentize(item)
select(item)
@ -47,8 +47,6 @@ abstract class Text(
content.applyMovementMethod(item)
clearTextWatchers()
setContent(
item = item,
clicked = clicked
@ -58,39 +56,6 @@ abstract class Text(
if (item.isFocused) setCursor(item)
setFocus(item)
observe(
item = item,
onTextChanged = onTextChanged,
onBackPressedCallback = onBackPressedCallback
)
}
content.apply {
enableEnterKeyDetector(
onEnterClicked = { range ->
content.text?.let { editable ->
onSplitLineEnterClicked(
item.id,
editable,
range
)
}
}
)
enableBackspaceDetector(
onEmptyBlockBackspaceClicked = {
onEmptyBlockBackspaceClicked(item.id)
},
onNonEmptyBlockBackspaceClicked = {
content.text?.let { editable ->
onNonEmptyBlockBackspaceClicked(
item.id,
editable
)
}
}
)
}
}
@ -119,16 +84,16 @@ abstract class Text(
setBackgroundColor(background = item.background)
}
fun observe(
item: BlockView.TextBlockProps,
onTextChanged: (String, Editable) -> Unit,
private fun observe(
onTextChanged: (Editable) -> Unit,
onBackPressedCallback: (() -> Boolean)? = null
) {
content.apply {
addTextChangedListener(
DefaultTextWatcher { text ->
onTextChanged(item.id, text)
provide<BlockView.Text>().performInEditMode { item ->
onTextChanged(text)
}
}
)
backButtonWatcher = onBackPressedCallback
@ -144,4 +109,47 @@ abstract class Text(
}
override fun getDefaultTextColor(): Int = defTextColor
@CallSuper
open fun setupViewHolder(
onTextChanged: (Editable) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onMentionEvent: ((MentionEvent) -> Unit),
onSlashEvent: (SlashEvent) -> Unit,
onBackPressedCallback: (() -> Boolean)? = null
) {
observe(onTextChanged, onBackPressedCallback)
content.apply {
enableEnterKeyDetector(
onEnterClicked = { range ->
val id = provide<BlockView.Text>()?.id ?: return@enableEnterKeyDetector
val editable = content.text ?: return@enableEnterKeyDetector
onSplitLineEnterClicked(
id,
editable,
range
)
}
)
enableBackspaceDetector(
onEmptyBlockBackspaceClicked = {
val id = provide<BlockView.Text>()?.id ?: return@enableBackspaceDetector
onEmptyBlockBackspaceClicked(id)
},
onNonEmptyBlockBackspaceClicked = {
val id = provide<BlockView.Text>()?.id ?: return@enableBackspaceDetector
val editable = content.text ?: return@enableBackspaceDetector
onNonEmptyBlockBackspaceClicked(
id,
editable
)
}
)
}
setupMentionWatcher(onMentionEvent) { provide() }
setupSlashWatcher(onSlashEvent) { provide() }
}
}

View file

@ -1,7 +1,6 @@
package com.anytypeio.anytype.core_ui.features.editor.holders.text
import android.graphics.drawable.Drawable
import android.text.Editable
import android.view.View
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
@ -16,7 +15,7 @@ import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
import com.anytypeio.anytype.core_ui.features.editor.SupportNesting
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
import com.anytypeio.anytype.core_ui.features.editor.marks
import com.anytypeio.anytype.core_ui.features.editor.provide
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.dimen
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
@ -27,7 +26,7 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
class Toggle(
val binding: ItemBlockToggleBinding,
clicked: (ListenerType) -> Unit,
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
) : Text<BlockView.Text.Toggle>(binding.root, clicked), SupportNesting, DecoratableViewHolder {
private var mode = BlockView.Mode.EDIT
@ -77,41 +76,29 @@ class Toggle(
}
}
fun bind(
item: BlockView.Text.Toggle,
onTextBlockTextChanged: (BlockView.Text) -> Unit,
onToggleClicked: (String) -> Unit,
onTogglePlaceholderClicked: (String) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit,
onEmptyBlockBackspaceClicked: (String) -> Unit,
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit,
onBackPressedCallback: () -> Boolean
) = super.bind(
item = item,
onTextChanged = { _, editable ->
item.apply {
text = editable.toString()
marks = editable.marks()
}
onTextBlockTextChanged(item)
},
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onBackPressedCallback = onBackPressedCallback
).also {
override fun bind(
item: BlockView.Text.Toggle
) = super.bind(item = item).also {
toggle.rotation = if (item.toggled) EXPANDED_ROTATION else COLLAPSED_ROTATION
if (item.mode == BlockView.Mode.READ) {
placeholder.isVisible = false
} else {
placeholder.isVisible = item.isEmpty && item.toggled
}
placeholder.setOnClickListener { onTogglePlaceholderClicked(item.id) }
toggle.setOnClickListener { onToggleClicked(item.id) }
setupMentionWatcher(onMentionEvent)
setupSlashWatcher(onSlashEvent, item.getViewType())
}
fun setupToggle(
onToggleClicked: (String) -> Unit,
onTogglePlaceholderClicked: (String) -> Unit
) {
placeholder.setOnClickListener {
val id = provide<BlockView.Text.Toggle>()?.id ?: return@setOnClickListener
onTogglePlaceholderClicked(id)
}
toggle.setOnClickListener {
val id = provide<BlockView.Text.Toggle>()?.id ?: return@setOnClickListener
onToggleClicked(id)
}
}
override fun getMentionIconSize(): Int = mentionIconSize
@ -143,21 +130,13 @@ class Toggle(
override fun processChangePayload(
payloads: List<BlockViewDiffUtil.Payload>,
item: BlockView,
onTextChanged: (BlockView.Text) -> Unit,
onSelectionChanged: (String, IntRange) -> Unit,
clicked: (ListenerType) -> Unit,
onMentionEvent: (MentionEvent) -> Unit,
onSlashEvent: (SlashEvent) -> Unit
clicked: (ListenerType) -> Unit
) {
check(item is BlockView.Text.Toggle) { "Expected a toggle block, but was: $item" }
super.processChangePayload(
payloads,
item,
onTextChanged,
onSelectionChanged,
clicked,
onMentionEvent,
onSlashEvent
)
payloads.forEach { payload ->
if (payload.isToggleStateChanged) {

View file

@ -119,7 +119,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -145,7 +145,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -180,7 +180,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -218,7 +218,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -244,11 +244,7 @@ class BlockAdapterTest {
changes = listOf(TEXT_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -275,7 +271,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -301,11 +297,7 @@ class BlockAdapterTest {
changes = listOf(BACKGROUND_COLOR_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
@ -334,7 +326,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -360,11 +352,7 @@ class BlockAdapterTest {
changes = listOf(TEXT_COLOR_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
val expected = context.resources.getColor(R.color.palette_dark_lime)
@ -392,7 +380,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -428,11 +416,7 @@ class BlockAdapterTest {
changes = listOf(CURSOR_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -465,7 +449,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -518,7 +502,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(
val adapter = givenAdapter(
views = views,
onTextChanged = { id, editable ->
events.add(Pair(id, editable.toString()))
@ -561,7 +545,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(
val adapter = givenAdapter(
views = views,
onTextChanged = { id, editable ->
events.add(Pair(id, editable.toString()))
@ -587,11 +571,7 @@ class BlockAdapterTest {
)
),
item = updated,
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -611,7 +591,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -638,7 +618,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -677,7 +657,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -726,7 +706,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(
val adapter = givenAdapter(
views = views,
onFocusChanged = { id, hasFocus ->
events.add(Pair(id, hasFocus))
@ -775,7 +755,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(
val adapter = givenAdapter(
views = views,
onTextChanged = { id, editable ->
events.add(Pair(id, editable.toString()))
@ -819,7 +799,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, HOLDER_PARAGRAPH)
@ -853,7 +833,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_HEADER_ONE)
@ -886,7 +866,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_HEADER_TWO)
@ -921,7 +901,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_HEADER_THREE)
@ -951,7 +931,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_CHECKBOX)
@ -984,7 +964,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_TOGGLE)
@ -1013,7 +993,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_FILE_PLACEHOLDER)
@ -1046,7 +1026,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_FILE_ERROR)
@ -1075,7 +1055,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_FILE_UPLOAD)
@ -1102,7 +1082,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO)
@ -1129,7 +1109,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO_PLACEHOLDER)
@ -1161,7 +1141,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO_UPLOAD)
@ -1194,7 +1174,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO_ERROR)
@ -1226,7 +1206,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_OBJECT_LINK_DEFAULT)
@ -1252,7 +1232,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_BOOKMARK_PLACEHOLDER)
@ -1262,7 +1242,8 @@ class BlockAdapterTest {
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
val actual = holder.itemView.findViewById<ViewGroup>(R.id.root).paddingLeft
val expected = view.indent * holder.dimen(R.dimen.indent) + holder.dimen(R.dimen.default_document_item_padding_start)
val expected =
view.indent * holder.dimen(R.dimen.indent) + holder.dimen(R.dimen.default_document_item_padding_start)
assertEquals(expected, actual)
} else {
val actual = holder.itemView.findViewById<ViewGroup>(R.id.root).paddingLeft
@ -1291,7 +1272,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_PICTURE)
@ -1320,7 +1301,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_PICTURE_PLACEHOLDER)
@ -1353,7 +1334,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_PICTURE_ERROR)
@ -1384,7 +1365,7 @@ class BlockAdapterTest {
layoutManager = LinearLayoutManager(context)
}
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_PICTURE_UPLOAD)
@ -1394,7 +1375,8 @@ class BlockAdapterTest {
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
val actual = holder.itemView.marginLeft
val expected = holder.dimen(R.dimen.bookmark_default_margin_start) + view.indent * holder.dimen(R.dimen.indent)
val expected =
holder.dimen(R.dimen.bookmark_default_margin_start) + view.indent * holder.dimen(R.dimen.indent)
assertEquals(expected, actual)
}
}
@ -1416,7 +1398,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1467,7 +1449,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1606,7 +1588,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1652,7 +1634,7 @@ class BlockAdapterTest {
val views = listOf(firstParagraph, secondParagraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1686,7 +1668,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1730,7 +1712,7 @@ class BlockAdapterTest {
val views = listOf(paragraph)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1763,11 +1745,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -1795,7 +1773,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1836,7 +1814,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1879,7 +1857,7 @@ class BlockAdapterTest {
val views = listOf(title)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -1951,7 +1929,7 @@ class BlockAdapterTest {
val views: List<BlockView> = listOf(h1, h2, h3)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2064,7 +2042,7 @@ class BlockAdapterTest {
h3Notselected
)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2135,7 +2113,7 @@ class BlockAdapterTest {
val views: List<BlockView> = listOf(h1, h2, h3)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2226,7 +2204,7 @@ class BlockAdapterTest {
val views: List<BlockView> = listOf(h1, h2, h3)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2265,11 +2243,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2301,11 +2275,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2337,11 +2307,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2369,7 +2335,7 @@ class BlockAdapterTest {
val views = listOf(highlight)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2411,7 +2377,7 @@ class BlockAdapterTest {
val views = listOf(highlight)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2437,11 +2403,7 @@ class BlockAdapterTest {
changes = listOf(TEXT_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2463,7 +2425,7 @@ class BlockAdapterTest {
val views = listOf(highlight)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2505,7 +2467,7 @@ class BlockAdapterTest {
val views = listOf(highlight)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2536,11 +2498,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2568,7 +2526,7 @@ class BlockAdapterTest {
val views = listOf(bullet)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2607,7 +2565,7 @@ class BlockAdapterTest {
val views = listOf(bullet)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2650,7 +2608,7 @@ class BlockAdapterTest {
val views = listOf(bullet)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2681,11 +2639,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2713,7 +2667,7 @@ class BlockAdapterTest {
val views = listOf(checkbox)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2752,7 +2706,7 @@ class BlockAdapterTest {
val views = listOf(checkbox)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2795,7 +2749,7 @@ class BlockAdapterTest {
val views = listOf(checkbox)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2826,11 +2780,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -2859,7 +2809,7 @@ class BlockAdapterTest {
val views = listOf(numbered)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2899,7 +2849,7 @@ class BlockAdapterTest {
val views = listOf(numbered)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2943,7 +2893,7 @@ class BlockAdapterTest {
val views = listOf(numbered)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -2974,11 +2924,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -3008,7 +2954,7 @@ class BlockAdapterTest {
val views = listOf(toggle)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -3049,7 +2995,7 @@ class BlockAdapterTest {
val views = listOf(toggle)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -3094,7 +3040,7 @@ class BlockAdapterTest {
val views = listOf(toggle)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -3125,11 +3071,7 @@ class BlockAdapterTest {
changes = listOf(READ_WRITE_MODE_CHANGED)
)
),
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -3173,7 +3115,7 @@ class BlockAdapterTest {
)
)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -3214,7 +3156,7 @@ class BlockAdapterTest {
val views = listOf(file)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -3257,7 +3199,7 @@ class BlockAdapterTest {
val views = listOf(file)
val adapter = buildAdapter(views)
val adapter = givenAdapter(views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
@ -3296,7 +3238,7 @@ class BlockAdapterTest {
val lifecycle = TestLifecycle()
val adapter = buildAdapter(listOf(givenVideo()), lifecycle = lifecycle)
val adapter = givenAdapter(listOf(givenVideo()), lifecycle = lifecycle)
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO)
@ -3318,7 +3260,7 @@ class BlockAdapterTest {
val recycler = givenRecycler()
val adapter = buildAdapter(listOf(givenVideo()))
val adapter = givenAdapter(listOf(givenVideo()))
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO)
@ -3345,7 +3287,7 @@ class BlockAdapterTest {
val recycler = givenRecycler()
val adapter = buildAdapter(listOf(givenVideo()))
val adapter = givenAdapter(listOf(givenVideo()))
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO)
@ -3372,7 +3314,7 @@ class BlockAdapterTest {
val recycler = givenRecycler()
val adapter = buildAdapter(listOf(givenVideo()))
val adapter = givenAdapter(listOf(givenVideo()))
val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_VIDEO)
@ -3403,7 +3345,7 @@ class BlockAdapterTest {
val runs = mutableListOf<PerformanceTestsResults>()
givenPerformancePackageList().forEach { pack ->
val adapter = buildAdapter(listOf(pack.block))
val adapter = givenAdapter(listOf(pack.block))
val holder = adapter.onCreateViewHolder(recycler, pack.holderId)
check(holder.javaClass.canonicalName == pack.className)
@ -3440,7 +3382,12 @@ class BlockAdapterTest {
givenPicture(),
Picture::class.qualifiedName!!
),
PerformancePackage(Types.HOLDER_TITLE, "Title", givenTitle(), Document::class.qualifiedName!!)
PerformancePackage(
Types.HOLDER_TITLE,
"Title",
givenTitle(),
Document::class.qualifiedName!!
)
)
private fun givenRecycler() = RecyclerView(context).apply {
@ -3476,12 +3423,13 @@ class BlockAdapterTest {
decorations = emptyList()
)
private fun buildAdapter(
private fun givenAdapter(
views: List<BlockView>,
onSplitLineEnterClicked: (String, Editable, IntRange) -> Unit = { _, _, _ -> },
onFocusChanged: (String, Boolean) -> Unit = { _, _ -> },
onTitleBlockTextChanged: (Id, String) -> Unit = { _, _ -> },
onTextChanged: (String, Editable) -> Unit = { _, _ -> },
onToggleClicked: (String) -> Unit = {},
lifecycle: Lifecycle = TestLifecycle()
): BlockAdapter {
return BlockAdapter(
@ -3498,7 +3446,7 @@ class BlockAdapterTest {
onTextInputClicked = {},
onPageIconClicked = {},
onTogglePlaceholderClicked = {},
onToggleClicked = {},
onToggleClicked = onToggleClicked,
onTextBlockTextChanged = {},
onTitleBlockTextChanged = onTitleBlockTextChanged,
onTitleTextInputClicked = {},

View file

@ -237,11 +237,7 @@ class HeaderBlockTest {
)
),
item = updated,
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -295,11 +291,7 @@ class HeaderBlockTest {
)
),
item = updated,
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -353,11 +345,7 @@ class HeaderBlockTest {
)
),
item = updated,
onSelectionChanged = { _, _ -> },
onTextChanged = {},
clicked = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(

View file

@ -129,49 +129,6 @@ class BlockAdapterCheckboxTest : BlockAdapterTestSetup() {
)
}
@Test
fun `should not have checkboxhighlight span when turn ckeckbox from true to false`() {
val checkbox = BlockView.Text.Checkbox(
id = MockDataFactory.randomUuid(),
text = MockDataFactory.randomString(),
isFocused = true,
isChecked = true
)
val views = listOf(checkbox)
val adapter = buildAdapter(views = views)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_CHECKBOX)
adapter.onBindViewHolder(holder, 0)
// TESTING
check(holder is Checkbox)
val spans = holder.content.text!!.getSpans<CheckedCheckboxColorSpan>(0)
assertEquals(
expected = 1,
actual = spans.size
)
holder.checkbox.performClick()
val spansAfter = holder.content.text!!.getSpans<CheckedCheckboxColorSpan>(0)
assertEquals(
expected = 0,
actual = spansAfter.size
)
}
@Test
fun `should have checkboxhighlight when payload text changed and is checked`() {
@ -209,10 +166,6 @@ class BlockAdapterCheckboxTest : BlockAdapterTestSetup() {
payloads = listOf(BlockViewDiffUtil.Payload(changes = listOf(BlockViewDiffUtil.TEXT_CHANGED))),
item = checkbox.copy(text = "$text Second"),
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -266,10 +219,6 @@ class BlockAdapterCheckboxTest : BlockAdapterTestSetup() {
)
),
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -323,10 +272,6 @@ class BlockAdapterCheckboxTest : BlockAdapterTestSetup() {
)
),
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -372,10 +317,6 @@ class BlockAdapterCheckboxTest : BlockAdapterTestSetup() {
payloads = listOf(BlockViewDiffUtil.Payload(changes = listOf(BlockViewDiffUtil.TEXT_CHANGED))),
item = checkbox.copy(text = "$text Second"),
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(
@ -420,10 +361,6 @@ class BlockAdapterCheckboxTest : BlockAdapterTestSetup() {
payloads = listOf(BlockViewDiffUtil.Payload(changes = listOf(BlockViewDiffUtil.TEXT_CHANGED))),
item = checkbox.copy(text = "$text Second"),
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
assertEquals(

View file

@ -264,10 +264,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -338,10 +334,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -412,10 +404,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -487,10 +475,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -561,10 +545,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -636,10 +616,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -716,10 +692,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -797,10 +769,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -879,10 +847,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = updated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod
@ -949,10 +913,6 @@ class BlockAdapterMovementMethodTest : BlockAdapterTestSetup() {
),
item = paragraphUpdated,
clicked = {},
onSelectionChanged = { _, _ -> },
onTextChanged = {},
onMentionEvent = {},
onSlashEvent = {}
)
val testMM = holder.content.movementMethod

View file

@ -18,6 +18,7 @@ import com.anytypeio.anytype.test_utils.MockDataFactory
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
@ -27,348 +28,6 @@ import kotlin.test.assertTrue
@Config(sdk = [Build.VERSION_CODES.P])
@RunWith(RobolectricTestRunner::class)
class BlockAdapterReadWriteModeTest : BlockAdapterTestSetup() {
@Test
fun `endline-enter press listener should be enabled when switching from read to edit mode`() {
// Setup
var trigger = 0
val block = BlockView.Text.Paragraph(
mode = BlockView.Mode.READ,
text = MockDataFactory.randomString(),
id = MockDataFactory.randomUuid()
)
val views = listOf(block)
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = block.text.length,
isFocused = true
)
)
val adapter = buildAdapter(
views = views,
onSplitLineEnterClicked = { _, _, _ -> trigger += 1 }
)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
this.adapter = adapter
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_PARAGRAPH)
check(holder is Paragraph)
// Testing
adapter.onBindViewHolder(holder, 0)
val payloads: MutableList<Any> = mutableListOf(
BlockViewDiffUtil.Payload(
changes = listOf(
BlockViewDiffUtil.READ_WRITE_MODE_CHANGED,
BlockViewDiffUtil.FOCUS_CHANGED,
BlockViewDiffUtil.CURSOR_CHANGED
)
)
)
adapter.updateWithDiffUtil(items = updated)
adapter.onBindViewHolder(holder, 0, payloads = payloads)
holder.content.onEditorAction(EditorInfo.IME_ACTION_GO)
assertEquals(
expected = 1,
actual = trigger
)
}
@Test
fun `split-line-enter press listener should be enabled when switching from read to edit mode`() {
// Setup
var trigger = 0
val block = BlockView.Text.Paragraph(
mode = BlockView.Mode.READ,
text = MockDataFactory.randomString(),
id = MockDataFactory.randomUuid(),
cursor = null
)
val views = listOf(block)
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = 5,
isFocused = true
)
)
val adapter = buildAdapter(
views = views,
onSplitLineEnterClicked = { _, _, _ -> trigger += 1 }
)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
this.adapter = adapter
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_PARAGRAPH)
check(holder is Paragraph)
// Testing
adapter.onBindViewHolder(holder, 0)
val payloads: MutableList<Any> = mutableListOf(
BlockViewDiffUtil.Payload(
changes = listOf(
BlockViewDiffUtil.READ_WRITE_MODE_CHANGED,
BlockViewDiffUtil.FOCUS_CHANGED,
BlockViewDiffUtil.CURSOR_CHANGED
)
)
)
adapter.updateWithDiffUtil(items = updated)
adapter.onBindViewHolder(holder, 0, payloads = payloads)
assertEquals(
expected = 5,
actual = holder.content.selectionStart
)
holder.content.onEditorAction(EditorInfo.IME_ACTION_GO)
assertEquals(
expected = 1,
actual = trigger
)
}
@Test
fun `on-non-empty-block-backspace-press listener should be enabled when switching from read to edit mode`() {
// Setup
var trigger = 0
val block = BlockView.Text.Paragraph(
mode = BlockView.Mode.READ,
text = MockDataFactory.randomString(),
id = MockDataFactory.randomUuid(),
cursor = null
)
val views = listOf(block)
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = 0,
isFocused = true
)
)
val adapter = buildAdapter(
views = views,
onNonEmptyBlockBackspaceClicked = { _, _ -> trigger += 1 }
)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
this.adapter = adapter
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_PARAGRAPH)
check(holder is Paragraph)
// Testing
adapter.onBindViewHolder(holder, 0)
val payloads: MutableList<Any> = mutableListOf(
BlockViewDiffUtil.Payload(
changes = listOf(
BlockViewDiffUtil.READ_WRITE_MODE_CHANGED,
BlockViewDiffUtil.FOCUS_CHANGED,
BlockViewDiffUtil.CURSOR_CHANGED
)
)
)
adapter.updateWithDiffUtil(items = updated)
adapter.onBindViewHolder(holder, 0, payloads = payloads)
assertEquals(
expected = 0,
actual = holder.content.selectionStart
)
holder.content.dispatchKeyEvent(
KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
)
assertEquals(
expected = 1,
actual = trigger
)
}
@Test
fun `on-empty-block-backspace-press listener should be enabled when switching from read to edit mode`() {
// Setup
var trigger = 0
val block = BlockView.Text.Paragraph(
mode = BlockView.Mode.READ,
text = "",
id = MockDataFactory.randomUuid(),
cursor = null
)
val views = listOf(block)
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = 0,
isFocused = true
)
)
val adapter = buildAdapter(
views = views,
onEmptyBlockBackspaceClicked = { trigger += 1 }
)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
this.adapter = adapter
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_PARAGRAPH)
check(holder is Paragraph)
// Testing
adapter.onBindViewHolder(holder, 0)
val payloads: MutableList<Any> = mutableListOf(
BlockViewDiffUtil.Payload(
changes = listOf(
BlockViewDiffUtil.READ_WRITE_MODE_CHANGED,
BlockViewDiffUtil.FOCUS_CHANGED,
BlockViewDiffUtil.CURSOR_CHANGED
)
)
)
adapter.updateWithDiffUtil(items = updated)
adapter.onBindViewHolder(holder, 0, payloads = payloads)
assertEquals(
expected = 0,
actual = holder.content.selectionStart
)
holder.content.dispatchKeyEvent(
KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
)
assertEquals(
expected = 1,
actual = trigger
)
}
@Test
fun `checkbox-clicked listener should be enabled when switching from read to edit mode`() {
// Setup
var trigger = 0
val block = BlockView.Text.Checkbox(
mode = BlockView.Mode.READ,
text = MockDataFactory.randomString(),
id = MockDataFactory.randomUuid(),
isChecked = false
)
val views = listOf(block)
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT
)
)
val adapter = buildAdapter(
views = views,
onCheckboxClicked = { trigger += 1 }
)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
this.adapter = adapter
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_CHECKBOX)
check(holder is Checkbox)
// Testing
adapter.onBindViewHolder(holder, 0)
holder.checkbox.performClick()
assertEquals(
expected = 0,
actual = trigger
)
val payloads: MutableList<Any> = mutableListOf(
BlockViewDiffUtil.Payload(
changes = listOf(
BlockViewDiffUtil.READ_WRITE_MODE_CHANGED
)
)
)
adapter.updateWithDiffUtil(items = updated)
adapter.onBindViewHolder(holder, 0, payloads = payloads)
holder.checkbox.performClick()
assertEquals(
expected = 1,
actual = trigger
)
}
/**
* Scenario:
* 1. Text block[bold, link spans] EDIT mode

View file

@ -1,91 +0,0 @@
package com.anytypeio.anytype.core_ui.features.editor
import android.os.Build
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Toggle
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_TOGGLE
import com.anytypeio.anytype.test_utils.MockDataFactory
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.assertEquals
@Config(sdk = [Build.VERSION_CODES.P])
@RunWith(RobolectricTestRunner::class)
class BlockAdapterToggleTest : BlockAdapterTestSetup() {
@Test
fun `toggle click should be intercepted when switching from read to edit mode`() {
// Setup
var triggerCount = 0
val text = MockDataFactory.randomString()
val block = BlockView.Text.Toggle(
mode = BlockView.Mode.READ,
text = text,
id = MockDataFactory.randomUuid(),
isFocused = false
)
val views = listOf(block)
val adapter = buildAdapter(
views = views,
onToggleClicked = { triggerCount = triggerCount.inc() }
)
val recycler = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context)
}
val holder = adapter.onCreateViewHolder(recycler, HOLDER_TOGGLE)
adapter.onBindViewHolder(holder, 0)
// TESTING
check(holder is Toggle)
// Performing click in read-mode
holder.toggle.performClick()
assertEquals(
actual = triggerCount,
expected = 1
)
// Updating views
adapter.updateWithDiffUtil(
listOf(
block.copy(
mode = BlockView.Mode.EDIT
)
)
)
val payload: MutableList<Any> = mutableListOf(
BlockViewDiffUtil.Payload(
changes = listOf(BlockViewDiffUtil.READ_WRITE_MODE_CHANGED)
)
)
adapter.onBindViewHolder(holder, 0, payload)
// Performing click in edit mode
holder.toggle.performClick()
assertEquals(
actual = triggerCount,
expected = 2
)
}
}

View file

@ -0,0 +1,148 @@
package com.anytypeio.anytype.core_ui.uitests
import android.content.Context
import android.os.Build
import android.widget.EditText
import androidx.core.text.getSpans
import androidx.fragment.app.Fragment
import androidx.fragment.app.testing.FragmentScenario
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.CheckedCheckboxColorSpan
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.test_utils.MockDataFactory
import com.anytypeio.anytype.test_utils.TestFragment
import com.anytypeio.anytype.test_utils.utils.onItemView
import com.anytypeio.anytype.test_utils.utils.performClick
import com.anytypeio.anytype.test_utils.utils.rVMatcher
import com.anytypeio.anytype.test_utils.utils.view_action.extractView
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.assertEquals
import com.anytypeio.anytype.test_utils.R as R_test
@RunWith(RobolectricTestRunner::class)
@Config(
manifest = Config.NONE,
sdk = [Build.VERSION_CODES.P],
instrumentedPackages = [
// required to access final members on androidx.loader.content.ModernAsyncTask
"androidx.loader.content"
]
)
class BlockAdapterCheckboxTest {
private val context: Context = ApplicationProvider.getApplicationContext()
lateinit var scenario: FragmentScenario<TestFragment>
@Before
fun setUp() {
context.setTheme(R.style.Theme_MaterialComponents)
scenario = launchFragmentInContainer()
}
@Test
fun `should not have checkbox highlight span - when turn checkbox from true to false`() {
scenario.onFragment {
val recycler = givenRecycler(it)
val block = givenCheckbox()
val adapter = givenAdapter(listOf(block))
recycler.adapter = adapter
R_test.id.recycler.rVMatcher().apply {
val spans =
onItemView(
0,
R.id.checkboxContent
).extractView<EditText>().text.getSpans<CheckedCheckboxColorSpan>(0)
assertEquals(
expected = 1,
actual = spans.size
)
onItemView(0, R.id.checkboxIcon).performClick()
val spansAfter =
onItemView(0, R.id.checkboxContent).extractView<EditText>().text
.getSpans<CheckedCheckboxColorSpan>(0)
assertEquals(
expected = 0,
actual = spansAfter.size
)
}
}
}
@Test
fun `checkbox-clicked listener should be enabled - when switching from read to edit mode`() {
scenario.onFragment {
var trigger = 0
val recycler = givenRecycler(it)
val block = givenCheckbox(BlockView.Mode.READ)
val adapter = givenAdapter(
views = listOf(block),
onCheckboxClicked = { trigger++ }
)
recycler.adapter = adapter
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.checkboxIcon).performClick()
assertEquals(
expected = 0,
actual = trigger
)
}
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT
)
)
adapter.updateWithDiffUtil(items = updated)
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.checkboxIcon).performClick()
assertEquals(
expected = 1,
actual = trigger
)
}
}
}
private fun givenRecycler(it: Fragment): RecyclerView =
it.view!!.findViewById<RecyclerView>(R_test.id.recycler).apply {
layoutManager = LinearLayoutManager(context)
}
private fun givenCheckbox(mode: BlockView.Mode = BlockView.Mode.EDIT) = BlockView.Text.Checkbox(
id = MockDataFactory.randomUuid(),
text = MockDataFactory.randomString(),
isFocused = true,
isChecked = true,
mode = mode
)
}

View file

@ -0,0 +1,246 @@
package com.anytypeio.anytype.core_ui.uitests
import android.content.Context
import android.os.Build
import android.view.KeyEvent
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.fragment.app.testing.FragmentScenario
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.action.ViewActions
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.test_utils.MockDataFactory
import com.anytypeio.anytype.test_utils.TestFragment
import com.anytypeio.anytype.test_utils.utils.onItemView
import com.anytypeio.anytype.test_utils.utils.rVMatcher
import com.anytypeio.anytype.test_utils.utils.view_action.extractView
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.assertEquals
import com.anytypeio.anytype.test_utils.R as R_test
@RunWith(RobolectricTestRunner::class)
@Config(
manifest = Config.NONE,
sdk = [Build.VERSION_CODES.P],
instrumentedPackages = [
// required to access final members on androidx.loader.content.ModernAsyncTask
"androidx.loader.content"
]
)
class BlockAdapterReadWriteModeTest {
private val context: Context = ApplicationProvider.getApplicationContext()
lateinit var scenario: FragmentScenario<TestFragment>
@Before
fun setUp() {
context.setTheme(R.style.Theme_MaterialComponents)
scenario = launchFragmentInContainer()
}
@Test
fun `split-line-enter press listener should be enabled - when switching from read to edit mode`() {
scenario.onFragment {
var trigger = 0
val recycler = givenRecycler(it)
val block = givenParagraph()
val adapter = givenAdapter(
views = listOf(block),
onSplitLineEnterClicked = { _, _, _ -> trigger++ }
)
recycler.adapter = adapter
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = 5,
isFocused = true
)
)
adapter.updateWithDiffUtil(items = updated)
R_test.id.recycler.rVMatcher().apply {
val selectionStart =
onItemView(0, R.id.textContent).extractView<TextView>().selectionStart
assertEquals(
expected = 5,
actual = selectionStart
)
onItemView(0, R.id.textContent).perform(ViewActions.pressImeActionButton())
assertEquals(
expected = 1,
actual = trigger
)
}
}
}
@Test
fun `endline-enter press listener should be enabled - when switching from read to edit mode`() {
scenario.onFragment {
var trigger = 0
val recycler = givenRecycler(it)
val block = givenParagraph()
val adapter = givenAdapter(
views = listOf(block),
onSplitLineEnterClicked = { _, _, _ -> trigger++ }
)
recycler.adapter = adapter
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = block.text.length,
isFocused = true
)
)
adapter.updateWithDiffUtil(items = updated)
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.textContent).perform(ViewActions.pressImeActionButton())
assertEquals(
expected = 1,
actual = trigger
)
}
}
}
@Test
fun `on-non-empty-block-backspace-press listener should be enabled - when switching from read to edit mode`() {
scenario.onFragment {
var trigger = 0
val recycler = givenRecycler(it)
val block = givenParagraph()
val adapter = givenAdapter(
views = listOf(block),
onNonEmptyBlockBackspaceClicked = { _, _ -> trigger++ }
)
recycler.adapter = adapter
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.textContent).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL))
assertEquals(
expected = 0,
actual = trigger
)
}
val updated = listOf(
block.copy(
mode = BlockView.Mode.EDIT,
cursor = 0,
isFocused = true
)
)
adapter.updateWithDiffUtil(items = updated)
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.textContent).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL))
assertEquals(
expected = 1,
actual = trigger
)
}
}
}
@Test
fun `on-empty-block-backspace-press listener should be enabled - when switching from read to edit mode`() {
scenario.onFragment {
var trigger = 0
val recycler = givenRecycler(it)
val block = givenParagraph()
val adapter = givenAdapter(
views = listOf(block),
onEmptyBlockBackspaceClicked = { trigger++ }
)
recycler.adapter = adapter
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.textContent).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL))
assertEquals(
expected = 0,
actual = trigger
)
}
val updated = listOf(
block.copy(
text = "",
mode = BlockView.Mode.EDIT,
cursor = 0,
isFocused = true
)
)
adapter.updateWithDiffUtil(items = updated)
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.textContent).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL))
assertEquals(
expected = 1,
actual = trigger
)
}
}
}
private fun givenRecycler(it: Fragment): RecyclerView =
it.view!!.findViewById<RecyclerView>(R_test.id.recycler).apply {
layoutManager = LinearLayoutManager(context)
}
private fun givenParagraph() = BlockView.Text.Paragraph(
mode = BlockView.Mode.READ,
text = MockDataFactory.randomString(),
id = MockDataFactory.randomUuid(),
cursor = null
)
}

View file

@ -25,24 +25,28 @@ fun givenAdapter(
onTitleCheckboxClicked: (BlockView.Title.Todo) -> Unit = {},
onTitleBlockTextChanged: (Id, String) -> Unit = { _, _ -> },
onTextChanged: (String, Editable) -> Unit = { _, _ -> },
onToggleClicked: (String) -> Unit = {},
onNonEmptyBlockBackspaceClicked: (String, Editable) -> Unit = { _, _ -> },
onEmptyBlockBackspaceClicked: (String) -> Unit = {},
onCheckboxClicked: (BlockView.Text.Checkbox) -> Unit = {},
lifecycle: Lifecycle = BlockAdapterTest.TestLifecycle(),
): BlockAdapter {
return BlockAdapter(
restore = LinkedList(),
initialBlock = views,
onNonEmptyBlockBackspaceClicked = { _, _ -> },
onEmptyBlockBackspaceClicked = {},
onNonEmptyBlockBackspaceClicked = onNonEmptyBlockBackspaceClicked,
onEmptyBlockBackspaceClicked = onEmptyBlockBackspaceClicked,
onSplitLineEnterClicked = onSplitLineEnterClicked,
onSplitDescription = { _, _, _ -> },
onTextChanged = onTextChanged,
onCheckboxClicked = {},
onCheckboxClicked = onCheckboxClicked,
onTitleCheckboxClicked = onTitleCheckboxClicked,
onFocusChanged = onFocusChanged,
onSelectionChanged = { _, _ -> },
onTextInputClicked = {},
onPageIconClicked = {},
onTogglePlaceholderClicked = {},
onToggleClicked = {},
onToggleClicked = onToggleClicked,
onTextBlockTextChanged = {},
onTitleBlockTextChanged = onTitleBlockTextChanged,
onTitleTextInputClicked = {},

View file

@ -0,0 +1,106 @@
package com.anytypeio.anytype.core_ui.uitests
import android.content.Context
import android.os.Build
import androidx.fragment.app.Fragment
import androidx.fragment.app.testing.FragmentScenario
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.test_utils.MockDataFactory
import com.anytypeio.anytype.test_utils.TestFragment
import com.anytypeio.anytype.test_utils.utils.checkHasTextColor
import com.anytypeio.anytype.test_utils.utils.checkIsDisplayed
import com.anytypeio.anytype.test_utils.utils.onItemView
import com.anytypeio.anytype.test_utils.utils.performClick
import com.anytypeio.anytype.test_utils.utils.rVMatcher
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.assertEquals
import com.anytypeio.anytype.test_utils.R as R_test
@RunWith(RobolectricTestRunner::class)
@Config(
manifest = Config.NONE,
sdk = [Build.VERSION_CODES.P],
instrumentedPackages = [
// required to access final members on androidx.loader.content.ModernAsyncTask
"androidx.loader.content"
]
)
class BlockAdapterToggleTest {
private val context: Context = ApplicationProvider.getApplicationContext()
lateinit var scenario: FragmentScenario<TestFragment>
@Before
fun setUp() {
context.setTheme(R.style.Theme_MaterialComponents)
scenario = launchFragmentInContainer()
}
@Test
fun `should intercept toggle click - when switching from read to edit mode`() {
scenario.onFragment {
var triggeredTimes = 0
val recycler = givenRecycler(it)
val block = givenToggle()
val adapter = givenAdapter(
views = listOf(block),
onToggleClicked = { triggeredTimes++ }
)
recycler.adapter = adapter
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.toggle).checkIsDisplayed()
onItemView(0, R.id.toggle).performClick()
}
assertEquals(
actual = triggeredTimes,
expected = 1
)
adapter.updateWithDiffUtil(
listOf(
block.copy(
mode = BlockView.Mode.EDIT
)
)
)
R_test.id.recycler.rVMatcher().apply {
onItemView(0, R.id.toggle).performClick()
}
assertEquals(
actual = triggeredTimes,
expected = 2
)
}
}
private fun givenRecycler(it: Fragment): RecyclerView =
it.view!!.findViewById<RecyclerView>(R_test.id.recycler).apply {
layoutManager = LinearLayoutManager(context)
}
private fun givenToggle() = BlockView.Text.Toggle(
mode = BlockView.Mode.READ,
text = MockDataFactory.randomString(),
id = MockDataFactory.randomUuid(),
isFocused = false
)
}

View file

@ -0,0 +1,31 @@
package com.anytypeio.anytype.test_utils.utils.view_action
import android.view.View
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
import org.hamcrest.Matcher
class ExtractViewAction <V: View> : ViewAction {
lateinit var view: V
override fun getConstraints(): Matcher<View> {
return isAssignableFrom(View::class.java)
}
override fun getDescription(): String {
return "Text of the view"
}
override fun perform(uiController: UiController, view: View) {
this.view = view as V
}
}
inline fun <reified V: View> ViewInteraction.extractView(): V {
val viewAction = ExtractViewAction<V>()
perform(viewAction)
return viewAction.view
}