mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-264 Editor | Enhancement | Enable search-on-page for simple table block - highlight and select target (#2669)
* DROID-264 stubs of the search field, the table block and the pattern * DROID-264 search highlighting and targeting for table cellls * DROID-264 tests Co-authored-by: konstantiniiv <ki@anytype.io>
This commit is contained in:
parent
8fb9e4c967
commit
7babee5052
3 changed files with 823 additions and 81 deletions
|
@ -1456,4 +1456,441 @@ class BlockViewSearchTextTest {
|
|||
|
||||
assertEquals(expected = expected, actual = actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when no highlighted text is targeted in simple table expect to target row2 column1 cell`() {
|
||||
|
||||
//SETUP
|
||||
val pattern = StubPattern(query = "bc")
|
||||
|
||||
val simpleTableBlock = StubTwoRowsThreeColumnsSimpleTable(
|
||||
textR1C1 = "ab1",
|
||||
textR1C2 = "ab2",
|
||||
textR1C3 = "ac3",
|
||||
textR2C1 = "bc1",
|
||||
textR2C2 = "bb2",
|
||||
textR2C3 = "bc3"
|
||||
)
|
||||
|
||||
val cellR1C1 = simpleTableBlock.cells[0] as BlockView.Table.Cell.Text
|
||||
val cellR1C2 = simpleTableBlock.cells[1] as BlockView.Table.Cell.Text
|
||||
val cellR1C3 = simpleTableBlock.cells[2] as BlockView.Table.Cell.Text
|
||||
val cellR2C1 = simpleTableBlock.cells[3] as BlockView.Table.Cell.Text
|
||||
val cellR2C2 = simpleTableBlock.cells[4] as BlockView.Table.Cell.Text
|
||||
val cellR2C3 = simpleTableBlock.cells[5] as BlockView.Table.Cell.Text
|
||||
|
||||
val blocks = listOf<BlockView>(simpleTableBlock)
|
||||
|
||||
//TESTING
|
||||
val actualHighlighted = blocks.highlight { pairs ->
|
||||
pairs.map { (key, txt) ->
|
||||
BlockView.Searchable.Field(
|
||||
key = key,
|
||||
highlights = txt.search(pattern)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualFirstHighlightedIsTargeted = actualHighlighted.nextSearchTarget()
|
||||
|
||||
//EXPECTING
|
||||
val expectedTargetedCell = cellR2C1.copy(
|
||||
block = cellR2C1.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2)),
|
||||
target = IntRange(0, 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expectedHighlightedCell = cellR2C3.copy(
|
||||
block = cellR2C3.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(
|
||||
IntRange(0, 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expectedCells = listOf(
|
||||
cellR1C1.copy(
|
||||
block = cellR1C1.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C2.copy(
|
||||
block = cellR1C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C3.copy(
|
||||
block = cellR1C3.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
expectedTargetedCell,
|
||||
cellR2C2.copy(
|
||||
block = cellR2C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
expectedHighlightedCell
|
||||
)
|
||||
|
||||
val expectedFirstHighlightedIsTargeted = listOf(
|
||||
simpleTableBlock.copy(cells = expectedCells)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(
|
||||
expected = expectedFirstHighlightedIsTargeted,
|
||||
actual = actualFirstHighlightedIsTargeted
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when first highlighted text is targeted in simple table expect to target next one`() {
|
||||
|
||||
//SETUP
|
||||
val pattern = StubPattern(query = "bc")
|
||||
|
||||
val simpleTableBlock = StubTwoRowsThreeColumnsSimpleTable(
|
||||
textR1C1 = "ab1",
|
||||
textR1C2 = "ab2",
|
||||
textR1C3 = "ac3",
|
||||
textR2C1 = "bc1",
|
||||
textR2C2 = "bb2",
|
||||
textR2C3 = "bc3"
|
||||
)
|
||||
|
||||
val cellR1C1 = simpleTableBlock.cells[0] as BlockView.Table.Cell.Text
|
||||
val cellR1C2 = simpleTableBlock.cells[1] as BlockView.Table.Cell.Text
|
||||
val cellR1C3 = simpleTableBlock.cells[2] as BlockView.Table.Cell.Text
|
||||
val cellR2C1 = simpleTableBlock.cells[3] as BlockView.Table.Cell.Text
|
||||
val cellR2C2 = simpleTableBlock.cells[4] as BlockView.Table.Cell.Text
|
||||
val cellR2C3 = simpleTableBlock.cells[5] as BlockView.Table.Cell.Text
|
||||
|
||||
val blocks = listOf<BlockView>(simpleTableBlock)
|
||||
|
||||
//TESTING
|
||||
val actualHighlighted = blocks.highlight { pairs ->
|
||||
pairs.map { (key, txt) ->
|
||||
BlockView.Searchable.Field(
|
||||
key = key,
|
||||
highlights = txt.search(pattern)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualFirstHighlightedIsTargeted = actualHighlighted.nextSearchTarget()
|
||||
|
||||
val actualSecondHighlightedIsTargeted = actualFirstHighlightedIsTargeted.nextSearchTarget()
|
||||
|
||||
//EXPECTING
|
||||
val expectedCells = listOf(
|
||||
cellR1C1.copy(
|
||||
block = cellR1C1.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C2.copy(
|
||||
block = cellR1C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C3.copy(
|
||||
block = cellR1C3.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C1.copy(
|
||||
block = cellR2C1.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cellR2C2.copy(
|
||||
block = cellR2C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C3.copy(
|
||||
block = cellR2C3.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2)),
|
||||
target = IntRange(0, 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expectedSecondHighlightedIsTargeted = listOf(
|
||||
simpleTableBlock.copy(
|
||||
cells = expectedCells
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(
|
||||
expected = expectedSecondHighlightedIsTargeted,
|
||||
actual = actualSecondHighlightedIsTargeted
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when second highlighted text is targeted in simple table expect to target second one`() {
|
||||
|
||||
//SETUP
|
||||
val pattern = StubPattern(query = "bc")
|
||||
|
||||
val simpleTableBlock = StubTwoRowsThreeColumnsSimpleTable(
|
||||
textR1C1 = "ab1",
|
||||
textR1C2 = "ab2",
|
||||
textR1C3 = "ac3",
|
||||
textR2C1 = "bc1",
|
||||
textR2C2 = "bb2",
|
||||
textR2C3 = "bc3"
|
||||
)
|
||||
|
||||
val cellR1C1 = simpleTableBlock.cells[0] as BlockView.Table.Cell.Text
|
||||
val cellR1C2 = simpleTableBlock.cells[1] as BlockView.Table.Cell.Text
|
||||
val cellR1C3 = simpleTableBlock.cells[2] as BlockView.Table.Cell.Text
|
||||
val cellR2C1 = simpleTableBlock.cells[3] as BlockView.Table.Cell.Text
|
||||
val cellR2C2 = simpleTableBlock.cells[4] as BlockView.Table.Cell.Text
|
||||
val cellR2C3 = simpleTableBlock.cells[5] as BlockView.Table.Cell.Text
|
||||
|
||||
val blocks = listOf<BlockView>(simpleTableBlock)
|
||||
|
||||
//TESTING
|
||||
val actualHighlighted = blocks.highlight { pairs ->
|
||||
pairs.map { (key, txt) ->
|
||||
BlockView.Searchable.Field(
|
||||
key = key,
|
||||
highlights = txt.search(pattern)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualFirstHighlightedIsTargeted = actualHighlighted.nextSearchTarget()
|
||||
val actualSecondHighlightedIsTargeted = actualFirstHighlightedIsTargeted.nextSearchTarget()
|
||||
val actualSecondHighlightedIsTargeted2 =
|
||||
actualSecondHighlightedIsTargeted.nextSearchTarget()
|
||||
|
||||
//EXPECTING
|
||||
val expectedCells = listOf(
|
||||
cellR1C1.copy(
|
||||
block = cellR1C1.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C2.copy(
|
||||
block = cellR1C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C3.copy(
|
||||
block = cellR1C3.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C1.copy(
|
||||
block = cellR2C1.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cellR2C2.copy(
|
||||
block = cellR2C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C3.copy(
|
||||
block = cellR2C3.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2)),
|
||||
target = IntRange(0, 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expectedSecondHighlightedIsTargeted = listOf(
|
||||
simpleTableBlock.copy(
|
||||
cells = expectedCells
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(
|
||||
expected = expectedSecondHighlightedIsTargeted,
|
||||
actual = actualSecondHighlightedIsTargeted2
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when second highlighted text is targeted in simple table expect to target first one`() {
|
||||
|
||||
//SETUP
|
||||
val pattern = StubPattern(query = "bc")
|
||||
|
||||
val simpleTableBlock = StubTwoRowsThreeColumnsSimpleTable(
|
||||
textR1C1 = "ab1",
|
||||
textR1C2 = "ab2",
|
||||
textR1C3 = "ac3",
|
||||
textR2C1 = "bc1",
|
||||
textR2C2 = "bb2",
|
||||
textR2C3 = "bc3"
|
||||
)
|
||||
|
||||
val cellR1C1 = simpleTableBlock.cells[0] as BlockView.Table.Cell.Text
|
||||
val cellR1C2 = simpleTableBlock.cells[1] as BlockView.Table.Cell.Text
|
||||
val cellR1C3 = simpleTableBlock.cells[2] as BlockView.Table.Cell.Text
|
||||
val cellR2C1 = simpleTableBlock.cells[3] as BlockView.Table.Cell.Text
|
||||
val cellR2C2 = simpleTableBlock.cells[4] as BlockView.Table.Cell.Text
|
||||
val cellR2C3 = simpleTableBlock.cells[5] as BlockView.Table.Cell.Text
|
||||
|
||||
val blocks = listOf<BlockView>(simpleTableBlock)
|
||||
|
||||
//TESTING
|
||||
val actualHighlighted = blocks.highlight { pairs ->
|
||||
pairs.map { (key, txt) ->
|
||||
BlockView.Searchable.Field(
|
||||
key = key,
|
||||
highlights = txt.search(pattern)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualFirstHighlightedIsTargeted = actualHighlighted.nextSearchTarget()
|
||||
val actualSecondHighlightedIsTargeted = actualFirstHighlightedIsTargeted.nextSearchTarget()
|
||||
val actualFirstHighlightedIsTargeted2 =
|
||||
actualSecondHighlightedIsTargeted.previousSearchTarget()
|
||||
|
||||
//EXPECTING
|
||||
val expectedCells = listOf(
|
||||
cellR1C1.copy(
|
||||
block = cellR1C1.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C2.copy(
|
||||
block = cellR1C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C3.copy(
|
||||
block = cellR1C3.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C1.copy(
|
||||
block = cellR2C1.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2)),
|
||||
target = IntRange(0, 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cellR2C2.copy(
|
||||
block = cellR2C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C3.copy(
|
||||
block = cellR2C3.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expectedSecondHighlightedIsTargeted = listOf(
|
||||
simpleTableBlock.copy(
|
||||
cells = expectedCells
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(
|
||||
expected = expectedSecondHighlightedIsTargeted,
|
||||
actual = actualFirstHighlightedIsTargeted2
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when first highlighted text is targeted in simple table expect to still target first one`() {
|
||||
|
||||
//SETUP
|
||||
val pattern = StubPattern(query = "bc")
|
||||
|
||||
val simpleTableBlock = StubTwoRowsThreeColumnsSimpleTable(
|
||||
textR1C1 = "ab1",
|
||||
textR1C2 = "ab2",
|
||||
textR1C3 = "ac3",
|
||||
textR2C1 = "bc1",
|
||||
textR2C2 = "bb2",
|
||||
textR2C3 = "bc3"
|
||||
)
|
||||
|
||||
val cellR1C1 = simpleTableBlock.cells[0] as BlockView.Table.Cell.Text
|
||||
val cellR1C2 = simpleTableBlock.cells[1] as BlockView.Table.Cell.Text
|
||||
val cellR1C3 = simpleTableBlock.cells[2] as BlockView.Table.Cell.Text
|
||||
val cellR2C1 = simpleTableBlock.cells[3] as BlockView.Table.Cell.Text
|
||||
val cellR2C2 = simpleTableBlock.cells[4] as BlockView.Table.Cell.Text
|
||||
val cellR2C3 = simpleTableBlock.cells[5] as BlockView.Table.Cell.Text
|
||||
|
||||
val blocks = listOf<BlockView>(simpleTableBlock)
|
||||
|
||||
//TESTING
|
||||
val actualHighlighted = blocks.highlight { pairs ->
|
||||
pairs.map { (key, txt) ->
|
||||
BlockView.Searchable.Field(
|
||||
key = key,
|
||||
highlights = txt.search(pattern)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualFirstHighlightedIsTargeted = actualHighlighted.nextSearchTarget()
|
||||
val actualSecondHighlightedIsTargeted = actualFirstHighlightedIsTargeted.nextSearchTarget()
|
||||
val actualFirstHighlightedIsTargeted2 =
|
||||
actualSecondHighlightedIsTargeted.previousSearchTarget()
|
||||
val actualFirstHighlightedIsTargeted3 =
|
||||
actualFirstHighlightedIsTargeted2.previousSearchTarget()
|
||||
|
||||
//EXPECTING
|
||||
val expectedCells = listOf(
|
||||
cellR1C1.copy(
|
||||
block = cellR1C1.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C2.copy(
|
||||
block = cellR1C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR1C3.copy(
|
||||
block = cellR1C3.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C1.copy(
|
||||
block = cellR2C1.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2)),
|
||||
target = IntRange(0, 2)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cellR2C2.copy(
|
||||
block = cellR2C2.block.copy(searchFields = listOf(StubBlockViewSearchFiled()))
|
||||
),
|
||||
cellR2C3.copy(
|
||||
block = cellR2C3.block.copy(
|
||||
searchFields = listOf(
|
||||
StubBlockViewSearchFiled(
|
||||
highlights = listOf(IntRange(0, 2))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expectedSecondHighlightedIsTargeted = listOf(
|
||||
simpleTableBlock.copy(
|
||||
cells = expectedCells
|
||||
)
|
||||
)
|
||||
|
||||
//ASSERT
|
||||
assertEquals(
|
||||
expected = expectedSecondHighlightedIsTargeted,
|
||||
actual = actualFirstHighlightedIsTargeted3
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package com.anytypeio.anytype.core_ui
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.StubParagraph
|
||||
import com.anytypeio.anytype.core_models.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Markup
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.Alignment
|
||||
|
@ -8,6 +10,7 @@ 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
|
||||
import java.util.regex.Pattern
|
||||
|
||||
fun StubParagraphView(
|
||||
id: Id = MockDataFactory.randomString(),
|
||||
|
@ -301,4 +304,111 @@ fun StubFilePlaceholderView(
|
|||
isPreviousBlockMedia = isPreviousBlockMedia,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
)
|
||||
|
||||
fun StubBlockViewSearchFiled(
|
||||
key: Key = BlockView.Searchable.Field.DEFAULT_SEARCH_FIELD_KEY,
|
||||
highlights: List<IntRange> = emptyList(),
|
||||
target: IntRange = IntRange.EMPTY
|
||||
): BlockView.Searchable.Field =
|
||||
BlockView.Searchable.Field(
|
||||
key = key,
|
||||
highlights = highlights,
|
||||
target = target
|
||||
)
|
||||
|
||||
fun StubTwoRowsThreeColumnsSimpleTable(
|
||||
tableId: String = MockDataFactory.randomUuid(),
|
||||
rowId1: String = "rowId1",
|
||||
rowId2: String = "rowId2",
|
||||
columnId1: String = "columnId1",
|
||||
columnId2: String = "columnId2",
|
||||
columnId3: String = "columnId3",
|
||||
textR1C1: String = MockDataFactory.randomString(),
|
||||
textR1C2: String = MockDataFactory.randomString(),
|
||||
textR1C3: String = MockDataFactory.randomString(),
|
||||
textR2C1: String = MockDataFactory.randomString(),
|
||||
textR2C2: String = MockDataFactory.randomString(),
|
||||
textR2C3: String = MockDataFactory.randomString(),
|
||||
): BlockView.Table {
|
||||
|
||||
val row1Block1 = StubParagraph(id = "$rowId1-$columnId1", text = textR1C1)
|
||||
val row1Block2 = StubParagraph(id = "$rowId1-$columnId2", text = textR1C2)
|
||||
val row1Block3 = StubParagraph(id = "$rowId1-$columnId3", text = textR1C3)
|
||||
val row2Block1 = StubParagraph(id = "$rowId2-$columnId1", text = textR2C1)
|
||||
val row2Block2 = StubParagraph(id = "$rowId2-$columnId2", text = textR2C2)
|
||||
val row2Block3 = StubParagraph(id = "$rowId2-$columnId3", text = textR2C3)
|
||||
|
||||
val cells = listOf(
|
||||
BlockView.Table.Cell.Text(
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = row1Block1.id,
|
||||
text = row1Block1.content.asText().text
|
||||
),
|
||||
rowId = rowId1,
|
||||
columnId = columnId1
|
||||
),
|
||||
BlockView.Table.Cell.Text(
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = row1Block2.id,
|
||||
text = row1Block2.content.asText().text
|
||||
),
|
||||
rowId = rowId1,
|
||||
columnId = columnId2
|
||||
),
|
||||
BlockView.Table.Cell.Text(
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = row1Block3.id,
|
||||
text = row1Block3.content.asText().text
|
||||
),
|
||||
rowId = rowId1,
|
||||
columnId = columnId3
|
||||
),
|
||||
BlockView.Table.Cell.Text(
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = row2Block1.id,
|
||||
text = row2Block1.content.asText().text
|
||||
),
|
||||
rowId = rowId2,
|
||||
columnId = columnId1
|
||||
),
|
||||
BlockView.Table.Cell.Text(
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = row2Block2.id,
|
||||
text = row2Block2.content.asText().text
|
||||
),
|
||||
rowId = rowId2,
|
||||
columnId = columnId2
|
||||
),
|
||||
BlockView.Table.Cell.Text(
|
||||
block = BlockView.Text.Paragraph(
|
||||
id = row2Block3.id,
|
||||
text = row2Block3.content.asText().text
|
||||
),
|
||||
rowId = rowId2,
|
||||
columnId = columnId3
|
||||
)
|
||||
)
|
||||
|
||||
val columns = listOf(
|
||||
BlockView.Table.Column(id = columnId1, background = ThemeColor.DEFAULT),
|
||||
BlockView.Table.Column(id = columnId2, background = ThemeColor.DEFAULT),
|
||||
BlockView.Table.Column(id = columnId3, background = ThemeColor.DEFAULT)
|
||||
)
|
||||
|
||||
return BlockView.Table(
|
||||
id = tableId,
|
||||
cells = cells,
|
||||
columns = columns,
|
||||
rowCount = 2,
|
||||
isSelected = false
|
||||
)
|
||||
}
|
||||
|
||||
fun StubPattern(
|
||||
query: String
|
||||
): Pattern {
|
||||
val flags = Pattern.MULTILINE or Pattern.CASE_INSENSITIVE
|
||||
val escaped = Pattern.quote(query)
|
||||
return Pattern.compile(escaped, flags)
|
||||
}
|
|
@ -731,13 +731,9 @@ fun BlockView.setGhostEditorSelection(
|
|||
}
|
||||
|
||||
fun List<BlockView>.nextSearchTarget(): List<BlockView> {
|
||||
val currentTargetView = find { view ->
|
||||
view is BlockView.Searchable && view.searchFields.any { it.isTargeted }
|
||||
}
|
||||
val currentTargetView: BlockView? = findHighlightedTarget()
|
||||
if (currentTargetView == null) {
|
||||
val nextCandidate = find { view ->
|
||||
view is BlockView.Searchable && view.searchFields.any { it.highlights.isNotEmpty() }
|
||||
}
|
||||
val nextCandidate: BlockView? = findFirstHighlighted()
|
||||
if (nextCandidate == null) {
|
||||
return this
|
||||
} else {
|
||||
|
@ -752,13 +748,10 @@ fun List<BlockView>.nextSearchTarget(): List<BlockView> {
|
|||
field
|
||||
}
|
||||
}
|
||||
return map { view ->
|
||||
if (view.id == nextCandidate.id) {
|
||||
view.setHighlight(highlights)
|
||||
} else {
|
||||
view
|
||||
}
|
||||
}
|
||||
return highlightBlockById(
|
||||
id = nextCandidate.id,
|
||||
highlights = highlights
|
||||
)
|
||||
}
|
||||
} else {
|
||||
check(currentTargetView is BlockView.Searchable)
|
||||
|
@ -772,13 +765,10 @@ fun List<BlockView>.nextSearchTarget(): List<BlockView> {
|
|||
field
|
||||
}
|
||||
}
|
||||
return map { view ->
|
||||
if (view.id == currentTargetView.id) {
|
||||
view.setHighlight(highlights)
|
||||
} else {
|
||||
view
|
||||
}
|
||||
}
|
||||
return highlightBlockById(
|
||||
id = currentTargetView.id,
|
||||
highlights = highlights
|
||||
)
|
||||
} else {
|
||||
val currentTargetFieldIndex = currentTargetView.searchFields.indexOf(currentField)
|
||||
val nextFields = currentTargetView.searchFields.subList(
|
||||
|
@ -796,18 +786,13 @@ fun List<BlockView>.nextSearchTarget(): List<BlockView> {
|
|||
else -> field
|
||||
}
|
||||
}
|
||||
return map { view ->
|
||||
if (view.id == currentTargetView.id) {
|
||||
view.setHighlight(highlights)
|
||||
} else {
|
||||
view
|
||||
}
|
||||
}
|
||||
return highlightBlockById(
|
||||
id = currentTargetView.id,
|
||||
highlights = highlights
|
||||
)
|
||||
} else {
|
||||
val nextViews = subList(indexOf(currentTargetView).inc(), size)
|
||||
val nextCandidate = nextViews.find { view ->
|
||||
view is BlockView.Searchable && view.searchFields.any { it.highlights.isNotEmpty() }
|
||||
}
|
||||
val nextViews = subListFromIdToEnd(id = currentTargetView.id)
|
||||
val nextCandidate = nextViews.findFirstHighlighted()
|
||||
if (nextCandidate == null) {
|
||||
return this
|
||||
} else {
|
||||
|
@ -816,22 +801,54 @@ fun List<BlockView>.nextSearchTarget(): List<BlockView> {
|
|||
field.highlights.isNotEmpty()
|
||||
}
|
||||
return map { view ->
|
||||
when (view.id) {
|
||||
nextCandidate.id -> view.setHighlight(
|
||||
nextCandidate.searchFields.mapIndexed { index, field ->
|
||||
if (index == nextFieldCandidateIndex) {
|
||||
field.copy(target = field.highlights.first())
|
||||
} else {
|
||||
field
|
||||
if (view is BlockView.Table) {
|
||||
val cells = view.cells
|
||||
val updatedCells = cells.map { cell ->
|
||||
when (cell) {
|
||||
is BlockView.Table.Cell.Empty -> cell
|
||||
BlockView.Table.Cell.Space -> cell
|
||||
is BlockView.Table.Cell.Text -> {
|
||||
val block = cell.block
|
||||
val updatedBlock = when (block.id) {
|
||||
nextCandidate.id -> block.copy(
|
||||
searchFields = nextCandidate.searchFields.mapIndexed { index, field ->
|
||||
if (index == nextFieldCandidateIndex) {
|
||||
field.copy(target = field.highlights.first())
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}
|
||||
)
|
||||
currentTargetView.id -> block.copy(
|
||||
searchFields = currentTargetView.searchFields.map { field ->
|
||||
field.copy(target = IntRange.EMPTY)
|
||||
}
|
||||
)
|
||||
else -> block
|
||||
}
|
||||
cell.copy(block = updatedBlock)
|
||||
}
|
||||
}
|
||||
)
|
||||
currentTargetView.id -> view.setHighlight(
|
||||
currentTargetView.searchFields.map { field ->
|
||||
field.copy(target = IntRange.EMPTY)
|
||||
}
|
||||
)
|
||||
else -> view
|
||||
}
|
||||
view.copy(cells = updatedCells)
|
||||
} else {
|
||||
when (view.id) {
|
||||
nextCandidate.id -> view.setHighlight(
|
||||
nextCandidate.searchFields.mapIndexed { index, field ->
|
||||
if (index == nextFieldCandidateIndex) {
|
||||
field.copy(target = field.highlights.first())
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}
|
||||
)
|
||||
currentTargetView.id -> view.setHighlight(
|
||||
currentTargetView.searchFields.map { field ->
|
||||
field.copy(target = IntRange.EMPTY)
|
||||
}
|
||||
)
|
||||
else -> view
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -841,9 +858,7 @@ fun List<BlockView>.nextSearchTarget(): List<BlockView> {
|
|||
}
|
||||
|
||||
fun List<BlockView>.previousSearchTarget(): List<BlockView> {
|
||||
val currentTargetView = find { view ->
|
||||
view is BlockView.Searchable && view.searchFields.any { it.isTargeted }
|
||||
}
|
||||
val currentTargetView = findHighlightedTarget()
|
||||
if (currentTargetView == null) {
|
||||
return this
|
||||
} else {
|
||||
|
@ -858,13 +873,10 @@ fun List<BlockView>.previousSearchTarget(): List<BlockView> {
|
|||
field
|
||||
}
|
||||
}
|
||||
return map { view ->
|
||||
if (view.id == currentTargetView.id) {
|
||||
view.setHighlight(highlights)
|
||||
} else {
|
||||
view
|
||||
}
|
||||
}
|
||||
return highlightBlockById(
|
||||
id = currentTargetView.id,
|
||||
highlights = highlights
|
||||
)
|
||||
} else {
|
||||
val currentTargetFieldIndex = currentTargetView.searchFields.indexOf(currentField)
|
||||
val previousFields = currentTargetView.searchFields.subList(
|
||||
|
@ -883,39 +895,67 @@ fun List<BlockView>.previousSearchTarget(): List<BlockView> {
|
|||
else -> field
|
||||
}
|
||||
}
|
||||
return map { view ->
|
||||
if (view.id == currentTargetView.id) {
|
||||
view.setHighlight(highlights)
|
||||
} else {
|
||||
view
|
||||
}
|
||||
}
|
||||
return highlightBlockById(
|
||||
id = currentTargetView.id,
|
||||
highlights = highlights
|
||||
)
|
||||
} else {
|
||||
val previousViews = subList(0, indexOf(currentTargetView))
|
||||
val previousCandidate = previousViews.findLast { view ->
|
||||
view is BlockView.Searchable && view.searchFields.any { it.highlights.isNotEmpty() }
|
||||
}
|
||||
val previousViews = subListFrom0ToId(id = currentTargetView.id)
|
||||
val previousCandidate = previousViews.findLastHighlighted()
|
||||
if (previousCandidate == null) {
|
||||
return this
|
||||
} else {
|
||||
check(previousCandidate is BlockView.Searchable)
|
||||
return map { view ->
|
||||
when (view.id) {
|
||||
previousCandidate.id -> view.setHighlight(
|
||||
previousCandidate.searchFields.mapIndexed { index, field ->
|
||||
if (index == previousCandidate.searchFields.size.dec()) {
|
||||
field.copy(target = field.highlights.last())
|
||||
} else {
|
||||
field
|
||||
if (view is BlockView.Table) {
|
||||
val cells = view.cells
|
||||
val updatedCells = cells.map { cell ->
|
||||
when (cell) {
|
||||
is BlockView.Table.Cell.Empty -> cell
|
||||
BlockView.Table.Cell.Space -> cell
|
||||
is BlockView.Table.Cell.Text -> {
|
||||
val block = cell.block
|
||||
val updatedBlock = when (block.id) {
|
||||
previousCandidate.id -> block.copy(
|
||||
searchFields = previousCandidate.searchFields.mapIndexed { index, field ->
|
||||
if (index == previousCandidate.searchFields.size.dec()) {
|
||||
field.copy(target = field.highlights.last())
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}
|
||||
)
|
||||
currentTargetView.id -> block.copy(
|
||||
searchFields = currentTargetView.searchFields.map { field ->
|
||||
field.copy(target = IntRange.EMPTY)
|
||||
}
|
||||
)
|
||||
else -> block
|
||||
}
|
||||
cell.copy(block = updatedBlock)
|
||||
}
|
||||
}
|
||||
)
|
||||
currentTargetView.id -> view.setHighlight(
|
||||
currentTargetView.searchFields.map { field ->
|
||||
field.copy(target = IntRange.EMPTY)
|
||||
}
|
||||
)
|
||||
else -> view
|
||||
}
|
||||
|
||||
view.copy(cells = updatedCells)
|
||||
} else {
|
||||
when (view.id) {
|
||||
previousCandidate.id -> view.setHighlight(
|
||||
previousCandidate.searchFields.mapIndexed { index, field ->
|
||||
if (index == previousCandidate.searchFields.size.dec()) {
|
||||
field.copy(target = field.highlights.last())
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}
|
||||
)
|
||||
currentTargetView.id -> view.setHighlight(
|
||||
currentTargetView.searchFields.map { field ->
|
||||
field.copy(target = IntRange.EMPTY)
|
||||
}
|
||||
)
|
||||
else -> view
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1199,4 +1239,159 @@ fun List<BlockView>.findTableCellView(id: Id): BlockView.Table.Cell? {
|
|||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun List<BlockView>.findHighlightedTarget(): BlockView? {
|
||||
forEach { block ->
|
||||
if (block is BlockView.Table) {
|
||||
val target =
|
||||
block.getTextCells().find { cell -> cell.searchFields.any { it.isTargeted } }
|
||||
if (target != null) return target
|
||||
} else {
|
||||
val isTargeted =
|
||||
block is BlockView.Searchable && block.searchFields.any { it.isTargeted }
|
||||
if (isTargeted) return block
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun List<BlockView>.findFirstHighlighted(): BlockView? {
|
||||
forEach { block ->
|
||||
if (block is BlockView.Table) {
|
||||
val target =
|
||||
block.getTextCells()
|
||||
.find { cell -> cell.searchFields.any { it.highlights.isNotEmpty() } }
|
||||
if (target != null) return target
|
||||
} else {
|
||||
val isHighlighted =
|
||||
block is BlockView.Searchable && block.searchFields.any { it.highlights.isNotEmpty() }
|
||||
if (isHighlighted) return block
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun List<BlockView>.findLastHighlighted(): BlockView? {
|
||||
var lastHighlighted: BlockView? = null
|
||||
forEach { block ->
|
||||
if (block is BlockView.Table) {
|
||||
val target =
|
||||
block.getTextCells()
|
||||
.findLast { cell -> cell.searchFields.any { it.highlights.isNotEmpty() } }
|
||||
if (target != null) lastHighlighted = target
|
||||
} else {
|
||||
val isHighlighted =
|
||||
block is BlockView.Searchable && block.searchFields.any { it.highlights.isNotEmpty() }
|
||||
if (isHighlighted) lastHighlighted = block
|
||||
}
|
||||
}
|
||||
return lastHighlighted
|
||||
}
|
||||
|
||||
fun BlockView.Table.getTextCells(): List<BlockView.Text.Paragraph> {
|
||||
return cells.mapNotNull { cell ->
|
||||
when (cell) {
|
||||
is BlockView.Table.Cell.Empty -> null
|
||||
BlockView.Table.Cell.Space -> null
|
||||
is BlockView.Table.Cell.Text -> cell.block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView>.highlightBlockById(
|
||||
id: Id,
|
||||
highlights: List<BlockView.Searchable.Field>
|
||||
): List<BlockView> = map { view ->
|
||||
if (view is BlockView.Table) {
|
||||
val updatedCells = view.cells.map { cell ->
|
||||
when (cell) {
|
||||
BlockView.Table.Cell.Space -> cell
|
||||
is BlockView.Table.Cell.Empty -> cell
|
||||
is BlockView.Table.Cell.Text -> {
|
||||
if (cell.getId() == id) {
|
||||
val block = cell.block
|
||||
cell.copy(
|
||||
block = block.copy(searchFields = highlights)
|
||||
)
|
||||
} else {
|
||||
cell
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
view.copy(cells = updatedCells)
|
||||
} else {
|
||||
if (view.id == id) {
|
||||
view.setHighlight(highlights)
|
||||
} else {
|
||||
view
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView>.subListFromIdToEnd(id: Id): List<BlockView> {
|
||||
val indexOfFirst = indexOfFirst { it.id == id }
|
||||
if (indexOfFirst != -1) {
|
||||
return subList(indexOfFirst.inc(), this.size)
|
||||
} else {
|
||||
val blockTable = findBlockTableByCellId(cellId = id)
|
||||
return if (blockTable != null) {
|
||||
val list = mutableListOf<BlockView>()
|
||||
val cells = blockTable.cells
|
||||
val indexOfTarget =
|
||||
cells.indexOfFirst { cell -> cell is BlockView.Table.Cell.Text && cell.block.id == id }
|
||||
val subListOfCells = if (indexOfTarget != -1 && indexOfTarget.inc() <= cells.size) {
|
||||
cells.subList(indexOfTarget.inc(), cells.size)
|
||||
} else {
|
||||
cells
|
||||
}
|
||||
list.add(blockTable.copy(cells = subListOfCells))
|
||||
val tableIndex = this.indexOfFirst { it.id == blockTable.id }
|
||||
list.addAll(subList(tableIndex.inc(), size))
|
||||
list
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView>.subListFrom0ToId(id: Id): List<BlockView> {
|
||||
val indexOfFirst = indexOfFirst { it.id == id }
|
||||
if (indexOfFirst != -1) {
|
||||
return subList(0, indexOfFirst)
|
||||
} else {
|
||||
val blockTable = findBlockTableByCellId(cellId = id)
|
||||
return if (blockTable != null) {
|
||||
val list = mutableListOf<BlockView>()
|
||||
val cells = blockTable.cells
|
||||
val indexOfTarget =
|
||||
cells.indexOfFirst { cell -> cell is BlockView.Table.Cell.Text && cell.block.id == id }
|
||||
val subListOfCells = if (indexOfTarget != -1 && indexOfTarget <= cells.size) {
|
||||
cells.subList(0, indexOfTarget)
|
||||
} else {
|
||||
cells
|
||||
}
|
||||
val tableIndex = this.indexOfFirst { it.id == blockTable.id }
|
||||
list.addAll(subList(0, tableIndex))
|
||||
list.add(blockTable.copy(cells = subListOfCells))
|
||||
list
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun List<BlockView>.findBlockTableByCellId(cellId: Id): BlockView.Table? {
|
||||
this.forEach { blockView ->
|
||||
if (blockView is BlockView.Table) {
|
||||
val cells = blockView.cells
|
||||
val index =
|
||||
cells.indexOfFirst { it is BlockView.Table.Cell.Text && it.block.id == cellId }
|
||||
if (index != -1) {
|
||||
return blockView
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue