1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-09 17:44:57 +09:00

Toggle block's business logic (#907)

This commit is contained in:
Evgenii Kozlov 2020-09-23 13:46:59 +02:00 committed by GitHub
parent 636837e7a4
commit d1a989f589
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 699 additions and 257 deletions

View file

@ -13,6 +13,8 @@
### Fixes & tech 🚒
* Should create a new toogle on enter press at the end of the non-empty toggle block (#907)
* Should convert toggle block to paragraph on enter press if toggle block's text is empty (#886)
* When creating a new document and focusing its title, cursor should be visible (#903)
* Should not crash Android client when changing media block's background color on Desktop client (#814)
* Stretched background cover affects app's performance on home dashboard screen (#901)

View file

@ -761,7 +761,7 @@ class PageViewModel(
replacement = { old -> old.copy(content = content) }
) { block -> block.id == id }
if (content.isList()) {
if (content.isList() || content.isToggle()) {
handleEndlineEnterPressedEventForListItem(content, id)
} else {
proceedWithCreatingNewTextBlock(

View file

@ -2077,262 +2077,6 @@ open class PageViewModelTest {
}
}
@Test
fun `should start creating a new bulleted-list item on endline-enter-pressed event inside a bullet block`() {
val style = Block.Content.Text.Style.BULLET
val root = MockDataFactory.randomUuid()
val child = MockDataFactory.randomUuid()
val page = MockBlockFactory.makeOnePageWithOneTextBlock(
root = root,
child = child,
style = style
)
val flow: Flow<List<Event.Command>> = flow {
delay(100)
emit(
listOf(
Event.Command.ShowBlock(
root = root,
blocks = page,
context = root
)
)
)
}
stubObserveEvents(flow)
stubOpenPage()
stubCreateBlock(root)
buildViewModel()
vm.onStart(root)
coroutineTestRule.advanceTime(100)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
vm.onEndLineEnterClicked(
id = child,
text = page.last().content<Block.Content.Text>().text,
marks = emptyList()
)
runBlockingTest {
verify(createBlock, times(1)).invoke(
params = eq(
CreateBlock.Params(
context = root,
target = child,
prototype = Block.Prototype.Text(
style = style
),
position = Position.BOTTOM
)
)
)
}
}
@Test
fun `should start creating a new checkbox item on endline-enter-pressed event inside a bullet block`() {
val style = Block.Content.Text.Style.CHECKBOX
val root = MockDataFactory.randomUuid()
val child = MockDataFactory.randomUuid()
val page = MockBlockFactory.makeOnePageWithOneTextBlock(
root = root,
child = child,
style = style
)
val flow: Flow<List<Event.Command>> = flow {
delay(100)
emit(
listOf(
Event.Command.ShowBlock(
root = root,
blocks = page,
context = root
)
)
)
}
stubObserveEvents(flow)
stubOpenPage()
stubCreateBlock(root)
buildViewModel()
vm.onStart(root)
coroutineTestRule.advanceTime(100)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
vm.onEndLineEnterClicked(
id = child,
marks = emptyList(),
text = page.last().content<Block.Content.Text>().text
)
runBlockingTest {
verify(createBlock, times(1)).invoke(
params = eq(
CreateBlock.Params(
context = root,
target = child,
prototype = Block.Prototype.Text(
style = style
),
position = Position.BOTTOM
)
)
)
}
}
@Test
fun `should convert list block with empty text to paragraph on enter-pressed event`() {
// SETUP
val style = Block.Content.Text.Style.CHECKBOX
val root = MockDataFactory.randomUuid()
val child = MockDataFactory.randomUuid()
val checkbox = Block(
id = child,
fields = Block.Fields(emptyMap()),
content = Block.Content.Text(
text = "",
marks = emptyList(),
style = style
),
children = emptyList()
)
val page = listOf(
Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Page(
style = Block.Content.Page.Style.SET
),
children = listOf(child)
),
checkbox
)
stubObserveEvents()
stubOpenPage(
context = root,
events = listOf(
Event.Command.ShowBlock(
root = root,
blocks = page,
context = root
)
)
)
stubCreateBlock(root)
stubUpdateTextStyle(
payload = Payload(
context = root,
events = listOf(
Event.Command.GranularChange(
context = root,
id = child,
style = Block.Content.Text.Style.P
)
)
)
)
buildViewModel()
// TESTING
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
// expected state before on-enter-pressed event
val before = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Checkbox(
id = child,
text = "",
isFocused = false,
isChecked = false,
indent = 0
)
)
)
vm.state.test().assertValue(before)
vm.onEndLineEnterClicked(
id = child,
marks = emptyList(),
text = page.last().content<Block.Content.Text>().text
)
runBlockingTest {
verify(updateTextStyle, times(1)).invoke(
params = eq(
UpdateTextStyle.Params(
context = root,
targets = listOf(child),
style = Block.Content.Text.Style.P
)
)
)
}
verifyZeroInteractions(createBlock)
// expected state after on-enter-pressed event
val after = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Paragraph(
id = child,
text = "",
isFocused = true
)
)
)
vm.state.test().assertValue(after)
}
@Test
fun `should start creating a new paragraph on endline-enter-pressed event inside a quote block`() {

View file

@ -0,0 +1,683 @@
package com.agileburo.anytype.presentation.page.editor
import MockDataFactory
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.agileburo.anytype.core_ui.features.page.BlockView
import com.agileburo.anytype.domain.block.interactor.CreateBlock
import com.agileburo.anytype.domain.block.interactor.UpdateTextStyle
import com.agileburo.anytype.domain.block.model.Block
import com.agileburo.anytype.domain.block.model.Position
import com.agileburo.anytype.domain.event.model.Event
import com.agileburo.anytype.domain.ext.content
import com.agileburo.anytype.presentation.MockBlockFactory
import com.agileburo.anytype.presentation.util.CoroutinesTestRule
import com.jraska.livedata.test
import com.nhaarman.mockitokotlin2.eq
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verifyBlocking
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.MockitoAnnotations
class EditorListBlockTest : EditorPresentationTestSetup() {
@get:Rule
val rule = InstantTaskExecutorRule()
@get:Rule
val coroutineTestRule = CoroutinesTestRule()
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
}
@Test
fun `should start creating a new bulleted-list item on endline-enter-pressed event inside a bullet block`() {
val style = Block.Content.Text.Style.BULLET
val child = MockDataFactory.randomUuid()
val page = MockBlockFactory.makeOnePageWithOneTextBlock(
root = root,
child = child,
style = style
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
val vm = buildViewModel()
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
vm.onEndLineEnterClicked(
id = child,
text = page.last().content<Block.Content.Text>().text,
marks = emptyList()
)
verifyBlocking(createBlock, times(1)) {
invoke(
params = CreateBlock.Params(
context = root,
target = child,
prototype = Block.Prototype.Text(
style = style
),
position = Position.BOTTOM
)
)
}
}
@Test
fun `should start creating a new checkbox item on endline-enter-pressed event inside a bullet block`() {
val style = Block.Content.Text.Style.CHECKBOX
val child = MockDataFactory.randomUuid()
val page = MockBlockFactory.makeOnePageWithOneTextBlock(
root = root,
child = child,
style = style
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
val vm = buildViewModel()
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
vm.onEndLineEnterClicked(
id = child,
text = page.last().content<Block.Content.Text>().text,
marks = emptyList()
)
verifyBlocking(createBlock, times(1)) {
invoke(
params = CreateBlock.Params(
context = root,
target = child,
prototype = Block.Prototype.Text(
style = style
),
position = Position.BOTTOM
)
)
}
}
@Test
fun `should start creating a new numbered item on endline-enter-pressed event inside a bullet block`() {
val style = Block.Content.Text.Style.NUMBERED
val child = MockDataFactory.randomUuid()
val page = MockBlockFactory.makeOnePageWithOneTextBlock(
root = root,
child = child,
style = style
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
val vm = buildViewModel()
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
vm.onEndLineEnterClicked(
id = child,
text = page.last().content<Block.Content.Text>().text,
marks = emptyList()
)
verifyBlocking(createBlock, times(1)) {
invoke(
params = CreateBlock.Params(
context = root,
target = child,
prototype = Block.Prototype.Text(
style = style
),
position = Position.BOTTOM
)
)
}
}
@Test
fun `should start creating a new toggle block on endline-enter-pressed event inside a bullet block`() {
val style = Block.Content.Text.Style.TOGGLE
val child = MockDataFactory.randomUuid()
val page = MockBlockFactory.makeOnePageWithOneTextBlock(
root = root,
child = child,
style = style
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
val vm = buildViewModel()
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
vm.onEndLineEnterClicked(
id = child,
text = page.last().content<Block.Content.Text>().text,
marks = emptyList()
)
verifyBlocking(createBlock, times(1)) {
invoke(
params = CreateBlock.Params(
context = root,
target = child,
prototype = Block.Prototype.Text(
style = style
),
position = Position.BOTTOM
)
)
}
}
@Test
fun `should convert checkbox block with empty text to paragraph on enter-pressed event`() {
// SETUP
val style = Block.Content.Text.Style.CHECKBOX
val child = MockDataFactory.randomUuid()
val checkbox = Block(
id = child,
fields = Block.Fields(emptyMap()),
content = Block.Content.Text(
text = "",
marks = emptyList(),
style = style
),
children = emptyList()
)
val page = listOf(
Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Page(
style = Block.Content.Page.Style.SET
),
children = listOf(child)
),
checkbox
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
stubUpdateTextStyle(
events = listOf(
Event.Command.GranularChange(
context = root,
id = child,
style = Block.Content.Text.Style.P
)
)
)
val vm = buildViewModel()
// TESTING
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
// expected state before on-enter-pressed event
val before = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Checkbox(
id = child,
text = "",
isFocused = false,
isChecked = false,
indent = 0
)
)
)
vm.state.test().assertValue(before)
vm.onEndLineEnterClicked(
id = child,
marks = emptyList(),
text = page.last().content<Block.Content.Text>().text
)
verifyBlocking(updateTextStyle, times(1)) {
invoke(
params = eq(
UpdateTextStyle.Params(
context = root,
targets = listOf(child),
style = Block.Content.Text.Style.P
)
)
)
}
verifyZeroInteractions(createBlock)
// expected state after on-enter-pressed event
val after = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Paragraph(
id = child,
text = "",
isFocused = true
)
)
)
vm.state.test().assertValue(after)
}
@Test
fun `should convert bullet block with empty text to paragraph on enter-pressed event`() {
// SETUP
val style = Block.Content.Text.Style.BULLET
val child = MockDataFactory.randomUuid()
val checkbox = Block(
id = child,
fields = Block.Fields(emptyMap()),
content = Block.Content.Text(
text = "",
marks = emptyList(),
style = style
),
children = emptyList()
)
val page = listOf(
Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Page(
style = Block.Content.Page.Style.SET
),
children = listOf(child)
),
checkbox
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
stubUpdateTextStyle(
events = listOf(
Event.Command.GranularChange(
context = root,
id = child,
style = Block.Content.Text.Style.P
)
)
)
val vm = buildViewModel()
// TESTING
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
// expected state before on-enter-pressed event
val before = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Bulleted(
id = child,
text = "",
isFocused = false,
indent = 0
)
)
)
vm.state.test().assertValue(before)
vm.onEndLineEnterClicked(
id = child,
marks = emptyList(),
text = page.last().content<Block.Content.Text>().text
)
verifyBlocking(updateTextStyle, times(1)) {
invoke(
params = eq(
UpdateTextStyle.Params(
context = root,
targets = listOf(child),
style = Block.Content.Text.Style.P
)
)
)
}
verifyZeroInteractions(createBlock)
// expected state after on-enter-pressed event
val after = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Paragraph(
id = child,
text = "",
isFocused = true
)
)
)
vm.state.test().assertValue(after)
}
@Test
fun `should convert toggle block with empty text to paragraph on enter-pressed event`() {
// SETUP
val style = Block.Content.Text.Style.TOGGLE
val child = MockDataFactory.randomUuid()
val checkbox = Block(
id = child,
fields = Block.Fields(emptyMap()),
content = Block.Content.Text(
text = "",
marks = emptyList(),
style = style
),
children = emptyList()
)
val page = listOf(
Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Page(
style = Block.Content.Page.Style.SET
),
children = listOf(child)
),
checkbox
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
stubUpdateTextStyle(
events = listOf(
Event.Command.GranularChange(
context = root,
id = child,
style = Block.Content.Text.Style.P
)
)
)
val vm = buildViewModel()
// TESTING
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
// expected state before on-enter-pressed event
val before = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Toggle(
id = child,
text = "",
isFocused = false,
indent = 0,
isEmpty = true
)
)
)
vm.state.test().assertValue(before)
vm.onEndLineEnterClicked(
id = child,
marks = emptyList(),
text = page.last().content<Block.Content.Text>().text
)
verifyBlocking(updateTextStyle, times(1)) {
invoke(
params = eq(
UpdateTextStyle.Params(
context = root,
targets = listOf(child),
style = Block.Content.Text.Style.P
)
)
)
}
verifyZeroInteractions(createBlock)
// expected state after on-enter-pressed event
val after = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Paragraph(
id = child,
text = "",
isFocused = true
)
)
)
vm.state.test().assertValue(after)
}
@Test
fun `should convert numbered block with empty text to paragraph on enter-pressed event`() {
// SETUP
val style = Block.Content.Text.Style.NUMBERED
val child = MockDataFactory.randomUuid()
val checkbox = Block(
id = child,
fields = Block.Fields(emptyMap()),
content = Block.Content.Text(
text = "",
marks = emptyList(),
style = style
),
children = emptyList()
)
val page = listOf(
Block(
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Page(
style = Block.Content.Page.Style.SET
),
children = listOf(child)
),
checkbox
)
stubInterceptEvents()
stubOpenDocument(page)
stubCreateBlock(root)
stubUpdateTextStyle(
events = listOf(
Event.Command.GranularChange(
context = root,
id = child,
style = Block.Content.Text.Style.P
)
)
)
val vm = buildViewModel()
// TESTING
vm.onStart(root)
vm.onBlockFocusChanged(
id = child,
hasFocus = true
)
// expected state before on-enter-pressed event
val before = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Numbered(
id = child,
text = "",
isFocused = false,
indent = 0,
number = 1
)
)
)
vm.state.test().assertValue(before)
vm.onEndLineEnterClicked(
id = child,
marks = emptyList(),
text = page.last().content<Block.Content.Text>().text
)
verifyBlocking(updateTextStyle, times(1)) {
invoke(
params = eq(
UpdateTextStyle.Params(
context = root,
targets = listOf(child),
style = Block.Content.Text.Style.P
)
)
)
}
verifyZeroInteractions(createBlock)
// expected state after on-enter-pressed event
val after = ViewState.Success(
blocks = listOf(
BlockView.Title.Document(
id = root,
text = null,
isFocused = false
),
BlockView.Text.Paragraph(
id = child,
text = "",
isFocused = true
)
)
)
vm.state.test().assertValue(after)
}
}

View file

@ -276,4 +276,17 @@ open class EditorPresentationTestSetup {
onBlocking { invoke(params) } doReturn Either.Right(emptyList())
}
}
fun stubCreateBlock(root: String) {
createBlock.stub {
onBlocking { invoke(any()) } doReturn Either.Right(
Pair(
MockDataFactory.randomString(), Payload(
context = root,
events = listOf()
)
)
)
}
}
}