mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Editor | Feature | Slash widget, color and background (#1455)
* update package * add color adapter + holder * adapters update * show items * color actions * ci off * tests * fix * ci * test fixes * update robolectric
This commit is contained in:
parent
4b10676603
commit
85092957e8
15 changed files with 1113 additions and 26 deletions
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
|
@ -1,7 +1,7 @@
|
|||
on:
|
||||
pull_request:
|
||||
# add "synchronize" in "types", in order to trigger workflow for pull request commit(s) pushes.
|
||||
types: [open]
|
||||
types: [open, synchronize]
|
||||
branches: [develop]
|
||||
name: Run debug unit tests
|
||||
jobs:
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.anytypeio.anytype.core_ui.features.page.slash.holders
|
||||
package com.anytypeio.anytype.core_ui.features.page.slash
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.features.page.slash.holders.AlignMenuHolder
|
||||
import com.anytypeio.anytype.core_ui.features.page.slash.holders.SubheaderMenuHolder
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashItem
|
||||
import kotlinx.android.synthetic.main.item_slash_widget_subheader.view.*
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.anytypeio.anytype.core_ui.features.page.slash
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.features.page.slash.holders.ColorMenuHolder
|
||||
import com.anytypeio.anytype.core_ui.features.page.slash.holders.SubheaderMenuHolder
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashItem
|
||||
import kotlinx.android.synthetic.main.item_slash_widget_subheader.view.*
|
||||
|
||||
class SlashColorAdapter(
|
||||
private var items: List<SlashItem>,
|
||||
private val clicks: (SlashItem) -> Unit,
|
||||
private val clickBack: () -> Unit
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
fun update(items: List<SlashItem>) {
|
||||
this.items = items
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
val size = items.size
|
||||
if (size > 0) {
|
||||
items = listOf()
|
||||
notifyItemRangeRemoved(0, size)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return when (viewType) {
|
||||
R.layout.item_slash_widget_color -> {
|
||||
ColorMenuHolder(
|
||||
view = inflater.inflate(viewType, parent, false)
|
||||
).apply {
|
||||
itemView.setOnClickListener {
|
||||
clicks(items[bindingAdapterPosition])
|
||||
}
|
||||
}
|
||||
}
|
||||
R.layout.item_slash_widget_subheader -> {
|
||||
SubheaderMenuHolder(
|
||||
view = inflater.inflate(viewType, parent, false)
|
||||
).apply {
|
||||
itemView.flBack.setOnClickListener {
|
||||
clickBack.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> throw IllegalArgumentException("Wrong viewtype:$viewType")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is ColorMenuHolder -> {
|
||||
val item = items[position] as SlashItem.Color
|
||||
holder.bind(item)
|
||||
}
|
||||
is SubheaderMenuHolder -> {
|
||||
val item = items[position] as SlashItem.Subheader
|
||||
holder.bind(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int = when (val item = items[position]) {
|
||||
is SlashItem.Color -> R.layout.item_slash_widget_color
|
||||
is SlashItem.Subheader -> R.layout.item_slash_widget_subheader
|
||||
else -> throw IllegalArgumentException("Wrong item type:$item")
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size
|
||||
}
|
|
@ -7,7 +7,6 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.features.page.slash.holders.SlashAlignmentAdapter
|
||||
import com.anytypeio.anytype.core_ui.tools.SlashHelper
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashCommand
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashItem
|
||||
|
@ -90,6 +89,22 @@ class SlashWidget @JvmOverloads constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private val colorAdapter by lazy {
|
||||
SlashColorAdapter(
|
||||
items = listOf(),
|
||||
clicks = { _clickEvents.offer(it) },
|
||||
clickBack = { _backEvent.offer(true) }
|
||||
)
|
||||
}
|
||||
|
||||
private val backgroundAdapter by lazy {
|
||||
SlashColorAdapter(
|
||||
items = listOf(),
|
||||
clicks = { _clickEvents.offer(it) },
|
||||
clickBack = { _backEvent.offer(true) }
|
||||
)
|
||||
}
|
||||
|
||||
private val concatAdapter = ConcatAdapter(
|
||||
mainAdapter,
|
||||
styleAdapter,
|
||||
|
@ -98,7 +113,9 @@ class SlashWidget @JvmOverloads constructor(
|
|||
relationsAdapter,
|
||||
otherAdapter,
|
||||
actionsAdapter,
|
||||
alignAdapter
|
||||
alignAdapter,
|
||||
colorAdapter,
|
||||
backgroundAdapter
|
||||
)
|
||||
|
||||
init {
|
||||
|
@ -127,6 +144,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowStyleItems -> {
|
||||
styleAdapter.update(command.items)
|
||||
|
@ -139,6 +158,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowMediaItems -> {
|
||||
mediaAdapter.update(command.items)
|
||||
|
@ -151,6 +172,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowRelations -> {
|
||||
relationsAdapter.update(command.relations)
|
||||
|
@ -163,6 +186,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowObjectTypes -> {
|
||||
objectTypesAdapter.update(command.items)
|
||||
|
@ -175,6 +200,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowOtherItems -> {
|
||||
otherAdapter.update(command.items)
|
||||
|
@ -187,6 +214,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
relationsAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowActionItems -> {
|
||||
actionsAdapter.update(command.items)
|
||||
|
@ -199,6 +228,8 @@ class SlashWidget @JvmOverloads constructor(
|
|||
relationsAdapter.clear()
|
||||
otherAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowAlignmentItems -> {
|
||||
alignAdapter.update(command.items)
|
||||
|
@ -211,6 +242,36 @@ class SlashWidget @JvmOverloads constructor(
|
|||
relationsAdapter.clear()
|
||||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowColorItems -> {
|
||||
colorAdapter.update(command.items)
|
||||
rvSlash.smoothScrollToPosition(0)
|
||||
|
||||
mainAdapter.clear()
|
||||
styleAdapter.clear()
|
||||
mediaAdapter.clear()
|
||||
objectTypesAdapter.clear()
|
||||
relationsAdapter.clear()
|
||||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
backgroundAdapter.clear()
|
||||
}
|
||||
is SlashCommand.ShowBackgroundItems -> {
|
||||
backgroundAdapter.update(command.items)
|
||||
rvSlash.smoothScrollToPosition(0)
|
||||
|
||||
mainAdapter.clear()
|
||||
styleAdapter.clear()
|
||||
mediaAdapter.clear()
|
||||
objectTypesAdapter.clear()
|
||||
relationsAdapter.clear()
|
||||
otherAdapter.clear()
|
||||
actionsAdapter.clear()
|
||||
alignAdapter.clear()
|
||||
colorAdapter.clear()
|
||||
}
|
||||
is SlashCommand.FilterItems -> {
|
||||
val filter = command.filter.removePrefix(SLASH_PREFIX)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.anytypeio.anytype.core_ui.features.page.slash.holders
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashItem
|
||||
import kotlinx.android.synthetic.main.item_slash_widget_color.view.*
|
||||
import java.util.*
|
||||
|
||||
class ColorMenuHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val locale: Locale = Locale.getDefault()
|
||||
|
||||
fun bind(item: SlashItem.Color) = with(itemView) {
|
||||
when (item) {
|
||||
is SlashItem.Color.Text -> {
|
||||
circle.isSelected = item.isSelected
|
||||
val color = ThemeColor.values().first { it.title == item.code }
|
||||
circle.innerColor = color.text
|
||||
title.text = item.code.capitalize(locale)
|
||||
}
|
||||
is SlashItem.Color.Background -> {
|
||||
circle.isSelected = item.isSelected
|
||||
val color = ThemeColor.values().first { it.title == item.code }
|
||||
circle.innerColor = color.background
|
||||
val background = item.code.capitalize(Locale.getDefault())
|
||||
title.text = resources.getString(R.string.slash_widget_background_item, background)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,6 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="55dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<com.anytypeio.anytype.core_ui.widgets.ColorCircleWidget
|
||||
android:id="@+id/circle"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginStart="9dp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
app:outerStrokeColor="#DFDDD0"
|
||||
app:innerRadius="11dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="52dp"
|
||||
style="@style/SlashWidgetStyleItemTitle"
|
||||
tools:text="Ultramarine" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginStart="52dp"
|
||||
android:background="@drawable/divider_relations"
|
||||
android:layout_gravity="bottom"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -374,6 +374,8 @@
|
|||
<string name="slash_widget_align_center">Center</string>
|
||||
<string name="slash_widget_align_left">Left</string>
|
||||
|
||||
<string name="slash_widget_background_item">%1$s background</string>
|
||||
|
||||
<string name="dv_filter_checkbox_checked">checked</string>
|
||||
<string name="dv_filter_checkbox_not_checked">not checked</string>
|
||||
<string name="paste_or_type_a_url">Paste or type a URL</string>
|
||||
|
|
|
@ -81,5 +81,6 @@ dependencies {
|
|||
testImplementation unitTestDependencies.liveDataTesting
|
||||
testImplementation unitTestDependencies.archCoreTesting
|
||||
testImplementation unitTestDependencies.androidXTestCore
|
||||
testImplementation unitTestDependencies.robolectricLatest
|
||||
testImplementation unitTestDependencies.timberJUnit
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import com.anytypeio.anytype.domain.block.interactor.RemoveLinkMark
|
|||
import com.anytypeio.anytype.domain.block.interactor.UpdateLinkMarks
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateText
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.clipboard.Copy
|
||||
import com.anytypeio.anytype.domain.clipboard.Paste
|
||||
import com.anytypeio.anytype.domain.cover.RemoveDocCover
|
||||
import com.anytypeio.anytype.domain.cover.SetDocCoverImage
|
||||
|
@ -3683,6 +3682,21 @@ class PageViewModel(
|
|||
val items = listOf(SlashItem.Subheader.AlignmentWithBack) + SlashExtensions.getAlignmentItems()
|
||||
onSlashCommand(SlashCommand.ShowAlignmentItems(items))
|
||||
}
|
||||
is SlashItem.Main.Color -> {
|
||||
val block = blocks.first { it.id == targetId }
|
||||
val items = listOf(SlashItem.Subheader.ColorWithBack) + SlashExtensions.getColorItems(
|
||||
code = block.content.asText().color
|
||||
)
|
||||
onSlashCommand(SlashCommand.ShowColorItems(items))
|
||||
}
|
||||
is SlashItem.Main.Background -> {
|
||||
val block = blocks.first { it.id == targetId }
|
||||
val items = listOf(SlashItem.Subheader.BackgroundWithBack) +
|
||||
SlashExtensions.getBackgroundItems(
|
||||
code = block.content.asText().backgroundColor
|
||||
)
|
||||
onSlashCommand(SlashCommand.ShowBackgroundItems(items))
|
||||
}
|
||||
is SlashItem.Style.Type -> {
|
||||
onSlashStyleTypeItemClicked(item, targetId)
|
||||
}
|
||||
|
@ -3707,12 +3721,46 @@ class PageViewModel(
|
|||
is SlashItem.Alignment -> {
|
||||
onSlashAlignmentItemClicked(item, targetId)
|
||||
}
|
||||
is SlashItem.Color -> {
|
||||
controlPanelInteractor.onEvent(ControlPanelMachine.Event.Slash.OnStop)
|
||||
onSlashItemColorClicked(item, targetId)
|
||||
}
|
||||
else -> {
|
||||
Timber.d("PRESSED ON SLASH ITEM : $item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSlashItemColorClicked(item: SlashItem.Color, targetId: Id) {
|
||||
viewModelScope.launch {
|
||||
orchestrator.stores.focus.update(
|
||||
Editor.Focus(
|
||||
id = targetId,
|
||||
cursor = Editor.Cursor.End
|
||||
)
|
||||
)
|
||||
}
|
||||
val intent = when (item) {
|
||||
is SlashItem.Color.Background -> {
|
||||
Intent.Text.UpdateBackgroundColor(
|
||||
context = context,
|
||||
targets = listOf(targetId),
|
||||
color = item.code
|
||||
)
|
||||
}
|
||||
is SlashItem.Color.Text -> {
|
||||
Intent.Text.UpdateColor(
|
||||
context = context,
|
||||
target = targetId,
|
||||
color = item.code
|
||||
)
|
||||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
orchestrator.proxies.intents.send(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSlashMediaItemClicked(item: SlashItem.Media) {
|
||||
when (item) {
|
||||
SlashItem.Media.Bookmark -> {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.anytypeio.anytype.presentation.page.editor.slash
|
||||
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.UiBlock
|
||||
|
||||
fun List<ObjectType>.toView(): List<SlashItem.ObjectType> = map { oType ->
|
||||
|
@ -85,4 +85,30 @@ object SlashExtensions {
|
|||
SlashItem.Alignment.Center,
|
||||
SlashItem.Alignment.Right
|
||||
)
|
||||
|
||||
fun getColorItems(code: String?): List<SlashItem.Color> =
|
||||
ThemeColor.values().map { themeColor ->
|
||||
val isSelected = if (themeColor.title == ThemeColor.DEFAULT.title && code == null) {
|
||||
true
|
||||
} else {
|
||||
themeColor.title == code
|
||||
}
|
||||
SlashItem.Color.Text(
|
||||
code = themeColor.title,
|
||||
isSelected = isSelected
|
||||
)
|
||||
}
|
||||
|
||||
fun getBackgroundItems(code: String?): List<SlashItem.Color> =
|
||||
ThemeColor.values().map { themeColor ->
|
||||
val isSelected = if (themeColor.title == ThemeColor.DEFAULT.title && code == null) {
|
||||
true
|
||||
} else {
|
||||
themeColor.title == code
|
||||
}
|
||||
SlashItem.Color.Background(
|
||||
code = themeColor.title,
|
||||
isSelected = isSelected
|
||||
)
|
||||
}
|
||||
}
|
|
@ -125,10 +125,17 @@ sealed class SlashItem {
|
|||
//endregion
|
||||
|
||||
//region ALIGNMENT
|
||||
sealed class Alignment : SlashItem(){
|
||||
object Left: Alignment()
|
||||
object Center: Alignment()
|
||||
object Right: Alignment()
|
||||
sealed class Alignment : SlashItem() {
|
||||
object Left : Alignment()
|
||||
object Center : Alignment()
|
||||
object Right : Alignment()
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region TEXT COLOR & BACKGROUND
|
||||
sealed class Color: SlashItem() {
|
||||
data class Text(val code: String, val isSelected: Boolean) : Color()
|
||||
data class Background(val code: String, val isSelected: Boolean) : Color()
|
||||
}
|
||||
//endregion
|
||||
}
|
|
@ -416,4 +416,24 @@ open class EditorPresentationTestSetup {
|
|||
onBlocking { invoke(any()) } doReturn Either.Right(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun stubUpdateBackground() {
|
||||
updateBackgroundColor.stub {
|
||||
onBlocking {
|
||||
invoke(any())
|
||||
} doReturn Either.Right(
|
||||
Payload(context = root, events = emptyList())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun stubUpdateTextColor() {
|
||||
updateTextColor.stub {
|
||||
onBlocking {
|
||||
invoke(any())
|
||||
} doReturn Either.Right(
|
||||
Payload(context = root, events = emptyList())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,797 @@
|
|||
package com.anytypeio.anytype.presentation.page.editor
|
||||
|
||||
import MockDataFactory
|
||||
import android.os.Build
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateBackgroundColor
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateTextColor
|
||||
import com.anytypeio.anytype.domain.editor.Editor
|
||||
import com.anytypeio.anytype.presentation.MockTypicalDocumentFactory
|
||||
import com.anytypeio.anytype.presentation.page.PageViewModel
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashCommand
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashEvent
|
||||
import com.anytypeio.anytype.presentation.page.editor.slash.SlashItem
|
||||
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verifyBlocking
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
@Config(sdk = [Build.VERSION_CODES.P])
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class EditorSlashWidgetColorTest : EditorPresentationTestSetup() {
|
||||
|
||||
@get:Rule
|
||||
val rule = InstantTaskExecutorRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
//region {TEXT COLOR}
|
||||
@Test
|
||||
fun `should selected red color when block text color is red`() {
|
||||
|
||||
val code = ThemeColor.RED.title
|
||||
|
||||
val header = MockTypicalDocumentFactory.header
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
||||
val block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = MockDataFactory.randomString(),
|
||||
color = code,
|
||||
marks = listOf(),
|
||||
style = Block.Content.Text.Style.NUMBERED
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, block.id)
|
||||
)
|
||||
|
||||
val doc = listOf(
|
||||
page,
|
||||
header,
|
||||
title,
|
||||
block
|
||||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateTextColor()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Color)
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
val command = state?.slashWidget?.command
|
||||
|
||||
assertNotNull(command)
|
||||
|
||||
val expected = listOf(
|
||||
SlashItem.Subheader.ColorWithBack,
|
||||
SlashItem.Color.Text(ThemeColor.DEFAULT.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.GREY.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.YELLOW.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.ORANGE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.RED.title, true),
|
||||
SlashItem.Color.Text(ThemeColor.PINK.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.PURPLE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.BLUE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.ICE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.TEAL.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.GREEN.title, false)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = (command as SlashCommand.ShowColorItems).items
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should selected default color when block text color is null`() {
|
||||
|
||||
val code: String? = null
|
||||
|
||||
val header = MockTypicalDocumentFactory.header
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
||||
val block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = MockDataFactory.randomString(),
|
||||
color = code,
|
||||
marks = listOf(),
|
||||
style = Block.Content.Text.Style.NUMBERED
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, block.id)
|
||||
)
|
||||
|
||||
val doc = listOf(
|
||||
page,
|
||||
header,
|
||||
title,
|
||||
block
|
||||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateTextColor()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Color)
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
val command = state?.slashWidget?.command as SlashCommand.ShowColorItems
|
||||
|
||||
assertNotNull(command)
|
||||
|
||||
val expected = listOf(
|
||||
SlashItem.Subheader.ColorWithBack,
|
||||
SlashItem.Color.Text(ThemeColor.DEFAULT.title, true),
|
||||
SlashItem.Color.Text(ThemeColor.GREY.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.YELLOW.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.ORANGE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.RED.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.PINK.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.PURPLE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.BLUE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.ICE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.TEAL.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.GREEN.title, false)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = command.items
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should selected default color when block text color is default`() {
|
||||
|
||||
val code: String = ThemeColor.DEFAULT.title
|
||||
|
||||
val header = MockTypicalDocumentFactory.header
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
||||
val block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = MockDataFactory.randomString(),
|
||||
color = code,
|
||||
marks = listOf(),
|
||||
style = Block.Content.Text.Style.NUMBERED
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, block.id)
|
||||
)
|
||||
|
||||
val doc = listOf(
|
||||
page,
|
||||
header,
|
||||
title,
|
||||
block
|
||||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateTextColor()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Color)
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
val command = state?.slashWidget?.command as SlashCommand.ShowColorItems
|
||||
|
||||
assertNotNull(command)
|
||||
|
||||
val expected = listOf(
|
||||
SlashItem.Subheader.ColorWithBack,
|
||||
SlashItem.Color.Text(ThemeColor.DEFAULT.title, true),
|
||||
SlashItem.Color.Text(ThemeColor.GREY.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.YELLOW.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.ORANGE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.RED.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.PINK.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.PURPLE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.BLUE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.ICE.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.TEAL.title, false),
|
||||
SlashItem.Color.Text(ThemeColor.GREEN.title, false)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = command.items
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should store focus as target block end when text color picked`() {
|
||||
val doc = MockTypicalDocumentFactory.page(root)
|
||||
val block = MockTypicalDocumentFactory.a
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateTextColor()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Color)
|
||||
vm.onSlashItemClicked(SlashItem.Color.Text(code = "red", isSelected = false))
|
||||
|
||||
val focusAfter = orchestrator.stores.focus.current()
|
||||
|
||||
assertEquals(block.id, focusAfter.id)
|
||||
assertEquals(Editor.Cursor.End, focusAfter.cursor)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should hide slash widget when text color picked`() {
|
||||
val doc = MockTypicalDocumentFactory.page(root)
|
||||
val block = MockTypicalDocumentFactory.a
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateTextColor()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Color)
|
||||
vm.onSlashItemClicked(SlashItem.Color.Text(code = "red", isSelected = false))
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
assertNotNull(state)
|
||||
assertFalse(state.slashWidget.isVisible)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should send updateTextColor UseCase when text color picked`() {
|
||||
val doc = MockTypicalDocumentFactory.page(root)
|
||||
val block = MockTypicalDocumentFactory.a
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateTextColor()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
val code = ThemeColor.ICE.title
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Color)
|
||||
vm.onSlashItemClicked(SlashItem.Color.Text(code = code, isSelected = false))
|
||||
|
||||
val params = UpdateTextColor.Params(
|
||||
context = root,
|
||||
target = block.id,
|
||||
color = code
|
||||
)
|
||||
|
||||
coroutineTestRule.advanceTime(PageViewModel.TEXT_CHANGES_DEBOUNCE_DURATION)
|
||||
verifyBlocking(updateTextColor, times(1)) { invoke(params) }
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region {BACKGROUND COLOR}
|
||||
@Test
|
||||
fun `should selected green color when block background color is green`() {
|
||||
|
||||
val code = ThemeColor.GREEN.title
|
||||
|
||||
val header = MockTypicalDocumentFactory.header
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
||||
val block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = MockDataFactory.randomString(),
|
||||
backgroundColor = code,
|
||||
marks = listOf(),
|
||||
style = Block.Content.Text.Style.NUMBERED
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, block.id)
|
||||
)
|
||||
|
||||
val doc = listOf(
|
||||
page,
|
||||
header,
|
||||
title,
|
||||
block
|
||||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateBackground()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Background)
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
val command = state?.slashWidget?.command as SlashCommand.ShowBackgroundItems
|
||||
|
||||
assertNotNull(command)
|
||||
|
||||
val expected = listOf(
|
||||
SlashItem.Subheader.BackgroundWithBack,
|
||||
SlashItem.Color.Background(ThemeColor.DEFAULT.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.GREY.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.YELLOW.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.ORANGE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.RED.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.PINK.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.PURPLE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.BLUE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.ICE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.TEAL.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.GREEN.title, true)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = command.items
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should selected default color when block background color is null`() {
|
||||
|
||||
val code: String? = null
|
||||
|
||||
val header = MockTypicalDocumentFactory.header
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
||||
val block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = MockDataFactory.randomString(),
|
||||
backgroundColor = code,
|
||||
marks = listOf(),
|
||||
style = Block.Content.Text.Style.NUMBERED
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, block.id)
|
||||
)
|
||||
|
||||
val doc = listOf(
|
||||
page,
|
||||
header,
|
||||
title,
|
||||
block
|
||||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateBackground()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Background)
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
val command = state?.slashWidget?.command as SlashCommand.ShowBackgroundItems
|
||||
|
||||
assertNotNull(command)
|
||||
|
||||
val expected = listOf(
|
||||
SlashItem.Subheader.BackgroundWithBack,
|
||||
SlashItem.Color.Background(ThemeColor.DEFAULT.title, true),
|
||||
SlashItem.Color.Background(ThemeColor.GREY.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.YELLOW.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.ORANGE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.RED.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.PINK.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.PURPLE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.BLUE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.ICE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.TEAL.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.GREEN.title, false)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = command.items
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should selected default color when block background color is default`() {
|
||||
|
||||
val code: String = ThemeColor.DEFAULT.title
|
||||
|
||||
val header = MockTypicalDocumentFactory.header
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
||||
val block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = MockDataFactory.randomString(),
|
||||
color = code,
|
||||
marks = listOf(),
|
||||
style = Block.Content.Text.Style.NUMBERED
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, block.id)
|
||||
)
|
||||
|
||||
val doc = listOf(
|
||||
page,
|
||||
header,
|
||||
title,
|
||||
block
|
||||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateBackground()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Background)
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
val command = state?.slashWidget?.command as SlashCommand.ShowBackgroundItems
|
||||
|
||||
assertNotNull(command)
|
||||
|
||||
val expected = listOf(
|
||||
SlashItem.Subheader.BackgroundWithBack,
|
||||
SlashItem.Color.Background(ThemeColor.DEFAULT.title, true),
|
||||
SlashItem.Color.Background(ThemeColor.GREY.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.YELLOW.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.ORANGE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.RED.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.PINK.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.PURPLE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.BLUE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.ICE.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.TEAL.title, false),
|
||||
SlashItem.Color.Background(ThemeColor.GREEN.title, false)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = command.items
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should store focus as target block end when background color picked`() {
|
||||
val doc = MockTypicalDocumentFactory.page(root)
|
||||
val block = MockTypicalDocumentFactory.a
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateBackground()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Background)
|
||||
vm.onSlashItemClicked(SlashItem.Color.Background(code = "red", isSelected = false))
|
||||
|
||||
val focusAfter = orchestrator.stores.focus.current()
|
||||
|
||||
assertEquals(block.id, focusAfter.id)
|
||||
assertEquals(Editor.Cursor.End, focusAfter.cursor)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should hide slash widget when background color picked`() {
|
||||
val doc = MockTypicalDocumentFactory.page(root)
|
||||
val block = MockTypicalDocumentFactory.a
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateBackground()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Background)
|
||||
vm.onSlashItemClicked(SlashItem.Color.Background(code = "red", isSelected = false))
|
||||
|
||||
val state = vm.controlPanelViewState.value
|
||||
|
||||
assertNotNull(state)
|
||||
assertFalse(state.slashWidget.isVisible)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should send updateBackgroundColor UseCase when background color picked`() {
|
||||
val doc = MockTypicalDocumentFactory.page(root)
|
||||
val block = MockTypicalDocumentFactory.a
|
||||
|
||||
stubInterceptEvents()
|
||||
stubUpdateBackground()
|
||||
stubOpenDocument(document = doc)
|
||||
val vm = buildViewModel()
|
||||
|
||||
vm.onStart(root)
|
||||
|
||||
vm.apply {
|
||||
onBlockFocusChanged(
|
||||
id = block.id,
|
||||
hasFocus = true
|
||||
)
|
||||
onSlashEvent(
|
||||
SlashEvent.Start(
|
||||
cursorCoordinate = 100,
|
||||
slashStart = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
val code = ThemeColor.PURPLE.title
|
||||
|
||||
vm.onSlashItemClicked(SlashItem.Main.Background)
|
||||
vm.onSlashItemClicked(SlashItem.Color.Background(code = code, isSelected = false))
|
||||
|
||||
val params = UpdateBackgroundColor.Params(
|
||||
context = root,
|
||||
targets = listOf(block.id),
|
||||
color = code
|
||||
)
|
||||
|
||||
coroutineTestRule.advanceTime(PageViewModel.TEXT_CHANGES_DEBOUNCE_DURATION)
|
||||
verifyBlocking(updateBackgroundColor, times(1)) { invoke(params) }
|
||||
}
|
||||
//endregion
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue