1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-12 10:40:25 +09:00

Editor | Undo/redo does not work correctly for relation values (#1932)

This commit is contained in:
Evgenii Kozlov 2021-11-16 13:58:04 +03:00 committed by GitHub
parent e00107123e
commit 0a82c244ba
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 441 additions and 40 deletions

View file

@ -9,6 +9,7 @@
* Editor | Should not crash when the target block is not found for the style panel (#1929)
* Editor | Should not crash when long-pressing empty space in the header when object layout has no title (#1930)
* Editor | Drag-and-dropping below or above a link to object always results in dropping inside this link (#1931)
* Editor | Undo/redo does not work correctly for relation values (#1932)
## Version 0.4.0

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.presentation.editor.editor.Markup
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Indentable
import com.anytypeio.anytype.presentation.editor.editor.model.Focusable
import com.anytypeio.anytype.presentation.relations.DocumentRelationView
import timber.log.Timber
class BlockViewDiffUtil(
@ -161,6 +162,53 @@ class BlockViewDiffUtil(
changes.add(BACKGROUND_COLOR_CHANGED)
}
if (newBlock is BlockView.Relation.Related && oldBlock is BlockView.Relation.Related) {
if (newBlock.background != oldBlock.background) {
changes.add(BACKGROUND_COLOR_CHANGED)
}
val newRelationView = newBlock.view
val oldRelationView = oldBlock.view
if (newBlock.view.name != oldBlock.view.name) {
changes.add(RELATION_NAME_CHANGED)
}
when {
newRelationView is DocumentRelationView.Default && oldRelationView is DocumentRelationView.Default -> {
if (newBlock.view.value != oldBlock.view.value) {
changes.add(RELATION_VALUE_CHANGED)
}
}
newRelationView is DocumentRelationView.Checkbox && oldRelationView is DocumentRelationView.Checkbox -> {
if (newRelationView.isChecked != oldRelationView.isChecked) {
changes.add(RELATION_VALUE_CHANGED)
}
}
newRelationView is DocumentRelationView.Status && oldRelationView is DocumentRelationView.Status -> {
if (newRelationView.status != oldRelationView.status) {
changes.add(RELATION_VALUE_CHANGED)
}
}
newRelationView is DocumentRelationView.Tags && oldRelationView is DocumentRelationView.Tags -> {
if (newRelationView.tags != oldRelationView.tags) {
changes.add(RELATION_VALUE_CHANGED)
}
}
newRelationView is DocumentRelationView.Object && oldRelationView is DocumentRelationView.Object -> {
if (newRelationView.objects != oldRelationView.objects) {
changes.add(RELATION_VALUE_CHANGED)
}
}
newRelationView is DocumentRelationView.File && oldRelationView is DocumentRelationView.File -> {
if (newRelationView.files != oldRelationView.files) {
changes.add(RELATION_VALUE_CHANGED)
}
}
}
}
return if (changes.isNotEmpty())
Payload(changes).also { Timber.d("Returning payload: $it") }
else
@ -187,9 +235,10 @@ class BlockViewDiffUtil(
val isSelectionChanged: Boolean get() = changes.contains(SELECTION_CHANGED)
val isTitleIconChanged: Boolean get() = changes.contains(TITLE_ICON_CHANGED)
val isSearchHighlightChanged: Boolean get() = changes.contains(SEARCH_HIGHLIGHT_CHANGED)
val isGhostEditorSelectionChanged: Boolean get() = changes.contains(
GHOST_EDITOR_SELECTION_CHANGED
)
val isGhostEditorSelectionChanged: Boolean
get() = changes.contains(
GHOST_EDITOR_SELECTION_CHANGED
)
val isAlignmentChanged: Boolean get() = changes.contains(ALIGNMENT_CHANGED)
val isTitleCheckboxChanged: Boolean get() = changes.contains(TITLE_CHECKBOX_CHANGED)
val isObjectTitleChanged: Boolean get() = changes.contains(OBJECT_TITLE_CHANGED)
@ -229,5 +278,7 @@ class BlockViewDiffUtil(
const val OBJECT_TITLE_CHANGED = 19
const val OBJECT_ICON_CHANGED = 20
const val LATEX_CHANGED = 21
const val RELATION_NAME_CHANGED = 22
const val RELATION_VALUE_CHANGED = 23
}
}

View file

@ -76,20 +76,17 @@ sealed class RelationViewHolder(
fun bind(item: DocumentRelationView) : Unit = with(itemView) {
findViewById<TextView>(R.id.tvRelationTitle).text = item.name
findViewById<TextView>(R.id.tvRelationValue).apply {
if (item.value != null) {
text = item.value
} else {
if (item is DocumentRelationView.Default) {
when (item.format) {
Relation.Format.SHORT_TEXT -> setHint(R.string.enter_text)
Relation.Format.LONG_TEXT -> setHint(R.string.enter_text)
Relation.Format.NUMBER -> setHint(R.string.enter_number)
Relation.Format.DATE -> setHint(R.string.enter_date)
Relation.Format.URL -> setHint(R.string.enter_url)
Relation.Format.EMAIL -> setHint(R.string.enter_email)
Relation.Format.PHONE -> setHint(R.string.enter_phone)
else -> setHint(R.string.enter_value)
}
text = item.value
if (item is DocumentRelationView.Default) {
when (item.format) {
Relation.Format.SHORT_TEXT -> setHint(R.string.enter_text)
Relation.Format.LONG_TEXT -> setHint(R.string.enter_text)
Relation.Format.NUMBER -> setHint(R.string.enter_number)
Relation.Format.DATE -> setHint(R.string.enter_date)
Relation.Format.URL -> setHint(R.string.enter_url)
Relation.Format.EMAIL -> setHint(R.string.enter_email)
Relation.Format.PHONE -> setHint(R.string.enter_phone)
else -> setHint(R.string.enter_value)
}
}
}

View file

@ -1,11 +1,18 @@
package com.anytypeio.anytype.core_ui
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.MARKUP_CHANGED
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.TEXT_CHANGED
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Payload
import com.anytypeio.anytype.presentation.editor.editor.Markup
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.relations.DocumentRelationView
import com.anytypeio.anytype.presentation.sets.model.FileView
import com.anytypeio.anytype.presentation.sets.model.ObjectView
import com.anytypeio.anytype.presentation.sets.model.StatusView
import com.anytypeio.anytype.presentation.sets.model.TagView
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
@ -998,4 +1005,346 @@ class BlockViewDiffUtilTest {
actual = payload
)
}
@Test
fun `should detect changes in the name of the relation`() {
val index = 0
val view = DocumentRelationView.Default(
relationId = MockDataFactory.randomUuid(),
value = null,
format = RelationFormat.values().random(),
name = MockDataFactory.randomString()
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = view
)
val newBlock: BlockView = oldBlock.copy(
view = view.copy(
name = MockDataFactory.randomString()
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_NAME_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
@Test
fun `should detect changes in default relation value`() {
val index = 0
val view = DocumentRelationView.Default(
relationId = MockDataFactory.randomUuid(),
value = null,
format = RelationFormat.values().random(),
name = MockDataFactory.randomString()
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = view
)
val newBlock: BlockView = oldBlock.copy(
view = view.copy(
value = MockDataFactory.randomString()
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_VALUE_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
@Test
fun `should detect changes in checkbox relation value`() {
val index = 0
val view = DocumentRelationView.Checkbox(
relationId = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
isChecked = MockDataFactory.randomBoolean()
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = view
)
val newBlock: BlockView = oldBlock.copy(
view = view.copy(
isChecked = !view.isChecked
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_VALUE_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
@Test
fun `should detect changes in status relation value`() {
val index = 0
val oldStatus = StatusView(
id = MockDataFactory.randomUuid(),
status = MockDataFactory.randomUuid(),
color = ""
)
val newStatus = StatusView(
id = MockDataFactory.randomUuid(),
status = MockDataFactory.randomUuid(),
color = ""
)
val oldView = DocumentRelationView.Status(
relationId = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
status = listOf(oldStatus)
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = oldView
)
val newBlock: BlockView = oldBlock.copy(
view = oldView.copy(
status = listOf(newStatus)
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_VALUE_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
@Test
fun `should detect changes in tag relation value`() {
val index = 0
val oldTag = TagView(
id = MockDataFactory.randomUuid(),
tag = MockDataFactory.randomString(),
color = ""
)
val newTag = TagView(
id = MockDataFactory.randomUuid(),
tag = MockDataFactory.randomString(),
color = ""
)
val oldView = DocumentRelationView.Tags(
relationId = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
tags = listOf(oldTag)
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = oldView
)
val newBlock: BlockView = oldBlock.copy(
view = oldView.copy(
tags = listOf(newTag)
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_VALUE_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
@Test
fun `should detect changes in object relation value`() {
val index = 0
val oldObject = ObjectView.Default(
id = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
types = emptyList(),
icon = ObjectIcon.None
)
val newObject = oldObject.copy(
name = MockDataFactory.randomString()
)
val oldView = DocumentRelationView.Object(
relationId = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
objects = listOf(oldObject)
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = oldView
)
val newBlock: BlockView = oldBlock.copy(
view = oldView.copy(
objects = listOf(newObject)
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_VALUE_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
@Test
fun `should detect changes in file-relation value`() {
val index = 0
val oldFile = FileView(
id = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
mime = MockDataFactory.randomString(),
ext = MockDataFactory.randomString()
)
val newFile = oldFile.copy(
name = MockDataFactory.randomString()
)
val oldView = DocumentRelationView.File(
relationId = MockDataFactory.randomUuid(),
name = MockDataFactory.randomString(),
files = listOf(oldFile)
)
val oldBlock = BlockView.Relation.Related(
id = MockDataFactory.randomUuid(),
isSelected = MockDataFactory.randomBoolean(),
indent = MockDataFactory.randomInt(),
view = oldView
)
val newBlock: BlockView = oldBlock.copy(
view = oldView.copy(
files = listOf(newFile)
)
)
val old = listOf(oldBlock)
val new = listOf(newBlock)
val diff = BlockViewDiffUtil(old = old, new = new)
val payload = diff.getChangePayload(index, index)
val expected = Payload(
changes = listOf(BlockViewDiffUtil.RELATION_VALUE_CHANGED)
)
assertEquals(
expected = expected,
actual = payload
)
}
}

View file

@ -1,5 +1,7 @@
package com.anytypeio.anytype.core_models
package com.anytypeio.anytype.domain.block.model
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Relations
import org.junit.Test
import kotlin.test.assertNull
import kotlin.test.assertTrue
@ -16,7 +18,7 @@ class FieldsTest {
fun `should return value for isArchived property`() {
Block.Fields(
map = mapOf(
Block.Fields.IS_ARCHIVED_KEY to false
Relations.IS_ARCHIVED to false
)
).apply {
assertTrue { isArchived == false }
@ -24,7 +26,7 @@ class FieldsTest {
Block.Fields(
map = mapOf(
Block.Fields.IS_ARCHIVED_KEY to true
Relations.IS_ARCHIVED to true
)
).apply {
assertTrue { isArchived == true }

View file

@ -100,8 +100,8 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -210,8 +210,8 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -308,8 +308,8 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -406,8 +406,8 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -517,8 +517,8 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(

View file

@ -108,8 +108,8 @@ class EditorNoteLayoutTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -217,8 +217,8 @@ class EditorNoteLayoutTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(

View file

@ -4,6 +4,7 @@ import MockDataFactory
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Relation
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.SmartBlockType
import com.anytypeio.anytype.core_models.ext.content
import com.anytypeio.anytype.presentation.MockTypicalDocumentFactory
@ -187,8 +188,8 @@ class EditorRelationBlockTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -291,8 +292,8 @@ class EditorRelationBlockTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(
@ -402,8 +403,8 @@ class EditorRelationBlockTest : EditorPresentationTestSetup() {
val objectTypeFields = Block.Fields(
mapOf(
Block.Fields.NAME_KEY to objectTypeName,
Block.Fields.DESCRIPTION_KEY to objectTypeDescription
Relations.NAME to objectTypeName,
Relations.DESCRIPTION to objectTypeDescription
)
)
val customDetails = Block.Details(