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

Editor | Enhancement | Callout cleanup (#2389)

Editor | Enhancement | Callout cleanup
This commit is contained in:
Sergey Boishtyan 2022-06-27 18:57:26 +03:00 committed by GitHub
parent 439ab0c502
commit c5198bae5b
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 149 additions and 494 deletions

View file

@ -57,7 +57,6 @@ import com.anytypeio.anytype.core_ui.extensions.color
import com.anytypeio.anytype.core_ui.extensions.cursorYBottomCoordinate
import com.anytypeio.anytype.core_ui.features.editor.BlockAdapter
import com.anytypeio.anytype.core_ui.features.editor.DragAndDropAdapterDelegate
import com.anytypeio.anytype.core_ui.features.editor.TurnIntoActionReceiver
import com.anytypeio.anytype.core_ui.features.editor.scrollandmove.DefaultScrollAndMoveTargetDescriptor
import com.anytypeio.anytype.core_ui.features.editor.scrollandmove.ScrollAndMoveStateListener
import com.anytypeio.anytype.core_ui.features.editor.scrollandmove.ScrollAndMoveTargetHighlighter
@ -106,7 +105,6 @@ import com.anytypeio.anytype.presentation.editor.editor.ThemeColor
import com.anytypeio.anytype.presentation.editor.editor.ViewState
import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.UiBlock
import com.anytypeio.anytype.presentation.editor.editor.sam.ScrollAndMoveTarget
import com.anytypeio.anytype.presentation.editor.editor.sam.ScrollAndMoveTargetDescriptor
import com.anytypeio.anytype.presentation.editor.markup.MarkupColorView
@ -164,7 +162,6 @@ import kotlin.math.abs
open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.fragment_editor),
OnFragmentInteractionListener,
TurnIntoActionReceiver,
SelectProgrammingLanguageReceiver,
RelationTextValueFragment.TextValueEditReceiver,
RelationDateValueFragment.DateValueEditReceiver,
@ -739,14 +736,6 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
vm.onAddBookmarkUrl(target = target, url = url)
}
override fun onTurnIntoBlockClicked(target: String, uiBlock: UiBlock) {
vm.onTurnIntoBlockClicked(target, uiBlock)
}
override fun onTurnIntoMultiSelectBlockClicked(block: UiBlock) {
vm.onTurnIntoMultiSelectBlockClicked(block)
}
override fun onAddMarkupLinkClicked(blockId: String, link: String, range: IntRange) {
vm.onAddLinkPressed(blockId, link, range)
}

View file

@ -35,7 +35,6 @@ class Callout(
override val root: View = itemView
override val content: TextInputWidget = binding.calloutText
private val icon: ObjectIconWidget = binding.calloutIcon
private val container = binding.calloutContainer
private val mentionIconSize: Int
private val mentionIconPadding: Int

View file

@ -1,8 +1,8 @@
package com.anytypeio.anytype.core_ui
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_models.StubParagraph
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.CALLOUT_ICON_CHANGED
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.DECORATION_CHANGED
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.MARKUP_CHANGED
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.TEXT_CHANGED
@ -1581,4 +1581,54 @@ class BlockViewDiffUtilTest {
expected = null
)
}
@Test
fun `should detect icon change for callout`() {
val index = 0
val oldBlock = StubCalloutView(
icon = ObjectIcon.Basic.Emoji("stub")
)
val newBlock = oldBlock.copy(
icon = ObjectIcon.None
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
assertEquals(
actual = payload,
expected = Payload(listOf(CALLOUT_ICON_CHANGED))
)
}
@Test
fun `should not detect icon change for callout`() {
val index = 0
val oldBlock = StubCalloutView(
icon = ObjectIcon.Basic.Emoji("stub")
)
val newBlock = oldBlock
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
assertEquals(
actual = payload,
expected = null
)
}
}

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.presentation.editor.editor.Markup
import com.anytypeio.anytype.presentation.editor.editor.model.Alignment
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.model.Indent
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.test_utils.MockDataFactory
fun StubParagraphView(
@ -22,7 +23,7 @@ fun StubParagraphView(
ghostSelection: IntRange? = null,
cursor: Int? = null,
alignment: Alignment? = null
) : BlockView.Text.Paragraph = BlockView.Text.Paragraph(
): BlockView.Text.Paragraph = BlockView.Text.Paragraph(
id = id,
text = text,
marks = marks,
@ -55,7 +56,7 @@ fun StubNumberedView(
cursor: Int? = null,
alignment: Alignment? = null,
number: Int = 1
) : BlockView.Text.Numbered = BlockView.Text.Numbered(
): BlockView.Text.Numbered = BlockView.Text.Numbered(
id = id,
text = text,
marks = marks,
@ -88,7 +89,7 @@ fun StubBulletedView(
ghostSelection: IntRange? = null,
cursor: Int? = null,
alignment: Alignment? = null,
) : BlockView.Text.Bulleted = BlockView.Text.Bulleted(
): BlockView.Text.Bulleted = BlockView.Text.Bulleted(
id = id,
text = text,
marks = marks,
@ -121,7 +122,7 @@ fun StubCheckboxView(
cursor: Int? = null,
alignment: Alignment? = null,
isChecked: Boolean = false
) : BlockView.Text.Checkbox = BlockView.Text.Checkbox(
): BlockView.Text.Checkbox = BlockView.Text.Checkbox(
id = id,
text = text,
marks = marks,
@ -156,7 +157,7 @@ fun StubToggleView(
alignment: Alignment? = null,
isEmpty: Boolean = false,
toggled: Boolean = false
) : BlockView.Text.Toggle = BlockView.Text.Toggle(
): BlockView.Text.Toggle = BlockView.Text.Toggle(
id = id,
text = text,
marks = marks,
@ -173,4 +174,36 @@ fun StubToggleView(
alignment = alignment,
isEmpty = isEmpty,
toggled = toggled
)
fun StubCalloutView(
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,
icon: ObjectIcon = ObjectIcon.None
): BlockView.Text.Callout = BlockView.Text.Callout(
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,
icon = icon
)

View file

@ -1,11 +1,13 @@
package com.anytypeio.anytype.presentation.editor
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Document
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.domain.editor.Editor
import com.anytypeio.anytype.domain.editor.Editor.Focus
import com.anytypeio.anytype.presentation.editor.editor.Proxy
import com.anytypeio.anytype.presentation.editor.editor.Store
import com.anytypeio.anytype.presentation.editor.editor.actions.ActionItemType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
import kotlinx.coroutines.flow.Flow
@ -13,21 +15,66 @@ import kotlinx.coroutines.flow.MutableStateFlow
interface Editor {
/**
* Mode of user interaction with the editor.
*/
sealed class Mode {
/**
* Default mode of interaction with the editor: content editing is fully enabled.
*/
object Edit : Mode()
/**
* Editor in preview state.
* Currently used for templates, which can't be edited.
*/
object Read : Mode()
/**
* Editor in locked state.
* Locked mode is toggled in object menu.
*/
object Locked: Mode()
/**
* Editor in select mode: when one or multiple blocks are selected.
* To enter this mode, user long-clicks a block.
*/
object Select : Mode()
/**
* Editor in scroll-and-move mode: one or multiple blocks are selected, then moved to new position by scrolling.
* @see [ActionItemType.SAM]
*/
object SAM : Mode()
object Action: Mode()
/**
* Editor in search-on-page state: searching plain text through blocks.
* @see [Block.Content.Text.Style]
*/
object Search : Mode()
/**
* Editor in text styling mode.
*/
sealed class Styling : Mode() {
/**
* Enabled when user selects style option in BlockToolbar for focused block.
* @property [target] id of the selected block
* @property [cursor] cursor position before selection (we might need to restore cursor position after unselecting [target] block)
*/
data class Single(
val target: Id,
val cursor: Int?
) : Styling()
/**
* Enabled when user selects multiple blocks and choose [ActionItemType.Style] from ActionToolbar
* @property [targets] ids of the selected blocks.
*/
data class Multi(val targets: Set<Id>) : Styling()
}
object Locked: Mode()
}
class Storage {

View file

@ -2460,7 +2460,7 @@ class EditorViewModel(
// ----------------- Turn Into -----------------------------------------
fun onTurnIntoBlockClicked(target: String, uiBlock: UiBlock) {
private fun onTurnIntoBlockClicked(target: String, uiBlock: UiBlock) {
Timber.d("onTurnIntoBlockClicked, taget:[$target] uiBlock:[$uiBlock]")
proceedUpdateBlockStyle(
targets = listOf(target),
@ -5071,19 +5071,6 @@ class EditorViewModel(
}
}
fun onTurnIntoMultiSelectBlockClicked(uiBlock: UiBlock) {
Timber.d("onTurnIntoMultiSelectBlockClicked, uiBlock:[$uiBlock]")
proceedUpdateBlockStyle(
targets = currentSelection().toList(),
uiBlock = uiBlock,
action = {
clearSelections()
controlPanelInteractor.onEvent(ControlPanelMachine.Event.MultiSelect.OnTurnInto)
},
errorAction = { sendToast("Cannot convert selected blocks to $uiBlock") }
)
}
//endregion
//region MENTION WIDGET

View file

@ -430,12 +430,12 @@ sealed class BlockView : ViewType {
override val mode: Mode = Mode.EDIT,
override val isSelected: Boolean = false,
override var cursor: Int? = null,
override val alignment: Alignment? = null,
override val searchFields: List<Searchable.Field> = emptyList(),
override val ghostEditorSelection: IntRange? = null,
override val decorations: List<Decoration>,
val icon: ObjectIcon,
) : Text() {
override val alignment: Alignment? = null
override fun getViewType() = HOLDER_CALLOUT
override val body: String get() = text
}

View file

@ -1055,7 +1055,7 @@ class DefaultBlockViewRenderer @Inject constructor(
text = normalizedText,
marks = normalizedMarks,
indent = indent,
alignment = content.align?.toView(), color = content.color,
color = content.color,
backgroundColor = block.backgroundColor ?: ThemeColor.GREY.code,
cursor = if (block.id == focus.id) setCursor(focus, content) else null,
isSelected = checkIfSelected(

View file

@ -6,7 +6,6 @@ import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Event
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_models.Position
import com.anytypeio.anytype.core_models.Relation
@ -85,8 +84,8 @@ import com.anytypeio.anytype.presentation.editor.editor.actions.ActionItemType
import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.UiBlock
import com.anytypeio.anytype.presentation.editor.editor.pattern.DefaultPatternMatcher
import com.anytypeio.anytype.presentation.editor.editor.slash.SlashItem
import com.anytypeio.anytype.presentation.editor.editor.styling.StyleToolbarState
import com.anytypeio.anytype.presentation.editor.editor.styling.StylingEvent
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
@ -2070,7 +2069,7 @@ open class EditorViewModelTest {
val newStyle = Block.Content.Text.Style.H1
vm.onTurnIntoBlockClicked(secondChild, UiBlock.HEADER_ONE)
vm.onSlashItemClicked(SlashItem.Style.Type.Title)
runBlockingTest {
verify(turnIntoStyle, times(1)).invoke(

View file

@ -3,11 +3,8 @@ package com.anytypeio.anytype.presentation.editor.editor
import android.os.Build
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Event
import com.anytypeio.anytype.core_models.ext.content
import com.anytypeio.anytype.domain.block.interactor.TurnIntoStyle
import com.anytypeio.anytype.domain.block.interactor.UnlinkBlocks
import com.anytypeio.anytype.domain.block.interactor.UpdateTextStyle
import com.anytypeio.anytype.domain.clipboard.Copy
import com.anytypeio.anytype.presentation.MockBlockContentFactory.StubLinkContent
import com.anytypeio.anytype.presentation.MockBlockFactory
@ -19,7 +16,6 @@ import com.anytypeio.anytype.presentation.editor.editor.actions.ActionItemType
import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.UiBlock
import com.anytypeio.anytype.presentation.editor.editor.styling.StyleToolbarState
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
import com.anytypeio.anytype.presentation.util.TXT
@ -71,333 +67,6 @@ class EditorMultiSelectModeTest : EditorPresentationTestSetup() {
MockitoAnnotations.openMocks(this)
}
@Test
fun `should clear selection after turn-into in multi-select mode`() {
// SETUP
val title = Block(
id = MockDataFactory.randomUuid(),
content = Block.Content.Text(
text = MockDataFactory.randomString(),
style = Block.Content.Text.Style.TITLE,
marks = emptyList()
),
children = emptyList(),
fields = Block.Fields.empty()
)
val header = Block(
id = MockDataFactory.randomUuid(),
content = Block.Content.Layout(
type = Block.Content.Layout.Type.HEADER
),
fields = Block.Fields.empty(),
children = listOf(title.id)
)
val a = Block(
id = MockDataFactory.randomUuid(),
fields = Block.Fields.empty(),
children = emptyList(),
content = Block.Content.Text(
text = MockDataFactory.randomString(),
marks = emptyList(),
style = Block.Content.Text.Style.NUMBERED
)
)
val page = Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Smart(),
children = listOf(header.id, a.id)
)
val document = listOf(page, header, title, a)
stubOpenDocument(document)
stubInterceptEvents()
stubTurnIntoStyle(
params = TurnIntoStyle.Params(
style = Block.Content.Text.Style.QUOTE,
context = root,
targets = listOf(a.id)
),
events = listOf(
Event.Command.GranularChange(
context = root,
id = a.id,
style = Block.Content.Text.Style.QUOTE
)
)
)
val vm = buildViewModel()
vm.onStart(root)
// TESTING
// Try entering multi-select mode
vm.apply {
onBlockFocusChanged(id = a.id, hasFocus = true)
onEnterMultiSelectModeClicked()
}
// Checking control panel entered multi-select mode
vm.controlPanelViewState.test().apply {
assertValue(
ControlPanelState(
multiSelect = ControlPanelState.Toolbar.MultiSelect(
isVisible = true,
isScrollAndMoveEnabled = false,
count = 0
)
)
)
}
// Checking editor entered multi-select mode
coroutineTestRule.advanceTime(DELAY_REFRESH_DOCUMENT_TO_ENTER_MULTI_SELECT_MODE)
vm.state.test().apply {
assertValue(
ViewState.Success(
blocks = listOf(
BlockView.Title.Basic(
id = title.id,
isFocused = false,
text = title.content<TXT>().text,
mode = BlockView.Mode.READ
),
BlockView.Text.Numbered(
id = a.id,
isSelected = false,
isFocused = false,
marks = emptyList(),
backgroundColor = null,
indent = 0,
number = 1,
text = a.content<Block.Content.Text>().text,
mode = BlockView.Mode.READ
)
)
)
)
}
// Perform click, to select block A
vm.onTextInputClicked(
target = a.id
)
// Checking whether block A is selected
vm.state.test().apply {
assertValue(
ViewState.Success(
blocks = listOf(
BlockView.Title.Basic(
id = title.id,
isFocused = false,
text = title.content<TXT>().text,
mode = BlockView.Mode.READ
),
BlockView.Text.Numbered(
id = a.id,
isSelected = true,
isFocused = false,
marks = emptyList(),
backgroundColor = null,
indent = 0,
number = 1,
text = a.content<Block.Content.Text>().text,
mode = BlockView.Mode.READ
)
)
)
)
}
// Turning block A into a highlight block.
vm.onTurnIntoMultiSelectBlockClicked(
UiBlock.HIGHLIGHTED
)
// Checking control panel state after turn-into
vm.controlPanelViewState.test().apply {
assertValue(
ControlPanelState(
multiSelect = ControlPanelState.Toolbar.MultiSelect(
isVisible = true,
isScrollAndMoveEnabled = false,
count = 0
)
)
)
}
// Checking view state state after turn-into
vm.state.test().apply {
assertValue(
ViewState.Success(
blocks = listOf(
BlockView.Title.Basic(
id = title.id,
isFocused = false,
text = title.content<TXT>().text,
mode = BlockView.Mode.READ
),
BlockView.Text.Highlight(
id = a.id,
isSelected = false,
isFocused = false,
marks = emptyList(),
backgroundColor = null,
color = null,
indent = 0,
text = a.content<Block.Content.Text>().text,
mode = BlockView.Mode.READ
)
)
)
)
}
clearPendingCoroutines()
}
@Test
fun `should show main toolbar when block view holder returning to edit mode gains focus after turn-into in multi-select-mode`() {
// SETUP
val a = Block(
id = MockDataFactory.randomUuid(),
fields = Block.Fields.empty(),
children = emptyList(),
content = Block.Content.Text(
text = MockDataFactory.randomString(),
marks = emptyList(),
style = Block.Content.Text.Style.P
)
)
val page = Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Smart(),
children = listOf(header.id, a.id)
)
val document = listOf(page, header, title, a)
stubOpenDocument(document)
stubInterceptEvents()
stubUpdateTextStyle(
params = UpdateTextStyle.Params(
style = Block.Content.Text.Style.QUOTE,
context = root,
targets = listOf(a.id)
),
events = listOf(
Event.Command.GranularChange(
context = root,
id = a.id,
style = Block.Content.Text.Style.QUOTE
)
)
)
val vm = buildViewModel()
// TESTING
vm.onStart(root)
// Try entering multi-select mode
vm.apply {
onBlockFocusChanged(id = a.id, hasFocus = true)
onEnterMultiSelectModeClicked()
}
// Checking control panel entered multi-select mode
vm.controlPanelViewState.test().apply {
assertValue(
ControlPanelState(
multiSelect = ControlPanelState.Toolbar.MultiSelect(
isVisible = true,
isScrollAndMoveEnabled = false,
count = 0
)
)
)
}
coroutineTestRule.advanceTime(DELAY_REFRESH_DOCUMENT_TO_ENTER_MULTI_SELECT_MODE)
// Perform click, to select block A
vm.onTextInputClicked(
target = a.id
)
// Turning block A into a highlight block.
vm.onTurnIntoMultiSelectBlockClicked(
UiBlock.HIGHLIGHTED
)
vm.onExitMultiSelectModeClicked()
vm.onTextInputClicked(
target = a.id
)
vm.onBlockFocusChanged(
id = a.id,
hasFocus = true
)
vm.controlPanelViewState.test().apply {
assertValue(
ControlPanelState(
navigationToolbar = ControlPanelState.Toolbar.Navigation(
isVisible = false
),
mainToolbar = ControlPanelState.Toolbar.Main(
isVisible = true
),
styleTextToolbar = ControlPanelState.Toolbar.Styling.reset(),
multiSelect = ControlPanelState.Toolbar.MultiSelect(
isVisible = false,
isScrollAndMoveEnabled = false,
count = 0
),
mentionToolbar = ControlPanelState.Toolbar.MentionToolbar(
isVisible = false,
cursorCoordinate = null,
mentionFilter = null,
mentionFrom = null
),
slashWidget = ControlPanelState.Toolbar.SlashWidget.reset()
)
)
}
clearPendingCoroutines()
}
@Test
fun `should select all children when selecting parent and unselect children when unselecting parent and exit multi-select mode`() {

View file

@ -6,7 +6,6 @@ import com.anytypeio.anytype.domain.block.interactor.TurnIntoDocument
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
import com.anytypeio.anytype.presentation.editor.EditorViewModel
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.UiBlock
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
import com.anytypeio.anytype.test_utils.MockDataFactory
import org.junit.Before
@ -49,127 +48,6 @@ class EditorTurnIntoTest : EditorPresentationTestSetup() {
MockitoAnnotations.openMocks(this)
}
@Test
fun `should start turning text block into page in edit mode`() {
// SETUP
val child = Block(
id = MockDataFactory.randomUuid(),
fields = Block.Fields.empty(),
children = emptyList(),
content = Block.Content.Text(
text = MockDataFactory.randomUuid(),
marks = emptyList(),
style = Block.Content.Text.Style.values().random()
)
)
val parent = Block(
id = "PARENT",
fields = Block.Fields.empty(),
children = listOf(child.id),
content = Block.Content.Text(
text = MockDataFactory.randomString(),
marks = emptyList(),
style = Block.Content.Text.Style.P
)
)
val page = Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Smart(),
children = listOf(parent.id)
)
val document = listOf(page, parent, child)
val params = TurnIntoDocument.Params(context = root, targets = listOf(child.id))
stubOpenDocument(document = document)
stubInterceptThreadStatus()
stubInterceptEvents(InterceptEvents.Params(context = root))
stubTurnIntoDocument(params)
val vm = buildViewModel()
// TESTING
vm.apply {
onStart(root)
onBlockFocusChanged(
id = child.id,
hasFocus = true
)
onTurnIntoBlockClicked(
target = child.id,
uiBlock = UiBlock.PAGE
)
}
verifyBlocking(turnIntoDocument, times(1)) { invoke(params) }
}
@Test
fun `should start turning into page in multi-select mode`() {
// SETUP
val child = Block(
id = MockDataFactory.randomUuid(),
fields = Block.Fields.empty(),
children = emptyList(),
content = Block.Content.Text(
text = MockDataFactory.randomUuid(),
marks = emptyList(),
style = Block.Content.Text.Style.values().random()
)
)
val parent = Block(
id = "PARENT",
fields = Block.Fields.empty(),
children = listOf(child.id),
content = Block.Content.Text(
text = MockDataFactory.randomString(),
marks = emptyList(),
style = Block.Content.Text.Style.P
)
)
val page = Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Smart(),
children = listOf(header.id, parent.id)
)
val document = listOf(page, header, title, parent, child)
val params = TurnIntoDocument.Params(context = root, targets = listOf(child.id))
stubOpenDocument(document = document)
stubInterceptEvents(InterceptEvents.Params(context = root))
stubInterceptThreadStatus()
stubTurnIntoDocument(params)
val vm = buildViewModel()
// TESTING
vm.apply {
onStart(root)
onBlockFocusChanged(id = child.id, hasFocus = true)
onEnterMultiSelectModeClicked()
coroutineTestRule.advanceTime(EditorViewModel.DELAY_REFRESH_DOCUMENT_TO_ENTER_MULTI_SELECT_MODE)
onTextInputClicked(child.id)
onTurnIntoMultiSelectBlockClicked(UiBlock.PAGE)
}
verifyBlocking(turnIntoDocument, times(1)) { invoke(params) }
}
@Test
fun `should invoke turnIntoDocument on for one text block and one file block in multi-select mode`() {

View file

@ -149,13 +149,17 @@ fun StubCallout(
text: String = MockDataFactory.randomString(),
children: List<Id> = emptyList(),
marks: List<Block.Content.Text.Mark> = emptyList(),
backgroundColor: String? = null
backgroundColor: String? = null,
iconEmoji: String? = null,
iconImage: String? = null,
): Block = Block(
id = MockDataFactory.randomUuid(),
content = StubTextContent(
text = text,
style = Block.Content.Text.Style.CALLOUT,
marks = marks
marks = marks,
iconEmoji = iconEmoji,
iconImage = iconImage,
),
children = children,
fields = Block.Fields.empty(),