mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-10 01:51:05 +09:00
New styling toolbar with styling config in control panel view state (#754)
* fix * fix * fix * added new event * push * #594: update * add todo * #594: add extension + tests * #594: fix selection changed event * #594: tests * #594: toolbar close * #594: fixes * #594: link fix * Update workflow.yml * Update workflow.yml Co-authored-by: Ivanov Konstantin <ki@agileburo.com> Co-authored-by: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com>
This commit is contained in:
parent
d309409887
commit
c38da9e53c
10 changed files with 588 additions and 42 deletions
|
@ -552,7 +552,7 @@ open class PageFragment :
|
|||
}
|
||||
|
||||
override fun onBlockActionClicked(id: String, action: ActionItemType) {
|
||||
vm.onActionBarItemClicked(id, action)
|
||||
vm.onActionMenuItemClicked(id, action)
|
||||
}
|
||||
|
||||
private fun handleFocus(focus: Id) {
|
||||
|
@ -786,12 +786,14 @@ open class PageFragment :
|
|||
|
||||
state.stylingToolbar.apply {
|
||||
if (isVisible) {
|
||||
styleToolbar.props = props
|
||||
styleToolbar.update(
|
||||
config = config!!,
|
||||
props = props
|
||||
)
|
||||
hideSoftInput()
|
||||
lifecycleScope.launch {
|
||||
delay(300)
|
||||
mode?.let { styleToolbar.mode = it }
|
||||
type?.let { styleToolbar.applyStylingType(it) }
|
||||
styleToolbar.showWithAnimation()
|
||||
recycler.updatePadding(bottom = dimen(R.dimen.dp_203) + dimen(R.dimen.dp_16))
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.agileburo.anytype.core_ui.widgets.toolbar.BlockStyleToolbarWidget
|
||||
<com.agileburo.anytype.core_ui.widgets.toolbar.style.StyleToolbarWidget
|
||||
android:id="@+id/styleToolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="203dp"
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.agileburo.anytype.core_ui.common.Alignment
|
|||
import com.agileburo.anytype.core_ui.common.Markup
|
||||
import com.agileburo.anytype.core_ui.features.page.styling.StylingMode
|
||||
import com.agileburo.anytype.core_ui.features.page.styling.StylingType
|
||||
import com.agileburo.anytype.core_ui.model.StyleConfig
|
||||
import com.agileburo.anytype.core_ui.widgets.toolbar.adapter.Mention
|
||||
|
||||
/**
|
||||
|
@ -42,6 +43,7 @@ data class ControlPanelState(
|
|||
*/
|
||||
data class Styling(
|
||||
val target: Target? = null,
|
||||
val config: StyleConfig? = null,
|
||||
val props: Props? = null,
|
||||
override val isVisible: Boolean,
|
||||
val mode: StylingMode? = null,
|
||||
|
@ -50,7 +52,12 @@ data class ControlPanelState(
|
|||
|
||||
companion object {
|
||||
fun reset() = Styling(
|
||||
isVisible = false
|
||||
isVisible = false,
|
||||
target = null,
|
||||
config = null,
|
||||
props = null,
|
||||
mode = null,
|
||||
type = null
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,14 @@ import com.agileburo.anytype.core_ui.features.page.styling.StylingEvent
|
|||
import com.agileburo.anytype.core_ui.features.page.styling.StylingMode
|
||||
import com.agileburo.anytype.core_ui.features.page.styling.StylingType
|
||||
import com.agileburo.anytype.core_ui.model.StyleConfig
|
||||
import com.agileburo.anytype.core_ui.reactive.clicks
|
||||
import com.agileburo.anytype.core_ui.state.ControlPanelState
|
||||
import com.agileburo.anytype.core_ui.widgets.toolbar.BlockStyleToolbarWidget
|
||||
import com.agileburo.anytype.core_utils.ext.dimen
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.android.synthetic.main.widget_block_style_toolbar_new.view.*
|
||||
import kotlinx.android.synthetic.main.widget_block_style_toolbar_new.view.close
|
||||
import kotlinx.android.synthetic.main.widget_block_style_toolbar_new.view.pager
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
import timber.log.Timber
|
||||
|
@ -92,4 +95,6 @@ class StyleToolbarWidget @JvmOverloads constructor(
|
|||
StylingType.BACKGROUND.ordinal -> context.getString(R.string.background)
|
||||
else -> throw IllegalStateException("Unexpected view type: $viewType")
|
||||
}
|
||||
|
||||
fun closeButtonClicks() = close.clicks()
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.agileburo.anytype.presentation.extension
|
||||
|
||||
import com.agileburo.anytype.core_ui.common.Markup
|
||||
import com.agileburo.anytype.domain.ext.overlap
|
||||
import com.agileburo.anytype.domain.misc.Overlap
|
||||
|
||||
/**
|
||||
* Check if list of marks contains [Markup.Type] in selection range
|
||||
*
|
||||
* @param marks list of marks
|
||||
* @param selection range to check if mark type is included
|
||||
*/
|
||||
fun Markup.Type.isInRange(marks: List<Markup.Mark>, selection: IntRange): Boolean {
|
||||
if (selection.first >= selection.last) return false
|
||||
val filtered = marks.filter { it.type == this }
|
||||
if (filtered.isEmpty()) return false
|
||||
filtered.forEach { mark ->
|
||||
val range = mark.from..mark.to
|
||||
val overlap = selection.overlap(range)
|
||||
if (overlap in listOf(
|
||||
Overlap.INNER,
|
||||
Overlap.INNER_LEFT,
|
||||
Overlap.INNER_RIGHT,
|
||||
Overlap.EQUAL
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -14,8 +14,10 @@ import com.agileburo.anytype.domain.ext.content
|
|||
import com.agileburo.anytype.domain.ext.overlap
|
||||
import com.agileburo.anytype.domain.misc.Overlap
|
||||
import com.agileburo.anytype.presentation.common.StateReducer
|
||||
import com.agileburo.anytype.presentation.extension.isInRange
|
||||
import com.agileburo.anytype.presentation.mapper.marks
|
||||
import com.agileburo.anytype.presentation.page.ControlPanelMachine.*
|
||||
import com.agileburo.anytype.presentation.page.editor.getStyleConfig
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -97,6 +99,12 @@ sealed class ControlPanelMachine {
|
|||
object OnBlockTextColorSelected : Event()
|
||||
|
||||
|
||||
data class OnEditorContextMenuStyleClicked(
|
||||
val selection: IntRange,
|
||||
val target: Block
|
||||
) : Event()
|
||||
|
||||
|
||||
object OnBlockStyleSelected : Event()
|
||||
|
||||
/**
|
||||
|
@ -285,6 +293,27 @@ sealed class ControlPanelMachine {
|
|||
)
|
||||
)
|
||||
}
|
||||
is Event.OnEditorContextMenuStyleClicked -> {
|
||||
selection = event.selection
|
||||
val config = event.target.getStyleConfig(
|
||||
focus = true,
|
||||
selection = selection
|
||||
)
|
||||
val target = target(event.target)
|
||||
val props = getMarkupLevelStylingProps(target, event.selection)
|
||||
state.copy(
|
||||
mainToolbar = state.mainToolbar.copy(
|
||||
isVisible = false
|
||||
),
|
||||
stylingToolbar = state.stylingToolbar.copy(
|
||||
isVisible = true,
|
||||
config = config,
|
||||
mode = StylingMode.MARKUP,
|
||||
target = target,
|
||||
props = props
|
||||
)
|
||||
)
|
||||
}
|
||||
is Event.OnClearFocusClicked -> init()
|
||||
is Event.OnTextInputClicked -> {
|
||||
if (state.stylingToolbar.isVisible) {
|
||||
|
@ -346,6 +375,10 @@ sealed class ControlPanelMachine {
|
|||
}
|
||||
is Event.OnBlockActionToolbarStyleClicked -> {
|
||||
val target = target(event.target)
|
||||
val config = event.target.getStyleConfig(
|
||||
focus = null,
|
||||
selection = null
|
||||
)
|
||||
val props = Toolbar.Styling.Props(
|
||||
isBold = target.isBold,
|
||||
isItalic = target.isItalic,
|
||||
|
@ -365,6 +398,7 @@ sealed class ControlPanelMachine {
|
|||
mode = StylingMode.BLOCK,
|
||||
type = StylingType.STYLE,
|
||||
target = target(event.target),
|
||||
config = config,
|
||||
props = props
|
||||
)
|
||||
)
|
||||
|
@ -506,11 +540,11 @@ sealed class ControlPanelMachine {
|
|||
}
|
||||
|
||||
return Toolbar.Styling.Props(
|
||||
isBold = target.isBold,
|
||||
isItalic = target.isItalic,
|
||||
isStrikethrough = target.isStrikethrough,
|
||||
isCode = target.isCode,
|
||||
isLinked = target.isLinked,
|
||||
isBold = Markup.Type.BOLD.isInRange(target.marks, selection),
|
||||
isItalic = Markup.Type.ITALIC.isInRange(target.marks, selection),
|
||||
isStrikethrough = Markup.Type.STRIKETHROUGH.isInRange(target.marks, selection),
|
||||
isCode = Markup.Type.KEYBOARD.isInRange(target.marks, selection),
|
||||
isLinked = Markup.Type.LINK.isInRange(target.marks, selection),
|
||||
color = color,
|
||||
background = background,
|
||||
alignment = target.alignment
|
||||
|
|
|
@ -806,15 +806,12 @@ class PageViewModel(
|
|||
|
||||
fun onEditorContextMenuStyleClicked(selection: IntRange) {
|
||||
val target = blocks.first { it.id == orchestrator.stores.focus.current().id }
|
||||
val config = target.getStyleConfig(focus = true, selection = selection)
|
||||
_error.value = "Style menu clicked"
|
||||
// controlPanelInteractor.onEvent(
|
||||
// ControlPanelMachine.Event.OnMarkupContextMenuStyleClicked(
|
||||
// target = target,
|
||||
// selection = selection,
|
||||
// config = config
|
||||
// )
|
||||
// )
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.OnEditorContextMenuStyleClicked(
|
||||
target = target,
|
||||
selection = selection
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun onMarkupActionClicked(markup: Markup.Type, selection: IntRange) {
|
||||
|
@ -848,38 +845,50 @@ class PageViewModel(
|
|||
when (event) {
|
||||
is StylingEvent.Coloring.Text -> {
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP)
|
||||
onMarkupTextColorAction(event.color.title)
|
||||
onStyleToolbarMarkupAction(Markup.Type.TEXT_COLOR, event.color.title)
|
||||
else
|
||||
onToolbarTextColorAction(event.color.title)
|
||||
}
|
||||
is StylingEvent.Coloring.Background -> {
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP)
|
||||
onMarkupBackgroundColorAction(event.color.title)
|
||||
onStyleToolbarMarkupAction(Markup.Type.BACKGROUND_COLOR, event.color.title)
|
||||
else
|
||||
onBlockBackgroundColorAction(event.color.title)
|
||||
}
|
||||
is StylingEvent.Markup.Bold -> {
|
||||
onBlockStyleMarkupActionClicked(
|
||||
action = Markup.Type.BOLD
|
||||
)
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP) {
|
||||
onStyleToolbarMarkupAction(type = Markup.Type.BOLD)
|
||||
} else {
|
||||
onBlockStyleMarkupActionClicked(action = Markup.Type.BOLD)
|
||||
}
|
||||
}
|
||||
is StylingEvent.Markup.Italic -> {
|
||||
onBlockStyleMarkupActionClicked(
|
||||
action = Markup.Type.ITALIC
|
||||
)
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP) {
|
||||
onStyleToolbarMarkupAction(type = Markup.Type.ITALIC)
|
||||
} else {
|
||||
onBlockStyleMarkupActionClicked(action = Markup.Type.ITALIC)
|
||||
}
|
||||
}
|
||||
is StylingEvent.Markup.StrikeThrough -> {
|
||||
onBlockStyleMarkupActionClicked(
|
||||
action = Markup.Type.STRIKETHROUGH
|
||||
)
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP) {
|
||||
onStyleToolbarMarkupAction(type = Markup.Type.STRIKETHROUGH)
|
||||
} else {
|
||||
onBlockStyleMarkupActionClicked(action = Markup.Type.STRIKETHROUGH)
|
||||
}
|
||||
}
|
||||
is StylingEvent.Markup.Code -> {
|
||||
onBlockStyleMarkupActionClicked(
|
||||
action = Markup.Type.KEYBOARD
|
||||
)
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP) {
|
||||
onStyleToolbarMarkupAction(type = Markup.Type.KEYBOARD)
|
||||
} else {
|
||||
onBlockStyleMarkupActionClicked(action = Markup.Type.KEYBOARD)
|
||||
}
|
||||
}
|
||||
is StylingEvent.Markup.Link -> {
|
||||
onBlockStyleLinkClicked()
|
||||
if (state.stylingToolbar.mode == StylingMode.MARKUP) {
|
||||
onStyleToolbarMarkupAction(type = Markup.Type.LINK)
|
||||
} else {
|
||||
onBlockStyleLinkClicked()
|
||||
}
|
||||
}
|
||||
is StylingEvent.Alignment.Left -> {
|
||||
onBlockAlignmentActionClicked(
|
||||
|
@ -945,7 +954,18 @@ class PageViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onBlockAlignmentActionClicked(alignment: Alignment) {
|
||||
private fun onStyleToolbarMarkupAction(type: Markup.Type, param: String? = null) {
|
||||
viewModelScope.launch {
|
||||
markupActionPipeline.send(
|
||||
MarkupAction(
|
||||
type = type,
|
||||
param = param
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onBlockAlignmentActionClicked(alignment: Alignment) {
|
||||
controlPanelInteractor.onEvent(ControlPanelMachine.Event.StylingToolbar.OnAlignmentSelected)
|
||||
|
||||
val state = stateData.value
|
||||
|
@ -997,7 +1017,7 @@ class PageViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onBlockBackgroundColorAction(color: String) {
|
||||
private fun onBlockBackgroundColorAction(color: String) {
|
||||
controlPanelInteractor.onEvent(ControlPanelMachine.Event.OnBlockBackgroundColorSelected)
|
||||
viewModelScope.launch {
|
||||
orchestrator.proxies.intents.send(
|
||||
|
@ -1010,7 +1030,7 @@ class PageViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onBlockStyleLinkClicked() {
|
||||
private fun onBlockStyleLinkClicked() {
|
||||
val target = blocks.first { it.id == orchestrator.stores.focus.current().id }
|
||||
val range = IntRange(
|
||||
start = 0,
|
||||
|
@ -1019,7 +1039,7 @@ class PageViewModel(
|
|||
stateData.value = ViewState.OpenLinkScreen(context, target, range)
|
||||
}
|
||||
|
||||
fun onBlockStyleMarkupActionClicked(action: Markup.Type) {
|
||||
private fun onBlockStyleMarkupActionClicked(action: Markup.Type) {
|
||||
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.OnBlockStyleSelected
|
||||
|
@ -1058,7 +1078,7 @@ class PageViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onActionBarItemClicked(id: String, action: ActionItemType) {
|
||||
fun onActionMenuItemClicked(id: String, action: ActionItemType) {
|
||||
when (action) {
|
||||
ActionItemType.TurnInto -> {
|
||||
dispatch(Command.OpenTurnIntoPanel(target = id))
|
||||
|
@ -1077,10 +1097,26 @@ class PageViewModel(
|
|||
ActionItemType.MoveTo -> {
|
||||
_error.value = "Move To not implemented"
|
||||
}
|
||||
ActionItemType.Color -> {
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.OnBlockActionToolbarTextColorClicked(
|
||||
target = blocks.first { it.id == id }
|
||||
)
|
||||
)
|
||||
dispatch(Command.PopBackStack)
|
||||
}
|
||||
ActionItemType.Background -> {
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.OnBlockActionToolbarBackgroundColorClicked(
|
||||
target = blocks.first { it.id == id }
|
||||
)
|
||||
)
|
||||
dispatch(Command.PopBackStack)
|
||||
}
|
||||
ActionItemType.Style -> {
|
||||
controlPanelInteractor.onEvent(
|
||||
ControlPanelMachine.Event.OnBlockActionToolbarStyleClicked(
|
||||
target = blocks.first { it.id == orchestrator.stores.focus.current().id }
|
||||
target = blocks.first { it.id == id }
|
||||
)
|
||||
)
|
||||
dispatch(Command.PopBackStack)
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
package com.agileburo.anytype.presentation.extension
|
||||
|
||||
import com.agileburo.anytype.core_ui.common.Markup
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class MarkupExtensionKtTest {
|
||||
|
||||
@Test
|
||||
fun `should be true in range with overlap EQUAL`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 0..5
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be true in range with overlap INNER`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 1..4
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be true in range with overlap INNER_LEFT`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 0..3
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be true in range with overlap INNER_RIGHT`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 3..5
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false in range with overlap LEFT`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 0..3
|
||||
|
||||
val marks = listOf(Markup.Mark(1, 4, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false in range with overlap RIGHT`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 3..5
|
||||
|
||||
val marks = listOf(Markup.Mark(1, 4, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false in range with overlap OUTER`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 0..5
|
||||
|
||||
val marks = listOf(Markup.Mark(1, 4, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false when markup is not present`() {
|
||||
val bold = Markup.Type.ITALIC
|
||||
|
||||
val selection = 0..5
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false when no markups`() {
|
||||
val bold = Markup.Type.ITALIC
|
||||
|
||||
val selection = 0..5
|
||||
|
||||
val marks = listOf<Markup.Mark>()
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false when selection is 0`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = 0..0
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be false when selection is EMPTY`() {
|
||||
val bold = Markup.Type.BOLD
|
||||
|
||||
val selection = IntRange.EMPTY
|
||||
|
||||
val marks = listOf(Markup.Mark(0, 5, Markup.Type.BOLD))
|
||||
|
||||
val result = bold.isInRange(marks, selection)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
package com.agileburo.anytype.presentation.page
|
||||
|
||||
import MockDataFactory
|
||||
import com.agileburo.anytype.core_ui.common.Alignment
|
||||
import com.agileburo.anytype.core_ui.common.Markup
|
||||
import com.agileburo.anytype.core_ui.features.page.styling.StylingMode
|
||||
import com.agileburo.anytype.core_ui.features.page.styling.StylingType
|
||||
import com.agileburo.anytype.core_ui.model.StyleConfig
|
||||
import com.agileburo.anytype.core_ui.state.ControlPanelState
|
||||
import com.agileburo.anytype.domain.block.model.Block
|
||||
import com.agileburo.anytype.presentation.util.CoroutinesTestRule
|
||||
|
@ -549,4 +554,278 @@ class ControlPanelStateReducerTest {
|
|||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should update style toolbar state with italic true after selection changed`() {
|
||||
|
||||
val id = MockDataFactory.randomUuid()
|
||||
val selectionFirst = IntRange(0, 2)
|
||||
val selectionSecond = IntRange(4, 6)
|
||||
|
||||
val given = ControlPanelState(
|
||||
focus = ControlPanelState.Focus(
|
||||
id = id,
|
||||
type = ControlPanelState.Focus.Type.P
|
||||
),
|
||||
mainToolbar = ControlPanelState.Toolbar.Main(
|
||||
isVisible = false
|
||||
),
|
||||
stylingToolbar = ControlPanelState.Toolbar.Styling(
|
||||
isVisible = true,
|
||||
target = ControlPanelState.Toolbar.Styling.Target(
|
||||
text = "Foo Bar",
|
||||
color = "yellow",
|
||||
background = "red",
|
||||
alignment = Alignment.START,
|
||||
marks = listOf(
|
||||
Markup.Mark(0, 3, Markup.Type.BOLD),
|
||||
Markup.Mark(4, 7, Markup.Type.ITALIC)
|
||||
)
|
||||
),
|
||||
config = StyleConfig(
|
||||
visibleTypes = listOf(
|
||||
StylingType.STYLE,
|
||||
StylingType.TEXT_COLOR,
|
||||
StylingType.BACKGROUND
|
||||
),
|
||||
enabledAlignment = listOf(),
|
||||
enabledMarkup = listOf(
|
||||
Markup.Type.BOLD,
|
||||
Markup.Type.ITALIC,
|
||||
Markup.Type.STRIKETHROUGH,
|
||||
Markup.Type.KEYBOARD,
|
||||
Markup.Type.LINK
|
||||
)
|
||||
),
|
||||
props = ControlPanelState.Toolbar.Styling.Props(
|
||||
isBold = true,
|
||||
isItalic = false,
|
||||
isStrikethrough = false,
|
||||
isCode = false,
|
||||
isLinked = false,
|
||||
alignment = Alignment.START,
|
||||
color = "yellow",
|
||||
background = "red"
|
||||
),
|
||||
mode = StylingMode.MARKUP,
|
||||
type = null
|
||||
),
|
||||
multiSelect = ControlPanelState.Toolbar.MultiSelect(
|
||||
isVisible = false
|
||||
),
|
||||
mentionToolbar = ControlPanelState.Toolbar.MentionToolbar(
|
||||
isVisible = false,
|
||||
cursorCoordinate = null,
|
||||
mentionFilter = null,
|
||||
mentionFrom = null
|
||||
)
|
||||
)
|
||||
|
||||
val result = runBlocking {
|
||||
reducer.selection = selectionFirst
|
||||
reducer.reduce(
|
||||
state = given,
|
||||
event = ControlPanelMachine.Event.OnSelectionChanged(selection = selectionSecond)
|
||||
)
|
||||
}
|
||||
|
||||
val expected = ControlPanelState(
|
||||
focus = ControlPanelState.Focus(
|
||||
id = id,
|
||||
type = ControlPanelState.Focus.Type.P
|
||||
),
|
||||
mainToolbar = ControlPanelState.Toolbar.Main(
|
||||
isVisible = false
|
||||
),
|
||||
stylingToolbar = ControlPanelState.Toolbar.Styling(
|
||||
isVisible = true,
|
||||
target = ControlPanelState.Toolbar.Styling.Target(
|
||||
text = "Foo Bar",
|
||||
color = "yellow",
|
||||
background = "red",
|
||||
alignment = Alignment.START,
|
||||
marks = listOf(
|
||||
Markup.Mark(0, 3, Markup.Type.BOLD),
|
||||
Markup.Mark(4, 7, Markup.Type.ITALIC)
|
||||
)
|
||||
),
|
||||
config = StyleConfig(
|
||||
visibleTypes = listOf(
|
||||
StylingType.STYLE,
|
||||
StylingType.TEXT_COLOR,
|
||||
StylingType.BACKGROUND
|
||||
),
|
||||
enabledAlignment = listOf(),
|
||||
enabledMarkup = listOf(
|
||||
Markup.Type.BOLD,
|
||||
Markup.Type.ITALIC,
|
||||
Markup.Type.STRIKETHROUGH,
|
||||
Markup.Type.KEYBOARD,
|
||||
Markup.Type.LINK
|
||||
)
|
||||
),
|
||||
props = ControlPanelState.Toolbar.Styling.Props(
|
||||
isBold = false,
|
||||
isItalic = true,
|
||||
isStrikethrough = false,
|
||||
isCode = false,
|
||||
isLinked = false,
|
||||
alignment = Alignment.START,
|
||||
color = "yellow",
|
||||
background = "red"
|
||||
),
|
||||
mode = StylingMode.MARKUP,
|
||||
type = null
|
||||
),
|
||||
multiSelect = ControlPanelState.Toolbar.MultiSelect(
|
||||
isVisible = false
|
||||
),
|
||||
mentionToolbar = ControlPanelState.Toolbar.MentionToolbar(
|
||||
isVisible = false,
|
||||
cursorCoordinate = null,
|
||||
mentionFilter = null,
|
||||
mentionFrom = null
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should update style toolbar state without markup after selection changed`() {
|
||||
|
||||
val id = MockDataFactory.randomUuid()
|
||||
val selectionFirst = IntRange(0, 2)
|
||||
val selectionSecond = IntRange(4, 6)
|
||||
|
||||
val given = ControlPanelState(
|
||||
focus = ControlPanelState.Focus(
|
||||
id = id,
|
||||
type = ControlPanelState.Focus.Type.P
|
||||
),
|
||||
mainToolbar = ControlPanelState.Toolbar.Main(
|
||||
isVisible = false
|
||||
),
|
||||
stylingToolbar = ControlPanelState.Toolbar.Styling(
|
||||
isVisible = true,
|
||||
target = ControlPanelState.Toolbar.Styling.Target(
|
||||
text = "Foo Bar",
|
||||
color = "yellow",
|
||||
background = "red",
|
||||
alignment = Alignment.START,
|
||||
marks = listOf(
|
||||
Markup.Mark(0, 3, Markup.Type.BOLD)
|
||||
)
|
||||
),
|
||||
config = StyleConfig(
|
||||
visibleTypes = listOf(
|
||||
StylingType.STYLE,
|
||||
StylingType.TEXT_COLOR,
|
||||
StylingType.BACKGROUND
|
||||
),
|
||||
enabledAlignment = listOf(),
|
||||
enabledMarkup = listOf(
|
||||
Markup.Type.BOLD,
|
||||
Markup.Type.ITALIC,
|
||||
Markup.Type.STRIKETHROUGH,
|
||||
Markup.Type.KEYBOARD,
|
||||
Markup.Type.LINK
|
||||
)
|
||||
),
|
||||
props = ControlPanelState.Toolbar.Styling.Props(
|
||||
isBold = true,
|
||||
isItalic = false,
|
||||
isStrikethrough = false,
|
||||
isCode = false,
|
||||
isLinked = false,
|
||||
alignment = Alignment.START,
|
||||
color = "yellow",
|
||||
background = "red"
|
||||
),
|
||||
mode = StylingMode.MARKUP,
|
||||
type = null
|
||||
),
|
||||
multiSelect = ControlPanelState.Toolbar.MultiSelect(
|
||||
isVisible = false
|
||||
),
|
||||
mentionToolbar = ControlPanelState.Toolbar.MentionToolbar(
|
||||
isVisible = false,
|
||||
cursorCoordinate = null,
|
||||
mentionFilter = null,
|
||||
mentionFrom = null
|
||||
)
|
||||
)
|
||||
|
||||
val result = runBlocking {
|
||||
reducer.selection = selectionFirst
|
||||
reducer.reduce(
|
||||
state = given,
|
||||
event = ControlPanelMachine.Event.OnSelectionChanged(selection = selectionSecond)
|
||||
)
|
||||
}
|
||||
|
||||
val expected = ControlPanelState(
|
||||
focus = ControlPanelState.Focus(
|
||||
id = id,
|
||||
type = ControlPanelState.Focus.Type.P
|
||||
),
|
||||
mainToolbar = ControlPanelState.Toolbar.Main(
|
||||
isVisible = false
|
||||
),
|
||||
stylingToolbar = ControlPanelState.Toolbar.Styling(
|
||||
isVisible = true,
|
||||
target = ControlPanelState.Toolbar.Styling.Target(
|
||||
text = "Foo Bar",
|
||||
color = "yellow",
|
||||
background = "red",
|
||||
alignment = Alignment.START,
|
||||
marks = listOf(
|
||||
Markup.Mark(0, 3, Markup.Type.BOLD)
|
||||
)
|
||||
),
|
||||
config = StyleConfig(
|
||||
visibleTypes = listOf(
|
||||
StylingType.STYLE,
|
||||
StylingType.TEXT_COLOR,
|
||||
StylingType.BACKGROUND
|
||||
),
|
||||
enabledAlignment = listOf(),
|
||||
enabledMarkup = listOf(
|
||||
Markup.Type.BOLD,
|
||||
Markup.Type.ITALIC,
|
||||
Markup.Type.STRIKETHROUGH,
|
||||
Markup.Type.KEYBOARD,
|
||||
Markup.Type.LINK
|
||||
)
|
||||
),
|
||||
props = ControlPanelState.Toolbar.Styling.Props(
|
||||
isBold = false,
|
||||
isItalic = false,
|
||||
isStrikethrough = false,
|
||||
isCode = false,
|
||||
isLinked = false,
|
||||
alignment = Alignment.START,
|
||||
color = "yellow",
|
||||
background = "red"
|
||||
),
|
||||
mode = StylingMode.MARKUP,
|
||||
type = null
|
||||
),
|
||||
multiSelect = ControlPanelState.Toolbar.MultiSelect(
|
||||
isVisible = false
|
||||
),
|
||||
mentionToolbar = ControlPanelState.Toolbar.MentionToolbar(
|
||||
isVisible = false,
|
||||
cursorCoordinate = null,
|
||||
mentionFilter = null,
|
||||
mentionFrom = null
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1605,7 +1605,7 @@ class PageViewModelTest {
|
|||
coroutineTestRule.advanceTime(1001)
|
||||
|
||||
vm.onBlockFocusChanged(id = child, hasFocus = true)
|
||||
vm.onActionBarItemClicked(id = child, action = ActionItemType.Delete)
|
||||
vm.onActionMenuItemClicked(id = child, action = ActionItemType.Delete)
|
||||
|
||||
runBlockingTest {
|
||||
verify(unlinkBlocks, times(1)).invoke(
|
||||
|
@ -1691,7 +1691,7 @@ class PageViewModelTest {
|
|||
|
||||
vm.onBlockFocusChanged(id = firstChild, hasFocus = true)
|
||||
//vm.onActionDeleteClicked()
|
||||
vm.onActionBarItemClicked(id = firstChild, action = ActionItemType.Delete)
|
||||
vm.onActionMenuItemClicked(id = firstChild, action = ActionItemType.Delete)
|
||||
|
||||
assertEquals(expected = 3, actual = vm.blocks.size)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue