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 4e184c0311..c46f41562f 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 @@ -26,6 +26,7 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockDividerDotsBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockDividerLineBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockFeaturedRelationsBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileBinding +import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileUploadingBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockHeaderOneBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockHeaderThreeBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockHeaderTwoBinding @@ -39,6 +40,7 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkCardBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkDeleteBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkLoadingBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureBinding +import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureUploadingBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationFileBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationObjectBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationPlaceholderBinding @@ -51,6 +53,7 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockTocBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockToggleBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockUnsupportedBinding import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoBinding +import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoUploadingBinding import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Payload import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder import com.anytypeio.anytype.core_ui.features.editor.holders.`interface`.TextHolder @@ -494,11 +497,7 @@ class BlockAdapter( } HOLDER_FILE_UPLOAD -> { FileUpload( - view = inflater.inflate( - R.layout.item_block_file_uploading, - parent, - false - ) + ItemBlockFileUploadingBinding.inflate(inflater, parent, false) ) } HOLDER_FILE_ERROR -> { @@ -522,11 +521,7 @@ class BlockAdapter( } HOLDER_VIDEO_UPLOAD -> { VideoUpload( - view = inflater.inflate( - R.layout.item_block_video_uploading, - parent, - false - ) + ItemBlockVideoUploadingBinding.inflate(inflater, parent, false) ) } HOLDER_VIDEO_ERROR -> { @@ -598,11 +593,7 @@ class BlockAdapter( } HOLDER_PICTURE_UPLOAD -> { PictureUpload( - view = inflater.inflate( - R.layout.item_block_picture_uploading, - parent, - false - ) + ItemBlockPictureUploadingBinding.inflate(inflater, parent, false) ) } HOLDER_PICTURE_ERROR -> { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/decoration/DecoratableViewHolder.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/decoration/DecoratableViewHolder.kt index 601c91b2e1..cd8bb49244 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/decoration/DecoratableViewHolder.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/decoration/DecoratableViewHolder.kt @@ -1,9 +1,70 @@ package com.anytypeio.anytype.core_ui.features.editor.decoration +import android.content.res.Resources +import android.graphics.Rect +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.annotation.CallSuper +import androidx.core.view.marginBottom +import androidx.core.view.marginEnd +import androidx.core.view.marginStart +import androidx.core.view.marginTop +import androidx.core.view.updateLayoutParams +import com.anytypeio.anytype.core_ui.BuildConfig +import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.presentation.editor.editor.model.BlockView +import com.anytypeio.anytype.presentation.editor.model.Indent interface DecoratableViewHolder { val decoratableContainer: EditorDecorationContainer fun applyDecorations(decorations: List) - fun onDecorationsChanged(decorations: List) + fun onDecorationsChanged(decorations: List) { + applyDecorations(decorations = decorations) + } +} + +interface DecoratableCardViewHolder: DecoratableViewHolder { + val decoratableCard: View + @CallSuper + override fun applyDecorations(decorations: List) { + if (BuildConfig.NESTED_DECORATION_ENABLED) { + decoratableContainer.decorate(decorations) { rect -> + decoratableCard.applyCardDecorations( + rect = rect, + res = decoratableCard.resources, + indent = decorations.lastIndex + ) + } + } + } +} + +/** + * Applying decorations for card blocks (media blocks, placeholders, etc.) + */ +inline fun View.applyCardDecorations( + rect: Rect, + res: Resources, + indent: Indent +) = updateLayoutParams { + val defaultIndentOffset = res.getDimension(R.dimen.default_indent).toInt() + marginStart = if (indent == 0) defaultIndentOffset + rect.left else rect.left + marginEnd = defaultIndentOffset + rect.right + topMargin = res.getDimension(R.dimen.card_block_extra_space_top).toInt() + bottomMargin = res.getDimension(R.dimen.card_block_extra_space_bottom).toInt() + rect.bottom +} + +/** + * Setting offsets for selection view. + */ +inline fun View.applySelectorOffset( + content: View, + res: Resources +) = updateLayoutParams { + val selectorLeftRightOffset = res.getDimension(R.dimen.selection_left_right_offset).toInt() + marginStart = content.marginStart - selectorLeftRightOffset + marginEnd = content.marginEnd - selectorLeftRightOffset + topMargin = content.marginTop + bottomMargin = content.marginBottom } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt index b4b86f6012..753b9800f4 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt @@ -15,8 +15,9 @@ import com.anytypeio.anytype.core_ui.common.SearchTargetHighlightSpan import com.anytypeio.anytype.core_ui.databinding.ItemBlockBookmarkBinding import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil import com.anytypeio.anytype.core_ui.features.editor.EditorTouchProcessor -import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer +import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.core_utils.ext.gone import com.anytypeio.anytype.core_utils.ext.removeSpans @@ -33,7 +34,7 @@ import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.target.Target import timber.log.Timber -class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), DecoratableViewHolder { +class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), DecoratableCardViewHolder { override val root: View = itemView override val container = binding.containerWithBackground @@ -48,6 +49,7 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec override val clickContainer: View = card override val decoratableContainer: EditorDecorationContainer = binding.decorationContainer + override val decoratableCard: View = binding.bookmarkRoot override val editorTouchProcessor: EditorTouchProcessor = EditorTouchProcessor( fallback = { e -> clickContainer.onTouchEvent(e) } @@ -64,7 +66,7 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec right = dimen(R.dimen.default_document_item_padding_end) ) binding.root.updateLayoutParams { - bottomMargin = dimen(R.dimen.default_card_block_extra_space_bottom) + bottomMargin = dimen(R.dimen.card_block_extra_space_bottom) } } } @@ -213,21 +215,12 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec } override fun applyDecorations(decorations: List) { + super.applyDecorations(decorations) if (BuildConfig.NESTED_DECORATION_ENABLED) { - decoratableContainer.decorate(decorations) { rect -> - binding.bookmarkRoot.updateLayoutParams { - marginStart = dimen(R.dimen.default_indent) + rect.left - topMargin = dimen(R.dimen.default_card_block_extra_space_top) - bottomMargin = - rect.bottom + dimen(R.dimen.default_card_block_extra_space_bottom) - marginEnd = dimen(R.dimen.default_indent) - } - binding.selected.updateLayoutParams { - leftMargin = rect.left + dimen(R.dimen.default_selected_view_offset) - rightMargin = dimen(R.dimen.default_document_item_padding_end) - // TODO handle top and bottom offsets - } - } + binding.selected.applySelectorOffset( + content = binding.bookmarkRoot, + res = itemView.resources + ) } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt index cd4cfa5deb..5f3be5382a 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt @@ -2,8 +2,16 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.media import android.graphics.drawable.Drawable import android.view.View +import android.widget.FrameLayout +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import androidx.recyclerview.widget.RecyclerView +import com.anytypeio.anytype.core_ui.BuildConfig import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureBinding +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer +import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.core_utils.ext.indentize import com.anytypeio.anytype.core_utils.ext.invisible @@ -17,7 +25,7 @@ import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.target.Target import timber.log.Timber -class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root) { +class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root), DecoratableCardViewHolder { override val root: View = itemView override val container: View = root @@ -25,8 +33,25 @@ class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root) { private val image = binding.image private val error = binding.error + override val decoratableContainer: EditorDecorationContainer = binding.decorationContainer + override val decoratableCard: View = binding.card + init { clickContainer.setOnTouchListener { v, e -> editorTouchProcessor.process(v, e) } + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + binding.root.updatePadding( + top = dimen(R.dimen.dp_6), + left = dimen(R.dimen.dp_12), + right = dimen(R.dimen.dp_12), + bottom = dimen(R.dimen.dp_6) + ) + binding.root.updateLayoutParams { + marginStart = dimen(R.dimen.dp_8) + marginEnd = dimen(R.dimen.dp_8) + bottomMargin = dimen(R.dimen.dp_1) + topMargin = dimen(R.dimen.dp_1) + } + } } private val listener: RequestListener = object : RequestListener { @@ -64,14 +89,30 @@ class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root) { } override fun indentize(item: BlockView.Indentable) { - itemView.indentize( - indent = item.indent, - defIndent = dimen(R.dimen.indent), - margin = dimen(R.dimen.picture_default_margin_start) - ) + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + itemView.indentize( + indent = item.indent, + defIndent = dimen(R.dimen.indent), + margin = dimen(R.dimen.picture_default_margin_start) + ) + } } override fun select(isSelected: Boolean) { - itemView.isSelected = isSelected + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + itemView.isSelected = isSelected + } else { + binding.selected.isSelected = isSelected + } + } + + override fun applyDecorations(decorations: List) { + super.applyDecorations(decorations) + if (BuildConfig.NESTED_DECORATION_ENABLED) { + binding.selected.applySelectorOffset( + content = binding.card, + res = itemView.resources + ) + } } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/placeholders/MediaPlaceholder.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/placeholders/MediaPlaceholder.kt index 3330e9e387..91bbcdf220 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/placeholders/MediaPlaceholder.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/placeholders/MediaPlaceholder.kt @@ -1,10 +1,12 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.placeholders import android.view.View +import android.widget.FrameLayout import android.widget.TextView import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.recyclerview.widget.RecyclerView +import com.anytypeio.anytype.core_ui.BuildConfig import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding import com.anytypeio.anytype.core_ui.extensions.veryLight @@ -12,23 +14,33 @@ import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder import com.anytypeio.anytype.core_ui.features.editor.EditorTouchProcessor import com.anytypeio.anytype.core_ui.features.editor.SupportCustomTouchProcessor +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer +import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.presentation.editor.editor.ThemeColor import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView import com.google.android.material.card.MaterialCardView -import timber.log.Timber -abstract class MediaPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : - BlockViewHolder(binding.root), +abstract class MediaPlaceholder( + val binding: ItemBlockMediaPlaceholderBinding +) : BlockViewHolder(binding.root), BlockViewHolder.DragAndDropHolder, BlockViewHolder.IndentableHolder, - SupportCustomTouchProcessor { + SupportCustomTouchProcessor, + DecoratableCardViewHolder { protected val root: View = binding.root protected val card: MaterialCardView = binding.card protected val title: TextView = binding.title + override val decoratableContainer: EditorDecorationContainer + get() = binding.decorationContainer + + override val decoratableCard: View + get() = binding.card + abstract fun placeholderClick(target: String, clicked: (ListenerType) -> Unit) abstract fun setup() @@ -37,6 +49,17 @@ abstract class MediaPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : ) init { + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + binding.card.updateLayoutParams { + marginStart = dimen(R.dimen.default_media_placeholder_card_margin_start) + marginEnd = dimen(R.dimen.default_media_placeholder_card_margin_end) + bottomMargin = dimen(R.dimen.default_media_placeholder_root_margin_bottom) + } + binding.root.updatePadding( + left = dimen(R.dimen.default_document_item_padding_start), + right = dimen(R.dimen.default_document_item_padding_end), + ) + } itemView.setOnTouchListener { v, e -> editorTouchProcessor.process(v, e) } } @@ -67,47 +90,65 @@ abstract class MediaPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : } private fun applyRootMargins(item: BlockView.MediaPlaceholder) { - if (item.isPreviousBlockMedia) { - root.updateLayoutParams { - apply { topMargin = 0 } - } - } else { - root.updateLayoutParams { - apply { - topMargin = - root.resources.getDimension(R.dimen.default_media_placeholder_root_margin_top) - .toInt() + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + if (item.isPreviousBlockMedia) { + root.updateLayoutParams { + apply { topMargin = 0 } + } + } else { + root.updateLayoutParams { + apply { + topMargin = + root.resources.getDimension(R.dimen.default_media_placeholder_root_margin_top) + .toInt() + } } } } } private fun select(isSelected: Boolean) { - root.isSelected = isSelected + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + root.isSelected = isSelected + } else { + binding.selected.isSelected = isSelected + } } private fun applyBackground( background: String? ) { - Timber.d("Setting background color: $background") + if (BuildConfig.NESTED_DECORATION_ENABLED) return if (!background.isNullOrEmpty()) { val value = ThemeColor.values().find { value -> value.code == background } if (value != null && value != ThemeColor.DEFAULT) { card.setCardBackgroundColor(card.resources.veryLight(value, 0)) } else { - Timber.e("Could not find value for background color: $background, setting background to null") card.setCardBackgroundColor(0) } } else { - Timber.d("Background color is null, setting background to null") card.setCardBackgroundColor(0) } } override fun indentize(item: BlockView.Indentable) { - val leftPadding = - dimen(R.dimen.default_document_item_padding_start) + item.indent * dimen(R.dimen.indent) - root.updatePadding(left = leftPadding) + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + val leftPadding = + dimen(R.dimen.default_document_item_padding_start) + item.indent * dimen(R.dimen.indent) + root.updatePadding(left = leftPadding) + } } -} + override fun applyDecorations(decorations: List) { + super.applyDecorations(decorations) + if (BuildConfig.NESTED_DECORATION_ENABLED) { + binding.selected.applySelectorOffset( + content = binding.card, + res = itemView.resources + ) + card.setCardBackgroundColor( + card.resources.veryLight(decorations.last().background, 0) + ) + } + } +} \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Bulleted.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Bulleted.kt index b82b4af140..efced79916 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Bulleted.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Bulleted.kt @@ -151,8 +151,4 @@ class Bulleted( } } } - - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations = decorations) - } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Callout.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Callout.kt index e67af2d3eb..3208bfb195 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Callout.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Callout.kt @@ -174,8 +174,4 @@ class Callout( ) } } - - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations) - } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Checkbox.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Checkbox.kt index 4dd043a1c5..edc881ff39 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Checkbox.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Checkbox.kt @@ -156,8 +156,4 @@ class Checkbox( } } } - - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations = decorations) - } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Highlight.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Highlight.kt index 2b962632b1..fa738b7152 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Highlight.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Highlight.kt @@ -127,8 +127,4 @@ class Highlight( } } } - - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations) - } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Numbered.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Numbered.kt index 5284638bd5..cee2d74f30 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Numbered.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Numbered.kt @@ -183,8 +183,4 @@ class Numbered( } } } - - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations = decorations) - } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt index 532b8d4bf1..37617137de 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Paragraph.kt @@ -115,8 +115,4 @@ class Paragraph( } } } - - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations = decorations) - } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Toggle.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Toggle.kt index bf5d4c1f26..c15b4cd745 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Toggle.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/text/Toggle.kt @@ -192,10 +192,6 @@ class Toggle( } } - override fun onDecorationsChanged(decorations: List) { - applyDecorations(decorations = decorations) - } - companion object { /** * Rotation value for a toggle icon for expanded state. diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/FileUpload.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/FileUpload.kt index 11281cfb39..e3e848d9b3 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/FileUpload.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/FileUpload.kt @@ -1,29 +1,58 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.upload import android.view.View +import android.widget.FrameLayout +import com.anytypeio.anytype.core_ui.BuildConfig import com.anytypeio.anytype.core_ui.R +import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileUploadingBinding +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer +import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.core_utils.ext.indentize import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView -class FileUpload(view: View) : MediaUpload(view) { +class FileUpload( + private val binding: ItemBlockFileUploadingBinding +) : MediaUpload(binding.root), DecoratableCardViewHolder { override val root: View = itemView + override val decoratableContainer: EditorDecorationContainer + get() = binding.decorationContainer + + override val decoratableCard: View = binding.card + override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) { clicked(ListenerType.File.Upload(target)) } override fun indentize(item: BlockView.Indentable) { - root.indentize( - indent = item.indent, - defIndent = dimen(R.dimen.indent), - margin = dimen(R.dimen.bookmark_default_margin_start) - ) + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + root.indentize( + indent = item.indent, + defIndent = dimen(R.dimen.indent), + margin = dimen(R.dimen.bookmark_default_margin_start) + ) + } } override fun select(isSelected: Boolean) { - root.isSelected = isSelected + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + root.isSelected = isSelected + } else { + binding.selected.isSelected = isSelected + } + } + + override fun applyDecorations(decorations: List) { + super.applyDecorations(decorations) + if (BuildConfig.NESTED_DECORATION_ENABLED) { + binding.selected.applySelectorOffset( + content = binding.card, + res = itemView.resources + ) + } } } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/MediaUpload.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/MediaUpload.kt index 97175650a6..347dfb76ae 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/MediaUpload.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/MediaUpload.kt @@ -1,18 +1,22 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.upload import android.view.View +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import androidx.recyclerview.widget.RecyclerView +import com.anytypeio.anytype.core_ui.BuildConfig +import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder import com.anytypeio.anytype.core_ui.features.editor.EditorTouchProcessor import com.anytypeio.anytype.core_ui.features.editor.SupportCustomTouchProcessor -import com.anytypeio.anytype.core_ui.widgets.text.EditorLongClickListener -import com.anytypeio.anytype.core_utils.ext.PopupExtensions -import com.anytypeio.anytype.presentation.editor.editor.BlockDimensions +import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView -abstract class MediaUpload(view: View) : - BlockViewHolder(view), +abstract class MediaUpload( + view: View +) : BlockViewHolder(view), BlockViewHolder.IndentableHolder, SupportCustomTouchProcessor { @@ -27,6 +31,20 @@ abstract class MediaUpload(view: View) : init { itemView.setOnTouchListener { v, e -> editorTouchProcessor.process(v, e) } + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + view.updatePadding( + top = dimen(R.dimen.dp_6), + left = dimen(R.dimen.dp_12), + right = dimen(R.dimen.dp_12), + bottom = dimen(R.dimen.dp_6) + ) + view.updateLayoutParams { + marginStart = dimen(R.dimen.dp_8) + marginEnd = dimen(R.dimen.dp_8) + bottomMargin = dimen(R.dimen.dp_1) + topMargin = dimen(R.dimen.dp_1) + } + } } fun bind( diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/PictureUpload.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/PictureUpload.kt index 0724136039..70bb3cf8c1 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/PictureUpload.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/PictureUpload.kt @@ -1,26 +1,40 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.upload import android.view.View +import com.anytypeio.anytype.core_ui.BuildConfig import com.anytypeio.anytype.core_ui.R +import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureUploadingBinding +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.core_utils.ext.indentize import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView -class PictureUpload(view: View) : MediaUpload(view) { +class PictureUpload( + private val binding: ItemBlockPictureUploadingBinding +) : MediaUpload(binding.root), DecoratableViewHolder, DecoratableCardViewHolder { override val root: View = itemView + override val decoratableContainer: EditorDecorationContainer + get() = binding.decorationContainer + + override val decoratableCard: View get() = binding.root + override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) { clicked(ListenerType.Video.Upload(target)) } override fun indentize(item: BlockView.Indentable) { - root.indentize( - indent = item.indent, - defIndent = dimen(R.dimen.indent), - margin = dimen(R.dimen.bookmark_default_margin_start) - ) + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + root.indentize( + indent = item.indent, + defIndent = dimen(R.dimen.indent), + margin = dimen(R.dimen.bookmark_default_margin_start) + ) + } } override fun select(isSelected: Boolean) { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/VideoUpload.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/VideoUpload.kt index ce51938f77..9c8e7bfa78 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/VideoUpload.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/VideoUpload.kt @@ -1,26 +1,39 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.upload import android.view.View +import com.anytypeio.anytype.core_ui.BuildConfig import com.anytypeio.anytype.core_ui.R +import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoUploadingBinding +import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder +import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.core_utils.ext.indentize import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView -class VideoUpload(view: View) : MediaUpload(view) { +class VideoUpload( + val binding: ItemBlockVideoUploadingBinding +) : MediaUpload(binding.root), DecoratableCardViewHolder { override val root: View = itemView + override val decoratableContainer: EditorDecorationContainer + get() = binding.decorationContainer + + override val decoratableCard: View = binding.root + override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) { clicked(ListenerType.Video.Upload(target)) } override fun indentize(item: BlockView.Indentable) { - root.indentize( - indent = item.indent, - defIndent = dimen(R.dimen.indent), - margin = dimen(R.dimen.bookmark_default_margin_start) - ) + if (!BuildConfig.NESTED_DECORATION_ENABLED) { + root.indentize( + indent = item.indent, + defIndent = dimen(R.dimen.indent), + margin = dimen(R.dimen.bookmark_default_margin_start) + ) + } } override fun select(isSelected: Boolean) { diff --git a/core-ui/src/main/res/layout/item_block_file_uploading.xml b/core-ui/src/main/res/layout/item_block_file_uploading.xml index 01ae5ad1ee..f7aa782983 100644 --- a/core-ui/src/main/res/layout/item_block_file_uploading.xml +++ b/core-ui/src/main/res/layout/item_block_file_uploading.xml @@ -1,13 +1,19 @@ + + @@ -61,4 +67,11 @@ app:layout_constraintTop_toTopOf="@+id/editUrl" /> + + diff --git a/core-ui/src/main/res/layout/item_block_media_placeholder.xml b/core-ui/src/main/res/layout/item_block_media_placeholder.xml index dff2d35ae1..62ab0726dd 100644 --- a/core-ui/src/main/res/layout/item_block_media_placeholder.xml +++ b/core-ui/src/main/res/layout/item_block_media_placeholder.xml @@ -2,9 +2,13 @@ + android:layout_height="wrap_content"> + + + + + + diff --git a/core-ui/src/main/res/layout/item_block_picture_uploading.xml b/core-ui/src/main/res/layout/item_block_picture_uploading.xml index caa227df12..650f20bb80 100644 --- a/core-ui/src/main/res/layout/item_block_picture_uploading.xml +++ b/core-ui/src/main/res/layout/item_block_picture_uploading.xml @@ -6,6 +6,11 @@ android:background="@drawable/item_block_multi_select_mode_selector" android:layout_height="wrap_content"> + + + + - 10dp - 10dp + 10dp + 10dp @@ -285,5 +285,6 @@ 12dp 12dp 20dp + 12dp \ No newline at end of file diff --git a/core-ui/src/main/res/values/styles.xml b/core-ui/src/main/res/values/styles.xml index cb2bd1c0a0..f40d0e4b13 100644 --- a/core-ui/src/main/res/values/styles.xml +++ b/core-ui/src/main/res/values/styles.xml @@ -897,8 +897,6 @@ @dimen/default_media_placeholder_root_margin_bottom - @dimen/default_document_item_padding_start - @dimen/default_document_item_padding_end @@ -907,10 +905,7 @@ 0dp @color/shape_primary 0.5dp - @dimen/default_media_placeholder_card_margin_end - - @dimen/default_media_placeholder_card_margin_start - + @android:color/transparent @dimen/default_media_placeholder_card_padding_start @dimen/default_media_placeholder_card_padding_end diff --git a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/BlockAdapterTest.kt b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/BlockAdapterTest.kt index 9f1577d212..27fb0ac244 100644 --- a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/BlockAdapterTest.kt +++ b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/BlockAdapterTest.kt @@ -1034,7 +1034,8 @@ class BlockAdapterTest { val view = BlockView.Error.File( id = MockDataFactory.randomUuid(), - indent = MockDataFactory.randomInt() + indent = MockDataFactory.randomInt(), + decorations = emptyList() ) val views = listOf(view) @@ -1182,7 +1183,8 @@ class BlockAdapterTest { val view = BlockView.Error.Video( id = MockDataFactory.randomUuid(), - indent = MockDataFactory.randomInt() + indent = MockDataFactory.randomInt(), + decorations = emptyList() ) val views = listOf(view) @@ -1315,7 +1317,8 @@ class BlockAdapterTest { mime = MockDataFactory.randomString(), name = MockDataFactory.randomString(), size = MockDataFactory.randomLong(), - url = MockDataFactory.randomString() + url = MockDataFactory.randomString(), + decorations = emptyList() ) val views = listOf(view) @@ -1357,8 +1360,7 @@ class BlockAdapterTest { val adapter = buildAdapter(views) - val holder = - adapter.onCreateViewHolder(recycler, Types.HOLDER_PICTURE_PLACEHOLDER) + val holder = adapter.onCreateViewHolder(recycler, Types.HOLDER_PICTURE_PLACEHOLDER) adapter.bindViewHolder(holder, 0) @@ -1366,8 +1368,7 @@ class BlockAdapterTest { val actual = holder.itemView.paddingLeft - val expected = - holder.dimen(R.dimen.default_document_item_padding_start) + view.indent * holder.dimen(R.dimen.indent) + val expected = holder.dimen(R.dimen.default_document_item_padding_start) + view.indent * holder.dimen(R.dimen.indent) assertEquals(expected, actual) } @@ -1377,7 +1378,8 @@ class BlockAdapterTest { val view = BlockView.Error.Picture( id = MockDataFactory.randomUuid(), - indent = MockDataFactory.randomInt() + indent = MockDataFactory.randomInt(), + decorations = emptyList() ) val views = listOf(view) @@ -3200,7 +3202,8 @@ class BlockAdapterTest { size = MockDataFactory.randomLong(), name = MockDataFactory.randomString(), url = MockDataFactory.randomString(), - isSelected = false + isSelected = false, + decorations = emptyList() ), BlockView.Media.File( id = MockDataFactory.randomString(), @@ -3210,7 +3213,8 @@ class BlockAdapterTest { size = MockDataFactory.randomLong(), name = MockDataFactory.randomString(), url = MockDataFactory.randomString(), - isSelected = true + isSelected = true, + decorations = emptyList() ) ) @@ -3247,7 +3251,8 @@ class BlockAdapterTest { size = MockDataFactory.randomLong(), name = MockDataFactory.randomString(), url = MockDataFactory.randomString(), - isSelected = false + isSelected = false, + decorations = emptyList() ) val updated = file.copy(isSelected = true) @@ -3502,7 +3507,8 @@ class BlockAdapterTest { mime = MockDataFactory.randomString(), name = MockDataFactory.randomString(), size = MockDataFactory.randomLong(), - url = MockDataFactory.randomString() + url = MockDataFactory.randomString(), + decorations = emptyList() ) private fun givenVideo() = BlockView.Media.Video( @@ -3512,7 +3518,8 @@ class BlockAdapterTest { url = MockDataFactory.randomString(), mime = MockDataFactory.randomString(), name = MockDataFactory.randomString(), - size = MockDataFactory.randomLong() + size = MockDataFactory.randomLong(), + decorations = emptyList() ) private fun buildAdapter( diff --git a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/page/BlockViewTest.kt b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/page/BlockViewTest.kt index 5500246ed8..45cb327032 100644 --- a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/page/BlockViewTest.kt +++ b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/page/BlockViewTest.kt @@ -39,7 +39,8 @@ class BlockViewTest { size = MockDataFactory.randomLong(), mime = MockDataFactory.randomString(), name = MockDataFactory.randomString(), - indent = MockDataFactory.randomInt() + indent = MockDataFactory.randomInt(), + decorations = emptyList() ) assertEquals(HOLDER_VIDEO, block.getViewType()) } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt index d648e936ae..c37e838449 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt @@ -436,7 +436,7 @@ sealed class BlockView : ViewType { override var cursor: Int? = null, override val searchFields: List = emptyList(), override val ghostEditorSelection: IntRange? = null, - override val decorations: List, + override val decorations: List = emptyList(), val icon: ObjectIcon, ) : Text() { override val alignment: Alignment? = null @@ -696,7 +696,7 @@ sealed class BlockView : ViewType { override fun getViewType() = HOLDER_CODE_SNIPPET } - sealed class Error : BlockView(), Indentable, Selectable, Permission { + sealed class Error : BlockView(), Indentable, Selectable, Permission, Decoratable { abstract override val id: String abstract override val indent: Int @@ -713,7 +713,8 @@ sealed class BlockView : ViewType { override val indent: Int, override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Error() { override fun getViewType() = HOLDER_FILE_ERROR } @@ -727,7 +728,8 @@ sealed class BlockView : ViewType { override val indent: Int, override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Error() { override fun getViewType() = HOLDER_VIDEO_ERROR } @@ -740,7 +742,8 @@ sealed class BlockView : ViewType { override val indent: Int, override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Error() { override fun getViewType() = HOLDER_PICTURE_ERROR } @@ -755,13 +758,14 @@ sealed class BlockView : ViewType { override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, val url: String, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Error() { override fun getViewType(): Int = HOLDER_BOOKMARK_ERROR } } - sealed class Upload : BlockView(), Indentable, Selectable, Permission { + sealed class Upload : BlockView(), Indentable, Selectable, Permission, Decoratable { abstract override val id: String abstract override val indent: Int @@ -778,7 +782,8 @@ sealed class BlockView : ViewType { override val indent: Int, override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Upload() { override fun getViewType() = HOLDER_FILE_UPLOAD } @@ -792,7 +797,8 @@ sealed class BlockView : ViewType { override val indent: Int, override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Upload() { override fun getViewType() = HOLDER_VIDEO_UPLOAD } @@ -805,7 +811,8 @@ sealed class BlockView : ViewType { override val indent: Int, override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, - override val backgroundColor: String? = null + override val backgroundColor: String? = null, + override val decorations: List = emptyList() ) : Upload() { override fun getViewType() = HOLDER_PICTURE_UPLOAD } @@ -884,7 +891,7 @@ sealed class BlockView : ViewType { } - sealed class Media : BlockView(), Indentable, Selectable, Permission { + sealed class Media : BlockView(), Indentable, Selectable, Permission, Decoratable { abstract override val id: String abstract override val indent: Int @@ -903,6 +910,7 @@ sealed class BlockView : ViewType { override val isSelected: Boolean = false, override val searchFields: List = emptyList(), override val backgroundColor: String? = null, + override val decorations: List = emptyList(), val size: Long?, val name: String?, val mime: String?, @@ -921,6 +929,7 @@ sealed class BlockView : ViewType { override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, override val backgroundColor: String? = null, + override val decorations: List = emptyList(), val size: Long?, val name: String?, val mime: String?, @@ -952,7 +961,7 @@ sealed class BlockView : ViewType { val faviconUrl: String? = null, val imageUrl: String? = null, val isPreviousBlockMedia: Boolean - ) : Media(), Searchable, Decoratable { + ) : Media(), Searchable { override fun getViewType() = HOLDER_BOOKMARK companion object { @@ -971,6 +980,7 @@ sealed class BlockView : ViewType { override val mode: Mode = Mode.EDIT, override val isSelected: Boolean = false, override val backgroundColor: String? = null, + override val decorations: List = emptyList(), val size: Long?, val name: String?, val mime: String?, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt index 500497c298..73843853b1 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt @@ -618,6 +618,14 @@ class DefaultBlockViewRenderer @Inject constructor( } is Content.File -> { mCounter = 0 + val blockDecorationScheme = buildNestedDecorationData( + block = block, + parentScheme = parentScheme, + currentDecoration = DecorationData( + style = DecorationData.Style.Card, + background = block.parseThemeBackgroundColor() + ) + ) result.add( file( mode = mode, @@ -625,7 +633,8 @@ class DefaultBlockViewRenderer @Inject constructor( block = block, indent = indent, selection = selection, - isPreviousBlockMedia = isPreviousBlockMedia + isPreviousBlockMedia = isPreviousBlockMedia, + schema = blockDecorationScheme ) ) isPreviousBlockMedia = true @@ -1180,7 +1189,8 @@ class DefaultBlockViewRenderer @Inject constructor( mode = mode, block = block, selection = selection - ) + ), + decorations = schema.toBlockViewDecoration(block) ) } } ?: BlockView.MediaPlaceholder.Bookmark( @@ -1193,7 +1203,8 @@ class DefaultBlockViewRenderer @Inject constructor( selection = selection ), backgroundColor = block.backgroundColor, - isPreviousBlockMedia = isPreviousBlockMedia + isPreviousBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) private fun divider( @@ -1231,7 +1242,8 @@ class DefaultBlockViewRenderer @Inject constructor( block: Block, indent: Int, selection: Set, - isPreviousBlockMedia: Boolean + isPreviousBlockMedia: Boolean, + schema: NestedDecorationData ): BlockView = when (content.type) { Content.File.Type.IMAGE -> content.toPictureView( id = block.id, @@ -1244,7 +1256,8 @@ class DefaultBlockViewRenderer @Inject constructor( selection = selection ), backgroundColor = block.backgroundColor, - isPreviousBlockMedia = isPreviousBlockMedia + isPreviousBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) Content.File.Type.FILE -> content.toFileView( id = block.id, @@ -1258,6 +1271,7 @@ class DefaultBlockViewRenderer @Inject constructor( ), backgroundColor = block.backgroundColor, isPrevBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) Content.File.Type.VIDEO -> content.toVideoView( id = block.id, @@ -1270,7 +1284,8 @@ class DefaultBlockViewRenderer @Inject constructor( selection = selection ), backgroundColor = block.backgroundColor, - isPrevBlockMedia = isPreviousBlockMedia + isPrevBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) Content.File.Type.AUDIO -> content.toFileView( id = block.id, @@ -1283,7 +1298,8 @@ class DefaultBlockViewRenderer @Inject constructor( selection = selection ), backgroundColor = block.backgroundColor, - isPrevBlockMedia = isPreviousBlockMedia + isPrevBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) Content.File.Type.PDF -> content.toFileView( id = block.id, @@ -1296,7 +1312,8 @@ class DefaultBlockViewRenderer @Inject constructor( selection = selection ), backgroundColor = block.backgroundColor, - isPrevBlockMedia = isPreviousBlockMedia + isPrevBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) Content.File.Type.NONE -> content.toFileView( id = block.id, @@ -1309,7 +1326,8 @@ class DefaultBlockViewRenderer @Inject constructor( selection = selection ), backgroundColor = block.backgroundColor, - isPrevBlockMedia = isPreviousBlockMedia + isPrevBlockMedia = isPreviousBlockMedia, + decorations = schema.toBlockViewDecoration(block) ) else -> throw IllegalStateException("Unexpected file type: ${content.type}") } @@ -1395,10 +1413,7 @@ class DefaultBlockViewRenderer @Inject constructor( id = block.id, text = content.text, emoji = details.details[root.id]?.iconEmoji?.let { name -> - if (name.isNotEmpty()) - name - else - null + name.ifEmpty { null } }, image = details.details[root.id]?.iconImage?.let { name -> if (name.isNotEmpty()) @@ -1457,10 +1472,7 @@ class DefaultBlockViewRenderer @Inject constructor( id = block.id, text = content.text, emoji = details.details[root.id]?.iconEmoji?.let { name -> - if (name.isNotEmpty()) - name - else - null + name.ifEmpty { null } }, image = details.details[root.id]?.iconImage?.let { name -> if (name.isNotEmpty()) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt index 06080cbc27..c0989a48f3 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt @@ -35,139 +35,154 @@ import com.anytypeio.anytype.presentation.sets.model.Viewer import com.anytypeio.anytype.presentation.settings.EditorSettings fun Block.Content.File.toPictureView( - id: String, - urlBuilder: UrlBuilder, - indent: Int, - mode: BlockView.Mode, - isSelected: Boolean = false, - backgroundColor: String?, - isPreviousBlockMedia: Boolean + id: String, + urlBuilder: UrlBuilder, + indent: Int, + mode: BlockView.Mode, + isSelected: Boolean = false, + backgroundColor: String?, + isPreviousBlockMedia: Boolean, + decorations: List ): BlockView = when (state) { Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.Picture( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor, - isPreviousBlockMedia = isPreviousBlockMedia + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + isPreviousBlockMedia = isPreviousBlockMedia, + decorations = decorations ) Block.Content.File.State.UPLOADING -> BlockView.Upload.Picture( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) Block.Content.File.State.DONE -> BlockView.Media.Picture( - id = id, - size = size, - name = name, - mime = mime, - hash = hash, - url = urlBuilder.image(hash), - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + size = size, + name = name, + mime = mime, + hash = hash, + url = urlBuilder.image(hash), + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) Block.Content.File.State.ERROR -> BlockView.Error.Picture( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) else -> throw IllegalStateException("Unexpected state: $state") } fun Block.Content.File.toVideoView( - id: String, - urlBuilder: UrlBuilder, - indent: Int, - mode: BlockView.Mode, - isSelected: Boolean = false, - backgroundColor: String?, - isPrevBlockMedia: Boolean + id: String, + urlBuilder: UrlBuilder, + indent: Int, + mode: BlockView.Mode, + isSelected: Boolean = false, + backgroundColor: String?, + isPrevBlockMedia: Boolean, + decorations: List ): BlockView = when (state) { Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.Video( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor, - isPreviousBlockMedia = isPrevBlockMedia + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + isPreviousBlockMedia = isPrevBlockMedia, + decorations = decorations ) Block.Content.File.State.UPLOADING -> BlockView.Upload.Video( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) Block.Content.File.State.DONE -> BlockView.Media.Video( - id = id, - size = size, - name = name, - mime = mime, - hash = hash, - url = urlBuilder.video(hash), - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + size = size, + name = name, + mime = mime, + hash = hash, + url = urlBuilder.video(hash), + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) Block.Content.File.State.ERROR -> BlockView.Error.Video( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations ) else -> throw IllegalStateException("Unexpected state: $state") } fun Block.Content.File.toFileView( - id: String, - urlBuilder: UrlBuilder, - indent: Int, - mode: BlockView.Mode, - isSelected: Boolean = false, - backgroundColor: String?, - isPrevBlockMedia: Boolean + id: String, + urlBuilder: UrlBuilder, + indent: Int, + mode: BlockView.Mode, + isSelected: Boolean = false, + backgroundColor: String?, + isPrevBlockMedia: Boolean, + decorations: List ): BlockView = when (state) { Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.File( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor, - isPreviousBlockMedia = isPrevBlockMedia + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + isPreviousBlockMedia = isPrevBlockMedia, + decorations = decorations ) Block.Content.File.State.UPLOADING -> BlockView.Upload.File( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) Block.Content.File.State.DONE -> BlockView.Media.File( - id = id, - size = size, - name = name, - mime = mime, - hash = hash, - url = urlBuilder.video(hash), - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + size = size, + name = name, + mime = mime, + hash = hash, + url = urlBuilder.video(hash), + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) Block.Content.File.State.ERROR -> BlockView.Error.File( - id = id, - indent = indent, - mode = mode, - isSelected = isSelected, - backgroundColor = backgroundColor + id = id, + indent = indent, + mode = mode, + isSelected = isSelected, + backgroundColor = backgroundColor, + decorations = decorations ) else -> throw IllegalStateException("Unexpected state: $state") } @@ -180,88 +195,88 @@ fun Block.Align.toView(): Alignment = when (this) { } fun Block.Content.Text.marks( - urlBuilder: UrlBuilder, - details: Block.Details + urlBuilder: UrlBuilder, + details: Block.Details ): List = marks - .filterByRange(text.length) - .mapNotNull { mark -> - when (mark.type) { - Block.Content.Text.Mark.Type.ITALIC -> { - Markup.Mark.Italic( - from = mark.range.first, - to = mark.range.last - ) - } - Block.Content.Text.Mark.Type.BOLD -> { - Markup.Mark.Bold( - from = mark.range.first, - to = mark.range.last - ) - } - Block.Content.Text.Mark.Type.STRIKETHROUGH -> { - Markup.Mark.Strikethrough( - from = mark.range.first, - to = mark.range.last - ) - } - Block.Content.Text.Mark.Type.TEXT_COLOR -> { - val color = mark.param - if (color.isNullOrBlank()) null - else Markup.Mark.TextColor( - from = mark.range.first, - to = mark.range.last, - color = color - ) - } - Block.Content.Text.Mark.Type.LINK -> { - val param = mark.param - if (param.isNullOrBlank()) null - else Markup.Mark.Link( - from = mark.range.first, - to = mark.range.last, - param = param - ) - } - Block.Content.Text.Mark.Type.BACKGROUND_COLOR -> { - val background = mark.param - if (background.isNullOrBlank()) null - else Markup.Mark.BackgroundColor( - from = mark.range.first, - to = mark.range.last, - background = background - ) - } - Block.Content.Text.Mark.Type.KEYBOARD -> { - Markup.Mark.Keyboard( - from = mark.range.first, - to = mark.range.last - ) - } - Block.Content.Text.Mark.Type.MENTION -> { - - val wrapper = if (!details.details.containsKey(mark.param)) { - null - } else { - ObjectWrapper.Basic(map = details.details[mark.param]?.map ?: emptyMap()) - } - - mark.createMentionMarkup( - obj = wrapper, - urlBuilder = urlBuilder - ) - } - Block.Content.Text.Mark.Type.OBJECT -> { - val param = mark.param - if (param.isNullOrBlank()) null - else Markup.Mark.Object( - from = mark.range.first, - to = mark.range.last, - param = param - ) - } - else -> null + .filterByRange(text.length) + .mapNotNull { mark -> + when (mark.type) { + Block.Content.Text.Mark.Type.ITALIC -> { + Markup.Mark.Italic( + from = mark.range.first, + to = mark.range.last + ) } + Block.Content.Text.Mark.Type.BOLD -> { + Markup.Mark.Bold( + from = mark.range.first, + to = mark.range.last + ) + } + Block.Content.Text.Mark.Type.STRIKETHROUGH -> { + Markup.Mark.Strikethrough( + from = mark.range.first, + to = mark.range.last + ) + } + Block.Content.Text.Mark.Type.TEXT_COLOR -> { + val color = mark.param + if (color.isNullOrBlank()) null + else Markup.Mark.TextColor( + from = mark.range.first, + to = mark.range.last, + color = color + ) + } + Block.Content.Text.Mark.Type.LINK -> { + val param = mark.param + if (param.isNullOrBlank()) null + else Markup.Mark.Link( + from = mark.range.first, + to = mark.range.last, + param = param + ) + } + Block.Content.Text.Mark.Type.BACKGROUND_COLOR -> { + val background = mark.param + if (background.isNullOrBlank()) null + else Markup.Mark.BackgroundColor( + from = mark.range.first, + to = mark.range.last, + background = background + ) + } + Block.Content.Text.Mark.Type.KEYBOARD -> { + Markup.Mark.Keyboard( + from = mark.range.first, + to = mark.range.last + ) + } + Block.Content.Text.Mark.Type.MENTION -> { + + val wrapper = if (!details.details.containsKey(mark.param)) { + null + } else { + ObjectWrapper.Basic(map = details.details[mark.param]?.map ?: emptyMap()) + } + + mark.createMentionMarkup( + obj = wrapper, + urlBuilder = urlBuilder + ) + } + Block.Content.Text.Mark.Type.OBJECT -> { + val param = mark.param + if (param.isNullOrBlank()) null + else Markup.Mark.Object( + from = mark.range.first, + to = mark.range.last, + param = param + ) + } + else -> null } + } fun List.filterByRange(textLength: Int): List { return this.mapNotNull { mark -> @@ -289,9 +304,9 @@ fun List.filterByRange(textLength: Int): List.toDashboardViews( - details: Block.Details = Block.Details(), - builder: UrlBuilder, - objectTypes: List = emptyList() + details: Block.Details = Block.Details(), + builder: UrlBuilder, + objectTypes: List = emptyList() ): List = this.mapNotNull { block -> when (val content = block.content) { is Block.Content.Link -> { @@ -306,28 +321,28 @@ fun List.toDashboardViews( } when (layout) { ObjectType.Layout.BASIC -> content.toPageView( - id = block.id, - details = details, - builder = builder, - type = type?.url, - typeName = type?.name, - layout = layout + id = block.id, + details = details, + builder = builder, + type = type?.url, + typeName = type?.name, + layout = layout ) ObjectType.Layout.SET -> content.toSetView(block.id, details, builder) else -> { when (content.type) { Block.Content.Link.Type.PAGE -> content.toPageView( - id = block.id, - details = details, - builder = builder, - type = type?.url, - typeName = type?.name, - layout = layout + id = block.id, + details = details, + builder = builder, + type = type?.url, + typeName = type?.name, + layout = layout ) Block.Content.Link.Type.DATA_VIEW -> content.toSetView( - block.id, - details, - builder + block.id, + details, + builder ) Block.Content.Link.Type.ARCHIVE -> content.toArchiveView(block.id, details) else -> null @@ -340,67 +355,67 @@ fun List.toDashboardViews( } fun Block.Content.Link.toArchiveView( - id: String, - details: Block.Details + id: String, + details: Block.Details ): DashboardView.Archive { return DashboardView.Archive( - id = id, - target = target, - title = details.details[target]?.name.orEmpty() + id = id, + target = target, + title = details.details[target]?.name.orEmpty() ) } fun Block.Content.Link.toPageView( - id: String, - details: Block.Details, - builder: UrlBuilder, - layout: ObjectType.Layout?, - typeName: String?, - type: String? + id: String, + details: Block.Details, + builder: UrlBuilder, + layout: ObjectType.Layout?, + typeName: String?, + type: String? ): DashboardView.Document { val obj = ObjectWrapper.Basic(details.details[target]?.map ?: emptyMap()) return DashboardView.Document( - id = id, - target = target, - title = obj.getProperName(), - emoji = details.details[target]?.iconEmoji?.let { unicode -> - if (unicode.isNotEmpty()) unicode else null - }, - image = details.details[target]?.iconImage?.let { hash -> - if (hash.isNotEmpty()) builder.image(hash) else null - }, - isArchived = details.details[target]?.isArchived ?: false, - isLoading = !details.details.containsKey(target), - typeName = typeName, - type = type, + id = id, + target = target, + title = obj.getProperName(), + emoji = details.details[target]?.iconEmoji?.let { unicode -> + if (unicode.isNotEmpty()) unicode else null + }, + image = details.details[target]?.iconImage?.let { hash -> + if (hash.isNotEmpty()) builder.image(hash) else null + }, + isArchived = details.details[target]?.isArchived ?: false, + isLoading = !details.details.containsKey(target), + typeName = typeName, + type = type, + layout = layout, + done = details.details[target]?.done, + icon = ObjectIcon.from( + obj = obj, layout = layout, - done = details.details[target]?.done, - icon = ObjectIcon.from( - obj = obj, - layout = layout, - builder = builder - ) + builder = builder + ) ) } fun Block.Content.Link.toSetView( - id: String, - details: Block.Details, - urlBuilder: UrlBuilder + id: String, + details: Block.Details, + urlBuilder: UrlBuilder ): DashboardView.ObjectSet { val obj = ObjectWrapper.Basic(details.details[target]?.map ?: emptyMap()) return DashboardView.ObjectSet( - id = id, - target = target, - title = details.details[target]?.name, - icon = ObjectIcon.from( - obj = obj, - layout = obj.layout, - builder = urlBuilder - ), - isArchived = details.details[target]?.isArchived ?: false + id = id, + target = target, + title = details.details[target]?.name, + icon = ObjectIcon.from( + obj = obj, + layout = obj.layout, + builder = urlBuilder + ), + isArchived = details.details[target]?.isArchived ?: false ) } @@ -428,72 +443,72 @@ fun UiBlock.style(): Block.Content.Text.Style = when (this) { } fun DebugSettings.toView(): EditorSettings = - EditorSettings(customContextMenu = this.isAnytypeContextMenuEnabled) + EditorSettings(customContextMenu = this.isAnytypeContextMenuEnabled) fun DocumentInfo.toView( - urlBuilder: UrlBuilder, - objectTypes: List + urlBuilder: UrlBuilder, + objectTypes: List ): ObjectView { val typeId = obj.type.firstOrNull() val type = objectTypes.find { it.url == typeId } return ObjectView( - id = id, - title = obj.name.orEmpty(), - subtitle = type?.name.orEmpty(), - icon = ObjectIcon.from( - obj = obj, - layout = obj.layout, - builder = urlBuilder - ) + id = id, + title = obj.name.orEmpty(), + subtitle = type?.name.orEmpty(), + icon = ObjectIcon.from( + obj = obj, + layout = obj.layout, + builder = urlBuilder + ) ) } fun Block.Fields.getName(): String = - this.name.let { name -> - if (name.isNullOrBlank()) Relations.RELATION_NAME_EMPTY else name - } + this.name.let { name -> + if (name.isNullOrBlank()) Relations.RELATION_NAME_EMPTY else name + } fun Markup.Mark.mark(): Block.Content.Text.Mark = when (this) { is Markup.Mark.Bold -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.BOLD + range = from..to, + type = Block.Content.Text.Mark.Type.BOLD ) is Markup.Mark.Italic -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.ITALIC + range = from..to, + type = Block.Content.Text.Mark.Type.ITALIC ) is Markup.Mark.Strikethrough -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.STRIKETHROUGH + range = from..to, + type = Block.Content.Text.Mark.Type.STRIKETHROUGH ) is Markup.Mark.TextColor -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.TEXT_COLOR, - param = color + range = from..to, + type = Block.Content.Text.Mark.Type.TEXT_COLOR, + param = color ) is Markup.Mark.BackgroundColor -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.BACKGROUND_COLOR, - param = background + range = from..to, + type = Block.Content.Text.Mark.Type.BACKGROUND_COLOR, + param = background ) is Markup.Mark.Link -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.LINK, - param = param + range = from..to, + type = Block.Content.Text.Mark.Type.LINK, + param = param ) is Markup.Mark.Keyboard -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.KEYBOARD + range = from..to, + type = Block.Content.Text.Mark.Type.KEYBOARD ) is Markup.Mark.Mention -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.MENTION, - param = param + range = from..to, + type = Block.Content.Text.Mark.Type.MENTION, + param = param ) is Markup.Mark.Object -> Block.Content.Text.Mark( - range = from..to, - type = Block.Content.Text.Mark.Type.OBJECT, - param = param + range = from..to, + type = Block.Content.Text.Mark.Type.OBJECT, + param = param ) } @@ -550,31 +565,31 @@ fun DVFilterCondition.toCheckboxView(): Viewer.Filter.Condition.Checkbox = when } fun SortingExpression.toDomain(): DVSort = DVSort( - relationKey = key, - type = when (type) { - Viewer.SortType.ASC -> Block.Content.DataView.Sort.Type.ASC - Viewer.SortType.DESC -> Block.Content.DataView.Sort.Type.DESC - } + relationKey = key, + type = when (type) { + Viewer.SortType.ASC -> Block.Content.DataView.Sort.Type.ASC + Viewer.SortType.DESC -> Block.Content.DataView.Sort.Type.DESC + } ) fun FilterExpression.toDomain(): DVFilter = DVFilter( - relationKey = key, - operator = operator.toDomain(), - condition = condition.toDomain(), - value = when (value) { - is FilterValue.Number -> value.value - is FilterValue.Status -> value.value - is FilterValue.Tag -> value.value - is FilterValue.Text -> value.value - is FilterValue.Url -> value.value - is FilterValue.Email -> value.value - is FilterValue.Phone -> value.value - is FilterValue.Date -> value.value - is FilterValue.TextShort -> value.value - is FilterValue.Check -> value.value - is FilterValue.Object -> value.value - null -> null - } + relationKey = key, + operator = operator.toDomain(), + condition = condition.toDomain(), + value = when (value) { + is FilterValue.Number -> value.value + is FilterValue.Status -> value.value + is FilterValue.Tag -> value.value + is FilterValue.Text -> value.value + is FilterValue.Url -> value.value + is FilterValue.Email -> value.value + is FilterValue.Phone -> value.value + is FilterValue.Date -> value.value + is FilterValue.TextShort -> value.value + is FilterValue.Check -> value.value + is FilterValue.Object -> value.value + null -> null + } ) fun Viewer.FilterOperator.toDomain(): DVFilterOperator = when (this) { @@ -621,11 +636,11 @@ fun List>.toGridRecordRows( val rows = mutableListOf() forEach { record -> val row = columns.buildGridRow( - showIcon = showIcon, - record = record, - relations = relations, - details = details, - builder = builder, + showIcon = showIcon, + record = record, + relations = relations, + details = details, + builder = builder, ) rows.add(row) } @@ -639,49 +654,49 @@ fun List.toViewerColumns( ): List { val columns = mutableListOf() this.filter { it.key !in filterBy } - .forEach { viewerRelation -> - relations - .firstOrNull { it.key == viewerRelation.key } - ?.let { relation -> - columns.add( - ColumnView( - key = relation.key, - text = relation.name, - format = relation.format.toView(), - width = viewerRelation.width ?: 0, - isVisible = viewerRelation.isVisible, - isHidden = relation.isHidden, - isReadOnly = relation.isReadOnly, - isDateIncludeTime = viewerRelation.isDateIncludeTime, - dateFormat = viewerRelation.dateFormat, - timeFormat = viewerRelation.timeFormat - ) - ) - } - } + .forEach { viewerRelation -> + relations + .firstOrNull { it.key == viewerRelation.key } + ?.let { relation -> + columns.add( + ColumnView( + key = relation.key, + text = relation.name, + format = relation.format.toView(), + width = viewerRelation.width ?: 0, + isVisible = viewerRelation.isVisible, + isHidden = relation.isHidden, + isReadOnly = relation.isReadOnly, + isDateIncludeTime = viewerRelation.isDateIncludeTime, + dateFormat = viewerRelation.dateFormat, + timeFormat = viewerRelation.timeFormat + ) + ) + } + } return columns } fun List.toSimpleRelations( - relations: List + relations: List ): ArrayList { val result = arrayListOf() this.forEach { viewerRelation -> relations - .firstOrNull { it.key == viewerRelation.key } - ?.let { relation -> - result.add( - SimpleRelationView( - key = relation.key, - title = relation.name, - format = relation.format.toView(), - isVisible = viewerRelation.isVisible, - isHidden = relation.isHidden, - isReadonly = relation.isReadOnly, - isDefault = Relations.defaultRelations.contains(relation.key) - ) + .firstOrNull { it.key == viewerRelation.key } + ?.let { relation -> + result.add( + SimpleRelationView( + key = relation.key, + title = relation.name, + format = relation.format.toView(), + isVisible = viewerRelation.isVisible, + isHidden = relation.isHidden, + isReadonly = relation.isReadOnly, + isDefault = Relations.defaultRelations.contains(relation.key) ) - } + ) + } } return result } @@ -705,10 +720,10 @@ fun Relation.Format.toView() = when (this) { fun List.toObjectTypeView(): List = map { oType -> ObjectTypeView.Item( - id = oType.url, - name = oType.name, - emoji = oType.emoji, - description = oType.description + id = oType.url, + name = oType.name, + emoji = oType.emoji, + description = oType.description ) } @@ -718,13 +733,25 @@ fun List.toView(): List = map { layout -> ObjectType.Layout.PROFILE -> ObjectLayoutView.Profile(id = layout.code, isSelected = false) ObjectType.Layout.TODO -> ObjectLayoutView.Todo(id = layout.code, isSelected = false) ObjectType.Layout.SET -> ObjectLayoutView.Set(id = layout.code, isSelected = false) - ObjectType.Layout.OBJECT_TYPE -> ObjectLayoutView.ObjectType(id = layout.code, isSelected = false) - ObjectType.Layout.RELATION -> ObjectLayoutView.Relation(id = layout.code, isSelected = false) + ObjectType.Layout.OBJECT_TYPE -> ObjectLayoutView.ObjectType( + id = layout.code, + isSelected = false + ) + ObjectType.Layout.RELATION -> ObjectLayoutView.Relation( + id = layout.code, + isSelected = false + ) ObjectType.Layout.FILE -> ObjectLayoutView.File(id = layout.code, isSelected = false) - ObjectType.Layout.DASHBOARD -> ObjectLayoutView.Dashboard(id = layout.code, isSelected = false) + ObjectType.Layout.DASHBOARD -> ObjectLayoutView.Dashboard( + id = layout.code, + isSelected = false + ) ObjectType.Layout.IMAGE -> ObjectLayoutView.Image(id = layout.code, isSelected = false) ObjectType.Layout.NOTE -> ObjectLayoutView.Note(id = layout.code, isSelected = false) - ObjectType.Layout.DATABASE -> ObjectLayoutView.Database(id = layout.code, isSelected = false) + ObjectType.Layout.DATABASE -> ObjectLayoutView.Database( + id = layout.code, + isSelected = false + ) ObjectType.Layout.SPACE -> ObjectLayoutView.Space(id = layout.code, isSelected = false) ObjectType.Layout.BOOKMARK -> ObjectLayoutView.Bookmark(id = layout.code, isSelected = false) } diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/DefaultBlockViewRendererTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/DefaultBlockViewRendererTest.kt index c75b1cb96d..55b689d3ca 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/DefaultBlockViewRendererTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/DefaultBlockViewRendererTest.kt @@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.SmartBlockType import com.anytypeio.anytype.core_models.StubBookmark import com.anytypeio.anytype.core_models.StubCallout +import com.anytypeio.anytype.core_models.StubFile import com.anytypeio.anytype.core_models.StubParagraph import com.anytypeio.anytype.core_models.StubSmartBlock import com.anytypeio.anytype.core_models.ext.asMap @@ -5645,5 +5646,180 @@ class DefaultBlockViewRendererTest { assertEquals(expected = expected, actual = result) } + /** + * C with background + * ...P with background + * ...P with background + */ + @Test + fun `should return blocks with expected decoration - when a callout with background contains one file in unploading state`() { + + val child1 = StubFile( + backgroundColor = null, + state = Block.Content.File.State.UPLOADING, + type = Block.Content.File.Type.FILE + ) + + val callout = StubCallout( + children = listOf(child1.id), + backgroundColor = ThemeColor.BLUE.code + ) + + val page = StubSmartBlock(children = listOf(callout.id)) + + val details = mapOf(page.id to Block.Fields.empty()) + + val blocks = listOf(page, callout, child1) + + val map = blocks.asMap() + + wrapper = BlockViewRenderWrapper( + blocks = map, + renderer = renderer + ) + + val result = runBlocking { + wrapper.render( + root = page, + anchor = page.id, + focus = Editor.Focus.empty(), + indent = 0, + details = Block.Details(details) + ) + } + + val expected = listOf( + BlockView.Text.Callout( + indent = 0, + isFocused = false, + id = callout.id, + marks = emptyList(), + backgroundColor = callout.backgroundColor, + color = callout.content().color, + text = callout.content().text, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + style = BlockView.Decoration.Style.Callout.Start, + background = callout.parseThemeBackgroundColor() + ) + ) + } else { + emptyList() + }, + icon = ObjectIcon.Basic.Emoji("💡") + ), + BlockView.Upload.File( + indent = 1, + id = child1.id, + backgroundColor = child1.backgroundColor, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = callout.parseThemeBackgroundColor(), + style = BlockView.Decoration.Style.Callout.End + ), + BlockView.Decoration( + style = BlockView.Decoration.Style.Card, + background = child1.parseThemeBackgroundColor() + ) + ) + } else { + emptyList() + } + ) + ) + + assertEquals(expected = expected, actual = result) + } + + /** + * C with background + * ...P with background + * ...P with background + */ + @Test + fun `should return blocks with expected decoration - when a callout with background contains one file in empty state`() { + + val child1 = StubFile( + backgroundColor = null, + state = Block.Content.File.State.EMPTY, + type = Block.Content.File.Type.FILE + ) + + val callout = StubCallout( + children = listOf(child1.id), + backgroundColor = ThemeColor.BLUE.code + ) + + val page = StubSmartBlock(children = listOf(callout.id)) + + val details = mapOf(page.id to Block.Fields.empty()) + + val blocks = listOf(page, callout, child1) + + val map = blocks.asMap() + + wrapper = BlockViewRenderWrapper( + blocks = map, + renderer = renderer + ) + + val result = runBlocking { + wrapper.render( + root = page, + anchor = page.id, + focus = Editor.Focus.empty(), + indent = 0, + details = Block.Details(details) + ) + } + + val expected = listOf( + BlockView.Text.Callout( + indent = 0, + isFocused = false, + id = callout.id, + marks = emptyList(), + backgroundColor = callout.backgroundColor, + color = callout.content().color, + text = callout.content().text, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + style = BlockView.Decoration.Style.Callout.Start, + background = callout.parseThemeBackgroundColor() + ) + ) + } else { + emptyList() + }, + icon = ObjectIcon.Basic.Emoji("💡") + ), + BlockView.MediaPlaceholder.File( + indent = 1, + id = child1.id, + backgroundColor = child1.backgroundColor, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = callout.parseThemeBackgroundColor(), + style = BlockView.Decoration.Style.Callout.End + ), + BlockView.Decoration( + style = BlockView.Decoration.Style.Card, + background = child1.parseThemeBackgroundColor() + ) + ) + } else { + emptyList() + }, + isPreviousBlockMedia = false + ) + ) + + assertEquals(expected = expected, actual = result) + } + //endregion } \ No newline at end of file diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/EditorViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/EditorViewModelTest.kt index 0187bce07c..2c331b1a91 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/EditorViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/EditorViewModelTest.kt @@ -58,6 +58,7 @@ import com.anytypeio.anytype.domain.objects.SetObjectIsArchived import com.anytypeio.anytype.domain.page.CloseBlock import com.anytypeio.anytype.domain.page.CreateDocument import com.anytypeio.anytype.domain.page.CreateNewDocument +import com.anytypeio.anytype.domain.page.CreateNewObject import com.anytypeio.anytype.domain.page.CreateObject import com.anytypeio.anytype.domain.page.OpenPage import com.anytypeio.anytype.domain.page.Redo @@ -71,10 +72,10 @@ import com.anytypeio.anytype.domain.templates.ApplyTemplate import com.anytypeio.anytype.domain.templates.GetTemplates import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage import com.anytypeio.anytype.domain.unsplash.UnsplashRepository +import com.anytypeio.anytype.presentation.BuildConfig import com.anytypeio.anytype.presentation.MockBlockFactory import com.anytypeio.anytype.presentation.common.Action import com.anytypeio.anytype.presentation.common.Delegator -import com.anytypeio.anytype.domain.page.CreateNewObject import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider import com.anytypeio.anytype.presentation.editor.editor.BlockDimensions import com.anytypeio.anytype.presentation.editor.editor.Command @@ -82,6 +83,7 @@ import com.anytypeio.anytype.presentation.editor.editor.Interactor import com.anytypeio.anytype.presentation.editor.editor.InternalDetailModificationManager import com.anytypeio.anytype.presentation.editor.editor.Markup import com.anytypeio.anytype.presentation.editor.editor.Orchestrator +import com.anytypeio.anytype.presentation.editor.editor.ThemeColor import com.anytypeio.anytype.presentation.editor.editor.ViewState import com.anytypeio.anytype.presentation.editor.editor.actions.ActionItemType import com.anytypeio.anytype.presentation.editor.editor.control.ControlPanelState @@ -119,7 +121,6 @@ import org.mockito.Mock import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.argThat -import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq @@ -3482,7 +3483,17 @@ open class EditorViewModelTest { BlockView.Error.Picture( id = picture.id, mode = BlockView.Mode.EDIT, - indent = 0 + indent = 0, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = ThemeColor.DEFAULT, + style = BlockView.Decoration.Style.None + ) + ) + } else { + emptyList() + } ) ) @@ -3551,7 +3562,17 @@ open class EditorViewModelTest { BlockView.Error.Video( id = video.id, mode = BlockView.Mode.EDIT, - indent = 0 + indent = 0, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = ThemeColor.DEFAULT, + style = BlockView.Decoration.Style.None + ) + ) + } else { + emptyList() + } ) ) @@ -3621,7 +3642,17 @@ open class EditorViewModelTest { BlockView.Error.File( id = file.id, mode = BlockView.Mode.EDIT, - indent = 0 + indent = 0, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = ThemeColor.DEFAULT, + style = BlockView.Decoration.Style.None + ) + ) + } else { + emptyList() + } ) ) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorLockPageTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorLockPageTest.kt index 0ad5b49e18..8e704ccc66 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorLockPageTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorLockPageTest.kt @@ -7,6 +7,7 @@ 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.core_utils.common.EventWrapper +import com.anytypeio.anytype.presentation.BuildConfig import com.anytypeio.anytype.presentation.MockBlockFactory import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView @@ -566,7 +567,17 @@ class EditorLockPageTest : EditorPresentationTestSetup() { mime = null, name = null, size = null, - url = builder.file(file.content().hash) + url = builder.file(file.content().hash), + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = ThemeColor.DEFAULT, + style = BlockView.Decoration.Style.None + ) + ) + } else { + emptyList() + } ) ) @@ -650,7 +661,17 @@ class EditorLockPageTest : EditorPresentationTestSetup() { name = null, size = null, url = builder.image(picture.content().hash), - indent = 0 + indent = 0, + decorations = if (BuildConfig.NESTED_DECORATION_ENABLED) { + listOf( + BlockView.Decoration( + background = ThemeColor.DEFAULT, + style = BlockView.Decoration.Style.None + ) + ) + } else { + emptyList() + } ) ) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/MapperExtensionKtTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/MapperExtensionKtTest.kt index fa6f8069f9..029e7d0b37 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/MapperExtensionKtTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/MapperExtensionKtTest.kt @@ -57,9 +57,10 @@ class MapperExtensionKtTest { hash = hash, mode = BlockView.Mode.EDIT, url = urlBuilder.video(hash), - indent = indent + indent = indent, + decorations = emptyList() ) - val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -82,7 +83,7 @@ class MapperExtensionKtTest { val expected = BlockView.MediaPlaceholder.File(id = id, indent = indent, isPreviousBlockMedia = false) - val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -104,8 +105,8 @@ class MapperExtensionKtTest { ) - val expected = BlockView.Error.File(id = id, indent = indent) - val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false) + val expected = BlockView.Error.File(id = id, indent = indent, decorations = emptyList()) + val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -127,7 +128,7 @@ class MapperExtensionKtTest { ) val expected = BlockView.Upload.File(id = id, indent = indent) - val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toFileView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -164,10 +165,11 @@ class MapperExtensionKtTest { mime = mime, hash = hash, url = urlBuilder.image(hash), - indent = indent + indent = indent, + decorations = emptyList() ) - val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -194,7 +196,7 @@ class MapperExtensionKtTest { indent = indent, isPreviousBlockMedia = false ) - val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -218,10 +220,11 @@ class MapperExtensionKtTest { val expected = BlockView.Error.Picture( id = id, - indent = indent + indent = indent, + decorations = emptyList() ) - val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -243,7 +246,7 @@ class MapperExtensionKtTest { ) val expected = BlockView.Upload.Picture(id = id, indent = indent) - val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toPictureView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -279,10 +282,11 @@ class MapperExtensionKtTest { mime = mime, hash = hash, url = urlBuilder.video(hash), - indent = indent + indent = indent, + decorations = emptyList() ) - val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -315,10 +319,11 @@ class MapperExtensionKtTest { mime = null, hash = null, url = urlBuilder.video(null), - indent = indent + indent = indent, + decorations = emptyList() ) - val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -349,7 +354,7 @@ class MapperExtensionKtTest { isPreviousBlockMedia = false ) - val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -379,7 +384,7 @@ class MapperExtensionKtTest { indent = indent ) - val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -406,10 +411,11 @@ class MapperExtensionKtTest { val expected = BlockView.Error.Video( id = id, - indent = indent + indent = indent, + decorations = emptyList() ) - val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false) + val actual = block.toVideoView(id, urlBuilder, indent, mode, false, null, false, emptyList()) assertEquals(expected, actual) } @@ -433,7 +439,7 @@ class MapperExtensionKtTest { type = type ) - block.toVideoView(id, urlBuilder, indent, mode, false, null, false) + block.toVideoView(id, urlBuilder, indent, mode, false, null, false, emptyList()) } @Test diff --git a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Block.kt b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Block.kt index 44716d0e8a..43cd9e8964 100644 --- a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Block.kt +++ b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Block.kt @@ -83,6 +83,29 @@ fun StubParagraph( backgroundColor = backgroundColor ) +fun StubFile( + id: Id = MockDataFactory.randomUuid(), + children: List = emptyList(), + backgroundColor: String? = null, + hash: String = MockDataFactory.randomString(), + name: String = MockDataFactory.randomString(), + size: Long = MockDataFactory.randomLong(), + type: Block.Content.File.Type? = null, + state: Block.Content.File.State? = null +) : Block = Block( + id = id, + children = children, + fields = Block.Fields.empty(), + backgroundColor = backgroundColor, + content = Block.Content.File( + size = size, + name = name, + hash = hash, + type = type, + state = state + ) +) + fun StubBulleted( text: String = MockDataFactory.randomString(), children: List = emptyList(),