diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt index 21caaca143..4022ad2bc9 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/BlockAdapter.kt @@ -182,6 +182,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_PLACEHOLDER import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_UPLOAD import com.anytypeio.anytype.presentation.editor.editor.slash.SlashEvent +import com.anytypeio.anytype.presentation.objects.ObjectIcon import timber.log.Timber import java.util.* @@ -556,7 +557,18 @@ class BlockAdapter( HOLDER_OBJECT_LINK_DEFAULT -> { LinkToObject( ItemBlockObjectLinkBinding.inflate(inflater, parent, false) - ) + ).apply { + objectIcon.checkbox.setOnClickListener { + val pos = bindingAdapterPosition + if (pos != RecyclerView.NO_POSITION) { + val view = views[pos] as BlockView.LinkToObject.Default.Text + onLinkToObjectCheckedIconClicked( + target = view.id, + icon = view.icon + ) + } + } + } } HOLDER_OBJECT_LINK_CARD_SMALL_ICON -> { LinkToObjectCardSmallIcon( @@ -565,7 +577,18 @@ class BlockAdapter( parent, false ) - ) + ).apply { + objectIconView.checkbox.setOnClickListener { + val pos = bindingAdapterPosition + if (pos != RecyclerView.NO_POSITION) { + val view = views[pos] as BlockView.LinkToObject.Default.Card.SmallIcon + onLinkToObjectCheckedIconClicked( + target = view.id, + icon = view.icon + ) + } + } + } } HOLDER_OBJECT_LINK_CARD_MEDIUM_ICON -> { LinkToObjectCardMediumIcon( @@ -574,7 +597,18 @@ class BlockAdapter( parent, false ) - ) + ).apply { + objectIconView.checkbox.setOnClickListener { + val pos = bindingAdapterPosition + if (pos != RecyclerView.NO_POSITION) { + val view = views[pos] as BlockView.LinkToObject.Default.Card.MediumIcon + onLinkToObjectCheckedIconClicked( + target = view.id, + icon = view.icon + ) + } + } + } } HOLDER_OBJECT_LINK_CARD_SMALL_ICON_COVER -> { LinkToObjectCardSmallIconCover( @@ -583,7 +617,19 @@ class BlockAdapter( parent, false ) - ) + ).apply { + objectIconView.checkbox.setOnClickListener { + val pos = bindingAdapterPosition + if (pos != RecyclerView.NO_POSITION) { + val view = + views[pos] as BlockView.LinkToObject.Default.Card.SmallIconCover + onLinkToObjectCheckedIconClicked( + target = view.id, + icon = view.icon + ) + } + } + } } HOLDER_OBJECT_LINK_CARD_MEDIUM_ICON_COVER -> { LinkToObjectCardMediumIconCover( @@ -592,7 +638,19 @@ class BlockAdapter( parent, false ) - ) + ).apply { + objectIconView.checkbox.setOnClickListener { + val pos = bindingAdapterPosition + if (pos != RecyclerView.NO_POSITION) { + val view = + views[pos] as BlockView.LinkToObject.Default.Card.MediumIconCover + onLinkToObjectCheckedIconClicked( + target = view.id, + icon = view.icon + ) + } + } + } } HOLDER_OBJECT_LINK_ARCHIVE -> { LinkToObjectArchive( @@ -1548,4 +1606,15 @@ class BlockAdapter( override fun provide(pos: Int): BlockView { return blocks[pos] } + + private fun onLinkToObjectCheckedIconClicked(target: Id, icon: ObjectIcon) { + if (icon is ObjectIcon.Task) { + onClickListener( + ListenerType.LinkToObjectCheckboxUpdate( + target = target, + isChecked = icon.isChecked + ) + ) + } + } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/LinkToObject.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/LinkToObject.kt index e817c1f34f..e0d995f08d 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/LinkToObject.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/LinkToObject.kt @@ -39,7 +39,7 @@ class LinkToObject( private val root = binding.root private val container = binding.container private val untitled = itemView.resources.getString(R.string.untitled) - private val objectIcon = binding.objectIconWidget + val objectIcon = binding.objectIconWidget private val objectIconContainer = binding.iconObjectContainer private val title = binding.text private val description = binding.tvDescription diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt index 1bdbe333ca..51778182e8 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt @@ -21,6 +21,7 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.core_models.Position 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.SyncStatus import com.anytypeio.anytype.core_models.Url @@ -2886,8 +2887,8 @@ class EditorViewModel( renderizePipeline.send(blocks) } - private fun onPageClicked(block: Id) { - val block = blocks.firstOrNull { it.id == block } + private fun onPageClicked(blockLinkId: Id) { + val block = blocks.firstOrNull { it.id == blockLinkId } when (val content = block?.content) { is Content.Link -> { proceedWithOpeningObjectByLayout(target = content.target) @@ -3542,8 +3543,8 @@ class EditorViewModel( } is ListenerType.LinkToObject -> { when (mode) { - EditorMode.Edit -> onPageClicked(clicked.target) - EditorMode.Locked -> onPageClicked(clicked.target) + EditorMode.Edit -> onPageClicked(blockLinkId = clicked.target) + EditorMode.Locked -> onPageClicked(blockLinkId = clicked.target) EditorMode.Select -> onBlockMultiSelectClicked(clicked.target) else -> Unit } @@ -3568,6 +3569,21 @@ class EditorViewModel( else -> Unit } } + is ListenerType.LinkToObjectCheckboxUpdate -> { + when (mode) { + EditorMode.Edit -> { + val content = blocks.firstOrNull { it.id == clicked.target }?.content + if (content is Content.Link) { + proceedWithSetObjectDetails( + ctx = content.target, + key = Relations.DONE, + value = !clicked.isChecked + ) + } + } + else -> Unit + } + } is ListenerType.Mention -> { when (mode) { EditorMode.Edit, EditorMode.Locked -> { @@ -3711,29 +3727,11 @@ class EditorViewModel( Relation.Format.CHECKBOX -> { val view = clicked.relation if (view is DocumentRelationView.Checkbox) { - viewModelScope.launch { - updateDetail( - UpdateDetail.Params( - ctx = context, - key = relationId, - value = !view.isChecked - ) - ).process( - success = { - dispatcher.send(it) - sendAnalyticsRelationValueEvent( - analytics = analytics, - context = analyticsContext - ) - }, - failure = { - Timber.e( - it, - "Error while updating relation values" - ) - } - ) - } + proceedWithSetObjectDetails( + ctx = context, + key = relationId, + value = !view.isChecked + ) } } Relation.Format.DATE -> { @@ -3882,25 +3880,12 @@ class EditorViewModel( value: BlockView.Relation.Related, relation: Id ) { - viewModelScope.launch { - val view = value.view as DocumentRelationView.Checkbox - updateDetail( - UpdateDetail.Params( - ctx = context, - key = relation, - value = !view.isChecked - ) - ).process( - success = { - dispatcher.send(it) - sendAnalyticsRelationValueEvent( - analytics = analytics, - context = analyticsContext - ) - }, - failure = { Timber.e(it, "Error while updating relation values") } - ) - } + val view = value.view as DocumentRelationView.Checkbox + proceedWithSetObjectDetails( + ctx = context, + key = relation, + value = !view.isChecked + ) } override fun onProceedWithFilePath(filePath: String?) { @@ -4087,6 +4072,29 @@ class EditorViewModel( } } + private fun proceedWithSetObjectDetails(ctx: Id, key: String, value: Any?) { + viewModelScope.launch { + updateDetail( + UpdateDetail.Params( + ctx = ctx, + key = key, + value = value + ) + ).process( + success = { + dispatcher.send(it) + sendAnalyticsRelationValueEvent( + analytics = analytics, + context = analyticsContext + ) + }, + failure = { + Timber.e(it, "Error while set object details") + } + ) + } + } + private fun sendToast(msg: String) { jobs += viewModelScope.launch { _toasts.emit(msg) @@ -4147,24 +4155,11 @@ class EditorViewModel( relationId: Id ) { Timber.d("onRelationTextValueChanged, ctx:[$ctx] value:[$value] relationId:[$relationId]") - viewModelScope.launch { - updateDetail( - UpdateDetail.Params( - ctx = ctx, - key = relationId, - value = value - ) - ).process( - success = { - dispatcher.send(it) - sendAnalyticsRelationValueEvent( - analytics = analytics, - context = analyticsContext - ) - }, - failure = { Timber.e(it, "Error while updating relation values") } - ) - } + proceedWithSetObjectDetails( + ctx = ctx, + key = relationId, + value = value + ) } fun onObjectTypeChanged(type: Id, isObjectDraft: Boolean) { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt index 28ff2d533b..b642598d89 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt @@ -54,6 +54,7 @@ sealed interface ListenerType { data class LinkToObjectArchived(val target: String) : ListenerType data class LinkToObjectDeleted(val target: String) : ListenerType data class LinkToObjectLoading(val target: String) : ListenerType + data class LinkToObjectCheckboxUpdate(val target: Id, val isChecked: Boolean) : ListenerType data class Mention(val target: String) : ListenerType diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/appearance/LinkAppearanceMenuTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/appearance/LinkAppearanceMenuTest.kt index 3222cdaa4c..9ef2aa155d 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/appearance/LinkAppearanceMenuTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/appearance/LinkAppearanceMenuTest.kt @@ -61,7 +61,55 @@ class LinkAppearanceMenuTest { } @Test - fun `when is todo note - no icon and no description`() { + fun `when is todo layout and card style without cover - no icon`() { + val factory = LinkAppearanceFactory( + content = StubLinkContent( + iconSize = Link.IconSize.SMALL, + cardStyle = Link.CardStyle.CARD, + description = Link.Description.NONE, + relations = setOf(Link.Relation.NAME) + ), + layout = ObjectType.Layout.TODO + ) + + val actual = factory.createAppearanceMenuItems() + val expected = BlockView.Appearance.Menu( + preview = MenuItem.PreviewLayout.CARD, + icon = null, + cover = MenuItem.Cover.WITHOUT, + description = MenuItem.Description.NONE, + objectType = MenuItem.ObjectType.WITHOUT, + iconMenus = listOf() + ) + assertEquals(expected, actual) + } + + @Test + fun `when is todo layout and card style with cover - no icon`() { + val factory = LinkAppearanceFactory( + content = StubLinkContent( + iconSize = Link.IconSize.SMALL, + cardStyle = Link.CardStyle.CARD, + description = Link.Description.NONE, + relations = setOf(Link.Relation.NAME, Link.Relation.COVER) + ), + layout = ObjectType.Layout.TODO + ) + + val actual = factory.createAppearanceMenuItems() + val expected = BlockView.Appearance.Menu( + preview = MenuItem.PreviewLayout.CARD, + icon = null, + cover = MenuItem.Cover.WITH, + description = MenuItem.Description.NONE, + objectType = MenuItem.ObjectType.WITHOUT, + iconMenus = listOf() + ) + assertEquals(expected, actual) + } + + @Test + fun `when is note - no icon and no description`() { val factory = LinkAppearanceFactory( content = defaultLinkAppearance.copy( description = Link.Description.ADDED