diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/SlashWidgetTesting.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/SlashWidgetTesting.kt
index 5a1e02b1c0..2f7a0a8ac5 100644
--- a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/SlashWidgetTesting.kt
+++ b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/SlashWidgetTesting.kt
@@ -19,6 +19,7 @@ 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.StubBookmark
+import com.anytypeio.anytype.core_models.StubFile
import com.anytypeio.anytype.core_ui.features.editor.slash.holders.MainMenuHolder
import com.anytypeio.anytype.core_ui.features.editor.slash.holders.MediaMenuHolder
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
@@ -526,14 +527,9 @@ class SlashWidgetTesting : EditorTestSetup() {
val paragraph = paragraph(text = "FooBar")
val paragraph2 = paragraph(text = "Second")
- val file = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields.empty(),
- children = emptyList(),
- content = Block.Content.File(
- type = Block.Content.File.Type.FILE,
- state = Block.Content.File.State.EMPTY
- )
+ val file = StubFile(
+ type = Block.Content.File.Type.FILE,
+ state = Block.Content.File.State.EMPTY
)
val page = Block(
@@ -599,14 +595,9 @@ class SlashWidgetTesting : EditorTestSetup() {
val paragraph = paragraph(text = "FooBar")
val paragraph2 = paragraph(text = "Second")
- val picture = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields.empty(),
- children = emptyList(),
- content = Block.Content.File(
- type = Block.Content.File.Type.IMAGE,
- state = Block.Content.File.State.EMPTY
- )
+ val picture = StubFile(
+ type = Block.Content.File.Type.IMAGE,
+ state = Block.Content.File.State.EMPTY
)
val page = Block(
@@ -678,14 +669,9 @@ class SlashWidgetTesting : EditorTestSetup() {
val paragraph2 = paragraph(text = "Second")
- val video = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields.empty(),
- children = emptyList(),
- content = Block.Content.File(
- type = Block.Content.File.Type.VIDEO,
- state = Block.Content.File.State.EMPTY
- )
+ val video = StubFile(
+ type = Block.Content.File.Type.VIDEO,
+ state = Block.Content.File.State.EMPTY
)
val page = Block(
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt
index 982ce219cb..65b6d247a8 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt
@@ -14,6 +14,7 @@ import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.debugging.DebugAccountSelectTrace
import com.anytypeio.anytype.domain.debugging.DebugGoroutines
+import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.misc.LocaleProvider
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
@@ -99,4 +100,5 @@ interface OnboardingMnemonicLoginDependencies : ComponentDependencies {
fun spaceManager(): SpaceManager
fun globalSubscriptionManager(): GlobalSubscriptionManager
fun debugAccountSelectTrace(): DebugAccountSelectTrace
+ fun logger(): Logger
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt
index 4b3d17363e..6b80e69322 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt
@@ -25,7 +25,6 @@ import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
-import com.anytypeio.anytype.providers.DefaultUriFileProvider
import com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment
import dagger.Binds
import dagger.BindsInstance
diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt
index 19ab47deea..cfd408f3a5 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt
@@ -337,8 +337,9 @@ object DataModule {
@Provides
@Singleton
fun provideFileProvider(
- context: Context
- ): UriFileProvider = DefaultUriFileProvider(context)
+ context: Context,
+ logger: Logger
+ ): UriFileProvider = DefaultUriFileProvider(context, logger)
@JvmStatic
@Provides
diff --git a/app/src/main/java/com/anytypeio/anytype/providers/DefaultUriFileProvider.kt b/app/src/main/java/com/anytypeio/anytype/providers/DefaultUriFileProvider.kt
index 23ebf32276..5b0aa4184d 100644
--- a/app/src/main/java/com/anytypeio/anytype/providers/DefaultUriFileProvider.kt
+++ b/app/src/main/java/com/anytypeio/anytype/providers/DefaultUriFileProvider.kt
@@ -4,19 +4,26 @@ import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
import com.anytypeio.anytype.BuildConfig
+import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
import java.io.File
import javax.inject.Inject
class DefaultUriFileProvider @Inject constructor(
- private val context: Context
+ private val context: Context,
+ private val logger: Logger
) : UriFileProvider {
- override fun getUriForFile(file: File): Uri = FileProvider.getUriForFile(
- context,
- BuildConfig.APPLICATION_ID + PROVIDER,
- file
- )
+ override fun getUriForFile(file: File): Uri {
+ logger.logInfo("DefaultUriFileProvider, start getting uri for file $file")
+ val contentUri = FileProvider.getUriForFile(
+ context,
+ BuildConfig.APPLICATION_ID + PROVIDER,
+ file
+ )
+ logger.logInfo("DefaultUriFileProvider, got uri $contentUri")
+ return contentUri
+ }
}
private const val PROVIDER = ".provider"
\ No newline at end of file
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
index 948ac11c51..23ca145757 100644
--- a/app/src/main/res/xml/provider_paths.xml
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt
index c21a8ac31e..79c1ba1713 100644
--- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt
+++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Block.kt
@@ -86,6 +86,7 @@ data class Block(
fun asText() = this as Text
fun asLink() = this as Link
+ fun asFile() = this as File
/**
* Smart block.
@@ -227,12 +228,13 @@ data class Block(
* @property state file state
*/
data class File(
- val targetObjectId: Id? = null,
- val name: String? = null,
- val mime: String? = null,
- val size: Long? = null,
- val type: Type? = null,
- val state: State? = null
+ val targetObjectId: Id,
+ val name: String,
+ val mime: String,
+ val size: Long,
+ val type: Type,
+ val state: State,
+ val addedAt: Long
) : Content() {
enum class Type { NONE, FILE, IMAGE, VIDEO, AUDIO, PDF }
enum class State { EMPTY, UPLOADING, DONE, ERROR }
diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/SupportedLayouts.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/SupportedLayouts.kt
index 5b305ac115..0fff11d579 100644
--- a/core-models/src/main/java/com/anytypeio/anytype/core_models/SupportedLayouts.kt
+++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/SupportedLayouts.kt
@@ -75,4 +75,8 @@ object SupportedLayouts {
fun isEditorOrFileLayout(layout: ObjectType.Layout?) : Boolean {
return editorLayouts.contains(layout) || fileLayouts.contains(layout)
}
+
+ fun isFileLayout(layout: ObjectType.Layout?) : Boolean {
+ return fileLayouts.contains(layout)
+ }
}
\ No newline at end of file
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 4d865876b2..68cfeba72b 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
@@ -43,6 +43,7 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkCardSmallIco
import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkCardSmallIconCoverBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkDeleteBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkLoadingBinding
+import com.anytypeio.anytype.core_ui.databinding.ItemBlockOpenFileBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationCheckboxBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationDefaultBinding
@@ -55,6 +56,7 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationTagBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTableBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTextBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleBinding
+import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleFileBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleProfileBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleTodoBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTocBinding
@@ -113,6 +115,8 @@ import com.anytypeio.anytype.core_ui.features.editor.holders.text.Text
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Toggle
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.BookmarkUpload
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.FileUpload
+import com.anytypeio.anytype.core_ui.features.editor.holders.upload.OpenFile
+import com.anytypeio.anytype.core_ui.features.editor.holders.upload.OpenImage
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.PictureUpload
import com.anytypeio.anytype.core_ui.features.editor.holders.upload.VideoUpload
import com.anytypeio.anytype.core_ui.features.table.holders.TableBlockHolder
@@ -148,6 +152,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_ERROR
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_PLACEHOLDER
+import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_TITLE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_UPLOAD
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_HEADER_ONE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_HEADER_THREE
@@ -163,6 +168,8 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_LINK_DEFAULT
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_LINK_DELETED
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_LINK_LOADING
+import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_BUTTON_OPEN_FILE
+import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_BUTTON_OPEN_IMAGE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PARAGRAPH
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE_ERROR
@@ -358,6 +365,11 @@ class BlockAdapter(
}
}
}
+ HOLDER_FILE_TITLE -> {
+ Title.File(
+ ItemBlockTitleFileBinding.inflate(inflater, parent, false)
+ )
+ }
HOLDER_TODO_TITLE -> {
Title.Todo(
ItemBlockTitleTodoBinding.inflate(inflater, parent, false)
@@ -530,6 +542,12 @@ class BlockAdapter(
ItemBlockMediaErrorBinding.inflate(inflater, parent, false)
)
}
+ HOLDER_BUTTON_OPEN_FILE -> {
+ OpenFile(ItemBlockOpenFileBinding.inflate(inflater, parent, false))
+ }
+ HOLDER_BUTTON_OPEN_IMAGE -> {
+ OpenImage(ItemBlockOpenFileBinding.inflate(inflater, parent, false))
+ }
HOLDER_VIDEO -> {
Video(
ItemBlockVideoBinding.inflate(inflater, parent, false)
@@ -1002,6 +1020,12 @@ class BlockAdapter(
item = blocks[position] as BlockView.Title.Todo
)
}
+ is Title.File -> {
+ holder.processPayloads(
+ payloads = payloads.typeOf(),
+ item = blocks[position] as BlockView.Title.File
+ )
+ }
is Numbered -> {
holder.processChangePayload(
payloads = payloads.typeOf(),
@@ -1361,6 +1385,11 @@ class BlockAdapter(
holder.content.clipboardInterceptor = clipboardInterceptor
}
}
+ is Title.File -> {
+ holder.apply {
+ bind(item = blocks[position] as BlockView.Title.File,)
+ }
+ }
is Code -> {
holder.bind(
item = blocks[position] as BlockView.Code,
@@ -1622,6 +1651,18 @@ class BlockAdapter(
clicked = onClickListener
)
}
+ is OpenFile -> {
+ holder.bind(
+ item = blocks[position] as BlockView.ButtonOpenFile.FileButton,
+ click = onClickListener
+ )
+ }
+ is OpenImage -> {
+ holder.bind(
+ item = blocks[position] as BlockView.ButtonOpenFile.ImageButton,
+ click = onClickListener
+ )
+ }
}
if (holder is Text<*>) {
diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt
index 405207d125..442aa63fb7 100644
--- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt
+++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt
@@ -3,11 +3,10 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.other
import android.text.Spannable
import android.view.View
import android.view.inputmethod.InputMethodManager
+import android.widget.FrameLayout.LayoutParams
import android.widget.ImageView
import android.widget.TextView
-import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
-import androidx.compose.ui.unit.dp
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams
@@ -16,6 +15,7 @@ import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.SearchHighlightSpan
import com.anytypeio.anytype.core_ui.common.SearchTargetHighlightSpan
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleBinding
+import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleFileBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleProfileBinding
import com.anytypeio.anytype.core_ui.databinding.ItemBlockTitleTodoBinding
import com.anytypeio.anytype.core_ui.extensions.setBlockBackgroundColor
@@ -23,7 +23,7 @@ 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.holders.`interface`.TextHolder
import com.anytypeio.anytype.core_ui.tools.DefaultSpannableFactory
-import com.anytypeio.anytype.core_ui.widgets.RadialGradientComposeView
+import com.anytypeio.anytype.core_ui.widgets.ObjectIconWidget
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.dimen
import com.anytypeio.anytype.core_utils.ext.gone
@@ -555,4 +555,37 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
content.setBlockBackgroundColor(item.background)
}
}
+
+ class File(val binding: ItemBlockTitleFileBinding) : Title(binding.root) {
+
+ override val icon: ObjectIconWidget = binding.objectIconWidget
+ override val image: ImageView = binding.cover
+ override val selectionView: View = itemView
+ override val root: View = itemView
+ override val content: TextInputWidget = binding.title
+
+ init {
+ icon.binding.ivImage.updateLayoutParams {
+ height = itemView.resources.getDimension(R.dimen.dp_80).toInt()
+ width = itemView.resources.getDimension(R.dimen.dp_64).toInt()
+ }
+ }
+
+ fun bind(
+ item: BlockView.Title.File,
+ ) {
+ super.bind(
+ item = item,
+ onCoverClicked = {}
+ )
+ icon.setIcon(item.icon)
+ }
+
+ override fun applyTextColor(item: BlockView.Title) {
+ //do nothing
+ }
+ override fun applyBackground(item: BlockView.Title) {
+ //do nothing
+ }
+ }
}
\ No newline at end of file
diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/OpenFile.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/OpenFile.kt
new file mode 100644
index 0000000000..0f48c101e5
--- /dev/null
+++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/upload/OpenFile.kt
@@ -0,0 +1,41 @@
+package com.anytypeio.anytype.core_ui.features.editor.holders.upload
+
+import android.view.View
+import com.anytypeio.anytype.core_ui.databinding.ItemBlockOpenFileBinding
+import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder
+import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
+import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
+
+class OpenFile(
+ binding: ItemBlockOpenFileBinding
+) : BlockViewHolder(binding.root) {
+
+ private val root: View = itemView
+
+ fun bind(item: BlockView.ButtonOpenFile.FileButton, click: (ListenerType) -> Unit) {
+ root.setOnClickListener {
+ click(
+ ListenerType.File.View(
+ target = item.id,
+ )
+ )
+ }
+ }
+}
+
+class OpenImage(
+ binding: ItemBlockOpenFileBinding
+) : BlockViewHolder(binding.root) {
+
+ private val root: View = itemView
+
+ fun bind(item: BlockView.ButtonOpenFile.ImageButton, click: (ListenerType) -> Unit) {
+ root.setOnClickListener {
+ click(
+ ListenerType.Picture.View(
+ target = item.id
+ )
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt
index 2ade1ca5e8..fa82e469ae 100644
--- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt
+++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt
@@ -144,7 +144,6 @@ class ObjectIconWidget @JvmOverloads constructor(
is ObjectIcon.None -> removeIcon()
is ObjectIcon.File -> setFileImage(
mime = icon.mime,
- fileName = icon.fileName,
extension = icon.extensions
)
ObjectIcon.Deleted -> setDeletedIcon()
@@ -220,7 +219,7 @@ class ObjectIconWidget @JvmOverloads constructor(
}
}
- private fun setFileImage(mime: String?, fileName: String?, extension: String?) {
+ private fun setFileImage(mime: String?, extension: String?) {
val icon = mime.getMimeIcon(extension)
with(binding) {
ivImage.visible()
diff --git a/core-ui/src/main/res/drawable/bg_button_open_file.xml b/core-ui/src/main/res/drawable/bg_button_open_file.xml
new file mode 100644
index 0000000000..44dcebe59f
--- /dev/null
+++ b/core-ui/src/main/res/drawable/bg_button_open_file.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core-ui/src/main/res/drawable/bg_title_file_icon.xml b/core-ui/src/main/res/drawable/bg_title_file_icon.xml
new file mode 100644
index 0000000000..e95165e6d5
--- /dev/null
+++ b/core-ui/src/main/res/drawable/bg_title_file_icon.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core-ui/src/main/res/layout/item_block_open_file.xml b/core-ui/src/main/res/layout/item_block_open_file.xml
new file mode 100644
index 0000000000..4cc3982984
--- /dev/null
+++ b/core-ui/src/main/res/layout/item_block_open_file.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-ui/src/main/res/layout/item_block_title_file.xml b/core-ui/src/main/res/layout/item_block_title_file.xml
new file mode 100644
index 0000000000..c5b76daec0
--- /dev/null
+++ b/core-ui/src/main/res/layout/item_block_title_file.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-ui/src/main/res/values/dimens.xml b/core-ui/src/main/res/values/dimens.xml
index 5880304c71..f78c571f44 100644
--- a/core-ui/src/main/res/values/dimens.xml
+++ b/core-ui/src/main/res/values/dimens.xml
@@ -35,6 +35,7 @@
46dp
48dp
54dp
+ 64dp
72dp
80dp
51dp
diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt
index dde7854031..bf909ac8fe 100644
--- a/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt
+++ b/domain/src/test/java/com/anytypeio/anytype/domain/auth/CreateAccountTest.kt
@@ -20,12 +20,10 @@ import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.stub
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
-import org.mockito.kotlin.verifyNoMoreInteractions
class CreateAccountTest {
diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/ext/BlockExtensionTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/ext/BlockExtensionTest.kt
index b925849b3c..888a879053 100644
--- a/domain/src/test/java/com/anytypeio/anytype/domain/ext/BlockExtensionTest.kt
+++ b/domain/src/test/java/com/anytypeio/anytype/domain/ext/BlockExtensionTest.kt
@@ -1,6 +1,7 @@
package com.anytypeio.anytype.domain.ext
import com.anytypeio.anytype.core_models.Block
+import com.anytypeio.anytype.core_models.StubFile
import com.anytypeio.anytype.core_models.ext.asMap
import com.anytypeio.anytype.core_models.ext.asRender
import com.anytypeio.anytype.core_models.ext.getChildrenIdsList
@@ -1096,19 +1097,9 @@ class BlockExtensionTest {
val root = MockDataFactory.randomUuid()
- val a = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields.empty(),
- children = emptyList(),
- content = Block.Content.File()
- )
+ val a = StubFile()
- val b = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields.empty(),
- children = emptyList(),
- content = Block.Content.File()
- )
+ val b = StubFile()
val document = listOf(a, b)
diff --git a/localization/src/main/res/values/strings.xml b/localization/src/main/res/values/strings.xml
index 8ad4844670..ec8d3b0892 100644
--- a/localization/src/main/res/values/strings.xml
+++ b/localization/src/main/res/values/strings.xml
@@ -525,6 +525,7 @@
Open source
Reload object content
Open link
+ Open file
Copy email
Copy phone number
Send email
diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt
index 0a7306c26b..5f426fef8c 100644
--- a/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt
+++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/mappers/ToCoreModelMappers.kt
@@ -376,7 +376,8 @@ fun MBlock.toCoreModelsFile(): Block.Content.File {
mime = content.mime,
size = content.size,
type = content.type.toCoreModels(),
- state = content.state.toCoreModels()
+ state = content.state.toCoreModels(),
+ addedAt = content.addedAt
)
}
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 e067c1a86b..a0a324d2b4 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
@@ -5,7 +5,6 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary
-import com.anytypeio.anytype.analytics.base.EventsDictionary.Routes.objDate
import com.anytypeio.anytype.analytics.base.EventsDictionary.searchScreenShow
import com.anytypeio.anytype.analytics.base.EventsPropertiesKey
import com.anytypeio.anytype.analytics.base.sendEvent
@@ -22,7 +21,6 @@ import com.anytypeio.anytype.core_models.InternalFlags
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.Marketplace.COLLECTION_MARKETPLACE_ID
import com.anytypeio.anytype.core_models.Marketplace.SET_MARKETPLACE_ID
-import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys
@@ -83,7 +81,6 @@ import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvid
import com.anytypeio.anytype.domain.icon.SetDocumentImageIcon
import com.anytypeio.anytype.domain.icon.SetImageIcon
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
-import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.DateProvider
import com.anytypeio.anytype.domain.misc.UrlBuilder
@@ -223,7 +220,6 @@ import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectShowEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectTypeSelectOrChangeEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsOpenAsObject
import com.anytypeio.anytype.presentation.extension.sendAnalyticsRelationEvent
-import com.anytypeio.anytype.presentation.extension.sendAnalyticsSearchResultEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsSearchWordsEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsSelectTemplateEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsSelectionMenuEvent
@@ -233,7 +229,6 @@ import com.anytypeio.anytype.presentation.extension.sendAnalyticsSlashMenuEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsStyleMenuEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsUpdateTextMarkupEvent
import com.anytypeio.anytype.presentation.extension.sendHideKeyboardEvent
-import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Companion.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
import com.anytypeio.anytype.presentation.home.navigation
import com.anytypeio.anytype.presentation.mapper.mark
@@ -259,13 +254,13 @@ import com.anytypeio.anytype.presentation.editor.model.OnEditorDatePickerEvent.O
import com.anytypeio.anytype.presentation.editor.model.OnEditorDatePickerEvent.OnDateSelected
import com.anytypeio.anytype.presentation.editor.model.OnEditorDatePickerEvent.OnTodayClick
import com.anytypeio.anytype.presentation.editor.model.OnEditorDatePickerEvent.OnTomorrowClick
+import com.anytypeio.anytype.presentation.extension.getFileDetailsForBlock
+import com.anytypeio.anytype.presentation.extension.getUrlForFileContent
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.objects.getObjectTypeViewsForSBPage
import com.anytypeio.anytype.presentation.objects.getProperType
import com.anytypeio.anytype.presentation.objects.isTemplatesAllowed
import com.anytypeio.anytype.presentation.objects.toViews
-import com.anytypeio.anytype.presentation.profile.ProfileIconView
-import com.anytypeio.anytype.presentation.profile.profileIcon
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
import com.anytypeio.anytype.presentation.relations.getNotIncludedRecommendedRelations
import com.anytypeio.anytype.presentation.relations.getObjectRelations
@@ -296,8 +291,6 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -366,8 +359,6 @@ class EditorViewModel(
val actions = MutableStateFlow(ActionItemType.defaultSorting)
- val icon = MutableStateFlow(ProfileIconView.Loading)
-
val isUndoEnabled = MutableStateFlow(false)
val isRedoEnabled = MutableStateFlow(false)
val isUndoRedoToolbarIsVisible = MutableStateFlow(false)
@@ -442,7 +433,6 @@ class EditorViewModel(
init {
Timber.i("EditorViewModel, init")
proceedWithObservingPermissions()
- proceedWithObservingProfileIcon()
startHandlingTextChanges()
startProcessingFocusChanges()
startProcessingControlPanelViewState()
@@ -489,35 +479,6 @@ class EditorViewModel(
}
}
- private fun proceedWithObservingProfileIcon() {
- viewModelScope.launch {
- spaceManager
- .observe()
- .flatMapLatest { config ->
- storelessSubscriptionContainer.subscribe(
- StoreSearchByIdsParams(
- space = SpaceId(config.techSpace),
- subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION,
- targets = listOf(config.profile),
- keys = listOf(
- Relations.ID,
- Relations.NAME,
- Relations.ICON_EMOJI,
- Relations.ICON_IMAGE,
- Relations.ICON_OPTION
- )
- )
- ).map { result ->
- val obj = result.firstOrNull()
- obj?.profileIcon(urlBuilder) ?: ProfileIconView.Placeholder(null)
- }
- }
- .catch { Timber.e(it, "Error while observing space icon") }
- .flowOn(dispatchers.io)
- .collect { icon.value = it }
- }
- }
-
override fun onPickedDocImageFromDevice(ctx: Id, path: String) {
viewModelScope.launch {
val obj = orchestrator.stores.details.getAsObject(ctx)
@@ -824,6 +785,7 @@ class EditorViewModel(
val flags = mutableListOf()
Timber.d("Rendering starting...")
val doc = models.asMap().render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -3827,8 +3789,8 @@ class EditorViewModel(
}
is ListenerType.File.View -> {
when (mode) {
- EditorMode.Edit -> onFileClicked(clicked.target)
- EditorMode.Locked, EditorMode.Read -> onFileClicked(clicked.target)
+ EditorMode.Edit -> onFileBlockClicked(clicked.target)
+ EditorMode.Locked, EditorMode.Read -> onFileBlockClicked(clicked.target)
EditorMode.Select -> onBlockMultiSelectClicked(clicked.target)
else -> Unit
}
@@ -4284,85 +4246,76 @@ class EditorViewModel(
}
}
- private fun onFileClicked(blockId: String) {
- val fileBlock = blocks.find { it.id == blockId }
- val url = urlBuilder.getUrlForFileBlock(
- fileBlock = fileBlock
- )
- if (url != null) {
- dispatch(
- Command.OpenFileByDefaultApp(
- id = blockId,
- uri = url
- )
+ private fun onFileBlockClicked(blockId: String) {
+ dispatch(
+ Command.OpenFileByDefaultApp(
+ id = blockId
)
- } else {
- Timber.e("Block is not File or with wrong state, can't proceed with open")
- sendToast("Something went wrong. Couldn't open file.")
- }
+ )
}
fun startSharingFile(id: String, onDownloaded: (Uri) -> Unit = {}) {
-
- Timber.d("startDownloadingFile, id:[$id]")
-
+ Timber.d("startSharingFile, fileBlockId: [$id]")
sendToast("Preparing file to share...")
- val block = blocks.firstOrNull { it.id == id }
- val content = block?.content
+ val fileDetails = blocks.getFileDetailsForBlock(id, orchestrator, fieldParser) ?: return
+ val (content, targetObjectId, fileName) = fileDetails
- if (content is Content.File && content.state == Content.File.State.DONE) {
- viewModelScope.launch {
- orchestrator.proxies.intents.send(
- Media.ShareFile(
- objectId = content.targetObjectId.orEmpty(),
- name = content.name.orEmpty(),
- type = content.type,
- onDownloaded = onDownloaded
- )
+ Timber.d("startSharingFile, fileObjectId: [$targetObjectId], fileName: [$fileName]")
+
+ viewModelScope.launch {
+ orchestrator.proxies.intents.send(
+ Media.ShareFile(
+ objectId = targetObjectId,
+ name = fileName,
+ type = content.type,
+ onDownloaded = onDownloaded
)
- }
- } else {
- Timber.e("Block is not File or with wrong state, can't proceed with share!")
+ )
}
}
- fun startDownloadingFileFromBlock(blockId: Id) {
+ fun startDownloadingFileFromBlock(id: Id) {
+ Timber.d("startDownloadingFile, for block:[$id]")
+ sendToast("Downloading file in background...")
- Timber.d("startDownloadingFile, for block:[$blockId]")
+ val fileDetails = blocks.getFileDetailsForBlock(id, orchestrator, fieldParser) ?: return
+ val (content, targetObjectId, fileName) = fileDetails
- sendToast("Downloading file in background...")
+ val url = urlBuilder.getUrlForFileContent(
+ fileContent = content,
+ isOriginalImage = true
+ )
+
+ Timber.d("startDownloadingFileFromBlock, fileObjectId: [$targetObjectId], fileName: [$fileName], url: [$url]")
- val fileBlock = blocks.firstOrNull { it.id == blockId }
- val fileContent = fileBlock?.content as? Content.File
- val url = urlBuilder.getUrlForFileBlock(fileBlock)
-
- if (fileContent != null && url != null) {
+ if (url != null) {
viewModelScope.launch {
orchestrator.proxies.intents.send(
Media.DownloadFile(
url = url,
- name = fileContent.name.orEmpty(),
- type = fileContent.type
+ name = fileName,
+ type = content.type
)
)
}
} else {
- Timber.e("Block is not File or with wrong state, can't proceed with download")
+ Timber.e("Couldn't proceed with downloading file, because url is null")
sendToast("Something went wrong. Couldn't download file.")
}
}
private fun proceedWithDownloadCurrentObjectAsFile() {
- val details = orchestrator.stores.details.current()
- val objectDetails = details.details[context]?.map ?: return
- if (objectDetails.isEmpty()) return
- val obj = ObjectWrapper.Basic(objectDetails)
+ val fileObject = orchestrator.stores.details.getAsObject(target = context)
+ if (fileObject == null) {
+ Timber.e("Object with id $context not found.")
+ return
+ }
- Timber.d("startDownloadingFileAsObject, for object:[$obj]")
+ Timber.d("startDownloadingFileAsObject, for object:[$context]")
- val layout = obj.layout
+ val layout = fileObject.layout
if (layout == null || layout !in SupportedLayouts.fileLayouts) {
Timber.e("Object with layout:$layout is not Media, can't proceed with download")
@@ -4373,7 +4326,7 @@ class EditorViewModel(
sendToast("Downloading file in background...")
val url = urlBuilder.getUrlBasedOnFileLayout(
- obj = obj.id,
+ obj = fileObject.id,
layout = layout
)
@@ -4382,7 +4335,7 @@ class EditorViewModel(
orchestrator.proxies.intents.send(
Media.DownloadFile(
url = url,
- name = fieldParser.getObjectName(obj),
+ name = fieldParser.getObjectName(fileObject),
type = null
)
)
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt
index a3dee935fc..b1c51f9672 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt
@@ -33,8 +33,7 @@ sealed class Command {
* @property [id] id of the file block
*/
data class OpenFileByDefaultApp(
- val id: String,
- val uri: String
+ val id: String
) : Command()
data class OpenObjectSnackbar(
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ext/BlockViewExt.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ext/BlockViewExt.kt
index 4f8cb14f91..c54ddf6e03 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ext/BlockViewExt.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/ext/BlockViewExt.kt
@@ -155,6 +155,9 @@ fun List.singleStylingMode(
is BlockView.Title.Todo -> view.copy(
mode = BlockView.Mode.READ
)
+ is BlockView.Title.File -> view.copy(
+ mode = BlockView.Mode.READ
+ )
is BlockView.Title.Profile -> view.copy(
mode = BlockView.Mode.READ
)
@@ -312,6 +315,9 @@ fun List.enterSAM(
is BlockView.Title.Todo -> view.copy(
mode = BlockView.Mode.READ
)
+ is BlockView.Title.File -> view.copy(
+ mode = BlockView.Mode.READ
+ )
is BlockView.Title.Archive -> view.copy(
mode = BlockView.Mode.READ
)
@@ -494,6 +500,7 @@ fun List.updateCursorAndEditMode(
)
is BlockView.Title.Basic -> view.copy(mode = BlockView.Mode.EDIT)
is BlockView.Title.Todo -> view.copy(mode = BlockView.Mode.EDIT)
+ is BlockView.Title.File -> view.copy(mode = BlockView.Mode.EDIT)
is BlockView.Title.Profile -> view.copy(mode = BlockView.Mode.EDIT)
is BlockView.Title.Archive -> view.copy(mode = BlockView.Mode.EDIT)
else -> view.also {
@@ -516,6 +523,7 @@ fun List.toReadMode(): List = map { view ->
is BlockView.Text.Callout -> view.copy(mode = BlockView.Mode.READ)
is BlockView.Title.Basic -> view.copy(mode = BlockView.Mode.READ)
is BlockView.Title.Todo -> view.copy(mode = BlockView.Mode.READ)
+ is BlockView.Title.File -> view.copy(mode = BlockView.Mode.READ)
is BlockView.Title.Profile -> view.copy(mode = BlockView.Mode.READ)
is BlockView.Title.Archive -> view.copy(mode = BlockView.Mode.READ)
is BlockView.Description -> view.copy(mode = BlockView.Mode.READ)
@@ -585,6 +593,7 @@ fun List.toEditMode(): List = map { view ->
is BlockView.Title.Basic -> view.copy(mode = BlockView.Mode.EDIT)
is BlockView.Title.Profile -> view.copy(mode = BlockView.Mode.EDIT)
is BlockView.Title.Todo -> view.copy(mode = BlockView.Mode.EDIT)
+ is BlockView.Title.File -> view.copy(mode = BlockView.Mode.EDIT)
is BlockView.Title.Archive -> view.copy(mode = BlockView.Mode.EDIT)
else -> view.also { check(view !is BlockView.Permission) }
}
@@ -605,6 +614,7 @@ fun List.clearSearchHighlights(): List = map { view ->
is BlockView.Title.Basic -> view.copy(searchFields = emptyList())
is BlockView.Title.Profile -> view.copy(searchFields = emptyList())
is BlockView.Title.Todo -> view.copy(searchFields = emptyList())
+ is BlockView.Title.File -> view.copy(searchFields = emptyList())
is BlockView.Media.Bookmark -> view.copy(searchFields = emptyList())
is BlockView.Media.File -> view.copy(searchFields = emptyList())
is BlockView.LinkToObject.Default.Text -> view.copy(searchFields = emptyList())
@@ -674,6 +684,10 @@ fun List.highlight(
val fields = listOf(DEFAULT_SEARCH_FIELD_KEY to view.text.orEmpty())
view.copy(searchFields = highlighter(fields))
}
+ is BlockView.Title.File -> {
+ val fields = listOf(DEFAULT_SEARCH_FIELD_KEY to view.text.orEmpty())
+ view.copy(searchFields = highlighter(fields))
+ }
is BlockView.Title.Profile -> {
val fields = listOf(DEFAULT_SEARCH_FIELD_KEY to view.text.orEmpty())
view.copy(searchFields = highlighter(fields))
@@ -781,6 +795,7 @@ fun BlockView.setHighlight(
is BlockView.Title.Basic -> copy(searchFields = highlights)
is BlockView.Title.Profile -> copy(searchFields = highlights)
is BlockView.Title.Todo -> copy(searchFields = highlights)
+ is BlockView.Title.File -> copy(searchFields = highlights)
is BlockView.Media.Bookmark -> copy(searchFields = highlights)
is BlockView.Media.File -> copy(searchFields = highlights)
is BlockView.LinkToObject.Default.Text -> copy(searchFields = highlights)
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 0dff6a24f5..533f32e42f 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
@@ -27,6 +27,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_ERROR
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_PLACEHOLDER
+import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_TITLE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_UPLOAD
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_HEADER_ONE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_HEADER_THREE
@@ -43,9 +44,9 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_LINK_DELETED
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_LINK_LOADING
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_TYPE
-import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_TYPE_COLLECTION
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_TYPE_DELETED
-import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_OBJECT_TYPE_SET
+import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_BUTTON_OPEN_FILE
+import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_BUTTON_OPEN_IMAGE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PARAGRAPH
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE_ERROR
@@ -75,7 +76,6 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseSettingsView
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
-import com.anytypeio.anytype.presentation.spaces.SpaceIconView
/**
* UI-models for different types of blocks.
@@ -668,6 +668,31 @@ sealed class BlockView : ViewType {
override fun getViewType() = HOLDER_TITLE
}
+ /**
+ * UI-model for a file-layout title block.
+ * @property id block's id
+ * @property text text content (i.e. title text)
+ */
+ data class File(
+ override val id: String,
+ override var isFocused: Boolean = false,
+ override var text: String,
+ override var coverColor: CoverColor? = null,
+ override var coverImage: Url? = null,
+ override var coverGradient: String? = null,
+ override val background: ThemeColor = ThemeColor.DEFAULT,
+ override val color: ThemeColor = ThemeColor.DEFAULT,
+ val emoji: String? = null,
+ override val image: String? = null,
+ override val mode: Mode = Mode.READ,
+ override var cursor: Int? = null,
+ override val searchFields: List = emptyList(),
+ override val hint: String? = null,
+ val icon: ObjectIcon
+ ) : Title(), Searchable {
+ override fun getViewType() = HOLDER_FILE_TITLE
+ }
+
/**
* UI-model for a profile-layout title block.
* @property id block's id
@@ -1268,6 +1293,28 @@ sealed class BlockView : ViewType {
override fun getViewType(): Int = HOLDER_FEATURED_RELATION
}
+ sealed class ButtonOpenFile(
+ override val id: String,
+ val isSelected: Boolean = false
+ ) : BlockView() {
+
+ abstract val targetId: Id?
+
+ data class ImageButton(
+ override val id: String,
+ override val targetId: Id
+ ) : ButtonOpenFile(id) {
+ override fun getViewType(): Int = HOLDER_BUTTON_OPEN_IMAGE
+ }
+
+ data class FileButton(
+ override val id: String,
+ override val targetId: Id
+ ) : ButtonOpenFile(id) {
+ override fun getViewType(): Int = HOLDER_BUTTON_OPEN_FILE
+ }
+ }
+
sealed class Relation : BlockView(), Selectable, Indentable, Decoratable {
abstract val background: ThemeColor
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt
index d34e1ecaa7..c1fb63c24a 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt
@@ -5,6 +5,7 @@ object Types {
const val HOLDER_TITLE = 1
const val HOLDER_PROFILE_TITLE = 35
const val HOLDER_ARCHIVE_TITLE = 36
+ const val HOLDER_FILE_TITLE = 37
const val HOLDER_TODO_TITLE = 48
const val HOLDER_HEADER_ONE = 2
const val HOLDER_HEADER_TWO = 3
@@ -45,6 +46,8 @@ object Types {
const val HOLDER_FILE_PLACEHOLDER = 32
const val HOLDER_FILE_UPLOAD = 33
const val HOLDER_FILE_ERROR = 34
+ const val HOLDER_BUTTON_OPEN_FILE = 134
+ const val HOLDER_BUTTON_OPEN_IMAGE = 135
const val HOLDER_DIVIDER_LINE = 16
const val HOLDER_DIVIDER_DOTS = 38
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/BlockViewRenderer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/BlockViewRenderer.kt
index c636943ab5..3def4602fa 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/BlockViewRenderer.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/BlockViewRenderer.kt
@@ -15,12 +15,14 @@ interface BlockViewRenderer {
/**
* Ext. function for recursively converting map to flattened view data structure.
+ * @param context object id
* @param root root block, from which rendering starts
* @param focus id of the current focus
* @param anchor id of the current anchor (current rendering node)
* @param indent current indent at this rendering node.
*/
suspend fun Map>.render(
+ context: Id,
mode: EditorMode = EditorMode.Edit,
root: Block,
focus: Editor.Focus,
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 7947c3aea5..8943c5f494 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
@@ -9,7 +9,6 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds.BOOKMARK
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.RelationLink
import com.anytypeio.anytype.core_models.Relations
-import com.anytypeio.anytype.core_models.SupportedLayouts
import com.anytypeio.anytype.core_models.ThemeColor
import com.anytypeio.anytype.core_models.ext.parseThemeTextColor
import com.anytypeio.anytype.core_models.ext.textColor
@@ -58,6 +57,7 @@ class DefaultBlockViewRenderer @Inject constructor(
) : BlockViewRenderer, ToggleStateHolder by toggleStateHolder {
override suspend fun Map>.render(
+ context: Id,
mode: EditorMode,
root: Block,
focus: Focus,
@@ -119,6 +119,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -164,6 +165,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -201,6 +203,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (toggleStateHolder.isToggled(block.id)) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -241,6 +244,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -281,6 +285,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -321,6 +326,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -364,6 +370,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -400,6 +407,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -458,6 +466,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -497,6 +506,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -541,6 +551,7 @@ class DefaultBlockViewRenderer @Inject constructor(
if (block.children.isNotEmpty()) {
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -623,11 +634,6 @@ class DefaultBlockViewRenderer @Inject constructor(
isPreviousBlockMedia = link is BlockView.LinkToObject.Default.Card
}
is Content.File -> {
- val detail = details.details.getOrDefault(root.id, Block.Fields.empty())
- val obj = ObjectWrapper.Basic(detail.map)
- if (SupportedLayouts.fileLayouts.contains(obj.layout)) {
- return@forEach
- }
mCounter = 0
val blockDecorationScheme = buildNestedDecorationData(
block = block,
@@ -640,18 +646,19 @@ class DefaultBlockViewRenderer @Inject constructor(
background = block.parseThemeBackgroundColor()
)
)
- result.add(
- file(
- mode = mode,
- content = content,
- block = block,
- indent = indent,
- selection = selection,
- isPreviousBlockMedia = isPreviousBlockMedia,
- schema = blockDecorationScheme,
- details = details
- )
+ val fileBlock = file(
+ context = context,
+ mode = mode,
+ content = content,
+ block = block,
+ indent = indent,
+ selection = selection,
+ isPreviousBlockMedia = isPreviousBlockMedia,
+ schema = blockDecorationScheme,
+ details = details,
+ fieldParser = fieldParser
)
+ result.add(fileBlock)
isPreviousBlockMedia = true
}
is Content.Layout -> {
@@ -666,6 +673,7 @@ class DefaultBlockViewRenderer @Inject constructor(
}
result.addAll(
render(
+ context = context,
mode = mode,
root = root,
focus = focus,
@@ -1376,6 +1384,7 @@ class DefaultBlockViewRenderer @Inject constructor(
}
private fun file(
+ context: Id,
mode: EditorMode,
content: Content.File,
block: Block,
@@ -1383,99 +1392,21 @@ class DefaultBlockViewRenderer @Inject constructor(
selection: Set,
isPreviousBlockMedia: Boolean,
schema: NestedDecorationData,
- details: Block.Details
- ): BlockView = when (content.type) {
- Content.File.Type.IMAGE -> content.toPictureView(
- blockId = block.id,
- urlBuilder = urlBuilder,
- indent = indent,
- mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
- isSelected = checkIfSelected(
- mode = mode,
- block = block,
- selection = selection
- ),
- background = block.parseThemeBackgroundColor(),
- isPreviousBlockMedia = isPreviousBlockMedia,
- decorations = schema.toBlockViewDecoration(block),
- details = details
- )
- Content.File.Type.FILE -> content.toFileView(
- blockId = block.id,
- urlBuilder = urlBuilder,
- indent = indent,
- mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
- isSelected = checkIfSelected(
- mode = mode,
- block = block,
- selection = selection
- ),
- background = block.parseThemeBackgroundColor(),
- isPrevBlockMedia = isPreviousBlockMedia,
- decorations = schema.toBlockViewDecoration(block),
- details = details
- )
- Content.File.Type.VIDEO -> content.toVideoView(
- blockId = block.id,
- urlBuilder = urlBuilder,
- indent = indent,
- mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
- isSelected = checkIfSelected(
- mode = mode,
- block = block,
- selection = selection
- ),
- background = block.parseThemeBackgroundColor(),
- isPrevBlockMedia = isPreviousBlockMedia,
- decorations = schema.toBlockViewDecoration(block),
- details = details
- )
- Content.File.Type.AUDIO -> content.toFileView(
- blockId = block.id,
- urlBuilder = urlBuilder,
- indent = indent,
- mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
- isSelected = checkIfSelected(
- mode = mode,
- block = block,
- selection = selection
- ),
- background = block.parseThemeBackgroundColor(),
- isPrevBlockMedia = isPreviousBlockMedia,
- decorations = schema.toBlockViewDecoration(block),
- details = details
- )
- Content.File.Type.PDF -> content.toFileView(
- blockId = block.id,
- urlBuilder = urlBuilder,
- indent = indent,
- mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
- isSelected = checkIfSelected(
- mode = mode,
- block = block,
- selection = selection
- ),
- background = block.parseThemeBackgroundColor(),
- isPrevBlockMedia = isPreviousBlockMedia,
- decorations = schema.toBlockViewDecoration(block),
- details = details
- )
- Content.File.Type.NONE -> content.toFileView(
- blockId = block.id,
- urlBuilder = urlBuilder,
- indent = indent,
- mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
- isSelected = checkIfSelected(
- mode = mode,
- block = block,
- selection = selection
- ),
- background = block.parseThemeBackgroundColor(),
- isPrevBlockMedia = isPreviousBlockMedia,
- decorations = schema.toBlockViewDecoration(block),
- details = details
- )
- else -> throw IllegalStateException("Unexpected file type: ${content.type}")
+ details: Block.Details,
+ fieldParser: FieldParser
+ ): BlockView {
+
+ val blockViewMode =
+ if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ
+ val isSelected = checkIfSelected(mode, block, selection)
+ val background = block.parseThemeBackgroundColor()
+ val decorations = schema.toBlockViewDecoration(block)
+
+ return when (content.type) {
+ Content.File.Type.IMAGE -> content.toPictureView(context, block.id, urlBuilder, indent, blockViewMode, isSelected, background, isPreviousBlockMedia, decorations, details, fieldParser)
+ Content.File.Type.VIDEO -> content.toVideoView(context, block.id, urlBuilder, indent, blockViewMode, isSelected, background, isPreviousBlockMedia, decorations, details, fieldParser)
+ else -> content.toFileView(context, block.id, urlBuilder, indent, blockViewMode, isSelected, background, isPreviousBlockMedia, decorations, details, fieldParser)
+ }
}
private fun title(
@@ -1511,7 +1442,7 @@ class DefaultBlockViewRenderer @Inject constructor(
val layoutCode = details.details[root.id]?.layout?.toInt()
- val layout = ObjectType.Layout.values().find {
+ val layout = ObjectType.Layout.entries.find {
it.code == layoutCode
} ?: ObjectType.Layout.BASIC
@@ -1572,18 +1503,32 @@ class DefaultBlockViewRenderer @Inject constructor(
)
}
ObjectType.Layout.FILE,
- ObjectType.Layout.IMAGE,
ObjectType.Layout.BOOKMARK,
ObjectType.Layout.VIDEO,
ObjectType.Layout.AUDIO,
ObjectType.Layout.PDF -> {
+ val objFile = ObjectWrapper.Basic(details.details[root.id]?.map.orEmpty())
+ BlockView.Title.File(
+ mode = blockMode,
+ id = block.id,
+ text = content.text,
+ isFocused = resolveIsFocused(focus, block),
+ cursor = cursor,
+ coverColor = coverContainer.coverColor,
+ coverImage = coverContainer.coverImage,
+ coverGradient = coverContainer.coverGradient,
+ background = block.parseThemeBackgroundColor(),
+ color = block.textColor(),
+ icon = objFile.objectIcon(builder = urlBuilder)
+ )
+ }
+ ObjectType.Layout.IMAGE -> {
BlockView.Title.Basic(
mode = blockMode,
id = block.id,
text = content.text,
- emoji = details.details[root.id]?.iconEmoji?.takeIf { it.isNotBlank() },
image = details.details[root.id]?.iconImage?.let { image ->
- if (image.isNotBlank() && layout != ObjectType.Layout.BOOKMARK)
+ if (image.isNotBlank())
urlBuilder.thumbnail(image)
else
null
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/selection/TableCellExt.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/selection/TableCellExt.kt
index 16a70566b7..403a17e199 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/selection/TableCellExt.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/selection/TableCellExt.kt
@@ -283,6 +283,7 @@ fun List.toggleTableMode(
is BlockView.Title.Basic -> view.copy(
mode = cellsMode
)
+ is BlockView.Title.File -> view
is BlockView.Title.Profile -> view.copy(
mode = cellsMode
)
@@ -352,6 +353,8 @@ fun List.toggleTableMode(
is BlockView.DataView.EmptyData -> view.copy(isSelected = false)
is BlockView.DataView.EmptySource -> view.copy(isSelected = false)
is BlockView.DataView.Deleted -> view.copy(isSelected = false)
+ is BlockView.ButtonOpenFile.ImageButton -> view
+ is BlockView.ButtonOpenFile.FileButton -> view
}
}
}
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FileUrlExt.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FileUrlExt.kt
index e26e9df5a3..bff85bb254 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FileUrlExt.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/extension/FileUrlExt.kt
@@ -1,10 +1,14 @@
package com.anytypeio.anytype.presentation.extension
import com.anytypeio.anytype.core_models.Block
+import com.anytypeio.anytype.core_models.Block.Content
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.domain.misc.UrlBuilder
+import com.anytypeio.anytype.domain.primitives.FieldParser
+import com.anytypeio.anytype.presentation.editor.editor.Orchestrator
+import timber.log.Timber
fun UrlBuilder.getUrlForFileBlock(
fileBlock: Block?,
@@ -66,3 +70,52 @@ fun UrlBuilder.getUrlBasedOnFileLayout(
else -> null
}
}
+
+
+data class FileDetails(
+ val content: Block.Content.File,
+ val targetObjectId: String,
+ val fileName: String,
+)
+
+/**
+ * Attempts to retrieve and validate the file details for a given block [blockId].
+ * Returns [FileDetails] if successful, or `null` if something went wrong.
+ */
+fun List.getFileDetailsForBlock(
+ blockId: String,
+ orchestrator: Orchestrator,
+ fieldParser: FieldParser
+): FileDetails? {
+
+ val block = firstOrNull { it.id == blockId } ?: run {
+ Timber.e("No block found with id $blockId")
+ return null
+ }
+
+ val content = block.content
+ if (content !is Content.File || content.state != Content.File.State.DONE) {
+ Timber.e("Block content is not a file or is not in the DONE state; cannot proceed.")
+ return null
+ }
+
+ val targetObjectId = content.targetObjectId
+ if (targetObjectId.isEmpty()) {
+ Timber.e("Target object ID is empty; cannot proceed with file sharing.")
+ return null
+ }
+
+ val fileObject = orchestrator.stores.details.getAsObject(target = targetObjectId)
+ if (fileObject == null) {
+ Timber.e("Object with id $targetObjectId not found.")
+ return null
+ }
+
+ val fileName = fieldParser.getObjectName(fileObject)
+
+ return FileDetails(
+ content = content,
+ targetObjectId = targetObjectId,
+ fileName = fileName,
+ )
+}
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt
index 5f041d1f6f..c05a74a52c 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt
@@ -529,6 +529,7 @@ class VersionHistoryViewModel(
defaultPayloadConsumer(payload)
val root = event.blocks.first { it.id == vmParams.objectId }
val blocks = event.blocks.asMap().render(
+ context = obj.id,
mode = Mode.Read,
root = root,
focus = Editor.Focus.empty(),
@@ -566,6 +567,7 @@ class VersionHistoryViewModel(
} else {
val root = event.blocks.first { it.id == vmParams.objectId }
val blocks = event.blocks.asMap().render(
+ context = obj.id,
mode = Mode.Read,
root = root,
focus = Editor.Focus.empty(),
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 bfa7b84a40..f658bb3af0 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
@@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_models.Relations
+import com.anytypeio.anytype.core_models.SupportedLayouts
import com.anytypeio.anytype.core_models.ThemeColor
import com.anytypeio.anytype.domain.config.DebugSettings
import com.anytypeio.anytype.domain.misc.UrlBuilder
@@ -31,6 +32,7 @@ import com.anytypeio.anytype.presentation.templates.TemplateObjectTypeView
import timber.log.Timber
fun Block.Content.File.toPictureView(
+ context: Id,
blockId: String,
urlBuilder: UrlBuilder,
indent: Int,
@@ -39,7 +41,8 @@ fun Block.Content.File.toPictureView(
background: ThemeColor,
isPreviousBlockMedia: Boolean,
decorations: List,
- details: Block.Details = Block.Details()
+ details: Block.Details = Block.Details(),
+ fieldParser: FieldParser
): BlockView = when (state) {
Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.Picture(
id = blockId,
@@ -59,25 +62,32 @@ fun Block.Content.File.toPictureView(
decorations = decorations
)
Block.Content.File.State.DONE -> {
+
val url = urlBuilder.getUrlForFileContent(this)
- val targetId = this.targetObjectId
- val struct = details.details[targetId]?.map
- if (url != null && targetId != null) {
- val targetObject = ObjectWrapper.File(struct.orEmpty())
- BlockView.Media.Picture(
- id = blockId,
- targetObjectId = targetId,
- url = url,
- indent = indent,
- mode = mode,
- isSelected = isSelected,
- background = background,
- decorations = decorations,
- size = targetObject.sizeInBytes?.toLong(),
- name = targetObject.name,
- mime = targetObject.fileMimeType
- )
+ val currentObject = ObjectWrapper.Basic(details.details[context]?.map.orEmpty())
+ val targetObject = ObjectWrapper.Basic(details.details[targetObjectId]?.map.orEmpty())
+ if (url != null && targetObject.isValid && targetObject.notDeletedNorArchived) {
+ if (currentObject.layout == ObjectType.Layout.IMAGE) {
+ BlockView.ButtonOpenFile.ImageButton(
+ id = blockId,
+ targetId = targetObjectId
+ )
+ } else {
+ BlockView.Media.Picture(
+ id = blockId,
+ targetObjectId = targetObjectId,
+ url = url,
+ indent = indent,
+ mode = mode,
+ isSelected = isSelected,
+ background = background,
+ decorations = decorations,
+ size = targetObject.sizeInBytes?.toLong(),
+ name = fieldParser.getObjectName(targetObject),
+ mime = targetObject.fileMimeType
+ )
+ }
} else {
Timber.w("Could not build picture view for block $blockId")
BlockView.Error.Picture(
@@ -99,10 +109,10 @@ fun Block.Content.File.toPictureView(
decorations = decorations,
name = name
)
- else -> throw IllegalStateException("Unexpected state: $state")
}
fun Block.Content.File.toVideoView(
+ context: Id,
blockId: Id,
urlBuilder: UrlBuilder,
indent: Int,
@@ -111,7 +121,8 @@ fun Block.Content.File.toVideoView(
background: ThemeColor,
isPrevBlockMedia: Boolean,
decorations: List,
- details: Block.Details = Block.Details()
+ details: Block.Details = Block.Details(),
+ fieldParser: FieldParser
): BlockView = when (state) {
Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.Video(
id = blockId,
@@ -131,25 +142,32 @@ fun Block.Content.File.toVideoView(
decorations = decorations
)
Block.Content.File.State.DONE -> {
+
val url = urlBuilder.getUrlForFileContent(this)
- val targetId = this.targetObjectId
- val struct = details.details[targetId]?.map
- if (url != null && targetId != null && !struct.isNullOrEmpty()) {
- val targetObject = ObjectWrapper.File(struct)
- BlockView.Media.Video(
- id = blockId,
- targetObjectId = targetId,
- url = url,
- indent = indent,
- mode = mode,
- isSelected = isSelected,
- background = background,
- decorations = decorations,
- size = targetObject.sizeInBytes?.toLong(),
- name = targetObject.name,
- mime = targetObject.fileMimeType
- )
+ val currentObject = ObjectWrapper.Basic(details.details[context]?.map.orEmpty())
+ val targetObject = ObjectWrapper.Basic(details.details[targetObjectId]?.map.orEmpty())
+ if (url != null && targetObject.isValid && targetObject.notDeletedNorArchived) {
+ if (currentObject.layout == ObjectType.Layout.VIDEO) {
+ BlockView.ButtonOpenFile.FileButton(
+ id = blockId,
+ targetId = targetObjectId
+ )
+ } else {
+ BlockView.Media.Video(
+ id = blockId,
+ targetObjectId = targetObjectId,
+ url = url,
+ indent = indent,
+ mode = mode,
+ isSelected = isSelected,
+ background = background,
+ decorations = decorations,
+ size = targetObject.sizeInBytes?.toLong(),
+ name = fieldParser.getObjectName(targetObject),
+ mime = targetObject.fileMimeType
+ )
+ }
} else {
Timber.w("Could not build video view for block $blockId")
BlockView.Error.Video(
@@ -171,10 +189,10 @@ fun Block.Content.File.toVideoView(
decorations = decorations,
name = name
)
- else -> throw IllegalStateException("Unexpected state: $state")
}
fun Block.Content.File.toFileView(
+ context: Id,
blockId: String,
urlBuilder: UrlBuilder,
indent: Int,
@@ -183,7 +201,8 @@ fun Block.Content.File.toFileView(
background: ThemeColor,
isPrevBlockMedia: Boolean,
decorations: List,
- details: Block.Details = Block.Details()
+ details: Block.Details = Block.Details(),
+ fieldParser: FieldParser
): BlockView = when (state) {
Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.File(
id = blockId,
@@ -203,24 +222,21 @@ fun Block.Content.File.toFileView(
decorations = decorations
)
Block.Content.File.State.DONE -> {
+
val url = urlBuilder.getUrlForFileContent(this)
- val targetId = this.targetObjectId
- val struct = details.details[targetId]?.map
- if (url != null && targetId != null) {
- if (struct.isNullOrEmpty()) {
- BlockView.Upload.File(
+ val currentObject = ObjectWrapper.Basic(details.details[context]?.map.orEmpty())
+ val targetObject = ObjectWrapper.Basic(details.details[targetObjectId]?.map.orEmpty())
+
+ if (url != null && targetObject.isValid && targetObject.notDeletedNorArchived) {
+ if (SupportedLayouts.fileLayouts.contains(currentObject.layout)) {
+ BlockView.ButtonOpenFile.FileButton(
id = blockId,
- indent = indent,
- mode = mode,
- isSelected = isSelected,
- background = background,
- decorations = decorations
+ targetId = targetObjectId
)
} else {
- val targetObject = ObjectWrapper.File(struct)
BlockView.Media.File(
id = blockId,
- targetObjectId = targetId,
+ targetObjectId = targetObjectId,
url = url,
indent = indent,
mode = mode,
@@ -228,7 +244,7 @@ fun Block.Content.File.toFileView(
background = background,
decorations = decorations,
size = targetObject.sizeInBytes?.toLong(),
- name = targetObject.name,
+ name = fieldParser.getObjectName(targetObject),
mime = targetObject.fileMimeType,
fileExt = targetObject.fileExt
)
@@ -254,7 +270,6 @@ fun Block.Content.File.toFileView(
decorations = decorations,
name = name
)
- else -> throw IllegalStateException("Unexpected state: $state")
}
fun Block.Align.toView(): Alignment = when (this) {
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/TemplateBlankViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/TemplateBlankViewModel.kt
index 1ce3ee21c8..9c96408b70 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/TemplateBlankViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/TemplateBlankViewModel.kt
@@ -94,6 +94,7 @@ class TemplateBlankViewModel(
viewModelScope.launch {
state.value = page.asMap().render(
+ context = DEFAULT_TEMPLATE_ID_BLANK,
mode = Editor.Mode.Read,
root = page.first(),
focus = com.anytypeio.anytype.domain.editor.Editor.Focus.empty(),
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 9259d1487f..318df39ecc 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
@@ -76,6 +76,7 @@ class DefaultBlockViewRendererTest {
details: Block.Details,
schema: NestedDecorationData = emptyList()
): List = blocks.render(
+ context = root.id,
root = root,
focus = focus,
anchor = anchor,
@@ -5754,24 +5755,106 @@ class DefaultBlockViewRendererTest {
//endregion
@Test
- fun `should not render file block in case of file layout`() {
+ fun `should render file open block in case of file, pdf, audio or video layouts`(){
+ val fileTypeExceptImage = listOf(
+ Block.Content.File.Type.FILE to Layout.FILE,
+ Block.Content.File.Type.PDF to Layout.PDF,
+ Block.Content.File.Type.VIDEO to Layout.VIDEO,
+ Block.Content.File.Type.AUDIO to Layout.AUDIO,
+ )
+
+ fileTypeExceptImage.forEach { (fileType, layout) ->
+ testFileLayout(type = fileType, layout = layout)
+ }
+ }
+
+ private fun testFileLayout(type: Block.Content.File.Type, layout: Layout) {
+
+ val currentObjectId = MockDataFactory.randomUuid()
+
+ val file = StubFile(type = type, targetObjectId = currentObjectId)
+
+ val paragraph = StubParagraph()
+
+ val page = StubSmartBlock(id = currentObjectId, children = listOf(paragraph.id, file.id))
+
+ val details = mapOf(
+ page.id to Block.Fields(
+ mapOf(
+ Relations.ID to currentObjectId,
+ Relations.NAME to "file-name",
+ Relations.LAYOUT to layout.code.toDouble()
+ )
+ )
+ )
+
+ val blocks = listOf(page, paragraph, file)
+
+ 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.Paragraph(
+ indent = 0,
+ isFocused = false,
+ id = paragraph.id,
+ marks = emptyList(),
+ background = paragraph.parseThemeBackgroundColor(),
+ text = paragraph.content().text,
+ decorations = listOf(
+ BlockView.Decoration(
+ style = BlockView.Decoration.Style.None,
+ background = paragraph.parseThemeBackgroundColor()
+ )
+ ),
+ ),
+ BlockView.ButtonOpenFile.FileButton(
+ id = file.id,
+ targetId = currentObjectId
+ )
+ )
+
+ assertEquals(expected = expected, actual = result)
+ }
+
+ @Test
+ fun `should render image open block in case of image layout`() {
+
+ val currentObjectId = MockDataFactory.randomUuid()
val file = StubFile(
- backgroundColor = null,
- state = Block.Content.File.State.DONE,
- type = Block.Content.File.Type.FILE
+ type = Block.Content.File.Type.IMAGE,
+ targetObjectId = currentObjectId,
+ state = Block.Content.File.State.DONE
)
val paragraph = StubParagraph()
- val page = StubSmartBlock(children = listOf(paragraph.id, file.id))
+ val page = StubSmartBlock(id = currentObjectId, children = listOf(paragraph.id, file.id))
- val details = mapOf(page.id to Block.Fields(
- mapOf(
- Relations.NAME to "file-name",
- Relations.LAYOUT to Layout.FILE.code.toDouble()
+ val details = mapOf(
+ page.id to Block.Fields(
+ mapOf(
+ Relations.ID to currentObjectId,
+ Relations.NAME to "image-name",
+ Relations.LAYOUT to ObjectType.Layout.IMAGE.code.toDouble()
+ )
)
- ))
+ )
val blocks = listOf(page, paragraph, file)
@@ -5806,6 +5889,10 @@ class DefaultBlockViewRendererTest {
background = paragraph.parseThemeBackgroundColor()
)
),
+ ),
+ BlockView.ButtonOpenFile.ImageButton(
+ id = file.id,
+ targetId = currentObjectId
)
)
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 c8af0443ea..b4901821c7 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
@@ -1,6 +1,7 @@
package com.anytypeio.anytype.presentation.editor
+import android.R
import android.net.Uri
import android.os.Build
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
@@ -9,11 +10,15 @@ import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Event
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.NetworkModeConfig
+import com.anytypeio.anytype.core_models.ObjectType
+import com.anytypeio.anytype.core_models.ObjectTypeIds
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.StubFile
import com.anytypeio.anytype.core_models.StubNumbered
+import com.anytypeio.anytype.core_models.StubObject
import com.anytypeio.anytype.core_models.StubParagraph
import com.anytypeio.anytype.core_models.ThemeColor
import com.anytypeio.anytype.core_models.ext.content
@@ -2555,68 +2560,24 @@ open class EditorViewModelTest {
}
@Test
- fun `should start sharing a file`() {
+ fun `should start downloading file`() {
val root = MockDataFactory.randomUuid()
- val file = MockBlockFactory.makeFileBlock()
+ val targetObjectId = MockDataFactory.randomUuid()
+ val file = StubFile(
+ targetObjectId = targetObjectId,
+ type = Block.Content.File.Type.FILE
+ )
val title = MockBlockFactory.makeTitleBlock()
- val page = listOf(
- Block(
- id = root,
- fields = Block.Fields(emptyMap()),
- content = Block.Content.Smart,
- children = listOf(title.id, file.id)
- ),
- title,
- file
+ val targetObject = StubObject(
+ id = targetObjectId,
+ name = "file1",
+ layout = ObjectType.Layout.FILE.code.toDouble(),
+ fileExt = ".pdf"
)
- val flow: Flow> = flow {
- delay(100)
- emit(
- listOf(
- Event.Command.ShowObject(
- root = root,
- blocks = page,
- context = root
- )
- )
- )
- }
-
- stubObserveEvents(flow)
- stubOpenPage()
- givenViewModel(builder)
-
- givenSharedFile()
-
- vm.onStart(id = root, space = defaultSpace)
-
- coroutineTestRule.advanceTime(100)
-
- // TESTING
-
- vm.startSharingFile(id = file.id)
-
- runTest {
- verify(documentFileShareDownloader, times(1)).async(
- params = eq(
- MiddlewareShareDownloader.Params(
- name = file.content().name.orEmpty(),
- objectId = file.content().targetObjectId.orEmpty(),
- )
- )
- )
- }
- }
-
- @Test
- fun `should start downloading file`() {
-
- val root = MockDataFactory.randomUuid()
- val file = MockBlockFactory.makeFileBlock()
- val title = MockBlockFactory.makeTitleBlock()
+ val objectDetails = Block.Fields(targetObject.map)
val page = listOf(
Block(
@@ -2636,12 +2597,19 @@ open class EditorViewModelTest {
Event.Command.ShowObject(
root = root,
blocks = page,
- context = root
+ context = root,
+ details = Block.Details(mapOf(
+ targetObjectId to objectDetails
+ ))
)
)
)
}
+ fieldParser.stub {
+ on { getObjectName(targetObject) } doReturn targetObject.name!!
+ }
+
stubObserveEvents(flow)
stubOpenPage()
givenViewModel(builder)
@@ -2654,16 +2622,14 @@ open class EditorViewModelTest {
// TESTING
- vm.startDownloadingFileFromBlock(blockId = file.id)
+ vm.startDownloadingFileFromBlock(id = file.id)
runBlockingTest {
verify(downloadFile, times(1)).invoke(
params = eq(
DownloadFile.Params(
- name = file.content().name.orEmpty(),
- url = builder.file(
- path = file.content().targetObjectId!!
- )
+ name = targetObject.name!!,
+ url = builder.file(path = targetObjectId)
)
)
)
@@ -3423,17 +3389,11 @@ open class EditorViewModelTest {
}
@Test
- fun `open select picture - when error in edit mode`() {
+ fun `open select picture - when error in edit mode`() = runTest {
- val picture = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(
- targetObjectId = MockDataFactory.randomString(),
- type = Block.Content.File.Type.IMAGE,
- state = Block.Content.File.State.ERROR
- ),
- children = emptyList()
+ val picture = StubFile(
+ state = Block.Content.File.State.ERROR,
+ type = Block.Content.File.Type.IMAGE
)
val page = listOf(
@@ -3457,10 +3417,10 @@ open class EditorViewModelTest {
)
givenViewModel()
-
+ advanceUntilIdle()
vm.onStart(id = root, space = defaultSpace)
-
+ advanceUntilIdle()
val expected = listOf(
BlockView.Title.Basic(
@@ -3477,7 +3437,8 @@ open class EditorViewModelTest {
background = ThemeColor.DEFAULT,
style = BlockView.Decoration.Style.Card
)
- )
+ ),
+ name = picture.content.asFile().name
)
)
@@ -3500,15 +3461,9 @@ open class EditorViewModelTest {
@Test
fun `open select video - when error in edit mode`() {
- val video = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(
- targetObjectId = MockDataFactory.randomString(),
- type = Block.Content.File.Type.VIDEO,
- state = Block.Content.File.State.ERROR
- ),
- children = emptyList()
+ val video = StubFile(
+ state = Block.Content.File.State.ERROR,
+ type = Block.Content.File.Type.VIDEO
)
val page = listOf(
@@ -3552,7 +3507,8 @@ open class EditorViewModelTest {
background = ThemeColor.DEFAULT,
style = BlockView.Decoration.Style.Card
)
- )
+ ),
+ name = video.content.asFile().name
)
)
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorErrorMessageTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorErrorMessageTest.kt
index 7bbcd44983..480e053843 100644
--- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorErrorMessageTest.kt
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorErrorMessageTest.kt
@@ -2,6 +2,10 @@ package com.anytypeio.anytype.presentation.editor.editor
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.anytypeio.anytype.core_models.Block
+import com.anytypeio.anytype.core_models.ObjectType
+import com.anytypeio.anytype.core_models.Relations
+import com.anytypeio.anytype.core_models.StubFile
+import com.anytypeio.anytype.core_models.StubObject
import com.anytypeio.anytype.domain.base.Either
import com.anytypeio.anytype.presentation.util.DefaultCoroutineTestRule
import com.anytypeio.anytype.test_utils.MockDataFactory
@@ -38,15 +42,26 @@ class EditorErrorMessageTest : EditorPresentationTestSetup() {
val consumed = mutableListOf()
- val file = Block(
- id = MockDataFactory.randomUuid(),
- content = Block.Content.File(
- targetObjectId = MockDataFactory.randomUuid(),
- type = Block.Content.File.Type.FILE,
- state = Block.Content.File.State.DONE
- ),
- fields = Block.Fields.empty(),
- children = emptyList()
+ val fileObjectId = MockDataFactory.randomUuid()
+
+ val fileBlock = StubFile(
+ type = Block.Content.File.Type.FILE,
+ state = Block.Content.File.State.DONE,
+ targetObjectId = fileObjectId
+ )
+
+ val details = Block.Details(
+ mapOf(
+ fileObjectId to Block.Fields(
+ mapOf(
+ Relations.ID to fileObjectId,
+ Relations.NAME to "file object",
+ Relations.SIZE_IN_BYTES to 10000.0,
+ Relations.FILE_MIME_TYPE to "pdf",
+ Relations.LAYOUT to ObjectType.Layout.FILE.code.toDouble()
+ )
+ )
+ )
)
val doc = listOf(
@@ -54,17 +69,19 @@ class EditorErrorMessageTest : EditorPresentationTestSetup() {
id = root,
fields = Block.Fields(emptyMap()),
content = Block.Content.Smart,
- children = listOf(file.id)
+ children = listOf(fileBlock.id)
),
- file
+ fileBlock
)
- stubOpenDocument(doc)
+ stubOpenDocument(doc, details)
stubInterceptEvents()
stubDownloadFile()
val vm = buildViewModel()
+ advanceUntilIdle()
+
vm.onStart(id = root, space = defaultSpace)
advanceUntilIdle()
@@ -73,7 +90,7 @@ class EditorErrorMessageTest : EditorPresentationTestSetup() {
// Launching operation that triggers a toast
- vm.startDownloadingFileFromBlock(blockId = file.id)
+ vm.startDownloadingFileFromBlock(id = fileBlock.id)
advanceUntilIdle()
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 1513c379c2..784dda8567 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
@@ -1,11 +1,11 @@
package com.anytypeio.anytype.presentation.editor.editor
-import android.R
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.StubBookmark
+import com.anytypeio.anytype.core_models.StubFile
import com.anytypeio.anytype.core_models.StubTitle
import com.anytypeio.anytype.core_models.ThemeColor
import com.anytypeio.anytype.core_models.ext.content
@@ -28,8 +28,6 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.MockitoAnnotations
-import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.stub
import org.mockito.kotlin.whenever
class EditorLockPageTest : EditorPresentationTestSetup() {
@@ -585,15 +583,11 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
val fileBlockId = MockDataFactory.randomUuid()
val targetObjectId = MockDataFactory.randomUuid()
- val file = Block(
+ val file = StubFile(
id = fileBlockId,
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(
- targetObjectId = targetObjectId,
- type = Block.Content.File.Type.FILE,
- state = Block.Content.File.State.DONE
- ),
- children = emptyList()
+ type = Block.Content.File.Type.FILE,
+ state = Block.Content.File.State.DONE,
+ targetObjectId = targetObjectId
)
val page = listOf(
@@ -680,8 +674,7 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
testObserver.assertValue { value ->
value is EventWrapper && value.peekContent() == Command.OpenFileByDefaultApp(
- id = fileBlockId,
- uri = builder.file(targetObjectId)
+ id = fileBlockId
)
}
}
@@ -697,15 +690,10 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
val fileName = "image.png"
val fileSize = 1000.0
- val picture = Block(
- id = fileBlockId,
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(
- targetObjectId = targetObjectId,
- type = Block.Content.File.Type.IMAGE,
- state = Block.Content.File.State.DONE
- ),
- children = emptyList()
+ val picture = StubFile(
+ type = Block.Content.File.Type.IMAGE,
+ state = Block.Content.File.State.DONE,
+ targetObjectId = targetObjectId
)
val page = listOf(
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMultiSelectModeTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMultiSelectModeTest.kt
index 9a42e8b278..3dea8cec04 100644
--- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMultiSelectModeTest.kt
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMultiSelectModeTest.kt
@@ -3,6 +3,7 @@ package com.anytypeio.anytype.presentation.editor.editor
import android.os.Build
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.anytypeio.anytype.core_models.Block
+import com.anytypeio.anytype.core_models.StubFile
import com.anytypeio.anytype.core_models.StubHeader
import com.anytypeio.anytype.core_models.StubLayoutColumns
import com.anytypeio.anytype.core_models.StubLayoutRows
@@ -1081,14 +1082,11 @@ class EditorMultiSelectModeTest : EditorPresentationTestSetup() {
)
val backgroundC = null
- val c = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields.empty(),
- children = emptyList(),
- content = Block.Content.File(
- state = Block.Content.File.State.EMPTY
- ),
- backgroundColor = backgroundC
+
+
+ val c = StubFile(
+ backgroundColor = backgroundC,
+ state = Block.Content.File.State.EMPTY
)
val page = Block(
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/styling/StyleToolbarExtKtTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/styling/StyleToolbarExtKtTest.kt
index a399c4856a..d9c647cf4e 100644
--- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/styling/StyleToolbarExtKtTest.kt
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/styling/StyleToolbarExtKtTest.kt
@@ -2,6 +2,7 @@ package com.anytypeio.anytype.presentation.editor.editor.styling
import android.os.Build
import com.anytypeio.anytype.core_models.Block
+import com.anytypeio.anytype.core_models.StubFile
import com.anytypeio.anytype.core_models.TextStyle
import com.anytypeio.anytype.core_models.ThemeColor
import com.anytypeio.anytype.test_utils.MockDataFactory
@@ -140,12 +141,9 @@ class StyleToolbarExtKtTest {
children = emptyList()
)
- val given2 = Block(
+ val given2 = StubFile(
id = child,
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(),
- backgroundColor = backgroundTeal,
- children = emptyList()
+ backgroundColor = backgroundTeal
)
val given3 = Block(
@@ -373,12 +371,9 @@ class StyleToolbarExtKtTest {
children = emptyList()
)
- val given3 = Block(
+ val given3 = StubFile(
id = child,
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(),
- backgroundColor = ThemeColor.LIME.code,
- children = emptyList()
+ backgroundColor = ThemeColor.LIME.code
)
val result =
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/table/TableBlockRendererTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/table/TableBlockRendererTest.kt
index 2f7e61e375..ccbacf5e19 100644
--- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/table/TableBlockRendererTest.kt
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/table/TableBlockRendererTest.kt
@@ -55,6 +55,7 @@ class TableBlockRendererTest {
indent: Int,
details: Block.Details
): List = blocks.render(
+ context = root.id,
root = root,
anchor = anchor,
focus = focus,
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 196b680680..8531eb33a3 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
@@ -2,11 +2,20 @@ package com.anytypeio.anytype.presentation.mapper
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Id
+import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Relations
+import com.anytypeio.anytype.core_models.StubFile
+import com.anytypeio.anytype.core_models.StubObject
import com.anytypeio.anytype.domain.config.Gateway
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.editor.editor.Markup
import com.anytypeio.anytype.core_models.ThemeColor
+import com.anytypeio.anytype.domain.debugging.Logger
+import com.anytypeio.anytype.domain.misc.DateProvider
+import com.anytypeio.anytype.domain.objects.GetDateObjectByTimestamp
+import com.anytypeio.anytype.domain.primitives.FieldParser
+import com.anytypeio.anytype.domain.primitives.FieldParserImpl
+import com.anytypeio.anytype.domain.resources.StringResourceProvider
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.test_utils.MockDataFactory
import org.junit.Before
@@ -23,10 +32,26 @@ class MapperExtensionKtTest {
private val urlBuilder: UrlBuilder get() = UrlBuilder(gateway)
private val targetObjectId : Id = "647tyhfgehf7ru"
+ private val objectId : Id = MockDataFactory.randomUuid()
+
+ lateinit var fieldParser: FieldParser
+
+ @Mock
+ lateinit var dateProvider: DateProvider
+
+ @Mock
+ lateinit var logger: Logger
+
+ @Mock
+ lateinit var getDateObjectByTimestamp: GetDateObjectByTimestamp
+
+ @Mock
+ lateinit var stringResourceProvider: StringResourceProvider
@Before
fun before() {
MockitoAnnotations.openMocks(this)
+ fieldParser = FieldParserImpl(dateProvider, logger, getDateObjectByTimestamp, stringResourceProvider)
}
@Test
@@ -44,25 +69,28 @@ class MapperExtensionKtTest {
val details = Block.Details(
mapOf(
+ objectId to Block.Fields(
+ StubObject(
+ layout = ObjectType.Layout.BASIC.code.toDouble()
+ ).map
+ ),
targetObjectId to Block.Fields(
mapOf(
+ Relations.ID to targetObjectId,
Relations.NAME to name,
Relations.SIZE_IN_BYTES to 10000.0,
Relations.FILE_MIME_TYPE to mime,
+ Relations.LAYOUT to ObjectType.Layout.FILE.code.toDouble()
)
)
)
)
- val block = Block.Content.File(
- name = name,
- size = 10000L,
- mime = mime,
- targetObjectId = targetObjectId,
+ val block = StubFile(
state = state,
- type = type
-
- )
+ type = type,
+ targetObjectId = targetObjectId
+ ).content as Block.Content.File
val expected = BlockView.Media.File(
id = id,
@@ -75,7 +103,7 @@ class MapperExtensionKtTest {
indent = indent,
decorations = emptyList()
)
- val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details)
+ val actual = block.toFileView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details, fieldParser)
assertEquals(expected, actual)
}
@@ -91,15 +119,15 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.FILE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
+ val block = StubFile(
state = state,
type = type,
targetObjectId = targetObjectId
- )
+ ).content as Block.Content.File
val expected =
BlockView.MediaPlaceholder.File(id = id, indent = indent, isPreviousBlockMedia = false)
- val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toFileView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -107,6 +135,8 @@ class MapperExtensionKtTest {
@Test
fun `should return error file block view`() {
+ val rootBlockId = MockDataFactory.randomUuid()
+
val id = MockDataFactory.randomUuid()
val indent = MockDataFactory.randomInt()
@@ -115,14 +145,14 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.FILE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
+ val block = StubFile(
state = state,
type = type,
targetObjectId = targetObjectId
- )
+ ).content as Block.Content.File
- val expected = BlockView.Error.File(id = id, indent = indent, decorations = emptyList())
- val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val expected = BlockView.Error.File(id = id, indent = indent, decorations = emptyList(), name = block.name)
+ val actual = block.toFileView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -138,14 +168,14 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.FILE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
+ val block = StubFile(
state = state,
type = type,
targetObjectId = targetObjectId
- )
+ ).content as Block.Content.File
val expected = BlockView.Upload.File(id = id, indent = indent)
- val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toFileView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -165,17 +195,17 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.IMAGE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- targetObjectId = targetObjectId,
+ val block = StubFile(
state = state,
- type = type
-
- )
+ type = type,
+ targetObjectId = targetObjectId
+ ).content as Block.Content.File
val details = Block.Details(
mapOf(
targetObjectId to Block.Fields(
mapOf(
+ Relations.ID to targetObjectId,
Relations.NAME to name,
Relations.SIZE_IN_BYTES to size,
Relations.FILE_MIME_TYPE to mime,
@@ -195,7 +225,7 @@ class MapperExtensionKtTest {
decorations = emptyList()
)
- val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details)
+ val actual = block.toPictureView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details, fieldParser)
assertEquals(expected, actual)
}
@@ -211,18 +241,18 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.IMAGE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
+ val block = StubFile(
state = state,
type = type,
targetObjectId = targetObjectId
- )
+ ).content as Block.Content.File
val expected = BlockView.MediaPlaceholder.Picture(
id = id,
indent = indent,
isPreviousBlockMedia = false
)
- val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toPictureView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -238,19 +268,20 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.IMAGE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
+ val block = StubFile(
state = state,
type = type,
targetObjectId = targetObjectId
- )
+ ).content as Block.Content.File
val expected = BlockView.Error.Picture(
id = id,
indent = indent,
- decorations = emptyList()
+ decorations = emptyList(),
+ name = block.name
)
- val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toPictureView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -266,14 +297,14 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.IMAGE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
+ val block = StubFile(
state = state,
type = type,
targetObjectId = targetObjectId
- )
+ ).content as Block.Content.File
val expected = BlockView.Upload.Picture(id = id, indent = indent)
- val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toPictureView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -293,16 +324,17 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.VIDEO
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- targetObjectId = targetObjectId,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = targetObjectId
+ ).content as Block.Content.File
val details = Block.Details(
mapOf(
targetObjectId to Block.Fields(
mapOf(
+ Relations.ID to targetObjectId,
Relations.NAME to name,
Relations.SIZE_IN_BYTES to 10000.0,
Relations.FILE_MIME_TYPE to mime,
@@ -322,7 +354,7 @@ class MapperExtensionKtTest {
decorations = emptyList()
)
- val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details)
+ val actual = block.toVideoView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details, fieldParser)
assertEquals(expected, actual)
}
@@ -338,11 +370,11 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.VIDEO
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = targetObjectId
+ ).content as Block.Content.File
val expected = BlockView.Error.Video(
id = id,
@@ -350,7 +382,7 @@ class MapperExtensionKtTest {
decorations = emptyList()
)
- val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toVideoView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -366,11 +398,11 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.IMAGE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = ""
+ ).content as Block.Content.File
val expected = BlockView.Error.Picture(
id = id,
@@ -378,7 +410,7 @@ class MapperExtensionKtTest {
decorations = emptyList()
)
- val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toPictureView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -394,11 +426,11 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.FILE
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = ""
+ ).content as Block.Content.File
val expected = BlockView.Error.File(
id = id,
@@ -406,7 +438,7 @@ class MapperExtensionKtTest {
decorations = emptyList()
)
- val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toFileView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -422,11 +454,11 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.PDF
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = ""
+ ).content as Block.Content.File
val expected = BlockView.Error.File(
id = id,
@@ -434,7 +466,7 @@ class MapperExtensionKtTest {
decorations = emptyList()
)
- val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toFileView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -450,14 +482,11 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.VIDEO
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- name = null,
- size = null,
- mime = null,
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = ""
+ ).content as Block.Content.File
val expected = BlockView.MediaPlaceholder.Video(
id = id,
@@ -465,7 +494,7 @@ class MapperExtensionKtTest {
isPreviousBlockMedia = false
)
- val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toVideoView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -481,21 +510,18 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.VIDEO
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- name = null,
- size = null,
- mime = null,
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = ""
+ ).content as Block.Content.File
val expected = BlockView.Upload.Video(
id = id,
indent = indent
)
- val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toVideoView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
@@ -511,48 +537,24 @@ class MapperExtensionKtTest {
val type = Block.Content.File.Type.VIDEO
val mode = BlockView.Mode.EDIT
- val block = Block.Content.File(
- name = null,
- size = null,
- mime = null,
- targetObjectId = null,
+ val block = StubFile(
state = state,
- type = type
- )
+ type = type,
+ targetObjectId = ""
+ ).content as Block.Content.File
val expected = BlockView.Error.Video(
id = id,
indent = indent,
- decorations = emptyList()
+ decorations = emptyList(),
+ name = block.name
)
- val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
+ val actual = block.toVideoView(objectId, id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), Block.Details(), fieldParser)
assertEquals(expected, actual)
}
- @Test(expected = IllegalStateException::class)
- fun `should throw exceptions when state not set`() {
-
- val id = MockDataFactory.randomUuid()
-
- val indent = MockDataFactory.randomInt()
-
- val type = Block.Content.File.Type.VIDEO
- val mode = BlockView.Mode.EDIT
-
- val block = Block.Content.File(
- name = null,
- size = null,
- mime = null,
- targetObjectId = null,
- state = null,
- type = type
- )
-
- block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
- }
-
@Test
fun `should not return mark when range from is equal text length`() {
// SETUP
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 2b16bf3bfd..f9f50eec4b 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
@@ -94,9 +94,11 @@ fun StubFile(
backgroundColor: String? = null,
targetObjectId: Id = MockDataFactory.randomString(),
name: String = MockDataFactory.randomString(),
+ mime: String = MockDataFactory.randomString(),
size: Long = MockDataFactory.randomLong(),
- type: Block.Content.File.Type? = null,
- state: Block.Content.File.State? = null,
+ type: Block.Content.File.Type = Block.Content.File.Type.FILE,
+ state: Block.Content.File.State = Block.Content.File.State.DONE,
+ addedAt: Long = MockDataFactory.randomLong()
) : Block = Block(
id = id,
children = children,
@@ -107,7 +109,9 @@ fun StubFile(
name = name,
targetObjectId = targetObjectId,
type = type,
- state = state
+ state = state,
+ mime = mime,
+ addedAt = addedAt
)
)
diff --git a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Object.kt b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Object.kt
index a89ac80856..a4feed51cc 100644
--- a/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Object.kt
+++ b/test/core-models-stub/src/main/java/com/anytypeio/anytype/core_models/Object.kt
@@ -22,7 +22,8 @@ fun StubObject(
isHidden: Boolean? = null,
links: List = emptyList(),
targetObjectType: Id? = null,
- identity: Id? = null
+ identity: Id? = null,
+ fileExt: String? = null,
): ObjectWrapper.Basic = ObjectWrapper.Basic(
map = mapOf(
Relations.ID to id,
@@ -40,7 +41,8 @@ fun StubObject(
Relations.LINKS to links,
Relations.TARGET_OBJECT_TYPE to targetObjectType,
Relations.UNIQUE_KEY to uniqueKey,
- Relations.IDENTITY to identity
+ Relations.IDENTITY to identity,
+ Relations.FILE_EXT to fileExt
)
)
diff --git a/test/core-models-stub/src/main/java/com/anytypeio/anytype/presentation/MockBlockFactory.kt b/test/core-models-stub/src/main/java/com/anytypeio/anytype/presentation/MockBlockFactory.kt
index 80755bf310..3b051be671 100644
--- a/test/core-models-stub/src/main/java/com/anytypeio/anytype/presentation/MockBlockFactory.kt
+++ b/test/core-models-stub/src/main/java/com/anytypeio/anytype/presentation/MockBlockFactory.kt
@@ -84,20 +84,6 @@ object MockBlockFactory {
)
)
- fun makeFileBlock(): Block = Block(
- id = MockDataFactory.randomUuid(),
- fields = Block.Fields(emptyMap()),
- content = Block.Content.File(
- targetObjectId = MockDataFactory.randomUuid(),
- name = MockDataFactory.randomString(),
- state = Block.Content.File.State.DONE,
- mime = MockDataFactory.randomString(),
- size = MockDataFactory.randomLong(),
- type = Block.Content.File.Type.FILE
- ),
- children = emptyList()
- )
-
fun makeTitleBlock(): Block = Block(
id = MockDataFactory.randomUuid(),
fields = Block.Fields(emptyMap()),