mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Editor | Enhancement | Nested decorations for text list blocks (#2373)
This commit is contained in:
parent
62f96685be
commit
cfb9c1a95f
14 changed files with 773 additions and 52 deletions
|
@ -2,9 +2,7 @@ package com.anytypeio.anytype.core_ui.features.editor.decoration
|
|||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.extensions.veryLight
|
||||
import com.anytypeio.anytype.presentation.editor.editor.ThemeColor
|
||||
|
@ -44,6 +42,8 @@ class EditorDecorationContainer @JvmOverloads constructor(
|
|||
.toInt()
|
||||
private val defaultGraphicContainerWidth = resources.getDimensionPixelSize(R.dimen.default_graphic_container_width)
|
||||
|
||||
private val defaultTextBottomExtraSpace = resources.getDimension(R.dimen.default_text_bottom_extra_space).toInt()
|
||||
|
||||
fun decorate(
|
||||
decorations: List<BlockView.Decoration>,
|
||||
onApplyContentOffset: (OffsetLeft, OffsetBottom) -> Unit = { _, _ -> }
|
||||
|
@ -96,12 +96,9 @@ class EditorDecorationContainer @JvmOverloads constructor(
|
|||
BlockView.Decoration.Style.Header.H3 -> {
|
||||
topMargin = defaultHeaderThreeExtraSpaceTop
|
||||
bottomOffset += defaultHeaderThreeExtraSpaceBottom
|
||||
}
|
||||
BlockView.Decoration.Style.Card -> {
|
||||
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,19 @@ 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
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBulletedBinding
|
||||
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
|
||||
|
@ -22,11 +28,11 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
|||
class Bulleted(
|
||||
val binding: ItemBlockBulletedBinding,
|
||||
clicked: (ListenerType) -> Unit,
|
||||
) : Text(binding.root, clicked), SupportNesting {
|
||||
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
|
||||
|
||||
val indent: View = binding.bulletIndent
|
||||
val bullet = binding.bullet
|
||||
private val container = binding.bulletBlockContainer
|
||||
private val container = binding.graphicPlusTextContainer
|
||||
override val content: TextInputWidget = binding.bulletedListContent
|
||||
override val root: View = itemView
|
||||
|
||||
|
@ -36,6 +42,8 @@ class Bulleted(
|
|||
private val mentionUncheckedIcon: Drawable?
|
||||
private val mentionInitialsSize: Float
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer = binding.decorationContainer
|
||||
|
||||
init {
|
||||
setup()
|
||||
with(itemView.context) {
|
||||
|
@ -47,6 +55,24 @@ class Bulleted(
|
|||
mentionCheckedIcon = ContextCompat.getDrawable(this, R.drawable.ic_task_1_text_16)
|
||||
mentionInitialsSize = resources.getDimension(R.dimen.mention_span_initials_size_default)
|
||||
}
|
||||
applyDefaultOffsets()
|
||||
}
|
||||
|
||||
private fun applyDefaultOffsets() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
binding.root.updatePadding(
|
||||
left = dimen(R.dimen.default_document_item_padding_start),
|
||||
right = dimen(R.dimen.default_document_item_padding_end)
|
||||
)
|
||||
binding.root.updateLayoutParams<RecyclerView.LayoutParams> {
|
||||
topMargin = dimen(R.dimen.default_document_item_margin_top)
|
||||
bottomMargin = dimen(R.dimen.default_document_item_margin_bottom)
|
||||
}
|
||||
binding.graphicPlusTextContainer.updatePadding(
|
||||
left = dimen(R.dimen.default_document_content_padding_start),
|
||||
right = dimen(R.dimen.default_document_content_padding_end),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(
|
||||
|
@ -104,10 +130,31 @@ class Bulleted(
|
|||
}
|
||||
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
indent.updateLayoutParams { width = item.indent * dimen(R.dimen.indent) }
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
indent.updateLayoutParams { width = item.indent * dimen(R.dimen.indent) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun select(item: BlockView.Selectable) {
|
||||
container.isSelected = item.isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
if (BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
decoratableContainer.decorate(
|
||||
decorations = decorations
|
||||
) { offsetLeft, offsetBottom ->
|
||||
binding.graphicPlusTextContainer.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
marginStart = dimen(R.dimen.default_indent) + offsetLeft
|
||||
marginEnd = dimen(R.dimen.dp_8)
|
||||
bottomMargin = offsetBottom
|
||||
// TODO handle top and bottom offsets
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDecorationsChanged(decorations: List<BlockView.Decoration>) {
|
||||
applyDecorations(decorations = decorations)
|
||||
}
|
||||
}
|
|
@ -3,12 +3,18 @@ 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
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
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.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
|
@ -20,12 +26,12 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
|||
class Checkbox(
|
||||
val binding: ItemBlockCheckboxBinding,
|
||||
clicked: (ListenerType) -> Unit,
|
||||
) : Text(binding.root, clicked), SupportNesting {
|
||||
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
|
||||
|
||||
var mode = BlockView.Mode.EDIT
|
||||
|
||||
val checkbox: ImageView = binding.checkboxIcon
|
||||
private val container = binding.checkboxBlockContentContainer
|
||||
private val container = binding.graphicPlusTextContainer
|
||||
override val content: TextInputWidget = binding.checkboxContent
|
||||
override val root: View = itemView
|
||||
|
||||
|
@ -35,6 +41,8 @@ class Checkbox(
|
|||
private val mentionUncheckedIcon: Drawable?
|
||||
private val mentionInitialsSize: Float
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer = binding.decorationContainer
|
||||
|
||||
init {
|
||||
setup()
|
||||
with(itemView.context) {
|
||||
|
@ -46,6 +54,24 @@ class Checkbox(
|
|||
mentionCheckedIcon = ContextCompat.getDrawable(this, R.drawable.ic_task_1_text_16)
|
||||
mentionInitialsSize = resources.getDimension(R.dimen.mention_span_initials_size_default)
|
||||
}
|
||||
applyDefaultOffsets()
|
||||
}
|
||||
|
||||
private fun applyDefaultOffsets() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
binding.root.updatePadding(
|
||||
left = dimen(R.dimen.default_document_item_padding_start),
|
||||
right = dimen(R.dimen.default_document_item_padding_end)
|
||||
)
|
||||
binding.root.updateLayoutParams<RecyclerView.LayoutParams> {
|
||||
topMargin = dimen(R.dimen.default_document_item_margin_top)
|
||||
bottomMargin = dimen(R.dimen.default_document_item_margin_bottom)
|
||||
}
|
||||
binding.graphicPlusTextContainer.updatePadding(
|
||||
left = dimen(R.dimen.default_document_content_padding_start),
|
||||
right = dimen(R.dimen.default_document_content_padding_end),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(
|
||||
|
@ -99,7 +125,9 @@ class Checkbox(
|
|||
override fun getMentionInitialsSize(): Float = mentionInitialsSize
|
||||
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
checkbox.updatePadding(left = item.indent * dimen(R.dimen.indent))
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
checkbox.updatePadding(left = item.indent * dimen(R.dimen.indent))
|
||||
}
|
||||
}
|
||||
|
||||
override fun enableEditMode() {
|
||||
|
@ -115,4 +143,23 @@ class Checkbox(
|
|||
override fun select(item: BlockView.Selectable) {
|
||||
container.isSelected = item.isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
if (BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
decoratableContainer.decorate(
|
||||
decorations = decorations
|
||||
) { offsetLeft, offsetBottom ->
|
||||
binding.graphicPlusTextContainer.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
marginStart = dimen(R.dimen.default_indent) + offsetLeft
|
||||
marginEnd = dimen(R.dimen.dp_8)
|
||||
bottomMargin = offsetBottom
|
||||
// TODO handle top and bottom offsets
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDecorationsChanged(decorations: List<BlockView.Decoration>) {
|
||||
applyDecorations(decorations = decorations)
|
||||
}
|
||||
}
|
|
@ -4,14 +4,20 @@ import android.graphics.drawable.Drawable
|
|||
import android.text.Editable
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockNumberedBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.setTextColor
|
||||
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
|
||||
|
@ -24,9 +30,9 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
|||
class Numbered(
|
||||
val binding: ItemBlockNumberedBinding,
|
||||
clicked: (ListenerType) -> Unit,
|
||||
) : Text(binding.root, clicked), SupportNesting {
|
||||
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
|
||||
|
||||
private val container = binding.numberedBlockContentContainer
|
||||
private val container = binding.graphicPlusTextContainer
|
||||
val number = binding.number
|
||||
override val content: TextInputWidget = binding.numberedListContent
|
||||
override val root: View = itemView
|
||||
|
@ -37,6 +43,8 @@ class Numbered(
|
|||
private val mentionUncheckedIcon: Drawable?
|
||||
private val mentionInitialsSize: Float
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer = binding.decorationContainer
|
||||
|
||||
init {
|
||||
setup()
|
||||
with(itemView.context) {
|
||||
|
@ -48,6 +56,24 @@ class Numbered(
|
|||
mentionCheckedIcon = ContextCompat.getDrawable(this, R.drawable.ic_task_1_text_16)
|
||||
mentionInitialsSize = resources.getDimension(R.dimen.mention_span_initials_size_default)
|
||||
}
|
||||
applyDefaultOffsets()
|
||||
}
|
||||
|
||||
private fun applyDefaultOffsets() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
binding.root.updatePadding(
|
||||
left = dimen(R.dimen.default_document_item_padding_start),
|
||||
right = dimen(R.dimen.default_document_item_padding_end)
|
||||
)
|
||||
binding.root.updateLayoutParams<RecyclerView.LayoutParams> {
|
||||
topMargin = dimen(R.dimen.default_document_item_margin_top)
|
||||
bottomMargin = dimen(R.dimen.default_document_item_margin_bottom)
|
||||
}
|
||||
binding.graphicPlusTextContainer.updatePadding(
|
||||
left = dimen(R.dimen.default_document_content_padding_start),
|
||||
right = dimen(R.dimen.default_document_content_padding_end),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(
|
||||
|
@ -127,17 +153,38 @@ class Numbered(
|
|||
}
|
||||
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
number.updateLayoutParams<LinearLayout.LayoutParams> {
|
||||
setMargins(
|
||||
item.indent * dimen(R.dimen.indent),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
number.updateLayoutParams<LinearLayout.LayoutParams> {
|
||||
setMargins(
|
||||
item.indent * dimen(R.dimen.indent),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun select(item: BlockView.Selectable) {
|
||||
container.isSelected = item.isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
if (BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
decoratableContainer.decorate(
|
||||
decorations = decorations
|
||||
) { offsetLeft, offsetBottom ->
|
||||
binding.graphicPlusTextContainer.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
marginStart = dimen(R.dimen.default_indent) + offsetLeft
|
||||
marginEnd = dimen(R.dimen.dp_8)
|
||||
bottomMargin = offsetBottom
|
||||
// TODO handle top and bottom offsets
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDecorationsChanged(decorations: List<BlockView.Decoration>) {
|
||||
applyDecorations(decorations = decorations)
|
||||
}
|
||||
}
|
|
@ -3,12 +3,19 @@ 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
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockToggleBinding
|
||||
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.dimen
|
||||
|
@ -20,14 +27,14 @@ import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent
|
|||
class Toggle(
|
||||
val binding: ItemBlockToggleBinding,
|
||||
clicked: (ListenerType) -> Unit,
|
||||
) : Text(binding.root, clicked), SupportNesting {
|
||||
) : Text(binding.root, clicked), SupportNesting, DecoratableViewHolder {
|
||||
|
||||
private var mode = BlockView.Mode.EDIT
|
||||
|
||||
val toggle = binding.toggle
|
||||
private val line = binding.guideline
|
||||
private val placeholder = binding.togglePlaceholder
|
||||
private val container = binding.toolbarBlockContentContainer
|
||||
private val container = binding.graphicPlusTextContainer
|
||||
override val content: TextInputWidget = binding.toggleContent
|
||||
override val root: View = itemView
|
||||
|
||||
|
@ -37,6 +44,8 @@ class Toggle(
|
|||
private val mentionUncheckedIcon: Drawable?
|
||||
private val mentionInitialsSize: Float
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer = binding.decorationContainer
|
||||
|
||||
init {
|
||||
setup()
|
||||
with(itemView.context) {
|
||||
|
@ -48,6 +57,24 @@ class Toggle(
|
|||
mentionCheckedIcon = ContextCompat.getDrawable(this, R.drawable.ic_task_1_text_16)
|
||||
mentionInitialsSize = resources.getDimension(R.dimen.mention_span_initials_size_default)
|
||||
}
|
||||
applyDefaultOffsets()
|
||||
}
|
||||
|
||||
private fun applyDefaultOffsets() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
binding.root.updatePadding(
|
||||
left = dimen(R.dimen.default_document_item_padding_start),
|
||||
right = dimen(R.dimen.default_document_item_padding_end)
|
||||
)
|
||||
binding.root.updateLayoutParams<RecyclerView.LayoutParams> {
|
||||
topMargin = dimen(R.dimen.default_document_item_margin_top)
|
||||
bottomMargin = dimen(R.dimen.default_document_item_margin_bottom)
|
||||
}
|
||||
binding.graphicPlusTextContainer.updatePadding(
|
||||
left = dimen(R.dimen.default_document_content_padding_start),
|
||||
right = dimen(R.dimen.default_document_content_padding_end),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(
|
||||
|
@ -94,7 +121,9 @@ class Toggle(
|
|||
override fun getMentionInitialsSize(): Float = mentionInitialsSize
|
||||
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
line.setGuidelineBegin(item.indent * dimen(R.dimen.indent))
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
line.setGuidelineBegin(item.indent * dimen(R.dimen.indent))
|
||||
}
|
||||
}
|
||||
|
||||
override fun select(item: BlockView.Selectable) {
|
||||
|
@ -148,6 +177,25 @@ class Toggle(
|
|||
}
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
if (BuildConfig.NESTED_DECORATION_ENABLED) {
|
||||
decoratableContainer.decorate(
|
||||
decorations = decorations
|
||||
) { offsetLeft, offsetBottom ->
|
||||
binding.graphicPlusTextContainer.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
marginStart = dimen(R.dimen.default_indent) + offsetLeft
|
||||
marginEnd = dimen(R.dimen.dp_8)
|
||||
bottomMargin = offsetBottom
|
||||
// TODO handle top and bottom offsets
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDecorationsChanged(decorations: List<BlockView.Decoration>) {
|
||||
applyDecorations(decorations = decorations)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Rotation value for a toggle icon for expanded state.
|
||||
|
|
|
@ -2,21 +2,20 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="1dp"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:paddingStart="@dimen/default_document_item_padding_start"
|
||||
android:paddingEnd="@dimen/default_document_item_padding_end">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:paddingStart="@dimen/default_document_content_padding_start"
|
||||
android:id="@+id/bulletBlockContainer"
|
||||
android:id="@+id/graphicPlusTextContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:addStatesFromChildren="true"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="@dimen/default_document_content_padding_end"
|
||||
tools:background="@drawable/item_block_multi_select_selected"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
|
@ -36,7 +35,7 @@
|
|||
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
android:id="@+id/bulletedListContent"
|
||||
style="@style/BlockBulletContentStyle"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginStart="@dimen/default_graphic_container_right_offset"
|
||||
android:gravity="center_vertical"
|
||||
android:hint="@string/hint_bullet"
|
||||
tools:text="@string/default_text_placeholder" />
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/DefaultDocumentContainerStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/checkboxBlockContentContainer"
|
||||
android:id="@+id/graphicPlusTextContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:addStatesFromChildren="true"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/default_document_content_padding_start"
|
||||
android:paddingEnd="@dimen/default_document_content_padding_end"
|
||||
tools:background="@drawable/item_block_multi_select_selected">
|
||||
|
||||
<ImageView
|
||||
|
@ -29,7 +31,7 @@
|
|||
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
android:id="@+id/checkboxContent"
|
||||
style="@style/BlockCheckboxContentStyle"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginStart="@dimen/default_graphic_container_right_offset"
|
||||
android:hint="@string/hint_checkbox"
|
||||
tools:text="New front-end based on design" />
|
||||
|
||||
|
|
|
@ -2,18 +2,20 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/DefaultDocumentContainerStyle">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/numberedBlockContentContainer"
|
||||
android:id="@+id/graphicPlusTextContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:addStatesFromChildren="true"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/default_document_content_padding_start"
|
||||
android:paddingEnd="@dimen/default_document_content_padding_end"
|
||||
tools:background="@drawable/item_block_multi_select_selected"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
|
@ -32,7 +34,7 @@
|
|||
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
android:id="@+id/numberedListContent"
|
||||
style="@style/BlockNumberedContentStyle"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginStart="@dimen/default_graphic_container_right_offset"
|
||||
android:hint="@string/hint_numbered_list"
|
||||
tools:text="@string/default_text_placeholder" />
|
||||
|
||||
|
|
|
@ -2,18 +2,20 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/DefaultDocumentContainerStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/toolbarBlockContentContainer"
|
||||
android:id="@+id/graphicPlusTextContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:addStatesFromChildren="true"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
android:paddingStart="@dimen/default_document_content_padding_start"
|
||||
android:paddingEnd="@dimen/default_document_content_padding_end"
|
||||
tools:background="@drawable/item_block_multi_select_selected">
|
||||
|
||||
<ImageView
|
||||
|
|
|
@ -277,5 +277,6 @@
|
|||
<dimen name="default_graphic_container_height">24dp</dimen>
|
||||
<dimen name="default_graphic_container_right_offset">4dp</dimen>
|
||||
<dimen name="default_selected_view_offset">8dp</dimen>
|
||||
<dimen name="default_text_bottom_extra_space">2dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -37,4 +37,140 @@ fun StubParagraphView(
|
|||
ghostEditorSelection = ghostSelection,
|
||||
cursor = cursor,
|
||||
alignment = alignment
|
||||
)
|
||||
|
||||
fun StubNumberedView(
|
||||
id: Id = MockDataFactory.randomString(),
|
||||
text: String = MockDataFactory.randomString(),
|
||||
marks: List<Markup.Mark> = emptyList(),
|
||||
isFocused: Boolean = MockDataFactory.randomBoolean(),
|
||||
isSelected: Boolean = MockDataFactory.randomBoolean(),
|
||||
color: String? = null,
|
||||
indent: Indent = 0,
|
||||
searchFields: List<BlockView.Searchable.Field> = emptyList(),
|
||||
backgroundColor: String? = null,
|
||||
mode: BlockView.Mode = BlockView.Mode.EDIT,
|
||||
decorations: List<BlockView.Decoration> = emptyList(),
|
||||
ghostSelection: IntRange? = null,
|
||||
cursor: Int? = null,
|
||||
alignment: Alignment? = null,
|
||||
number: Int = 1
|
||||
) : BlockView.Text.Numbered = BlockView.Text.Numbered(
|
||||
id = id,
|
||||
text = text,
|
||||
marks = marks,
|
||||
isFocused = isFocused,
|
||||
isSelected = isSelected,
|
||||
color = color,
|
||||
indent = indent,
|
||||
searchFields = searchFields,
|
||||
backgroundColor = backgroundColor,
|
||||
mode = mode,
|
||||
decorations = decorations,
|
||||
ghostEditorSelection = ghostSelection,
|
||||
cursor = cursor,
|
||||
alignment = alignment,
|
||||
number = number
|
||||
)
|
||||
|
||||
fun StubBulletedView(
|
||||
id: Id = MockDataFactory.randomString(),
|
||||
text: String = MockDataFactory.randomString(),
|
||||
marks: List<Markup.Mark> = emptyList(),
|
||||
isFocused: Boolean = MockDataFactory.randomBoolean(),
|
||||
isSelected: Boolean = MockDataFactory.randomBoolean(),
|
||||
color: String? = null,
|
||||
indent: Indent = 0,
|
||||
searchFields: List<BlockView.Searchable.Field> = emptyList(),
|
||||
backgroundColor: String? = null,
|
||||
mode: BlockView.Mode = BlockView.Mode.EDIT,
|
||||
decorations: List<BlockView.Decoration> = emptyList(),
|
||||
ghostSelection: IntRange? = null,
|
||||
cursor: Int? = null,
|
||||
alignment: Alignment? = null,
|
||||
) : BlockView.Text.Bulleted = BlockView.Text.Bulleted(
|
||||
id = id,
|
||||
text = text,
|
||||
marks = marks,
|
||||
isFocused = isFocused,
|
||||
isSelected = isSelected,
|
||||
color = color,
|
||||
indent = indent,
|
||||
searchFields = searchFields,
|
||||
backgroundColor = backgroundColor,
|
||||
mode = mode,
|
||||
decorations = decorations,
|
||||
ghostEditorSelection = ghostSelection,
|
||||
cursor = cursor,
|
||||
alignment = alignment
|
||||
)
|
||||
|
||||
fun StubCheckboxView(
|
||||
id: Id = MockDataFactory.randomString(),
|
||||
text: String = MockDataFactory.randomString(),
|
||||
marks: List<Markup.Mark> = emptyList(),
|
||||
isFocused: Boolean = MockDataFactory.randomBoolean(),
|
||||
isSelected: Boolean = MockDataFactory.randomBoolean(),
|
||||
color: String? = null,
|
||||
indent: Indent = 0,
|
||||
searchFields: List<BlockView.Searchable.Field> = emptyList(),
|
||||
backgroundColor: String? = null,
|
||||
mode: BlockView.Mode = BlockView.Mode.EDIT,
|
||||
decorations: List<BlockView.Decoration> = emptyList(),
|
||||
ghostSelection: IntRange? = null,
|
||||
cursor: Int? = null,
|
||||
alignment: Alignment? = null,
|
||||
isChecked: Boolean = false
|
||||
) : BlockView.Text.Checkbox = BlockView.Text.Checkbox(
|
||||
id = id,
|
||||
text = text,
|
||||
marks = marks,
|
||||
isFocused = isFocused,
|
||||
isSelected = isSelected,
|
||||
color = color,
|
||||
indent = indent,
|
||||
searchFields = searchFields,
|
||||
backgroundColor = backgroundColor,
|
||||
mode = mode,
|
||||
decorations = decorations,
|
||||
ghostEditorSelection = ghostSelection,
|
||||
cursor = cursor,
|
||||
alignment = alignment,
|
||||
isChecked = isChecked
|
||||
)
|
||||
|
||||
fun StubToggleView(
|
||||
id: Id = MockDataFactory.randomString(),
|
||||
text: String = MockDataFactory.randomString(),
|
||||
marks: List<Markup.Mark> = emptyList(),
|
||||
isFocused: Boolean = MockDataFactory.randomBoolean(),
|
||||
isSelected: Boolean = MockDataFactory.randomBoolean(),
|
||||
color: String? = null,
|
||||
indent: Indent = 0,
|
||||
searchFields: List<BlockView.Searchable.Field> = emptyList(),
|
||||
backgroundColor: String? = null,
|
||||
mode: BlockView.Mode = BlockView.Mode.EDIT,
|
||||
decorations: List<BlockView.Decoration> = emptyList(),
|
||||
ghostSelection: IntRange? = null,
|
||||
cursor: Int? = null,
|
||||
alignment: Alignment? = null,
|
||||
isEmpty: Boolean = false,
|
||||
toggled: Boolean = false
|
||||
) : BlockView.Text.Toggle = BlockView.Text.Toggle(
|
||||
id = id,
|
||||
text = text,
|
||||
marks = marks,
|
||||
isFocused = isFocused,
|
||||
isSelected = isSelected,
|
||||
color = color,
|
||||
indent = indent,
|
||||
searchFields = searchFields,
|
||||
backgroundColor = backgroundColor,
|
||||
mode = mode,
|
||||
decorations = decorations,
|
||||
ghostEditorSelection = ghostSelection,
|
||||
cursor = cursor,
|
||||
alignment = alignment,
|
||||
isEmpty = isEmpty,
|
||||
toggled = toggled
|
||||
)
|
|
@ -0,0 +1,294 @@
|
|||
package com.anytypeio.anytype.core_ui.uitests.editor
|
||||
|
||||
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 androidx.test.espresso.ViewInteraction
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.StubBulletedView
|
||||
import com.anytypeio.anytype.core_ui.StubCheckboxView
|
||||
import com.anytypeio.anytype.core_ui.StubNumberedView
|
||||
import com.anytypeio.anytype.core_ui.StubToggleView
|
||||
import com.anytypeio.anytype.core_ui.extensions.veryLight
|
||||
import com.anytypeio.anytype.core_ui.uitests.givenAdapter
|
||||
import com.anytypeio.anytype.presentation.editor.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.test_utils.TestFragment
|
||||
import com.anytypeio.anytype.test_utils.utils.checkHasChildViewCount
|
||||
import com.anytypeio.anytype.test_utils.utils.checkHasMarginStart
|
||||
import com.anytypeio.anytype.test_utils.utils.checkHasViewGroupChildWithBackground
|
||||
import com.anytypeio.anytype.test_utils.utils.checkHasViewGroupChildWithMarginLeft
|
||||
import com.anytypeio.anytype.test_utils.utils.checkIsDisplayed
|
||||
import com.anytypeio.anytype.test_utils.utils.onItemView
|
||||
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
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(
|
||||
manifest = Config.NONE,
|
||||
sdk = [Build.VERSION_CODES.P],
|
||||
instrumentedPackages = [ "androidx.loader.content" ]
|
||||
)
|
||||
class EditorNestedDecorationListBlockTest {
|
||||
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
private lateinit var scenario: FragmentScenario<TestFragment>
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context.setTheme(R.style.Theme_MaterialComponents)
|
||||
scenario = launchFragmentInContainer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Block with background
|
||||
* ...Numbered block with background (rendered block)
|
||||
*/
|
||||
@Test
|
||||
fun `numbered should have two backgrounds with indentation - when current block of another block`() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) return
|
||||
scenario.onFragment {
|
||||
|
||||
// SETUP
|
||||
|
||||
val bg1 = ThemeColor.YELLOW
|
||||
val bg2 = ThemeColor.ORANGE
|
||||
|
||||
val numbered = StubNumberedView(
|
||||
indent = 1,
|
||||
decorations = listOf(
|
||||
BlockView.Decoration(
|
||||
background = bg1
|
||||
),
|
||||
BlockView.Decoration(
|
||||
background = bg2
|
||||
)
|
||||
),
|
||||
backgroundColor = bg2.code
|
||||
)
|
||||
|
||||
val recycler = givenRecycler(it)
|
||||
val adapter = givenAdapter(listOf(numbered))
|
||||
recycler.adapter = adapter
|
||||
|
||||
val rvMatcher = com.anytypeio.anytype.test_utils.R.id.recycler.rVMatcher()
|
||||
|
||||
// TESTING
|
||||
|
||||
val decorationContainerView = rvMatcher.onItemView(0, R.id.decorationContainer)
|
||||
val graphicPlusTextContainerView = rvMatcher.onItemView(0, R.id.graphicPlusTextContainer)
|
||||
|
||||
// Checking our decorations
|
||||
|
||||
`first child view should have its background and zero margin, second child view should have its background and one-indent margin`(
|
||||
decorationContainerView, bg1, bg2
|
||||
)
|
||||
|
||||
// Checking content left indentation
|
||||
|
||||
graphicPlusTextContainerView.checkHasMarginStart(
|
||||
marginStart = context.resources.getDimension(R.dimen.default_indent).toInt() * 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block with background
|
||||
* ...Bulleted block with background (rendered block)
|
||||
*/
|
||||
@Test
|
||||
fun `bulleted should have two backgrounds with indentation - when current block of another block`() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) return
|
||||
scenario.onFragment {
|
||||
|
||||
// SETUP
|
||||
|
||||
val bg1 = ThemeColor.YELLOW
|
||||
val bg2 = ThemeColor.ORANGE
|
||||
|
||||
val bulleted = StubBulletedView(
|
||||
indent = 1,
|
||||
decorations = listOf(
|
||||
BlockView.Decoration(
|
||||
background = bg1
|
||||
),
|
||||
BlockView.Decoration(
|
||||
background = bg2
|
||||
)
|
||||
),
|
||||
backgroundColor = bg2.code
|
||||
)
|
||||
|
||||
val recycler = givenRecycler(it)
|
||||
val adapter = givenAdapter(listOf(bulleted))
|
||||
recycler.adapter = adapter
|
||||
|
||||
val rvMatcher = com.anytypeio.anytype.test_utils.R.id.recycler.rVMatcher()
|
||||
|
||||
// TESTING
|
||||
|
||||
val decorationContainerView = rvMatcher.onItemView(0, R.id.decorationContainer)
|
||||
val graphicPlusTextContainerView = rvMatcher.onItemView(0, R.id.graphicPlusTextContainer)
|
||||
|
||||
// Checking our decorations
|
||||
|
||||
`first child view should have its background and zero margin, second child view should have its background and one-indent margin`(
|
||||
decorationContainerView, bg1, bg2
|
||||
)
|
||||
|
||||
// Checking content left indentation
|
||||
|
||||
graphicPlusTextContainerView.checkHasMarginStart(
|
||||
marginStart = context.resources.getDimension(R.dimen.default_indent).toInt() * 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block with background
|
||||
* ...Checkbox block with background (rendered block)
|
||||
*/
|
||||
@Test
|
||||
fun `checkbox should have two backgrounds with indentation - when current block of another block`() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) return
|
||||
scenario.onFragment {
|
||||
|
||||
// SETUP
|
||||
|
||||
val bg1 = ThemeColor.YELLOW
|
||||
val bg2 = ThemeColor.ORANGE
|
||||
|
||||
val bulleted = StubCheckboxView(
|
||||
indent = 1,
|
||||
decorations = listOf(
|
||||
BlockView.Decoration(
|
||||
background = bg1
|
||||
),
|
||||
BlockView.Decoration(
|
||||
background = bg2
|
||||
)
|
||||
),
|
||||
backgroundColor = bg2.code
|
||||
)
|
||||
|
||||
val recycler = givenRecycler(it)
|
||||
val adapter = givenAdapter(listOf(bulleted))
|
||||
recycler.adapter = adapter
|
||||
|
||||
val rvMatcher = com.anytypeio.anytype.test_utils.R.id.recycler.rVMatcher()
|
||||
|
||||
// TESTING
|
||||
|
||||
val decorationContainerView = rvMatcher.onItemView(0, R.id.decorationContainer)
|
||||
val graphicPlusTextContainerView = rvMatcher.onItemView(0, R.id.graphicPlusTextContainer)
|
||||
|
||||
// Checking our decorations
|
||||
|
||||
`first child view should have its background and zero margin, second child view should have its background and one-indent margin`(
|
||||
decorationContainerView, bg1, bg2
|
||||
)
|
||||
|
||||
// Checking content left indentation
|
||||
|
||||
graphicPlusTextContainerView.checkHasMarginStart(
|
||||
marginStart = context.resources.getDimension(R.dimen.default_indent).toInt() * 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block with background
|
||||
* ...Toggle block with background (rendered block)
|
||||
*/
|
||||
@Test
|
||||
fun `toggle should have two backgrounds with indentation - when current block of another block`() {
|
||||
if (!BuildConfig.NESTED_DECORATION_ENABLED) return
|
||||
scenario.onFragment {
|
||||
|
||||
// SETUP
|
||||
|
||||
val bg1 = ThemeColor.YELLOW
|
||||
val bg2 = ThemeColor.ORANGE
|
||||
|
||||
val bulleted = StubToggleView(
|
||||
indent = 1,
|
||||
decorations = listOf(
|
||||
BlockView.Decoration(
|
||||
background = bg1
|
||||
),
|
||||
BlockView.Decoration(
|
||||
background = bg2
|
||||
)
|
||||
),
|
||||
backgroundColor = bg2.code
|
||||
)
|
||||
|
||||
val recycler = givenRecycler(it)
|
||||
val adapter = givenAdapter(listOf(bulleted))
|
||||
recycler.adapter = adapter
|
||||
|
||||
val rvMatcher = com.anytypeio.anytype.test_utils.R.id.recycler.rVMatcher()
|
||||
|
||||
// TESTING
|
||||
|
||||
val decorationContainerView = rvMatcher.onItemView(0, R.id.decorationContainer)
|
||||
val graphicPlusTextContainerView = rvMatcher.onItemView(0, R.id.graphicPlusTextContainer)
|
||||
|
||||
// Checking our decorations
|
||||
|
||||
`first child view should have its background and zero margin, second child view should have its background and one-indent margin`(
|
||||
decorationContainerView, bg1, bg2
|
||||
)
|
||||
|
||||
// Checking content left indentation
|
||||
|
||||
graphicPlusTextContainerView.checkHasMarginStart(
|
||||
marginStart = context.resources.getDimension(R.dimen.default_indent).toInt() * 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun `first child view should have its background and zero margin, second child view should have its background and one-indent margin`(
|
||||
decorationContainerView: ViewInteraction,
|
||||
bg1: ThemeColor,
|
||||
bg2: ThemeColor
|
||||
) {
|
||||
decorationContainerView.checkIsDisplayed()
|
||||
decorationContainerView.checkHasChildViewCount(2)
|
||||
|
||||
decorationContainerView.checkHasViewGroupChildWithBackground(
|
||||
pos = 0,
|
||||
background = context.resources.veryLight(bg1, 0),
|
||||
)
|
||||
decorationContainerView.checkHasViewGroupChildWithMarginLeft(
|
||||
pos = 0,
|
||||
margin = 0
|
||||
)
|
||||
|
||||
decorationContainerView.checkHasViewGroupChildWithBackground(
|
||||
pos = 1,
|
||||
background = context.resources.veryLight(bg2, 0),
|
||||
)
|
||||
decorationContainerView.checkHasViewGroupChildWithMarginLeft(
|
||||
pos = 1,
|
||||
margin = context.resources.getDimension(R.dimen.default_indent).toInt()
|
||||
)
|
||||
}
|
||||
|
||||
private fun givenRecycler(fr: Fragment): RecyclerView {
|
||||
val root = checkNotNull(fr.view)
|
||||
return root.findViewById<RecyclerView>(com.anytypeio.anytype.test_utils.R.id.recycler).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,8 +16,11 @@ import androidx.test.espresso.matcher.ViewMatchers.withInputType
|
|||
import com.anytypeio.anytype.test_utils.utils.TestUtils.withRecyclerView
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.HasChildViewWithText
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.HasViewGroupChildViewWithText
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.HasViewGroupChildWithBackground
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.HasViewGroupChildWithMarginLeft
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.WithBackgroundColor
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.WithChildViewCount
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.WithMarginStart
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.WithTextColor
|
||||
import com.anytypeio.anytype.test_utils.utils.espresso.WithoutBackgroundColor
|
||||
import org.hamcrest.Matchers.not
|
||||
|
@ -83,6 +86,16 @@ fun ViewInteraction.checkHasNoBackground() {
|
|||
check(matches(WithoutBackgroundColor()))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasMarginStart(marginStart: Int) {
|
||||
check(
|
||||
matches(
|
||||
WithMarginStart(
|
||||
marginStartExpected = marginStart
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasChildViewCount(count: Int) : ViewInteraction {
|
||||
return check(matches(WithChildViewCount(count)))
|
||||
}
|
||||
|
@ -104,6 +117,34 @@ fun ViewInteraction.checkHasChildViewWithText(
|
|||
return check(matches(HasChildViewWithText(pos, text, target)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasViewGroupChildWithBackground(
|
||||
pos: Int,
|
||||
background: Int
|
||||
) : ViewInteraction {
|
||||
return check(
|
||||
matches(
|
||||
HasViewGroupChildWithBackground(
|
||||
pos = pos,
|
||||
background = background
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasViewGroupChildWithMarginLeft(
|
||||
pos: Int,
|
||||
margin: Int
|
||||
) : ViewInteraction {
|
||||
return check(
|
||||
matches(
|
||||
HasViewGroupChildWithMarginLeft(
|
||||
pos = pos,
|
||||
margin = margin
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasViewGroupChildWithText(
|
||||
pos: Int,
|
||||
text: String
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.widget.TextView
|
|||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.marginStart
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
|
@ -22,8 +23,7 @@ import org.hamcrest.TypeSafeMatcher
|
|||
class WithTextColor(
|
||||
@ColorInt
|
||||
private val expectedColor: Int
|
||||
) :
|
||||
BoundedMatcher<View, TextView>(TextView::class.java) {
|
||||
) : BoundedMatcher<View, TextView>(TextView::class.java) {
|
||||
override fun matchesSafely(item: TextView) = item.currentTextColor == expectedColor
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with text color:")
|
||||
|
@ -64,8 +64,24 @@ class WithChildViewCount(private val expectedCount: Int) :
|
|||
}
|
||||
}
|
||||
|
||||
class HasViewGroupChildViewWithText(private val pos: Int, val text: String) :
|
||||
BoundedMatcher<View, ViewGroup>(ViewGroup::class.java) {
|
||||
class WithMarginStart(
|
||||
private val marginStartExpected: Int
|
||||
) : BoundedMatcher<View, View>(View::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with margin start:")
|
||||
description.appendValue(marginStartExpected)
|
||||
}
|
||||
|
||||
override fun matchesSafely(item: View): Boolean {
|
||||
val actual = item.marginStart
|
||||
return actual == marginStartExpected
|
||||
}
|
||||
}
|
||||
|
||||
class HasViewGroupChildViewWithText(
|
||||
private val pos: Int,
|
||||
val text: String
|
||||
) : BoundedMatcher<View, ViewGroup>(ViewGroup::class.java) {
|
||||
|
||||
private var actual: String? = null
|
||||
|
||||
|
@ -84,6 +100,48 @@ class HasViewGroupChildViewWithText(private val pos: Int, val text: String) :
|
|||
}
|
||||
}
|
||||
|
||||
class HasViewGroupChildWithBackground(
|
||||
private val pos: Int,
|
||||
private val background: Int
|
||||
) : BoundedMatcher<View, ViewGroup>(ViewGroup::class.java) {
|
||||
|
||||
private var actual: Int? = null
|
||||
|
||||
override fun matchesSafely(item: ViewGroup): Boolean {
|
||||
val child = item.getChildAt(pos)
|
||||
checkNotNull(child) { throw IllegalStateException("No view child at position: $pos") }
|
||||
actual = (child.background as ColorDrawable).color
|
||||
return actual == background
|
||||
}
|
||||
|
||||
override fun describeTo(description: Description) {
|
||||
if (actual != null) {
|
||||
description.appendText("Should have background [${background}] at position: $pos but was: [$actual]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HasViewGroupChildWithMarginLeft(
|
||||
private val pos: Int,
|
||||
private val margin: Int
|
||||
) : BoundedMatcher<View, ViewGroup>(ViewGroup::class.java) {
|
||||
|
||||
private var actual: Int? = null
|
||||
|
||||
override fun matchesSafely(item: ViewGroup): Boolean {
|
||||
val child = item.getChildAt(pos)
|
||||
checkNotNull(child) { throw IllegalStateException("No view child at position: $pos") }
|
||||
actual = child.marginStart
|
||||
return actual == margin
|
||||
}
|
||||
|
||||
override fun describeTo(description: Description) {
|
||||
if (actual != null) {
|
||||
description.appendText("Should have margin [${margin}] at position: $pos but was: [$actual]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HasChildViewWithText(private val pos: Int, val text: String, val target: Int) :
|
||||
BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue