Compare commits
18 Commits
main
...
DROID-2156
Author | SHA1 | Date | |
---|---|---|---|
|
83d7847a8e | ||
|
70dca79974 | ||
|
ce984bdd13 | ||
|
a83a81182c | ||
|
8f5a850fd3 | ||
|
30661412a5 | ||
|
76cdcacb16 | ||
|
ecb51a431e | ||
|
c1369553f1 | ||
|
26343a21a7 | ||
|
297eb36dc1 | ||
|
68a77d586b | ||
|
ece65b089f | ||
|
ded7702c92 | ||
|
c68327cde9 | ||
|
b5d8f55b65 | ||
|
d6d894d93a | ||
|
0a52e65f2e |
|
@ -57,6 +57,21 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="application/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.settings.system.SettingsActivity"
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
|||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import com.anytypeio.anytype.domain.device.FileSharer
|
||||
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
|
@ -55,4 +56,5 @@ interface AddToAnytypeDependencies : ComponentDependencies {
|
|||
fun urlBuilder(): UrlBuilder
|
||||
fun awaitAccountStartedManager(): AwaitAccountStartManager
|
||||
fun analytics(): Analytics
|
||||
fun fileSharer(): FileSharer
|
||||
}
|
|
@ -4,10 +4,13 @@ import android.content.Context
|
|||
import com.anytypeio.anytype.data.auth.other.DataDownloader
|
||||
import com.anytypeio.anytype.data.auth.other.Device
|
||||
import com.anytypeio.anytype.device.DefaultLocalProvider
|
||||
import com.anytypeio.anytype.device.SharedFileUploader
|
||||
import com.anytypeio.anytype.device.base.AndroidDevice
|
||||
import com.anytypeio.anytype.device.download.AndroidDeviceDownloader
|
||||
import com.anytypeio.anytype.domain.device.FileSharer
|
||||
import com.anytypeio.anytype.domain.download.Downloader
|
||||
import com.anytypeio.anytype.domain.misc.LocaleProvider
|
||||
import com.anytypeio.anytype.providers.DefaultUriFileProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
@ -40,4 +43,9 @@ object DeviceModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideLocaleProvider(context: Context): LocaleProvider = DefaultLocalProvider(context)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFileSharer(context: Context): FileSharer = SharedFileUploader(context)
|
||||
}
|
|
@ -3,8 +3,11 @@ package com.anytypeio.anytype.ui.main
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
|
@ -18,6 +21,7 @@ import com.anytypeio.anytype.R
|
|||
import com.anytypeio.anytype.app.DefaultAppActionManager
|
||||
import com.anytypeio.anytype.core_models.ThemeMode
|
||||
import com.anytypeio.anytype.core_models.Wallpaper
|
||||
import com.anytypeio.anytype.core_utils.ext.Mimetype
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
|
@ -31,12 +35,15 @@ import com.anytypeio.anytype.presentation.main.MainViewModel
|
|||
import com.anytypeio.anytype.presentation.main.MainViewModel.Command
|
||||
import com.anytypeio.anytype.presentation.main.MainViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.navigation.AppNavigation
|
||||
import com.anytypeio.anytype.presentation.util.getExternalFilesDirTemp
|
||||
import com.anytypeio.anytype.presentation.wallpaper.WallpaperColor
|
||||
import com.anytypeio.anytype.ui.editor.CreateObjectFragment
|
||||
import com.anytypeio.anytype.ui.sharing.SharingFragment
|
||||
import com.anytypeio.anytype.ui_settings.appearance.ThemeApplicator
|
||||
import com.github.javiersantos.appupdater.AppUpdater
|
||||
import com.github.javiersantos.appupdater.enums.UpdateFrom
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
@ -107,8 +114,20 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
|
|||
)
|
||||
)
|
||||
}
|
||||
is Command.AddToAnytype -> {
|
||||
SharingFragment.new(command.data).show(
|
||||
is Command.Sharing.Text -> {
|
||||
SharingFragment.text(command.data).show(
|
||||
supportFragmentManager,
|
||||
SHARE_DIALOG_LABEL
|
||||
)
|
||||
}
|
||||
is Command.Sharing.Image -> {
|
||||
SharingFragment.image(command.path).show(
|
||||
supportFragmentManager,
|
||||
SHARE_DIALOG_LABEL
|
||||
)
|
||||
}
|
||||
is Command.Sharing.Images -> {
|
||||
SharingFragment.images(command.uris).show(
|
||||
supportFragmentManager,
|
||||
SHARE_DIALOG_LABEL
|
||||
)
|
||||
|
@ -121,8 +140,11 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
|
|||
}
|
||||
}
|
||||
}
|
||||
if (savedInstanceState == null && intent.action == Intent.ACTION_SEND) {
|
||||
proceedWithShareIntent(intent)
|
||||
if (savedInstanceState == null) {
|
||||
val action = intent.action
|
||||
if (action == Intent.ACTION_SEND || action == Intent.ACTION_SEND_MULTIPLE) {
|
||||
proceedWithShareIntent(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,6 +194,9 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
|
|||
Intent.ACTION_SEND -> {
|
||||
proceedWithShareIntent(intent)
|
||||
}
|
||||
Intent.ACTION_SEND_MULTIPLE -> {
|
||||
proceedWithShareIntent(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
|
@ -180,8 +205,170 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
|
|||
}
|
||||
|
||||
private fun proceedWithShareIntent(intent: Intent) {
|
||||
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
|
||||
vm.onIntentShare(it)
|
||||
Timber.d("Got intent: $intent")
|
||||
when {
|
||||
intent.type == Mimetype.MIME_TEXT_PLAIN.value -> {
|
||||
vm.onIntentTextShare(intent.getStringExtra(Intent.EXTRA_TEXT).orEmpty())
|
||||
}
|
||||
intent.type?.startsWith("image/") == true -> {
|
||||
if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
|
||||
val extras = intent
|
||||
.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)
|
||||
?: arrayListOf()
|
||||
val uris = extras.mapNotNull { extra ->
|
||||
if (extra is Uri)
|
||||
extra.toString()
|
||||
else
|
||||
null
|
||||
}
|
||||
Timber.d("Parsed multiple uris: ${uris}")
|
||||
vm.onIntentMultipleImageShare(uris)
|
||||
} else {
|
||||
proceedWithReceivingImage(intent)
|
||||
}
|
||||
}
|
||||
intent.type?.startsWith("application/") == true -> {
|
||||
if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
|
||||
// TODO
|
||||
} else {
|
||||
proceedWithReceivingFile(intent)
|
||||
}
|
||||
Mimetype.MIME_FILE_ALL
|
||||
}
|
||||
intent.type == Mimetype.MIME_FILE_ALL.value -> {
|
||||
if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
|
||||
val extras = intent
|
||||
.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)
|
||||
?: arrayListOf()
|
||||
val uris = extras.mapNotNull { extra ->
|
||||
if (extra is Uri)
|
||||
extra.toString()
|
||||
else
|
||||
null
|
||||
}
|
||||
Timber.d("Parsed multiple uris: ${uris}")
|
||||
vm.onIntentMultipleImageShare(uris)
|
||||
}
|
||||
}
|
||||
else -> Timber.e("Unexpected scenario: ${intent.type}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithReceivingFile(intent: Intent) {
|
||||
val extra = intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM)
|
||||
if (extra is Uri) {
|
||||
val name = if (extra.scheme == "content") {
|
||||
contentResolver.query(
|
||||
extra,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
val idx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||
if (idx != -1) {
|
||||
cursor.getString(idx)
|
||||
} else {
|
||||
"Untitled"
|
||||
}
|
||||
} else {
|
||||
"Untitled"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Timber.w("Not content scheme")
|
||||
extra.path!!.substring(extra.path!!.lastIndexOf("/"))
|
||||
}
|
||||
val inputStream = contentResolver.openInputStream(extra)
|
||||
var path = ""
|
||||
inputStream?.use { input ->
|
||||
val newFile = File(cacheDir?.path + "/" + name);
|
||||
FileOutputStream(newFile).use { output ->
|
||||
val buffer = ByteArray(1024)
|
||||
var read: Int = input.read(buffer)
|
||||
while (read != -1) {
|
||||
output.write(buffer, 0, read)
|
||||
read = input.read(buffer)
|
||||
}
|
||||
}
|
||||
path = newFile.path
|
||||
}
|
||||
|
||||
val parsed = runCatching { path }
|
||||
Timber.d("Parsed APPLICATION uri: ${parsed.getOrNull()} for path: ${extra.path} with scheme: ${extra.scheme}")
|
||||
parsed.fold(
|
||||
onSuccess = {
|
||||
vm.onIntentImageShare(it)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while parsing path")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithReceivingImage(intent: Intent) {
|
||||
val extra = intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM)
|
||||
if (extra is Uri) {
|
||||
Timber.d("Uri path: ${extra.path}")
|
||||
val name = if (extra.scheme == "content") {
|
||||
contentResolver.query(
|
||||
extra,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
val result = if (cursor != null && cursor.moveToFirst()) {
|
||||
val idx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||
if (idx != -1) {
|
||||
cursor.getString(idx)
|
||||
} else {
|
||||
"Untitled"
|
||||
}
|
||||
} else {
|
||||
"Untitled"
|
||||
}
|
||||
cursor?.close()
|
||||
result
|
||||
}
|
||||
} else {
|
||||
extra.path!!.substring(extra.path!!.lastIndexOf("/"))
|
||||
}
|
||||
Timber.d("Extracted name: $name")
|
||||
val inputStream = contentResolver.openInputStream(extra)
|
||||
val cacheDir = context.getExternalFilesDirTemp()
|
||||
if (cacheDir != null && !cacheDir.exists()) {
|
||||
Timber.d("Created temp dir")
|
||||
cacheDir.mkdirs()
|
||||
}
|
||||
var path = ""
|
||||
inputStream?.use { input ->
|
||||
val newFile = File(cacheDir?.path + "/" + name);
|
||||
FileOutputStream(newFile).use { output ->
|
||||
val buffer = ByteArray(1024)
|
||||
var read: Int = input.read(buffer)
|
||||
while (read != -1) {
|
||||
output.write(buffer, 0, read)
|
||||
read = input.read(buffer)
|
||||
}
|
||||
}
|
||||
path = newFile.path
|
||||
}
|
||||
|
||||
val parsed = runCatching { path }
|
||||
Timber.d("Parse IMAGE uri: ${parsed.getOrNull()} for path: ${extra.path} with scheme: ${extra.scheme}")
|
||||
parsed.fold(
|
||||
onSuccess = {
|
||||
vm.onIntentImageShare(it)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while parsing path")
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Timber.w("URI not found")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,14 +80,16 @@ fun AddToAnytypeScreen(
|
|||
onSelectSpaceClicked: (SpaceView) -> Unit
|
||||
) {
|
||||
var isSaveAsMenuExpanded by remember { mutableStateOf(false) }
|
||||
val items = if (data is SharingData.Url)
|
||||
listOf(SAVE_AS_NOTE, SAVE_AS_BOOKMARK)
|
||||
else
|
||||
listOf(SAVE_AS_NOTE)
|
||||
val items = when (data) {
|
||||
is SharingData.Url -> listOf(SAVE_AS_NOTE, SAVE_AS_BOOKMARK)
|
||||
is SharingData.Image -> listOf(SAVE_AS_IMAGE)
|
||||
else -> listOf(SAVE_AS_NOTE)
|
||||
}
|
||||
var selectedIndex by remember {
|
||||
mutableStateOf(
|
||||
when(data) {
|
||||
is SharingData.Url -> SAVE_AS_BOOKMARK
|
||||
is SharingData.Image -> SAVE_AS_IMAGE
|
||||
else -> SAVE_AS_NOTE
|
||||
}
|
||||
)
|
||||
|
@ -111,10 +113,11 @@ fun AddToAnytypeScreen(
|
|||
)
|
||||
|
||||
Text(
|
||||
text = if (selectedIndex == SAVE_AS_BOOKMARK)
|
||||
stringResource(id = R.string.sharing_menu_save_as_bookmark_option)
|
||||
else
|
||||
stringResource(id = R.string.sharing_menu_save_as_note_option),
|
||||
text = when (selectedIndex) {
|
||||
SAVE_AS_BOOKMARK -> stringResource(id = R.string.sharing_menu_save_as_bookmark_option)
|
||||
SAVE_AS_IMAGE -> stringResource(id = R.string.sharing_menu_save_as_image_option)
|
||||
else -> stringResource(id = R.string.sharing_menu_save_as_note_option)
|
||||
},
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.padding(bottom = 14.dp, start = 20.dp),
|
||||
|
@ -390,6 +393,7 @@ private fun SmallSpaceIcon(
|
|||
|
||||
const val SAVE_AS_NOTE = 0
|
||||
const val SAVE_AS_BOOKMARK = 1
|
||||
const val SAVE_AS_IMAGE = 2
|
||||
typealias SaveAsOption = Int
|
||||
|
||||
sealed class SharingData {
|
||||
|
@ -402,4 +406,13 @@ sealed class SharingData {
|
|||
override val data: String
|
||||
get() = raw
|
||||
}
|
||||
data class Image(val path: String) : SharingData() {
|
||||
override val data: String
|
||||
get() = path
|
||||
}
|
||||
|
||||
data class Images(val uris: List<String>): SharingData() {
|
||||
override val data: String
|
||||
get() = uris.toString()
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
import com.anytypeio.anytype.core_utils.ext.argStringList
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
|
@ -22,16 +23,28 @@ import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
|
|||
import com.anytypeio.anytype.presentation.sharing.AddToAnytypeViewModel
|
||||
import com.anytypeio.anytype.ui.editor.EditorFragment
|
||||
import com.anytypeio.anytype.ui.settings.typography
|
||||
import java.lang.IllegalStateException
|
||||
import javax.inject.Inject
|
||||
|
||||
class SharingFragment : BaseBottomSheetComposeFragment() {
|
||||
|
||||
private val sharedData : SharingData get() {
|
||||
val result = arg<String>(SHARING_DATE_KEY)
|
||||
return if (URLUtil.isValidUrl(result)) {
|
||||
SharingData.Url(result)
|
||||
} else {
|
||||
SharingData.Raw(result)
|
||||
val args = requireArguments()
|
||||
return if (args.containsKey(SHARING_TEXT_KEY)) {
|
||||
val result = arg<String>(SHARING_TEXT_KEY)
|
||||
if (URLUtil.isValidUrl(result)) {
|
||||
SharingData.Url(result)
|
||||
} else {
|
||||
SharingData.Raw(result)
|
||||
}
|
||||
} else if (args.containsKey(SHARING_IMAGE_KEY)) {
|
||||
val result = arg<String>(SHARING_IMAGE_KEY)
|
||||
SharingData.Image(path = result)
|
||||
} else if (args.containsKey(SHARING_MULTIPLE_IMAGES_KEY)) {
|
||||
val result = argStringList(SHARING_MULTIPLE_IMAGES_KEY)
|
||||
SharingData.Images(uris = result)
|
||||
}else {
|
||||
throw IllegalStateException("Unexpected result")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,10 +66,14 @@ class SharingFragment : BaseBottomSheetComposeFragment() {
|
|||
AddToAnytypeScreen(
|
||||
data = sharedData,
|
||||
onDoneClicked = { option ->
|
||||
when(option) {
|
||||
SAVE_AS_BOOKMARK -> vm.onCreateBookmark(url = sharedData.data)
|
||||
SAVE_AS_NOTE -> vm.onCreateNote(sharedData.data)
|
||||
}
|
||||
// when(option) {
|
||||
// SAVE_AS_BOOKMARK -> vm.onCreateBookmark(url = sharedData.data)
|
||||
// SAVE_AS_NOTE -> vm.onCreateNote(sharedData.data)
|
||||
// SAVE_AS_IMAGE -> vm.onUploadImage(sharedData.data)
|
||||
// }
|
||||
vm.onShareImages(
|
||||
uris = (sharedData as SharingData.Images).uris
|
||||
)
|
||||
},
|
||||
onCancelClicked = {
|
||||
vm.onCancelClicked().also {
|
||||
|
@ -120,9 +137,20 @@ class SharingFragment : BaseBottomSheetComposeFragment() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
private const val SHARING_DATE_KEY = "arg.sharing.data-key"
|
||||
fun new(data: String) : SharingFragment = SharingFragment().apply {
|
||||
arguments = bundleOf(SHARING_DATE_KEY to data)
|
||||
private const val SHARING_TEXT_KEY = "arg.sharing.text-key"
|
||||
private const val SHARING_IMAGE_KEY = "arg.sharing.image-key"
|
||||
private const val SHARING_MULTIPLE_IMAGES_KEY = "arg.sharing.multiple-images-key"
|
||||
|
||||
fun text(data: String) : SharingFragment = SharingFragment().apply {
|
||||
arguments = bundleOf(SHARING_TEXT_KEY to data)
|
||||
}
|
||||
|
||||
fun image(image: String) : SharingFragment = SharingFragment().apply {
|
||||
arguments = bundleOf(SHARING_IMAGE_KEY to image)
|
||||
}
|
||||
|
||||
fun images(uris: List<String>) : SharingFragment = SharingFragment().apply {
|
||||
arguments = bundleOf(SHARING_MULTIPLE_IMAGES_KEY to ArrayList(uris))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -218,7 +218,7 @@ data class Block(
|
|||
|
||||
/**
|
||||
* File block.
|
||||
* @property hash file hash
|
||||
* @property targetObjectId id of the target object
|
||||
* @property name filename
|
||||
* @property mime mime type
|
||||
* @property size file size (in bytes)
|
||||
|
@ -226,7 +226,7 @@ data class Block(
|
|||
* @property state file state
|
||||
*/
|
||||
data class File(
|
||||
val hash: String? = null,
|
||||
val targetObjectId: Id? = null,
|
||||
val name: String? = null,
|
||||
val mime: String? = null,
|
||||
val size: Long? = null,
|
||||
|
@ -397,7 +397,8 @@ data class Block(
|
|||
|
||||
data class File(
|
||||
val type: Content.File.Type,
|
||||
val state: Content.File.State
|
||||
val state: Content.File.State,
|
||||
val targetObjectId: Id? = null
|
||||
) : Prototype()
|
||||
|
||||
data class Link(
|
||||
|
|
|
@ -21,13 +21,14 @@ sealed class Command {
|
|||
) : Command()
|
||||
|
||||
class UploadFile(
|
||||
val space: SpaceId? = null,
|
||||
val path: String,
|
||||
val type: Block.Content.File.Type?
|
||||
)
|
||||
|
||||
class DownloadFile(
|
||||
val path: String,
|
||||
val hash: Hash
|
||||
val objectId: Id
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -177,11 +177,11 @@ sealed class Event {
|
|||
*/
|
||||
data class UpdateFileBlock(
|
||||
override val context: String,
|
||||
val id: Id,
|
||||
val blockId: Id,
|
||||
val targetObjectId: Id? = null,
|
||||
val state: Block.Content.File.State? = null,
|
||||
val type: Block.Content.File.Type? = null,
|
||||
val name: String? = null,
|
||||
val hash: String? = null,
|
||||
val mime: String? = null,
|
||||
val size: Long? = null
|
||||
) : Command()
|
||||
|
|
|
@ -296,4 +296,17 @@ sealed class ObjectWrapper {
|
|||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
data class File(override val map: Struct) : ObjectWrapper() {
|
||||
private val default = map.withDefault { null }
|
||||
val id: Id by default
|
||||
val name: String? by default
|
||||
val description: String? by default
|
||||
val fileExt: String? by default
|
||||
val fileMimeType: String? by default
|
||||
val sizeInBytes: Double? by default
|
||||
val url: String? by default
|
||||
val isArchived: Boolean? by default
|
||||
val isDeleted: Boolean? by default
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ sealed class Response {
|
|||
|
||||
sealed class Media : Response() {
|
||||
class Upload(
|
||||
val hash: String
|
||||
val objectId: Id
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBookmarkBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBookmarkErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBookmarkUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBulletedBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockCalloutBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockCheckboxBinding
|
||||
|
@ -29,13 +27,12 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockDividerDotsBinding
|
|||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockDividerLineBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFeaturedRelationsBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockHeaderOneBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockHeaderThreeBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockHeaderTwoBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockHighlightBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockLatexBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockNumberedBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkArchiveBinding
|
||||
|
@ -47,8 +44,6 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkCardSmallIco
|
|||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkDeleteBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockObjectLinkLoadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationCheckboxBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationDefaultBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockRelationDeletedBinding
|
||||
|
@ -66,8 +61,6 @@ import com.anytypeio.anytype.core_ui.databinding.ItemBlockTocBinding
|
|||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockToggleBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockUnsupportedBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Payload
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.holders.dataview.DataViewBlockDefaultHolder
|
||||
|
@ -528,12 +521,12 @@ class BlockAdapter(
|
|||
}
|
||||
HOLDER_FILE_UPLOAD -> {
|
||||
FileUpload(
|
||||
ItemBlockFileUploadingBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaPlaceholderBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_FILE_ERROR -> {
|
||||
FileError(
|
||||
ItemBlockFileErrorBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaErrorBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_VIDEO -> {
|
||||
|
@ -548,12 +541,12 @@ class BlockAdapter(
|
|||
}
|
||||
HOLDER_VIDEO_UPLOAD -> {
|
||||
VideoUpload(
|
||||
ItemBlockVideoUploadingBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaPlaceholderBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_VIDEO_ERROR -> {
|
||||
VideoError(
|
||||
ItemBlockVideoErrorBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaErrorBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_OBJECT_LINK_DEFAULT -> {
|
||||
|
@ -681,12 +674,12 @@ class BlockAdapter(
|
|||
}
|
||||
HOLDER_BOOKMARK_ERROR -> {
|
||||
BookmarkError(
|
||||
ItemBlockBookmarkErrorBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaErrorBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_BOOKMARK_UPLOAD -> {
|
||||
BookmarkUpload(
|
||||
ItemBlockBookmarkUploadingBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaPlaceholderBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_PICTURE -> {
|
||||
|
@ -701,12 +694,12 @@ class BlockAdapter(
|
|||
}
|
||||
HOLDER_PICTURE_UPLOAD -> {
|
||||
PictureUpload(
|
||||
ItemBlockPictureUploadingBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaPlaceholderBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_PICTURE_ERROR -> {
|
||||
PictureError(
|
||||
ItemBlockPictureErrorBinding.inflate(inflater, parent, false)
|
||||
ItemBlockMediaErrorBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
HOLDER_DIVIDER_LINE -> {
|
||||
|
|
|
@ -36,6 +36,19 @@ interface DecoratableCardViewHolder : DecoratableViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
interface DecoratableMediaErrorViewHolder : DecoratableViewHolder {
|
||||
val decoratableCard: View
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
decoratableContainer.decorate(decorations) { rect ->
|
||||
decoratableCard.applyMediaErrorDecorations<FrameLayout.LayoutParams>(
|
||||
rect = rect,
|
||||
res = decoratableCard.resources
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applying decorations for card blocks (media blocks, placeholders, link-to-objects, bookmarks, etc.)
|
||||
*/
|
||||
|
@ -62,4 +75,18 @@ inline fun <reified LP : ViewGroup.MarginLayoutParams> View.applySelectorOffset(
|
|||
marginEnd = content.marginEnd - selectorLeftRightOffset
|
||||
topMargin = content.marginTop
|
||||
bottomMargin = content.marginBottom
|
||||
}
|
||||
|
||||
/**
|
||||
* Applying decorations for media error blocks
|
||||
*/
|
||||
inline fun <reified LP : ViewGroup.MarginLayoutParams> View.applyMediaErrorDecorations(
|
||||
rect: Rect,
|
||||
res: Resources
|
||||
) = updateLayoutParams<LP> {
|
||||
val defaultIndentOffset = res.getDimension(R.dimen.default_indent).toInt()
|
||||
marginStart = defaultIndentOffset + rect.left
|
||||
marginEnd = defaultIndentOffset + rect.right
|
||||
topMargin = res.getDimension(R.dimen.card_block_extra_space_top).toInt()
|
||||
bottomMargin = res.getDimension(R.dimen.dp_8).toInt() + rect.bottom
|
||||
}
|
|
@ -1,35 +1,14 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.error
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBookmarkErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class BookmarkError(
|
||||
val binding: ItemBlockBookmarkErrorBinding
|
||||
) : MediaError(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = binding.bookmarkErrorRoot
|
||||
private val urlView: TextView = binding.errorBookmarkUrl
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
override val decoratableCard: View
|
||||
get() = binding.card
|
||||
|
||||
fun setUrl(url: String) {
|
||||
urlView.text = url.ifEmpty { null }
|
||||
}
|
||||
binding: ItemBlockMediaErrorBinding
|
||||
) : MediaError(binding) {
|
||||
|
||||
override fun errorClick(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
if (item is BlockView.Error.Bookmark) {
|
||||
|
@ -37,20 +16,11 @@ class BookmarkError(
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_bookmark_inactive))
|
||||
if (item is BlockView.Error.Bookmark) {
|
||||
binding.fileName.text = item.url.ifEmpty { null }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +1,30 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.error
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class FileError(
|
||||
val binding: ItemBlockFileErrorBinding
|
||||
) : MediaError(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
override val decoratableCard: View
|
||||
get() = binding.card
|
||||
binding: ItemBlockMediaErrorBinding
|
||||
) : MediaError(binding) {
|
||||
|
||||
override fun errorClick(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.File.Error(item.id))
|
||||
if (item is BlockView.Error.File) {
|
||||
clicked(ListenerType.File.Error(item.id))
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
if (item is BlockView.Error.File) {
|
||||
binding.fileName.text = if (item.name.isNullOrBlank()) {
|
||||
itemView.resources.getString(R.string.hint_upload_file)
|
||||
} else
|
||||
item.name
|
||||
}
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_file_light_inactive))
|
||||
}
|
||||
}
|
|
@ -1,24 +1,31 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.error
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.marginEnd
|
||||
import androidx.core.view.marginStart
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.EditorTouchProcessor
|
||||
import com.anytypeio.anytype.core_ui.features.editor.SupportCustomTouchProcessor
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableMediaErrorViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
abstract class MediaError(
|
||||
view: View
|
||||
) : BlockViewHolder(view),
|
||||
val binding: ItemBlockMediaErrorBinding
|
||||
) : BlockViewHolder(binding.root),
|
||||
BlockViewHolder.IndentableHolder,
|
||||
BlockViewHolder.DragAndDropHolder,
|
||||
SupportCustomTouchProcessor {
|
||||
SupportCustomTouchProcessor, DecoratableMediaErrorViewHolder {
|
||||
|
||||
abstract val root: View
|
||||
override val decoratableContainer: EditorDecorationContainer get() = binding.decorationContainer
|
||||
override val decoratableCard: View get() = binding.card
|
||||
val errorIcon: View get() = binding.errorMessage
|
||||
abstract fun errorClick(item: BlockView.Error, clicked: (ListenerType) -> Unit)
|
||||
abstract override fun indentize(item: BlockView.Indentable)
|
||||
abstract fun select(isSelected: Boolean)
|
||||
|
||||
override val editorTouchProcessor = EditorTouchProcessor(
|
||||
fallback = { e -> itemView.onTouchEvent(e) }
|
||||
|
@ -28,23 +35,45 @@ abstract class MediaError(
|
|||
itemView.setOnTouchListener { v, e -> editorTouchProcessor.process(v, e) }
|
||||
}
|
||||
|
||||
fun bind(
|
||||
open fun bind(
|
||||
item: BlockView.Error,
|
||||
clicked: (ListenerType) -> Unit
|
||||
) {
|
||||
indentize(item)
|
||||
select(item.isSelected)
|
||||
with(itemView) {
|
||||
setOnClickListener { errorClick(item, clicked) }
|
||||
}
|
||||
}
|
||||
|
||||
fun processChangePayload(payloads: List<BlockViewDiffUtil.Payload>, item: BlockView) {
|
||||
check(item is BlockView.Error) { "Expected error block, but was: $item" }
|
||||
open fun processChangePayload(payloads: List<BlockViewDiffUtil.Payload>, item: BlockView) {
|
||||
check(item is BlockView.Error) { "Expected error media block, but was: $item" }
|
||||
payloads.forEach { payload ->
|
||||
if (payload.isSelectionChanged) {
|
||||
itemView.isSelected = item.isSelected
|
||||
select(item.isSelected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
val selectorLeftRightOffset = itemView.resources.getDimension(R.dimen.selection_left_right_offset).toInt()
|
||||
marginStart = binding.card.marginStart - selectorLeftRightOffset
|
||||
marginEnd = binding.card.marginEnd - selectorLeftRightOffset
|
||||
topMargin = itemView.resources.getDimension(R.dimen.card_block_extra_space_top).toInt()
|
||||
bottomMargin = 0
|
||||
}
|
||||
errorIcon.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
marginStart = binding.card.marginStart
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
|
@ -1,48 +1,30 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.error
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class PictureError(
|
||||
val binding: ItemBlockPictureErrorBinding
|
||||
) : MediaError(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
override val decoratableCard: View
|
||||
get() = binding.card
|
||||
binding: ItemBlockMediaErrorBinding
|
||||
) : MediaError(binding) {
|
||||
|
||||
override fun errorClick(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.Picture.Error(item.id))
|
||||
if (item is BlockView.Error.Picture) {
|
||||
clicked(ListenerType.Picture.Error(item.id))
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
if (item is BlockView.Error.Picture) {
|
||||
binding.fileName.text = if (item.name.isNullOrBlank()) {
|
||||
itemView.resources.getString(R.string.hint_upload_image)
|
||||
} else
|
||||
item.name
|
||||
}
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_picture_inactive))
|
||||
}
|
||||
}
|
|
@ -1,48 +1,30 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.error
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaErrorBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class VideoError(
|
||||
val binding: ItemBlockVideoErrorBinding
|
||||
) : MediaError(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
override val decoratableCard: View
|
||||
get() = binding.card
|
||||
binding: ItemBlockMediaErrorBinding
|
||||
) : MediaError(binding) {
|
||||
|
||||
override fun errorClick(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.Video.Error(item.id))
|
||||
if (item is BlockView.Error.Video) {
|
||||
clicked(ListenerType.Video.Error(item.id))
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Error, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
if (item is BlockView.Error.Video) {
|
||||
binding.fileName.text = if (item.name.isNullOrBlank()) {
|
||||
itemView.resources.getString(R.string.hint_upload_video)
|
||||
} else
|
||||
item.name
|
||||
}
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_video_inactive))
|
||||
}
|
||||
}
|
|
@ -45,9 +45,22 @@ class File(val binding: ItemBlockFileBinding) : Media(binding.root), Decoratable
|
|||
name.enableReadMode()
|
||||
if (item.size != null && item.name != null) {
|
||||
val size = item.size!!.readableFileSize()
|
||||
val spannable = SpannableString("${item.name} $size")
|
||||
val start = item.name!!.length + 2
|
||||
val end = item.name!!.length + 2 + size.length
|
||||
|
||||
val spannable = if (item.fileExt.isNullOrBlank()) {
|
||||
SpannableString("${item.name} $size")
|
||||
} else {
|
||||
SpannableString("${item.name}.${item.fileExt} $size")
|
||||
}
|
||||
val start = if (item.fileExt.isNullOrBlank()) {
|
||||
item.name!!.length + 2
|
||||
} else {
|
||||
item.name!!.length + item.fileExt!!.length + 2
|
||||
}
|
||||
val end = if (item.fileExt.isNullOrBlank()) {
|
||||
item.name!!.length + 2 + size.length
|
||||
} else {
|
||||
item.name!!.length + item.fileExt!!.length + 3 + size.length
|
||||
}
|
||||
spannable.setSpan(
|
||||
RelativeSizeSpan(0.87f),
|
||||
start,
|
||||
|
|
|
@ -2,9 +2,8 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.placeholders
|
|||
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class BookmarkPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlaceholder(binding) {
|
||||
|
||||
|
@ -14,15 +13,6 @@ class BookmarkPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlac
|
|||
|
||||
override fun setup() {
|
||||
title.text = itemView.resources.getString(R.string.hint_add_a_web_bookmark)
|
||||
title.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_bookmark_placeholder, 0, 0, 0)
|
||||
}
|
||||
|
||||
override fun processChangePayload(payloads: List<BlockViewDiffUtil.Payload>, item: BlockView) {
|
||||
super.processChangePayload(payloads, item)
|
||||
// TODO process loading state changes
|
||||
}
|
||||
|
||||
fun isLoading(boolean: Boolean) {
|
||||
// TODO process loading state changes
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_bookmark_placeholder))
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.placeholders
|
|||
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
|
||||
class FilePlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlaceholder(binding) {
|
||||
|
@ -12,6 +13,6 @@ class FilePlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlacehol
|
|||
|
||||
override fun setup() {
|
||||
title.text = itemView.resources.getString(R.string.hint_upload_file)
|
||||
title.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_file_light, 0, 0, 0)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_file_light))
|
||||
}
|
||||
}
|
|
@ -3,11 +3,6 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.placeholders
|
|||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.veryLight
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
|
||||
|
@ -17,8 +12,7 @@ import com.anytypeio.anytype.core_ui.features.editor.SupportCustomTouchProcessor
|
|||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_models.ThemeColor
|
||||
import com.anytypeio.anytype.core_utils.ext.invisible
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
@ -33,7 +27,7 @@ abstract class MediaPlaceholder(
|
|||
|
||||
protected val root: View = binding.root
|
||||
protected val card: MaterialCardView = binding.card
|
||||
protected val title: TextView = binding.title
|
||||
protected val title: TextView = binding.fileName
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
|
@ -61,6 +55,7 @@ abstract class MediaPlaceholder(
|
|||
with(itemView) {
|
||||
setOnClickListener { placeholderClick(item.id, clicked) }
|
||||
}
|
||||
binding.progressBar.invisible()
|
||||
}
|
||||
|
||||
open fun processChangePayload(payloads: List<BlockViewDiffUtil.Payload>, item: BlockView) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.placeholders
|
|||
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
|
||||
class PicturePlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlaceholder(binding) {
|
||||
|
@ -12,6 +13,6 @@ class PicturePlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlace
|
|||
|
||||
override fun setup() {
|
||||
title.text = itemView.resources.getString(R.string.hint_upload_image)
|
||||
title.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_picture, 0, 0, 0)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_picture))
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.core_ui.features.editor.holders.placeholders
|
|||
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
|
||||
class VideoPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlaceholder(binding) {
|
||||
|
@ -12,6 +13,6 @@ class VideoPlaceholder(binding: ItemBlockMediaPlaceholderBinding) : MediaPlaceho
|
|||
|
||||
override fun setup() {
|
||||
title.text = itemView.resources.getString(R.string.hint_upload_video)
|
||||
title.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_video, 0, 0, 0)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_video))
|
||||
}
|
||||
}
|
|
@ -1,54 +1,27 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.upload
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import com.anytypeio.anytype.core_models.Url
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockBookmarkUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class BookmarkUpload(
|
||||
private val binding: ItemBlockBookmarkUploadingBinding
|
||||
) : MediaUpload(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
|
||||
override val decoratableCard: View = binding.card
|
||||
binding: ItemBlockMediaPlaceholderBinding
|
||||
) : MediaUpload(binding), DecoratableCardViewHolder {
|
||||
|
||||
override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.File.Upload(target))
|
||||
clicked(ListenerType.Bookmark.Upload(target))
|
||||
}
|
||||
|
||||
fun setUrl(url: Url?) {
|
||||
binding.editUrl.text = url
|
||||
binding.fileName.text = url
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Upload, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_bookmark_inactive))
|
||||
}
|
||||
}
|
|
@ -1,47 +1,22 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.upload
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockFileUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class FileUpload(
|
||||
private val binding: ItemBlockFileUploadingBinding
|
||||
) : MediaUpload(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
|
||||
override val decoratableCard: View = binding.card
|
||||
binding: ItemBlockMediaPlaceholderBinding
|
||||
) : MediaUpload(binding), DecoratableCardViewHolder {
|
||||
|
||||
override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.File.Upload(target))
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Upload, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_file_light_inactive))
|
||||
}
|
||||
}
|
|
@ -1,29 +1,27 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.upload
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import android.widget.FrameLayout
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
|
||||
import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.EditorTouchProcessor
|
||||
import com.anytypeio.anytype.core_ui.features.editor.SupportCustomTouchProcessor
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
abstract class MediaUpload(
|
||||
view: View
|
||||
) : BlockViewHolder(view),
|
||||
val binding: ItemBlockMediaPlaceholderBinding
|
||||
) : BlockViewHolder(binding.root),
|
||||
BlockViewHolder.IndentableHolder,
|
||||
SupportCustomTouchProcessor {
|
||||
SupportCustomTouchProcessor, DecoratableCardViewHolder {
|
||||
|
||||
abstract val root: View
|
||||
override val decoratableContainer: EditorDecorationContainer get() = binding.decorationContainer
|
||||
override val decoratableCard: View get() = binding.card
|
||||
abstract fun uploadClick(target: String, clicked: (ListenerType) -> Unit)
|
||||
abstract override fun indentize(item: BlockView.Indentable)
|
||||
abstract fun select(isSelected: Boolean)
|
||||
|
||||
override val editorTouchProcessor = EditorTouchProcessor(
|
||||
fallback = { e -> itemView.onTouchEvent(e) }
|
||||
|
@ -33,11 +31,10 @@ abstract class MediaUpload(
|
|||
itemView.setOnTouchListener { v, e -> editorTouchProcessor.process(v, e) }
|
||||
}
|
||||
|
||||
fun bind(
|
||||
open fun bind(
|
||||
item: BlockView.Upload,
|
||||
clicked: (ListenerType) -> Unit
|
||||
) {
|
||||
indentize(item)
|
||||
select(item.isSelected)
|
||||
with(itemView) {
|
||||
setOnClickListener { uploadClick(item.id, clicked) }
|
||||
|
@ -52,4 +49,21 @@ abstract class MediaUpload(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,38 +1,22 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.upload
|
||||
|
||||
import android.view.View
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockPictureUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class PictureUpload(
|
||||
private val binding: ItemBlockPictureUploadingBinding
|
||||
) : MediaUpload(binding.root), DecoratableViewHolder, DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
|
||||
override val decoratableCard: View get() = binding.card
|
||||
binding: ItemBlockMediaPlaceholderBinding
|
||||
) : MediaUpload(binding), DecoratableCardViewHolder {
|
||||
|
||||
override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.Video.Upload(target))
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
root.isSelected = isSelected
|
||||
override fun bind(item: BlockView.Upload, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_picture_inactive))
|
||||
}
|
||||
}
|
|
@ -1,47 +1,22 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.upload
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import com.anytypeio.anytype.core_ui.BuildConfig
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockVideoUploadingBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemBlockMediaPlaceholderBinding
|
||||
import com.anytypeio.anytype.core_ui.extensions.drawable
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.DecoratableCardViewHolder
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
import com.anytypeio.anytype.core_ui.features.editor.decoration.applySelectorOffset
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.indentize
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
||||
class VideoUpload(
|
||||
val binding: ItemBlockVideoUploadingBinding
|
||||
) : MediaUpload(binding.root), DecoratableCardViewHolder {
|
||||
|
||||
override val root: View = itemView
|
||||
|
||||
override val decoratableContainer: EditorDecorationContainer
|
||||
get() = binding.decorationContainer
|
||||
|
||||
override val decoratableCard: View = binding.card
|
||||
binding: ItemBlockMediaPlaceholderBinding
|
||||
) : MediaUpload(binding), DecoratableCardViewHolder {
|
||||
|
||||
override fun uploadClick(target: String, clicked: (ListenerType) -> Unit) {
|
||||
clicked(ListenerType.Video.Upload(target))
|
||||
}
|
||||
|
||||
@Deprecated("Pre-nested-styling legacy.")
|
||||
override fun indentize(item: BlockView.Indentable) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
override fun select(isSelected: Boolean) {
|
||||
binding.selected.isSelected = isSelected
|
||||
}
|
||||
|
||||
override fun applyDecorations(decorations: List<BlockView.Decoration>) {
|
||||
super.applyDecorations(decorations)
|
||||
binding.selected.applySelectorOffset<FrameLayout.LayoutParams>(
|
||||
content = binding.card,
|
||||
res = itemView.resources
|
||||
)
|
||||
override fun bind(item: BlockView.Upload, clicked: (ListenerType) -> Unit) {
|
||||
super.bind(item, clicked)
|
||||
binding.fileIcon.setImageDrawable(itemView.context.drawable(R.drawable.ic_video_inactive))
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="32"
|
||||
android:viewportHeight="32">
|
||||
<path
|
||||
android:pathData="M15.627,21.766L8.75,25.706V9C8.75,7.205 10.205,5.75 12,5.75H20C21.795,5.75 23.25,7.205 23.25,9V25.706L16.373,21.766L16,21.552L15.627,21.766Z"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/glyph_inactive"/>
|
||||
</vector>
|
11
core-ui/src/main/res/drawable/ic_bookmark_inactive.xml
Normal file
11
core-ui/src/main/res/drawable/ic_bookmark_inactive.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="25">
|
||||
<path
|
||||
android:pathData="M11.6272,18.0496L4.75,21.9896V5.2837C4.75,3.4888 6.2051,2.0337 8,2.0337H16C17.7949,2.0337 19.25,3.4888 19.25,5.2837V21.9896L12.3728,18.0496L12,17.836L11.6272,18.0496Z"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/glyph_inactive"/>
|
||||
</vector>
|
27
core-ui/src/main/res/drawable/ic_file_light_inactive.xml
Normal file
27
core-ui/src/main/res/drawable/ic_file_light_inactive.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="25">
|
||||
<path
|
||||
android:pathData="M12.2487,2.6655L13.2208,3.6377L5.1197,11.7388L4.1476,10.7667L12.2487,2.6655Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M18.7246,9.1415C20.0866,7.6118 20.0341,5.2662 18.5673,3.7994C17.1005,2.3326 14.7549,2.2801 13.2252,3.6421L12.2519,2.6687C14.3196,0.7706 17.5356,0.8235 19.5394,2.8273C21.5432,4.8311 21.5961,8.0471 19.698,10.1148L18.7246,9.1415Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M13.5449,20.164C11.2183,22.4905 7.4463,22.4905 5.1197,20.164C2.7932,17.8374 2.7932,14.0653 5.1197,11.7388L4.1476,10.7667C1.2841,13.6301 1.2841,18.2727 4.1476,21.1361C7.011,23.9996 11.6536,23.9996 14.517,21.1361L13.5449,20.164Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M14.193,6.5541L15.1651,7.5262L8.6842,14.0071L7.7121,13.035L14.193,6.5541Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M11.2766,16.5995C10.5607,17.3153 9.4001,17.3153 8.6842,16.5995C7.9683,15.8836 7.9683,14.723 8.6842,14.0071L7.7121,13.035C6.4593,14.2877 6.4593,16.3189 7.7121,17.5716C8.9648,18.8244 10.996,18.8244 12.2487,17.5716L11.2766,16.5995Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M18.7296,9.1464L19.7017,10.1186L12.2487,17.5716L11.2766,16.5995L18.7296,9.1464Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M20.6739,13.035L21.646,14.0071L14.517,21.1361L13.5449,20.164L20.6739,13.035Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
</vector>
|
17
core-ui/src/main/res/drawable/ic_picture_inactive.xml
Normal file
17
core-ui/src/main/res/drawable/ic_picture_inactive.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="25">
|
||||
<path
|
||||
android:pathData="M9,2.7837H15C16.4249,2.7837 17.4033,2.7849 18.1618,2.8468C18.9028,2.9074 19.3009,3.0184 19.589,3.1652C20.2475,3.5007 20.783,4.0362 21.1185,4.6947C21.2653,4.9828 21.3763,5.3808 21.4369,6.1219C21.4988,6.8804 21.5,7.8588 21.5,9.2837V15.2837C21.5,16.7086 21.4988,17.687 21.4369,18.4455C21.3763,19.1865 21.2653,19.5846 21.1185,19.8727C20.783,20.5312 20.2475,21.0667 19.589,21.4022C19.3009,21.549 18.9028,21.66 18.1618,21.7206C17.4033,21.7825 16.4249,21.7837 15,21.7837H9C7.5751,21.7837 6.5967,21.7825 5.8382,21.7206C5.0972,21.66 4.6991,21.549 4.411,21.4022C3.7525,21.0667 3.217,20.5312 2.8815,19.8727C2.7347,19.5846 2.6237,19.1865 2.5631,18.4455C2.5012,17.687 2.5,16.7086 2.5,15.2837V9.2837C2.5,7.8588 2.5012,6.8804 2.5631,6.1219C2.6237,5.3808 2.7347,4.9828 2.8815,4.6947C3.217,4.0362 3.7525,3.5007 4.411,3.1652C4.6991,3.0184 5.0972,2.9074 5.8382,2.8468C6.5967,2.7849 7.5751,2.7837 9,2.7837ZM22.455,4.0137C23,5.0833 23,6.4834 23,9.2837V15.2837C23,18.084 23,19.4841 22.455,20.5536C21.9757,21.4945 21.2108,22.2594 20.27,22.7387C19.2004,23.2837 17.8003,23.2837 15,23.2837H9C6.1997,23.2837 4.7996,23.2837 3.7301,22.7387C2.7892,22.2594 2.0243,21.4945 1.545,20.5536C1,19.4841 1,18.084 1,15.2837V9.2837C1,6.4834 1,5.0833 1.545,4.0137C2.0243,3.0729 2.7892,2.308 3.7301,1.8287C4.7996,1.2837 6.1997,1.2837 9,1.2837H15C17.8003,1.2837 19.2004,1.2837 20.27,1.8287C21.2108,2.308 21.9757,3.0729 22.455,4.0137Z"
|
||||
android:fillColor="@color/glyph_inactive"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M8.5,10.2837C7.3954,10.2837 6.5,9.3883 6.5,8.2837C6.5,7.1791 7.3954,6.2837 8.5,6.2837C9.6046,6.2837 10.5,7.1791 10.5,8.2837C10.5,9.3883 9.6046,10.2837 8.5,10.2837Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M14.5015,11.8428C14.5126,11.8539 14.5244,11.8656 14.5368,11.878L21.4712,18.773L22.5288,17.7094L15.5945,10.8143C15.5897,10.8096 15.585,10.8048 15.5802,10.8001C15.4938,10.7141 15.4001,10.6209 15.3124,10.5469C15.2131,10.463 15.0734,10.361 14.8849,10.3002C14.6341,10.2192 14.3642,10.2196 14.1137,10.3013C13.9254,10.3626 13.786,10.4651 13.6869,10.5492C13.5994,10.6235 13.506,10.717 13.4198,10.8031C13.4151,10.8079 13.4103,10.8127 13.4056,10.8174L9.5004,14.7226L8.0817,13.3018C7.9954,13.2153 7.9018,13.1215 7.8142,13.047C7.715,12.9627 7.5753,12.8599 7.3866,12.7985C7.1356,12.7167 6.8652,12.7165 6.6141,12.7979C6.4253,12.8591 6.2854,12.9616 6.1861,13.0458C6.0984,13.1202 6.0047,13.2138 5.9183,13.3001L1.47,17.7417L2.5299,18.8031L6.9638,14.3759C6.9763,14.3634 6.988,14.3517 6.9992,14.3406C7.0103,14.3517 7.0221,14.3635 7.0345,14.3759L9.4996,16.8447L14.4662,11.8781C14.4787,11.8656 14.4904,11.8539 14.5015,11.8428Z"
|
||||
android:fillColor="@color/glyph_inactive"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
18
core-ui/src/main/res/drawable/ic_video_inactive.xml
Normal file
18
core-ui/src/main/res/drawable/ic_video_inactive.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="25dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="25">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0.2837h24v24h-24z"/>
|
||||
<path
|
||||
android:pathData="M12,1.0337L12,1.0337A11.25,11.25 0,0 1,23.25 12.2837L23.25,12.2837A11.25,11.25 0,0 1,12 23.5337L12,23.5337A11.25,11.25 0,0 1,0.75 12.2837L0.75,12.2837A11.25,11.25 0,0 1,12 1.0337z"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="@color/glyph_inactive"/>
|
||||
<path
|
||||
android:pathData="M17.7526,12.7162C18.0852,12.5236 18.0852,12.0434 17.7526,11.8508L9.7505,7.2182C9.4172,7.0252 9,7.2657 9,7.6509V16.9165C9,17.3016 9.4172,17.5422 9.7505,17.3492L17.7526,12.7162Z"
|
||||
android:fillColor="@color/glyph_inactive"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -1,68 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/fileUploadingPlaceholderRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_48"
|
||||
android:background="@drawable/rectangle_media_block_placeholder">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivBookmark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:contentDescription="@string/content_description_bookmark_image"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_bookmark_block_loading" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editUrl"
|
||||
style="@style/TextView.ContentStyle.Relations.3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:inputType="none"
|
||||
android:hint="@string/loading_wait"
|
||||
android:textColor="@color/glyph_inactive"
|
||||
android:textColorHint="@color/glyph_inactive"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ivBookmark"
|
||||
app:layout_constraintStart_toEndOf="@+id/ivBookmark"
|
||||
app:layout_constraintTop_toTopOf="@+id/ivBookmark" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:indeterminateTint="@color/glyph_inactive"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/editUrl" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
tools:background="@drawable/item_block_multi_select_selected" />
|
||||
|
||||
</FrameLayout>
|
|
@ -18,6 +18,8 @@
|
|||
android:paddingEnd="@dimen/default_document_content_padding_start"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/dp_4"
|
||||
android:paddingBottom="@dimen/dp_4"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
tools:background="@drawable/item_block_multi_select_selected">
|
||||
|
||||
|
@ -30,17 +32,25 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/graphic"
|
||||
style="@style/DefaultGraphicTextBlockGraphicStyle"
|
||||
android:layout_width="@dimen/dp_24"
|
||||
android:layout_height="@dimen/dp_24"
|
||||
android:contentDescription="@string/content_description_file_icon"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:background="@drawable/ic_mime_image" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
android:id="@+id/text"
|
||||
style="@style/DefaultGraphicTextBlockTextStyle"
|
||||
style="@style/TextView.ContentStyle.Body.Regular"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:ellipsize="middle"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:background="@null"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/graphic"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/fileUploadingPlaceholderRoot"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_48"
|
||||
android:background="@drawable/rectangle_media_block_placeholder">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icFile"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:contentDescription="@string/content_description_file_icon"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_file_light" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editUrl"
|
||||
style="@style/UploadMediaInActiveTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:text="@string/loading_wait"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/icFile"
|
||||
app:layout_constraintStart_toEndOf="@+id/icFile"
|
||||
app:layout_constraintTop_toTopOf="@+id/icFile" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icMore"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_block_more" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:indeterminateTint="@color/glyph_inactive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
|
||||
app:layout_constraintStart_toEndOf="@+id/editUrl"
|
||||
app:layout_constraintTop_toTopOf="@+id/editUrl" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
tools:background="@drawable/item_block_multi_select_selected" />
|
||||
</FrameLayout>
|
87
core-ui/src/main/res/layout/item_block_media_error.xml
Normal file
87
core-ui/src/main/res/layout/item_block_media_error.xml
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card"
|
||||
style="@style/DefaultMediaPlaceholderBlockCardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fileIcon"
|
||||
android:layout_width="@dimen/dp_32"
|
||||
android:layout_height="@dimen/dp_32"
|
||||
android:scaleType="center"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_picture" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileName"
|
||||
style="@style/TextView.ContentStyle.Body.Callout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:drawablePadding="@dimen/default_media_placeholder_title_icon_padding"
|
||||
android:ellipsize="middle"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:text="@string/loading_please_wait"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/progressBar"
|
||||
app:layout_constraintStart_toEndOf="@+id/fileIcon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="https://github.com/anyproto/anytype-kotlin"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/try_again"
|
||||
style="@style/TextView.UXStyle.Captions.1.Medium"
|
||||
android:textColor="@color/text_primary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="@dimen/dp_12"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorMessage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="66dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:textColor="@color/palette_system_red"
|
||||
style="@style/TextView.UXStyle.Captions.2.Regular"
|
||||
android:text="@string/block_media_error"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
tools:background="@drawable/item_block_multi_select_selected" />
|
||||
</FrameLayout>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -14,22 +15,59 @@
|
|||
android:id="@+id/card"
|
||||
style="@style/DefaultMediaPlaceholderBlockCardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="52dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextView.ContentStyle.Body.Callout"
|
||||
android:textColor="@color/glyph_active"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/default_media_placeholder_title_margin_start"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:drawablePadding="@dimen/default_media_placeholder_title_icon_padding"
|
||||
android:gravity="center_vertical"
|
||||
tools:drawableStart="@drawable/ic_picture"
|
||||
tools:text="Add a web bookmark" />
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fileIcon"
|
||||
android:layout_width="@dimen/dp_32"
|
||||
android:layout_height="@dimen/dp_32"
|
||||
android:scaleType="center"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_picture" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileName"
|
||||
style="@style/TextView.ContentStyle.Body.Callout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:drawablePadding="@dimen/default_media_placeholder_title_icon_padding"
|
||||
android:ellipsize="middle"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:text="@string/loading_please_wait"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/progressBar"
|
||||
app:layout_constraintStart_toEndOf="@+id/fileIcon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="https://github.com/anyproto/anytype-kotlin"/>
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
app:trackColor="@color/glyph_inactive"
|
||||
app:indicatorColor="#B6B6B6"
|
||||
app:indicatorSize="20dp"
|
||||
app:trackThickness="@dimen/dp_2"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginEnd="@dimen/dp_12"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<View
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
style="@style/BlockMediaRootLayoutStyle"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_48"
|
||||
android:background="@drawable/rectangle_media_block_placeholder">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icPicture"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:contentDescription="@string/content_description_file_icon"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_file_light" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editUrl"
|
||||
style="@style/UploadMediaTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:inputType="none"
|
||||
android:text="@string/loading_wait"
|
||||
android:textColor="@color/glyph_active"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/icPicture"
|
||||
app:layout_constraintStart_toEndOf="@+id/icPicture"
|
||||
app:layout_constraintTop_toTopOf="@+id/icPicture" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:indeterminateTint="@color/glyph_inactive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
|
||||
app:layout_constraintStart_toEndOf="@+id/editUrl"
|
||||
app:layout_constraintTop_toTopOf="@+id/editUrl" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
|
@ -1,63 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/videoUploadingPlaceholderRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.features.editor.decoration.EditorDecorationContainer
|
||||
android:id="@+id/decorationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dp_48"
|
||||
android:background="@drawable/rectangle_media_block_placeholder">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icVideo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:contentDescription="@string/content_description_file_icon"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_video" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editUrl"
|
||||
style="@style/UploadMediaInActiveTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:text="@string/loading_wait"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/icVideo"
|
||||
app:layout_constraintStart_toEndOf="@+id/icVideo"
|
||||
app:layout_constraintTop_toTopOf="@+id/icVideo" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:indeterminateTint="@color/glyph_inactive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
|
||||
app:layout_constraintStart_toEndOf="@+id/editUrl"
|
||||
app:layout_constraintTop_toTopOf="@+id/editUrl" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/item_block_multi_select_mode_selector" />
|
||||
|
||||
</FrameLayout>
|
|
@ -652,16 +652,6 @@
|
|||
<item name="android:layout_marginTop">@dimen/default_graphic_text_graphic_margin_top</item>
|
||||
</style>
|
||||
|
||||
<!-- text -->
|
||||
<style name="DefaultGraphicTextBlockTextStyle" parent="TextView.ContentStyle.Body.Regular">
|
||||
<item name="android:layout_width">@dimen/default_graphic_text_graphic_width</item>
|
||||
<item name="android:layout_height">@dimen/default_graphic_text_graphic_width</item>
|
||||
<item name="android:layout_marginStart">@dimen/default_graphic_text_text_margin_start</item>
|
||||
<item name="android:paddingTop">@dimen/default_graphic_text_text_padding_top</item>
|
||||
<item name="android:paddingBottom">@dimen/default_graphic_text_text_padding_bottom</item>
|
||||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- Media placeholder {root {card {title}} selected}-->
|
||||
<!-- root -->
|
||||
<style name="DefaultMediaPlaceholderBlockRootStyle">
|
||||
|
|
|
@ -2281,7 +2281,7 @@ class BlockAdapterTest {
|
|||
val views = listOf(
|
||||
BlockView.Media.File(
|
||||
id = MockDataFactory.randomString(),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
indent = MockDataFactory.randomInt(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
size = MockDataFactory.randomLong(),
|
||||
|
@ -2292,7 +2292,7 @@ class BlockAdapterTest {
|
|||
),
|
||||
BlockView.Media.File(
|
||||
id = MockDataFactory.randomString(),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
indent = MockDataFactory.randomInt(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
size = MockDataFactory.randomLong(),
|
||||
|
@ -2330,7 +2330,7 @@ class BlockAdapterTest {
|
|||
|
||||
val file = BlockView.Media.File(
|
||||
id = MockDataFactory.randomString(),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
indent = MockDataFactory.randomInt(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
size = MockDataFactory.randomLong(),
|
||||
|
@ -2594,7 +2594,7 @@ class BlockAdapterTest {
|
|||
|
||||
private fun givenPicture() = BlockView.Media.Picture(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
indent = MockDataFactory.randomInt(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
name = MockDataFactory.randomString(),
|
||||
|
@ -2606,7 +2606,7 @@ class BlockAdapterTest {
|
|||
private fun givenVideo() = BlockView.Media.Video(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
indent = MockDataFactory.randomInt(),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
url = MockDataFactory.randomString(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
name = MockDataFactory.randomString(),
|
||||
|
|
|
@ -646,7 +646,7 @@ class BlockViewDiffUtilTest {
|
|||
|
||||
val oldBlock = BlockView.Media.File(
|
||||
id = id,
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
indent = MockDataFactory.randomInt(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
size = MockDataFactory.randomLong(),
|
||||
|
|
|
@ -114,7 +114,7 @@ class BlockViewSearchTextTest {
|
|||
id = MockDataFactory.randomString(),
|
||||
name = MockDataFactory.randomString(),
|
||||
searchFields = listOf(field1),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
size = MockDataFactory.randomLong(),
|
||||
indent = 0,
|
||||
|
|
|
@ -34,7 +34,7 @@ class BlockViewTest {
|
|||
fun `should return video block with view type Done`() {
|
||||
val block = BlockView.Media.Video(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
url = MockDataFactory.randomString(),
|
||||
size = MockDataFactory.randomLong(),
|
||||
mime = MockDataFactory.randomString(),
|
||||
|
|
|
@ -46,6 +46,10 @@ fun <T : Parcelable> Fragment.argList(key: String): ArrayList<T> {
|
|||
return checkNotNull(value)
|
||||
}
|
||||
|
||||
fun Fragment.argStringList(key: String): ArrayList<String> {
|
||||
return requireArguments().getStringArrayList(key) ?: ArrayList()
|
||||
}
|
||||
|
||||
fun <T> CoroutineScope.subscribe(flow: Flow<T>, body: suspend (T) -> Unit): Job =
|
||||
flow.cancellable().onEach { body(it) }.launchIn(this)
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.anytypeio.anytype.core_utils.ext
|
||||
|
||||
enum class Mimetype(val value: String) {
|
||||
MIME_TEXT_PLAIN("text/plain"),
|
||||
MIME_VIDEO_ALL("video/*"),
|
||||
MIME_IMAGE_ALL("image/*"),
|
||||
MIME_FILE_ALL("*/*"),
|
||||
MIME_IMAGE_AND_VIDEO("image/*,video/*"),
|
||||
MIME_YAML("application/zip")
|
||||
MIME_YAML("application/zip"),
|
||||
MIME_APPLICATION_ALL("application/*")
|
||||
}
|
|
@ -256,7 +256,7 @@ class BlockDataRepository(
|
|||
|
||||
override suspend fun uploadFile(
|
||||
command: Command.UploadFile
|
||||
): Hash = remote.uploadFile(command)
|
||||
): Id = remote.uploadFile(command)
|
||||
|
||||
override suspend fun downloadFile(
|
||||
command: Command.DownloadFile
|
||||
|
|
|
@ -80,7 +80,7 @@ interface BlockRemote {
|
|||
suspend fun paste(command: Command.Paste): Response.Clipboard.Paste
|
||||
suspend fun copy(command: Command.Copy): Response.Clipboard.Copy
|
||||
|
||||
suspend fun uploadFile(command: Command.UploadFile): String
|
||||
suspend fun uploadFile(command: Command.UploadFile): Id
|
||||
suspend fun downloadFile(command: Command.DownloadFile): String
|
||||
|
||||
suspend fun setRelationKey(command: Command.SetRelationKey): Payload
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package com.anytypeio.anytype.device
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import android.provider.OpenableColumns
|
||||
import com.anytypeio.anytype.domain.device.FileSharer
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber
|
||||
|
||||
class SharedFileUploader @Inject constructor(
|
||||
private val context: Context
|
||||
) : FileSharer {
|
||||
|
||||
override fun getPath(uri: String): String {
|
||||
Timber.d("Getting path for: ${uri}")
|
||||
val parsed = Uri.parse(uri)
|
||||
checkNotNull(parsed)
|
||||
return parsePathFromFile(parsed)
|
||||
}
|
||||
|
||||
private fun parsePathFromFile(extra: Uri) : String {
|
||||
val name = if (extra.scheme == "content") {
|
||||
context.contentResolver.query(
|
||||
extra,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
val idx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||
if (idx != -1) {
|
||||
cursor.getString(idx)
|
||||
} else {
|
||||
"Untitled"
|
||||
}
|
||||
} else {
|
||||
"Untitled"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
extra.path!!.substring(extra.path!!.lastIndexOf("/"))
|
||||
}
|
||||
val inputStream = context.contentResolver.openInputStream(extra)
|
||||
val cacheDir = context.getExternalFilesDir(null)
|
||||
if (cacheDir != null && !cacheDir.exists()) {
|
||||
cacheDir.mkdirs()
|
||||
}
|
||||
var path = ""
|
||||
inputStream?.use { input ->
|
||||
val newFile = File(cacheDir?.path + "/" + name);
|
||||
FileOutputStream(newFile).use { output ->
|
||||
val buffer = ByteArray(1024)
|
||||
var read: Int = input.read(buffer)
|
||||
while (read != -1) {
|
||||
output.write(buffer, 0, read)
|
||||
read = input.read(buffer)
|
||||
}
|
||||
}
|
||||
path = newFile.path
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ import com.anytypeio.anytype.domain.page.Undo
|
|||
|
||||
interface BlockRepository {
|
||||
|
||||
suspend fun uploadFile(command: Command.UploadFile): Hash
|
||||
suspend fun uploadFile(command: Command.UploadFile): Id
|
||||
suspend fun downloadFile(command: Command.DownloadFile): String
|
||||
|
||||
suspend fun move(command: Command.Move): Payload
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package com.anytypeio.anytype.domain.device
|
||||
|
||||
interface FileSharer {
|
||||
fun getPath(uri: String) : String?
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.anytypeio.anytype.domain.media
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class UploadFile @Inject constructor(
|
||||
private val repo: BlockRepository,
|
||||
private val dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<UploadFile.Params, Id>(dispatchers.io) {
|
||||
|
||||
override suspend fun doWork(params: Params) : Id = repo.uploadFile(
|
||||
command = Command.UploadFile(
|
||||
path = params.path,
|
||||
type = Block.Content.File.Type.FILE,
|
||||
space = params.space
|
||||
)
|
||||
)
|
||||
|
||||
data class Params(val path: String, val space: SpaceId)
|
||||
}
|
|
@ -10,29 +10,29 @@ import com.anytypeio.anytype.domain.config.Gateway
|
|||
class UrlBuilder(val gateway: Gateway) {
|
||||
|
||||
/**
|
||||
* Builds image url for given [hash]
|
||||
* Builds image url for given [path]
|
||||
*/
|
||||
fun image(hash: String?): Url = gateway.provide() + IMAGE_PATH + hash + DEFAULT_WIDTH_PARAM
|
||||
fun image(path: String): Url = gateway.provide() + IMAGE_PATH + path + DEFAULT_WIDTH_PARAM
|
||||
|
||||
/**
|
||||
* Builds original image url for given [hash]
|
||||
* Builds original image url for given [path]
|
||||
*/
|
||||
fun original(hash: String?): Url = gateway.provide() + IMAGE_PATH + hash
|
||||
fun original(path: String): Url = gateway.provide() + IMAGE_PATH + path
|
||||
|
||||
/**
|
||||
* Builds small image url for given [hash]
|
||||
* Builds small image url for given [path]
|
||||
*/
|
||||
fun thumbnail(hash: String): Url = gateway.provide() + IMAGE_PATH + hash + THUMBNAIL_WIDTH_PARAM
|
||||
fun thumbnail(path: String): Url = gateway.provide() + IMAGE_PATH + path + THUMBNAIL_WIDTH_PARAM
|
||||
|
||||
/**
|
||||
* Builds file url for given [hash]
|
||||
* Builds file url for given [path]
|
||||
*/
|
||||
fun file(hash: String?): Url = gateway.provide() + FILE_PATH + hash
|
||||
fun file(path: String): Url = gateway.provide() + FILE_PATH + path
|
||||
|
||||
/**
|
||||
* Builds video url for given [hash]
|
||||
* Builds video url for given [path]
|
||||
*/
|
||||
fun video(hash: String?): Url = gateway.provide() + FILE_PATH + hash
|
||||
fun video(path: String): Url = gateway.provide() + FILE_PATH + path
|
||||
|
||||
companion object {
|
||||
const val IMAGE_PATH = "/image/"
|
||||
|
|
|
@ -40,6 +40,19 @@ class CreatePrefilledNote @Inject constructor(
|
|||
target = NO_VALUE
|
||||
)
|
||||
)
|
||||
params.attachments.forEach { attachment ->
|
||||
repo.create(
|
||||
command = Command.Create(
|
||||
context = obj.id,
|
||||
prototype = Block.Prototype.Link(
|
||||
target = attachment,
|
||||
cardStyle = Block.Content.Link.CardStyle.CARD
|
||||
),
|
||||
position = Position.NONE,
|
||||
target = NO_VALUE
|
||||
)
|
||||
)
|
||||
}
|
||||
return obj.id
|
||||
}
|
||||
|
||||
|
@ -50,6 +63,7 @@ class CreatePrefilledNote @Inject constructor(
|
|||
val space: Id,
|
||||
val text: String,
|
||||
val details: Struct,
|
||||
val customType: TypeKey? = null
|
||||
val customType: TypeKey? = null,
|
||||
val attachments: List<Id> = emptyList()
|
||||
)
|
||||
}
|
|
@ -30,16 +30,6 @@ class UrlBuilderTest {
|
|||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return url with null at the end when image hash is null`() {
|
||||
val hash = null
|
||||
|
||||
val expected =
|
||||
gateway.provide() + UrlBuilder.IMAGE_PATH + null + UrlBuilder.DEFAULT_WIDTH_PARAM
|
||||
val actual = urlBuilder.image(hash)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return url without hash when image hash is empty`() {
|
||||
val hash = ""
|
||||
|
@ -58,15 +48,6 @@ class UrlBuilderTest {
|
|||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return url with null at the end when file hash is null`() {
|
||||
val hash = null
|
||||
|
||||
val expected = gateway.provide() + UrlBuilder.FILE_PATH + null
|
||||
val actual = urlBuilder.file(hash)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return url without hash when file hash is empty`() {
|
||||
val hash = ""
|
||||
|
@ -85,15 +66,6 @@ class UrlBuilderTest {
|
|||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return url with null at the end when video hash is null`() {
|
||||
val hash = null
|
||||
|
||||
val expected = gateway.provide() + UrlBuilder.FILE_PATH + null
|
||||
val actual = urlBuilder.video(hash)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return url without hash when video hash is empty`() {
|
||||
val hash = ""
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[versions]
|
||||
middlewareVersion = "v0.30.11"
|
||||
middlewareVersion = "651da12f6"
|
||||
kotlinVersion = '1.8.22'
|
||||
|
||||
androidxCoreVersion = "1.12.0"
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
<string name="hint_upload_image">Upload a picture</string>
|
||||
<string name="hint_upload_file">Upload a file</string>
|
||||
<string name="hint_upload_audio">Upload an audio</string>
|
||||
<string name="hint_add_a_web_bookmark">Add a web bookmark</string>
|
||||
<string name="hint_add_a_web_bookmark">Add bookmark</string>
|
||||
<string name="hint_bullet">Bulleted list item</string>
|
||||
<string name="hint_numbered_list">Numbered list item</string>
|
||||
<string name="hint_toggle">Toggle block</string>
|
||||
|
@ -808,6 +808,7 @@
|
|||
<string name="anytype_analytics">Anytype Analytics</string>
|
||||
<string name="anytype_analytics_msg">Understanding how people use Anytype helps us improve the product. This version of Anytype includes the analytics code that protects your privacy.\nIt doesn\'t record the actual document\'s content but still allows us to understand how you use Anytype.\nStay subscribed to our mailing list, as we will soon announce a new release that enables you to opt-out.</string>
|
||||
<string name="retry">Retry</string>
|
||||
<string name="try_again">Try again</string>
|
||||
<string name="unsplash">Unsplash</string>
|
||||
<string name="cancel_deletion">Cancel deletion</string>
|
||||
<string name="logout_and_clear_local_data">Logout and clear local data</string>
|
||||
|
@ -1191,6 +1192,7 @@
|
|||
<string name="sharing_menu_save_as_section_name">Save as</string>
|
||||
<string name="sharing_menu_save_as_note_option">Note</string>
|
||||
<string name="sharing_menu_save_as_bookmark_option">Bookmark</string>
|
||||
<string name="sharing_menu_save_as_image_option">Image</string>
|
||||
<string name="sharing_menu_data">Data</string>
|
||||
<string name="sharing_menu_add_to_anytype_header_title">Add to Anytype</string>
|
||||
<string name="sharing_menu_toast_object_added">New object is added to the space \'%1$s\'</string>
|
||||
|
@ -1249,4 +1251,5 @@
|
|||
<string name="any_object_creation_menu_move_right">Move right</string>
|
||||
<string name="clipboard_panel_create_object_from_clipboard">Create object from clipboard</string>
|
||||
|
||||
<string name="block_media_error">Something went wrong, please try again</string>
|
||||
</resources>
|
|
@ -28,6 +28,6 @@ class UnsplashMiddleware @Inject constructor(
|
|||
override fun download(id: Id): Hash {
|
||||
val request = Download.Request(pictureId = id).also { logger.logRequest(it) }
|
||||
val response = service.unsplashDownload(request = request).also { logger.logResponse(it) }
|
||||
return response.hash
|
||||
return response.objectId
|
||||
}
|
||||
}
|
|
@ -220,7 +220,7 @@ class BlockMiddleware(
|
|||
|
||||
override suspend fun uploadFile(
|
||||
command: Command.UploadFile
|
||||
): String = middleware.fileUpload(command).hash
|
||||
): Id = middleware.fileUpload(command).objectId
|
||||
|
||||
override suspend fun downloadFile(
|
||||
command: Command.DownloadFile
|
||||
|
|
|
@ -34,6 +34,8 @@ import com.anytypeio.anytype.core_utils.tools.ThreadInfo
|
|||
import com.anytypeio.anytype.middleware.BuildConfig
|
||||
import com.anytypeio.anytype.middleware.auth.toAccountSetup
|
||||
import com.anytypeio.anytype.middleware.const.Constants
|
||||
import com.anytypeio.anytype.middleware.mappers.MBFile
|
||||
import com.anytypeio.anytype.middleware.mappers.MBFileType
|
||||
import com.anytypeio.anytype.middleware.mappers.MDVFilter
|
||||
import com.anytypeio.anytype.middleware.mappers.MNetworkMode
|
||||
import com.anytypeio.anytype.middleware.mappers.MRelationFormat
|
||||
|
@ -821,18 +823,19 @@ class Middleware @Inject constructor(
|
|||
val type = command.type.toMiddlewareModel()
|
||||
val request = Rpc.File.Upload.Request(
|
||||
localPath = command.path,
|
||||
type = type
|
||||
type = MBFileType.None,
|
||||
spaceId = command.space?.id.orEmpty()
|
||||
)
|
||||
if (BuildConfig.DEBUG) logRequest(request)
|
||||
val response = service.fileUpload(request)
|
||||
if (BuildConfig.DEBUG) logResponse(response)
|
||||
return Response.Media.Upload(response.hash)
|
||||
return Response.Media.Upload(response.objectId)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun fileDownload(command: Command.DownloadFile): Rpc.File.Download.Response {
|
||||
val request = Rpc.File.Download.Request(
|
||||
hash = command.hash,
|
||||
objectId = command.objectId,
|
||||
path = command.path
|
||||
)
|
||||
if (BuildConfig.DEBUG) logRequest(request)
|
||||
|
|
|
@ -126,11 +126,11 @@ fun anytype.Event.Message.toCoreModels(
|
|||
with(event) {
|
||||
Event.Command.UpdateFileBlock(
|
||||
context = context,
|
||||
id = id,
|
||||
blockId = id,
|
||||
targetObjectId = targetObjectId?.value_,
|
||||
state = state?.value_?.toCoreModels(),
|
||||
type = type?.value_?.toCoreModels(),
|
||||
name = name?.value_,
|
||||
hash = hash?.value_,
|
||||
mime = mime?.value_,
|
||||
size = size?.value_
|
||||
)
|
||||
|
|
|
@ -46,7 +46,8 @@ class MiddlewareFactory {
|
|||
is Block.Prototype.File -> {
|
||||
val file = MBFile(
|
||||
state = prototype.state.toMiddlewareModel(),
|
||||
type = prototype.type.toMiddlewareModel()
|
||||
type = prototype.type.toMiddlewareModel(),
|
||||
targetObjectId = prototype.targetObjectId.orEmpty()
|
||||
)
|
||||
MBlock(file_ = file)
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ fun MBlock.toCoreModelsDivider(): Block.Content.Divider {
|
|||
fun MBlock.toCoreModelsFile(): Block.Content.File {
|
||||
val content = checkNotNull(file_)
|
||||
return Block.Content.File(
|
||||
hash = content.hash,
|
||||
targetObjectId = content.targetObjectId,
|
||||
name = content.name,
|
||||
mime = content.mime,
|
||||
size = content.size,
|
||||
|
|
|
@ -113,7 +113,7 @@ fun Block.Content.Bookmark.State.toMiddlewareModel(): MBookmarkState = when (thi
|
|||
}
|
||||
|
||||
fun Block.Content.File.toMiddlewareModel(): MBFile = MBFile(
|
||||
hash = hash.orEmpty(),
|
||||
targetObjectId = targetObjectId.orEmpty(),
|
||||
name = name.orEmpty(),
|
||||
mime = mime.orEmpty(),
|
||||
size = size ?: 0,
|
||||
|
|
|
@ -150,7 +150,7 @@ class MiddlewareEventChannelTest {
|
|||
@Test
|
||||
fun `should return UpdateBlockFile event`() {
|
||||
|
||||
val hash = "785687346534hfjdbsjfbds"
|
||||
val targetObjectId = "785687346534hfjdbsjfbds"
|
||||
val name = "video1.mp4"
|
||||
val mime = "video/*"
|
||||
val size = 999111L
|
||||
|
@ -162,7 +162,7 @@ class MiddlewareEventChannelTest {
|
|||
|
||||
val msg = anytype.Event.Block.Set.File(
|
||||
id = id,
|
||||
hash = anytype.Event.Block.Set.File.Hash(hash),
|
||||
targetObjectId = anytype.Event.Block.Set.File.TargetObjectId(targetObjectId),
|
||||
mime = anytype.Event.Block.Set.File.Mime(mime),
|
||||
size = anytype.Event.Block.Set.File.Size(size),
|
||||
type = anytype.Event.Block.Set.File.Type(type),
|
||||
|
@ -181,8 +181,8 @@ class MiddlewareEventChannelTest {
|
|||
val expected = listOf(
|
||||
Event.Command.UpdateFileBlock(
|
||||
context = context,
|
||||
id = id,
|
||||
hash = hash,
|
||||
blockId = id,
|
||||
targetObjectId = targetObjectId,
|
||||
mime = mime,
|
||||
size = size,
|
||||
type = com.anytypeio.anytype.core_models.Block.Content.File.Type.VIDEO,
|
||||
|
@ -220,7 +220,7 @@ class MiddlewareEventChannelTest {
|
|||
val expected = listOf(
|
||||
Event.Command.UpdateFileBlock(
|
||||
context = context,
|
||||
id = id
|
||||
blockId = id
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ class DocumentExternalEventReducer : StateReducer<List<Block>, Event> {
|
|||
val content = block.content<Block.Content.File>()
|
||||
block.copy(
|
||||
content = content.copy(
|
||||
hash = event.hash ?: content.hash,
|
||||
targetObjectId = event.targetObjectId ?: content.targetObjectId,
|
||||
name = event.name ?: content.name,
|
||||
mime = event.mime ?: content.mime,
|
||||
size = event.size ?: content.size,
|
||||
|
@ -83,7 +83,7 @@ class DocumentExternalEventReducer : StateReducer<List<Block>, Event> {
|
|||
)
|
||||
)
|
||||
},
|
||||
target = { block -> block.id == event.id }
|
||||
target = { block -> block.id == event.blockId }
|
||||
)
|
||||
is Event.Command.BookmarkGranularChange -> state.replace(
|
||||
replacement = { block ->
|
||||
|
|
|
@ -196,6 +196,7 @@ import com.anytypeio.anytype.presentation.editor.selection.updateTableBlockTab
|
|||
import com.anytypeio.anytype.presentation.editor.template.SelectTemplateViewState
|
||||
import com.anytypeio.anytype.presentation.editor.toggle.ToggleStateHolder
|
||||
import com.anytypeio.anytype.presentation.extension.getProperObjectName
|
||||
import com.anytypeio.anytype.presentation.extension.getUrlForFileBlock
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsBlockActionEvent
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsBlockAlignEvent
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsBlockBackgroundEvent
|
||||
|
@ -1806,6 +1807,7 @@ class EditorViewModel(
|
|||
needSortByDownloads = true
|
||||
if (content.state == Content.File.State.DONE) {
|
||||
targetActions.addIfNotExists(ActionItemType.Download)
|
||||
targetActions.addIfNotExists(ActionItemType.OpenObject)
|
||||
} else {
|
||||
excludedActions.add(ActionItemType.Download)
|
||||
}
|
||||
|
@ -3107,6 +3109,7 @@ class EditorViewModel(
|
|||
ObjectType.Layout.NOTE,
|
||||
ObjectType.Layout.TODO,
|
||||
ObjectType.Layout.FILE,
|
||||
ObjectType.Layout.IMAGE,
|
||||
ObjectType.Layout.BOOKMARK -> {
|
||||
proceedWithOpeningObject(target = target)
|
||||
}
|
||||
|
@ -3608,6 +3611,13 @@ class EditorViewModel(
|
|||
else -> Unit
|
||||
}
|
||||
}
|
||||
is ListenerType.Bookmark.Upload -> {
|
||||
when (mode) {
|
||||
EditorMode.Edit -> Unit
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(clicked.target)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
is ListenerType.Bookmark.Error -> {
|
||||
when (mode) {
|
||||
EditorMode.Edit -> onFailedBookmarkClicked(clicked.item)
|
||||
|
@ -3647,18 +3657,21 @@ class EditorViewModel(
|
|||
is ListenerType.Picture.View -> {
|
||||
when (mode) {
|
||||
EditorMode.Edit, EditorMode.Locked -> {
|
||||
val target = blocks.find { it.id == clicked.target }
|
||||
if (target != null) {
|
||||
val content = target.content
|
||||
check(content is Content.File)
|
||||
val fileBlock = blocks.find { it.id == clicked.target }
|
||||
val url = urlBuilder.getUrlForFileBlock(
|
||||
fileBlock = fileBlock,
|
||||
isOriginalImage = true
|
||||
)
|
||||
if (url != null ) {
|
||||
dispatch(
|
||||
Command.OpenFullScreenImage(
|
||||
target = clicked.target,
|
||||
url = urlBuilder.original(content.hash)
|
||||
url = url
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Timber.e("Could not find target for picture")
|
||||
Timber.e("Block is not File or with wrong state, can't proceed with download")
|
||||
sendToast("Something went wrong. Couldn't open image")
|
||||
}
|
||||
}
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(clicked.target)
|
||||
|
@ -4118,17 +4131,21 @@ class EditorViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onFileClicked(id: String) {
|
||||
val file = blocks.find { it.id == id }
|
||||
if (file != null && file.content is Content.File) {
|
||||
val cnt = (file.content as Content.File)
|
||||
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 = id,
|
||||
mime = cnt.mime.orEmpty(),
|
||||
uri = urlBuilder.file(cnt.hash)
|
||||
id = blockId,
|
||||
uri = url
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Timber.e("Block is not File or with wrong state, can't proceed with open")
|
||||
sendToast("Something went wrong. Couldn't open file.")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4145,7 +4162,7 @@ class EditorViewModel(
|
|||
viewModelScope.launch {
|
||||
orchestrator.proxies.intents.send(
|
||||
Media.ShareFile(
|
||||
hash = content.hash.orEmpty(),
|
||||
objectId = content.targetObjectId.orEmpty(),
|
||||
name = content.name.orEmpty(),
|
||||
type = content.type,
|
||||
onDownloaded = onDownloaded
|
||||
|
@ -4157,30 +4174,29 @@ class EditorViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun startDownloadingFile(id: String) {
|
||||
fun startDownloadingFile(blockId: Id) {
|
||||
|
||||
Timber.d("startDownloadingFile, id:[$id]")
|
||||
Timber.d("startDownloadingFile, for block:[$blockId]")
|
||||
|
||||
sendToast("Downloading file in background...")
|
||||
|
||||
val block = blocks.firstOrNull { it.id == id }
|
||||
val content = block?.content
|
||||
|
||||
if (content is Content.File && content.state == Content.File.State.DONE) {
|
||||
val fileBlock = blocks.firstOrNull { it.id == blockId }
|
||||
val fileContent = fileBlock?.content as? Content.File
|
||||
val url = urlBuilder.getUrlForFileBlock(fileBlock)
|
||||
|
||||
if (fileContent != null && url != null) {
|
||||
viewModelScope.launch {
|
||||
orchestrator.proxies.intents.send(
|
||||
Media.DownloadFile(
|
||||
url = when (content.type) {
|
||||
Content.File.Type.IMAGE -> urlBuilder.image(content.hash)
|
||||
else -> urlBuilder.file(content.hash)
|
||||
},
|
||||
name = content.name.orEmpty(),
|
||||
type = content.type
|
||||
url = url,
|
||||
name = fileContent.name.orEmpty(),
|
||||
type = fileContent.type
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Timber.e("Block is not File or with wrong state, can't proceed with download")
|
||||
sendToast("Something went wrong. Couldn't download file.")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5581,6 +5597,18 @@ class EditorViewModel(
|
|||
sendToast("This bookmark doesn’t have a source.")
|
||||
}
|
||||
}
|
||||
is Content.File -> {
|
||||
val target = content.targetObjectId
|
||||
if (target != null) {
|
||||
proceedWithOpeningObject(target)
|
||||
viewModelScope.sendAnalyticsOpenAsObject(
|
||||
analytics = analytics,
|
||||
type = EventsDictionary.Type.bookmark
|
||||
)
|
||||
} else {
|
||||
sendToast("This object doesn’t have a target id")
|
||||
}
|
||||
}
|
||||
else -> sendToast("Unexpected object")
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -31,7 +31,6 @@ sealed class Command {
|
|||
*/
|
||||
data class OpenFileByDefaultApp(
|
||||
val id: String,
|
||||
val mime: String,
|
||||
val uri: String
|
||||
) : Command()
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ sealed class Intent {
|
|||
) : Media()
|
||||
|
||||
class ShareFile(
|
||||
val hash: Hash,
|
||||
val objectId: Id,
|
||||
val name: String,
|
||||
val type: Block.Content.File.Type?,
|
||||
val onDownloaded: (Uri) -> Unit
|
||||
|
|
|
@ -449,7 +449,7 @@ class Orchestrator(
|
|||
is Intent.Media.ShareFile -> {
|
||||
documentFileShareDownloader.async(
|
||||
params = MiddlewareShareDownloader.Params(
|
||||
hash = intent.hash,
|
||||
objectId = intent.objectId,
|
||||
name = intent.name
|
||||
)
|
||||
).suspendFold(
|
||||
|
|
|
@ -113,6 +113,10 @@ fun List<BlockView>.singleStylingMode(
|
|||
mode = BlockView.Mode.READ,
|
||||
isSelected = isSelected
|
||||
)
|
||||
is BlockView.Upload.Bookmark -> view.copy(
|
||||
mode = BlockView.Mode.READ,
|
||||
isSelected = isSelected
|
||||
)
|
||||
is BlockView.MediaPlaceholder.File -> view.copy(
|
||||
mode = BlockView.Mode.READ,
|
||||
isSelected = isSelected
|
||||
|
@ -263,6 +267,10 @@ fun List<BlockView>.enterSAM(
|
|||
mode = BlockView.Mode.READ,
|
||||
isSelected = isSelected
|
||||
)
|
||||
is BlockView.Upload.Bookmark -> view.copy(
|
||||
mode = BlockView.Mode.READ,
|
||||
isSelected = isSelected
|
||||
)
|
||||
is BlockView.MediaPlaceholder.File -> view.copy(
|
||||
mode = BlockView.Mode.READ,
|
||||
isSelected = isSelected
|
||||
|
@ -458,6 +466,7 @@ fun List<BlockView>.updateCursorAndEditMode(
|
|||
is BlockView.Upload.File -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.Upload.Video -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.Upload.Picture -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.Upload.Bookmark -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.MediaPlaceholder.File -> view.copy(
|
||||
mode = BlockView.Mode.EDIT,
|
||||
isSelected = false
|
||||
|
@ -518,6 +527,7 @@ fun List<BlockView>.toReadMode(): List<BlockView> = map { view ->
|
|||
is BlockView.Upload.File -> view.copy(mode = BlockView.Mode.READ)
|
||||
is BlockView.Upload.Video -> view.copy(mode = BlockView.Mode.READ)
|
||||
is BlockView.Upload.Picture -> view.copy(mode = BlockView.Mode.READ)
|
||||
is BlockView.Upload.Bookmark -> view.copy(mode = BlockView.Mode.READ)
|
||||
is BlockView.MediaPlaceholder.File -> view.copy(mode = BlockView.Mode.READ)
|
||||
is BlockView.MediaPlaceholder.Video -> view.copy(mode = BlockView.Mode.READ)
|
||||
is BlockView.MediaPlaceholder.Bookmark -> view.copy(mode = BlockView.Mode.READ)
|
||||
|
@ -550,6 +560,7 @@ fun List<BlockView>.toEditMode(): List<BlockView> = map { view ->
|
|||
is BlockView.Upload.File -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.Upload.Video -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.Upload.Picture -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.Upload.Bookmark -> view.copy(mode = BlockView.Mode.EDIT, isSelected = false)
|
||||
is BlockView.MediaPlaceholder.File -> view.copy(
|
||||
mode = BlockView.Mode.EDIT,
|
||||
isSelected = false
|
||||
|
@ -1065,6 +1076,7 @@ fun BlockView.updateSelection(newSelection: Boolean) = when (this) {
|
|||
is BlockView.MediaPlaceholder.Picture -> copy(isSelected = newSelection)
|
||||
is BlockView.Error.Picture -> copy(isSelected = newSelection)
|
||||
is BlockView.Upload.Picture -> copy(isSelected = newSelection)
|
||||
is BlockView.Upload.Bookmark -> copy(isSelected = newSelection)
|
||||
is BlockView.DividerLine -> copy(isSelected = newSelection)
|
||||
is BlockView.DividerDots -> copy(isSelected = newSelection)
|
||||
is BlockView.Code -> copy(isSelected = newSelection)
|
||||
|
|
|
@ -11,6 +11,7 @@ sealed interface ListenerType {
|
|||
sealed class Bookmark : ListenerType {
|
||||
data class View(val item: BlockView.Media.Bookmark) : Bookmark()
|
||||
data class Placeholder(val target: String) : Bookmark()
|
||||
data class Upload(val target: String) : File()
|
||||
data class Error(val item: BlockView.Error.Bookmark) : Bookmark()
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ private fun createBaseMentionMark(
|
|||
)
|
||||
}
|
||||
|
||||
if (!image.isNullOrEmpty()) {
|
||||
if (!image.isNullOrBlank()) {
|
||||
return Markup.Mark.Mention.WithImage(
|
||||
from = from,
|
||||
to = to,
|
||||
|
|
|
@ -780,7 +780,8 @@ sealed class BlockView : ViewType {
|
|||
override val mode: Mode = Mode.EDIT,
|
||||
override val isSelected: Boolean = false,
|
||||
override val background: ThemeColor = ThemeColor.DEFAULT,
|
||||
override val decorations: List<Decoration> = emptyList()
|
||||
override val decorations: List<Decoration> = emptyList(),
|
||||
val name: String? = null
|
||||
) : Error() {
|
||||
override fun getViewType() = HOLDER_FILE_ERROR
|
||||
}
|
||||
|
@ -795,7 +796,8 @@ sealed class BlockView : ViewType {
|
|||
override val mode: Mode = Mode.EDIT,
|
||||
override val isSelected: Boolean = false,
|
||||
override val background: ThemeColor = ThemeColor.DEFAULT,
|
||||
override val decorations: List<Decoration> = emptyList()
|
||||
override val decorations: List<Decoration> = emptyList(),
|
||||
val name: String? = null
|
||||
) : Error() {
|
||||
override fun getViewType() = HOLDER_VIDEO_ERROR
|
||||
}
|
||||
|
@ -809,7 +811,8 @@ sealed class BlockView : ViewType {
|
|||
override val mode: Mode = Mode.EDIT,
|
||||
override val isSelected: Boolean = false,
|
||||
override val background: ThemeColor = ThemeColor.DEFAULT,
|
||||
override val decorations: List<Decoration> = emptyList()
|
||||
override val decorations: List<Decoration> = emptyList(),
|
||||
val name: String? = null
|
||||
) : Error() {
|
||||
override fun getViewType() = HOLDER_PICTURE_ERROR
|
||||
}
|
||||
|
@ -997,8 +1000,9 @@ sealed class BlockView : ViewType {
|
|||
val size: Long?,
|
||||
val name: String?,
|
||||
val mime: String?,
|
||||
val hash: String?,
|
||||
val url: String
|
||||
val targetObjectId: Id,
|
||||
val url: String,
|
||||
val fileExt: String? = null
|
||||
) : Media(), Searchable {
|
||||
override fun getViewType() = HOLDER_FILE
|
||||
}
|
||||
|
@ -1016,7 +1020,7 @@ sealed class BlockView : ViewType {
|
|||
val size: Long?,
|
||||
val name: String?,
|
||||
val mime: String?,
|
||||
val hash: String?,
|
||||
val targetObjectId: Id,
|
||||
val url: String
|
||||
) : Media() {
|
||||
override fun getViewType() = HOLDER_VIDEO
|
||||
|
@ -1067,8 +1071,8 @@ sealed class BlockView : ViewType {
|
|||
val size: Long?,
|
||||
val name: String?,
|
||||
val mime: String?,
|
||||
val hash: String?,
|
||||
val url: String
|
||||
val targetObjectId: Id,
|
||||
val url: String,
|
||||
) : Media() {
|
||||
override fun getViewType() = HOLDER_PICTURE
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper
|
|||
import com.anytypeio.anytype.presentation.relations.BlockFieldsCoverWrapper
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.relations.getCover
|
||||
import com.anytypeio.anytype.presentation.relations.isSystemKey
|
||||
import com.anytypeio.anytype.presentation.relations.linksFeaturedRelation
|
||||
import com.anytypeio.anytype.presentation.relations.objectTypeRelation
|
||||
import com.anytypeio.anytype.presentation.relations.view
|
||||
|
@ -635,7 +634,8 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
indent = indent,
|
||||
selection = selection,
|
||||
isPreviousBlockMedia = isPreviousBlockMedia,
|
||||
schema = blockDecorationScheme
|
||||
schema = blockDecorationScheme,
|
||||
details = details
|
||||
)
|
||||
)
|
||||
isPreviousBlockMedia = true
|
||||
|
@ -1265,8 +1265,8 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
url = obj.source.orEmpty(),
|
||||
title = obj.name,
|
||||
description = obj.description,
|
||||
imageUrl = obj.picture?.ifEmpty { null }?.let { urlBuilder.image(it) },
|
||||
faviconUrl = obj.iconImage?.ifEmpty { null }?.let { urlBuilder.image(it) },
|
||||
imageUrl = obj.picture?.takeIf { it.isNotBlank() }?.let { urlBuilder.image(it) },
|
||||
faviconUrl = obj.iconImage?.takeIf { it.isNotBlank() }?.let { urlBuilder.image(it) },
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
isSelected = checkIfSelected(
|
||||
|
@ -1336,10 +1336,11 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
indent: Int,
|
||||
selection: Set<Id>,
|
||||
isPreviousBlockMedia: Boolean,
|
||||
schema: NestedDecorationData
|
||||
schema: NestedDecorationData,
|
||||
details: Block.Details
|
||||
): BlockView = when (content.type) {
|
||||
Content.File.Type.IMAGE -> content.toPictureView(
|
||||
id = block.id,
|
||||
blockId = block.id,
|
||||
urlBuilder = urlBuilder,
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
|
@ -1350,10 +1351,11 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
),
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
isPreviousBlockMedia = isPreviousBlockMedia,
|
||||
decorations = schema.toBlockViewDecoration(block)
|
||||
decorations = schema.toBlockViewDecoration(block),
|
||||
details = details
|
||||
)
|
||||
Content.File.Type.FILE -> content.toFileView(
|
||||
id = block.id,
|
||||
blockId = block.id,
|
||||
urlBuilder = urlBuilder,
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
|
@ -1364,10 +1366,11 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
),
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
isPrevBlockMedia = isPreviousBlockMedia,
|
||||
decorations = schema.toBlockViewDecoration(block)
|
||||
decorations = schema.toBlockViewDecoration(block),
|
||||
details = details
|
||||
)
|
||||
Content.File.Type.VIDEO -> content.toVideoView(
|
||||
id = block.id,
|
||||
blockId = block.id,
|
||||
urlBuilder = urlBuilder,
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
|
@ -1378,10 +1381,11 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
),
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
isPrevBlockMedia = isPreviousBlockMedia,
|
||||
decorations = schema.toBlockViewDecoration(block)
|
||||
decorations = schema.toBlockViewDecoration(block),
|
||||
details = details
|
||||
)
|
||||
Content.File.Type.AUDIO -> content.toFileView(
|
||||
id = block.id,
|
||||
blockId = block.id,
|
||||
urlBuilder = urlBuilder,
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
|
@ -1392,10 +1396,11 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
),
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
isPrevBlockMedia = isPreviousBlockMedia,
|
||||
decorations = schema.toBlockViewDecoration(block)
|
||||
decorations = schema.toBlockViewDecoration(block),
|
||||
details = details
|
||||
)
|
||||
Content.File.Type.PDF -> content.toFileView(
|
||||
id = block.id,
|
||||
blockId = block.id,
|
||||
urlBuilder = urlBuilder,
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
|
@ -1406,10 +1411,11 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
),
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
isPrevBlockMedia = isPreviousBlockMedia,
|
||||
decorations = schema.toBlockViewDecoration(block)
|
||||
decorations = schema.toBlockViewDecoration(block),
|
||||
details = details
|
||||
)
|
||||
Content.File.Type.NONE -> content.toFileView(
|
||||
id = block.id,
|
||||
blockId = block.id,
|
||||
urlBuilder = urlBuilder,
|
||||
indent = indent,
|
||||
mode = if (mode == EditorMode.Edit) BlockView.Mode.EDIT else BlockView.Mode.READ,
|
||||
|
@ -1420,7 +1426,8 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
),
|
||||
background = block.parseThemeBackgroundColor(),
|
||||
isPrevBlockMedia = isPreviousBlockMedia,
|
||||
decorations = schema.toBlockViewDecoration(block)
|
||||
decorations = schema.toBlockViewDecoration(block),
|
||||
details = details
|
||||
)
|
||||
else -> throw IllegalStateException("Unexpected file type: ${content.type}")
|
||||
}
|
||||
|
@ -1474,15 +1481,9 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
mode = blockMode,
|
||||
id = block.id,
|
||||
text = content.text,
|
||||
emoji = details.details[root.id]?.iconEmoji?.let { name ->
|
||||
name.ifEmpty { null }
|
||||
},
|
||||
image = details.details[root.id]?.iconImage?.let { name ->
|
||||
if (name.isNotEmpty())
|
||||
urlBuilder.thumbnail(name)
|
||||
else
|
||||
null
|
||||
},
|
||||
emoji = details.details[root.id]?.iconEmoji?.takeIf { it.isNotBlank() },
|
||||
image = details.details[root.id]?.iconImage?.takeIf { it.isNotBlank() }
|
||||
?.let { urlBuilder.thumbnail(it) },
|
||||
isFocused = resolveIsFocused(focus, block),
|
||||
cursor = cursor,
|
||||
coverColor = coverContainer.coverColor,
|
||||
|
@ -1512,11 +1513,8 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
mode = blockMode,
|
||||
id = block.id,
|
||||
text = content.text,
|
||||
image = details.details[root.id]?.iconImage?.let { name ->
|
||||
if (name.isNotEmpty())
|
||||
urlBuilder.thumbnail(name)
|
||||
else
|
||||
null
|
||||
image = details.details[root.id]?.iconImage?.takeIf { it.isNotBlank() }?.let {
|
||||
urlBuilder.thumbnail(it)
|
||||
},
|
||||
spaceGradient = null,
|
||||
isFocused = resolveIsFocused(focus, block),
|
||||
|
@ -1533,11 +1531,9 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
mode = blockMode,
|
||||
id = block.id,
|
||||
text = content.text,
|
||||
emoji = details.details[root.id]?.iconEmoji?.let { name ->
|
||||
name.ifEmpty { null }
|
||||
},
|
||||
emoji = details.details[root.id]?.iconEmoji?.takeIf { it.isNotBlank() },
|
||||
image = details.details[root.id]?.iconImage?.let { image ->
|
||||
if (image.isNotEmpty() && layout != ObjectType.Layout.BOOKMARK)
|
||||
if (image.isNotBlank() && layout != ObjectType.Layout.BOOKMARK)
|
||||
urlBuilder.thumbnail(image)
|
||||
else
|
||||
null
|
||||
|
@ -1557,14 +1553,9 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
mode = blockMode,
|
||||
id = block.id,
|
||||
text = content.text,
|
||||
emoji = details.details[root.id]?.iconEmoji?.let { name ->
|
||||
name.ifEmpty { null }
|
||||
},
|
||||
image = details.details[root.id]?.iconImage?.let { name ->
|
||||
if (name.isNotEmpty())
|
||||
urlBuilder.thumbnail(name)
|
||||
else
|
||||
null
|
||||
emoji = details.details[root.id]?.iconEmoji?.takeIf { it.isNotBlank() },
|
||||
image = details.details[root.id]?.iconImage?.takeIf { it.isNotBlank() }?.let {
|
||||
urlBuilder.thumbnail(it)
|
||||
},
|
||||
isFocused = resolveIsFocused(focus, block),
|
||||
cursor = cursor,
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package com.anytypeio.anytype.presentation.extension
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Url
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
|
||||
fun UrlBuilder.getUrlForFileBlock(
|
||||
fileBlock: Block?,
|
||||
isOriginalImage: Boolean = false,
|
||||
isThumbnail: Boolean = false
|
||||
): Url? {
|
||||
if (fileBlock == null) return null
|
||||
val fileContent = fileBlock.content as? Block.Content.File ?: return null
|
||||
return getUrlForFileContent(fileContent, isOriginalImage, isThumbnail)
|
||||
}
|
||||
|
||||
fun UrlBuilder.getUrlForFileContent(
|
||||
fileContent: Block.Content.File,
|
||||
isOriginalImage: Boolean = false,
|
||||
isThumbnail: Boolean = false
|
||||
): Url? {
|
||||
val targetObjectId = fileContent.targetObjectId
|
||||
if (fileContent.state != Block.Content.File.State.DONE || targetObjectId.isNullOrBlank()) {
|
||||
return null
|
||||
}
|
||||
return getUrlBasedOnType(fileContent.type, targetObjectId, isOriginalImage, isThumbnail)
|
||||
}
|
||||
|
||||
private fun UrlBuilder.getUrlBasedOnType(
|
||||
fileType: Block.Content.File.Type?,
|
||||
targetObjectId: String,
|
||||
isOriginalImage: Boolean,
|
||||
isThumbnail: Boolean
|
||||
): Url? {
|
||||
return when (fileType) {
|
||||
Block.Content.File.Type.IMAGE -> {
|
||||
when {
|
||||
isOriginalImage -> original(targetObjectId)
|
||||
isThumbnail -> thumbnail(targetObjectId)
|
||||
else -> image(targetObjectId)
|
||||
}
|
||||
}
|
||||
|
||||
Block.Content.File.Type.VIDEO -> video(targetObjectId)
|
||||
Block.Content.File.Type.FILE,
|
||||
Block.Content.File.Type.PDF,
|
||||
Block.Content.File.Type.AUDIO -> file(targetObjectId)
|
||||
|
||||
Block.Content.File.Type.NONE, null -> null
|
||||
}
|
||||
}
|
|
@ -164,13 +164,41 @@ class MainViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onIntentShare(data: String) {
|
||||
fun onIntentTextShare(data: String) {
|
||||
viewModelScope.launch {
|
||||
checkAuthorizationStatus(Unit).process(
|
||||
failure = { e -> Timber.e(e, "Error while checking auth status") },
|
||||
success = { status ->
|
||||
if (status == AuthStatus.AUTHORIZED) {
|
||||
commands.emit(Command.AddToAnytype(data))
|
||||
commands.emit(Command.Sharing.Text(data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onIntentImageShare(data: String) {
|
||||
Timber.d("onIntentImageShare: $data")
|
||||
viewModelScope.launch {
|
||||
checkAuthorizationStatus(Unit).process(
|
||||
failure = { e -> Timber.e(e, "Error while checking auth status") },
|
||||
success = { status ->
|
||||
if (status == AuthStatus.AUTHORIZED) {
|
||||
commands.emit(Command.Sharing.Image(data))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onIntentMultipleImageShare(uris: List<String>) {
|
||||
Timber.d("onIntentMultipleImageShare: $uris")
|
||||
viewModelScope.launch {
|
||||
checkAuthorizationStatus(Unit).process(
|
||||
failure = { e -> Timber.e(e, "Error while checking auth status") },
|
||||
success = { status ->
|
||||
if (status == AuthStatus.AUTHORIZED) {
|
||||
commands.emit(Command.Sharing.Images(uris))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -182,6 +210,10 @@ class MainViewModel(
|
|||
object LogoutDueToAccountDeletion : Command()
|
||||
class OpenCreateNewType(val type: Id) : Command()
|
||||
data class Error(val msg: String) : Command()
|
||||
data class AddToAnytype(val data: String): Command()
|
||||
sealed class Sharing : Command() {
|
||||
data class Text(val data: String) : Sharing()
|
||||
data class Image(val path: String): Sharing()
|
||||
data class Images(val uris: List<String>): Sharing()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,8 @@ import com.anytypeio.anytype.presentation.editor.editor.mention.createMentionMar
|
|||
import com.anytypeio.anytype.presentation.editor.editor.model.Alignment
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.UiBlock
|
||||
import com.anytypeio.anytype.presentation.extension.getUrlForFileBlock
|
||||
import com.anytypeio.anytype.presentation.extension.getUrlForFileContent
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectLayoutView
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectTypeView
|
||||
import com.anytypeio.anytype.presentation.sets.buildGridRow
|
||||
|
@ -28,17 +30,18 @@ import com.anytypeio.anytype.presentation.templates.TemplateObjectTypeView
|
|||
import timber.log.Timber
|
||||
|
||||
fun Block.Content.File.toPictureView(
|
||||
id: String,
|
||||
blockId: String,
|
||||
urlBuilder: UrlBuilder,
|
||||
indent: Int,
|
||||
mode: BlockView.Mode,
|
||||
isSelected: Boolean = false,
|
||||
background: ThemeColor,
|
||||
isPreviousBlockMedia: Boolean,
|
||||
decorations: List<BlockView.Decoration>
|
||||
decorations: List<BlockView.Decoration>,
|
||||
details: Block.Details = Block.Details()
|
||||
): BlockView = when (state) {
|
||||
Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.Picture(
|
||||
id = id,
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
|
@ -47,49 +50,70 @@ fun Block.Content.File.toPictureView(
|
|||
decorations = decorations
|
||||
)
|
||||
Block.Content.File.State.UPLOADING -> BlockView.Upload.Picture(
|
||||
id = id,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
Block.Content.File.State.DONE -> BlockView.Media.Picture(
|
||||
id = id,
|
||||
size = size,
|
||||
name = name,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
url = urlBuilder.image(hash),
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
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.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
|
||||
)
|
||||
|
||||
} else {
|
||||
Timber.w("Could not build picture view for block $blockId")
|
||||
BlockView.Error.Picture(
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
}
|
||||
}
|
||||
Block.Content.File.State.ERROR -> BlockView.Error.Picture(
|
||||
id = id,
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
decorations = decorations,
|
||||
name = name
|
||||
)
|
||||
else -> throw IllegalStateException("Unexpected state: $state")
|
||||
}
|
||||
|
||||
fun Block.Content.File.toVideoView(
|
||||
id: String,
|
||||
blockId: Id,
|
||||
urlBuilder: UrlBuilder,
|
||||
indent: Int,
|
||||
mode: BlockView.Mode,
|
||||
isSelected: Boolean = false,
|
||||
background: ThemeColor,
|
||||
isPrevBlockMedia: Boolean,
|
||||
decorations: List<BlockView.Decoration>
|
||||
decorations: List<BlockView.Decoration>,
|
||||
details: Block.Details = Block.Details()
|
||||
): BlockView = when (state) {
|
||||
Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.Video(
|
||||
id = id,
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
|
@ -98,49 +122,70 @@ fun Block.Content.File.toVideoView(
|
|||
decorations = decorations
|
||||
)
|
||||
Block.Content.File.State.UPLOADING -> BlockView.Upload.Video(
|
||||
id = id,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
Block.Content.File.State.DONE -> BlockView.Media.Video(
|
||||
id = id,
|
||||
size = size,
|
||||
name = name,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
url = urlBuilder.video(hash),
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
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
|
||||
)
|
||||
|
||||
} else {
|
||||
Timber.w("Could not build video view for block $blockId")
|
||||
BlockView.Error.Video(
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
}
|
||||
}
|
||||
Block.Content.File.State.ERROR -> BlockView.Error.Video(
|
||||
id = id,
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations
|
||||
decorations = decorations,
|
||||
name = name
|
||||
)
|
||||
else -> throw IllegalStateException("Unexpected state: $state")
|
||||
}
|
||||
|
||||
fun Block.Content.File.toFileView(
|
||||
id: String,
|
||||
blockId: String,
|
||||
urlBuilder: UrlBuilder,
|
||||
indent: Int,
|
||||
mode: BlockView.Mode,
|
||||
isSelected: Boolean = false,
|
||||
background: ThemeColor,
|
||||
isPrevBlockMedia: Boolean,
|
||||
decorations: List<BlockView.Decoration>
|
||||
decorations: List<BlockView.Decoration>,
|
||||
details: Block.Details = Block.Details()
|
||||
): BlockView = when (state) {
|
||||
Block.Content.File.State.EMPTY -> BlockView.MediaPlaceholder.File(
|
||||
id = id,
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
|
@ -149,33 +194,54 @@ fun Block.Content.File.toFileView(
|
|||
decorations = decorations
|
||||
)
|
||||
Block.Content.File.State.UPLOADING -> BlockView.Upload.File(
|
||||
id = id,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
Block.Content.File.State.DONE -> BlockView.Media.File(
|
||||
id = id,
|
||||
size = size,
|
||||
name = name,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
url = urlBuilder.video(hash),
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
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.File(
|
||||
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,
|
||||
fileExt = targetObject.fileExt
|
||||
)
|
||||
|
||||
} else {
|
||||
Timber.w("Could not build file view for block $blockId")
|
||||
BlockView.Error.File(
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
)
|
||||
}
|
||||
}
|
||||
Block.Content.File.State.ERROR -> BlockView.Error.File(
|
||||
id = id,
|
||||
id = blockId,
|
||||
indent = indent,
|
||||
mode = mode,
|
||||
isSelected = isSelected,
|
||||
background = background,
|
||||
decorations = decorations
|
||||
decorations = decorations,
|
||||
name = name
|
||||
)
|
||||
else -> throw IllegalStateException("Unexpected state: $state")
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.mapper
|
||||
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
|
||||
|
||||
fun ObjectWrapper.Basic.getImagePath(urlBuilder: UrlBuilder): String? {
|
||||
val image = this.iconImage
|
||||
return if (image.isNullOrBlank()) {
|
||||
null
|
||||
} else {
|
||||
urlBuilder.image(iconImage)
|
||||
}
|
||||
}
|
||||
|
||||
fun ObjectWrapper.Basic.getEmojiPath(): String? {
|
||||
val emoji = this.iconEmoji
|
||||
return if (emoji.isNullOrBlank()) {
|
||||
null
|
||||
} else {
|
||||
emoji
|
||||
}
|
||||
}
|
|
@ -152,7 +152,7 @@ class ObjectMenuViewModel(
|
|||
override fun onDiagnosticsClicked(ctx: Id) {
|
||||
jobs += viewModelScope.launch {
|
||||
debugTreeShareDownloader.stream(
|
||||
MiddlewareShareDownloader.Params(hash = ctx, name = "$ctx.zip")
|
||||
MiddlewareShareDownloader.Params(objectId = ctx, name = "$ctx.zip")
|
||||
).collect { result ->
|
||||
result.fold(
|
||||
onSuccess = { success ->
|
||||
|
|
|
@ -339,7 +339,7 @@ abstract class ObjectMenuViewModelBase(
|
|||
fun onDiagnosticsGoroutinesClicked(ctx: Id) {
|
||||
jobs += viewModelScope.launch {
|
||||
debugGoroutinesShareDownloader.stream(
|
||||
MiddlewareShareDownloader.Params(hash = ctx, name = "goroutines")
|
||||
MiddlewareShareDownloader.Params(objectId = ctx, name = "goroutines")
|
||||
).collect { result ->
|
||||
result.fold(
|
||||
onSuccess = { success -> commands.emit(Command.ShareDebugGoroutines(success.path)) },
|
||||
|
|
|
@ -21,15 +21,18 @@ fun CoverWrapper.getCover(
|
|||
when (type) {
|
||||
CoverType.UPLOADED_IMAGE,
|
||||
CoverType.UNSPLASH_IMAGE -> {
|
||||
coverImage = coverId?.let { id ->
|
||||
urlBuilder.image(id)
|
||||
val targetObjectId = coverId
|
||||
coverImage = if (!targetObjectId.isNullOrBlank()) {
|
||||
urlBuilder.image(targetObjectId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
CoverType.BUNDLED_IMAGE -> {
|
||||
val hash = coverId?.let { id ->
|
||||
coverImageHashProvider.provide(id)
|
||||
}
|
||||
if (hash != null) coverImage = urlBuilder.image(hash)
|
||||
if (!hash.isNullOrBlank()) coverImage = urlBuilder.image(hash)
|
||||
}
|
||||
CoverType.COLOR -> {
|
||||
coverColor = coverId?.let { id ->
|
||||
|
|
|
@ -209,9 +209,7 @@ fun title(
|
|||
id = title.id,
|
||||
text = wrapper.name.orEmpty(),
|
||||
emoji = wrapper.iconEmoji.orNull(),
|
||||
image = wrapper.iconImage.orNull()?.let { hash ->
|
||||
urlBuilder.thumbnail(hash = hash)
|
||||
},
|
||||
image = wrapper.iconImage?.takeIf { it.isNotBlank() }?.let { urlBuilder.thumbnail(it) },
|
||||
coverImage = coverContainer.coverImage,
|
||||
coverColor = coverContainer.coverColor,
|
||||
coverGradient = coverContainer.coverGradient
|
||||
|
|
|
@ -138,7 +138,7 @@ private suspend fun ObjectWrapper.Basic.mapToCoverItem(
|
|||
val preview = details[id]
|
||||
preview != null && preview.type.contains(IMAGE)
|
||||
}
|
||||
if (previewId != null) {
|
||||
if (!previewId.isNullOrBlank()) {
|
||||
coverImage = urlBuilder.image(previewId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -457,7 +457,7 @@ fun ObjectWrapper.Basic.toTemplateView(
|
|||
name = name.orEmpty(),
|
||||
targetTypeId = TypeId(targetObjectType.orEmpty()),
|
||||
emoji = if (!iconEmoji.isNullOrBlank()) iconEmoji else null,
|
||||
image = if (!iconImage.isNullOrBlank()) urlBuilder.thumbnail(iconImage!!) else null,
|
||||
image = iconImage?.takeIf { it.isNotBlank() }?.let { urlBuilder.thumbnail(it) },
|
||||
layout = layout ?: ObjectType.Layout.BASIC,
|
||||
coverColor = coverContainer?.coverColor,
|
||||
coverImage = coverContainer?.coverImage,
|
||||
|
|
|
@ -207,7 +207,7 @@ suspend fun List<ColumnView>.buildGridRow(
|
|||
type = type,
|
||||
name = name,
|
||||
emoji = emoji,
|
||||
image = image?.let { if (it.isEmpty()) null else builder.thumbnail(it) },
|
||||
image = image?.takeIf { it.isNotBlank() }?.let { builder.thumbnail(it) },
|
||||
cells = cells,
|
||||
layout = layout,
|
||||
isChecked = done,
|
||||
|
|
|
@ -11,14 +11,19 @@ import com.anytypeio.anytype.analytics.base.EventsDictionary.CLICK_ONBOARDING_TO
|
|||
import com.anytypeio.anytype.analytics.base.EventsPropertiesKey
|
||||
import com.anytypeio.anytype.analytics.event.EventAnalytics
|
||||
import com.anytypeio.anytype.analytics.props.Props
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.NO_VALUE
|
||||
import com.anytypeio.anytype.core_models.ObjectOrigin
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_utils.ext.msg
|
||||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.base.onSuccess
|
||||
import com.anytypeio.anytype.domain.device.FileSharer
|
||||
import com.anytypeio.anytype.domain.media.UploadFile
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.objects.CreateBookmarkObject
|
||||
import com.anytypeio.anytype.domain.objects.CreatePrefilledNote
|
||||
|
@ -31,6 +36,8 @@ import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
|
|||
import com.anytypeio.anytype.presentation.spaces.SpaceIconView
|
||||
import com.anytypeio.anytype.presentation.spaces.spaceIcon
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
@ -48,7 +55,9 @@ class AddToAnytypeViewModel(
|
|||
private val getSpaceViews: GetSpaceViews,
|
||||
private val urlBuilder: UrlBuilder,
|
||||
private val awaitAccountStartManager: AwaitAccountStartManager,
|
||||
private val analytics: Analytics
|
||||
private val analytics: Analytics,
|
||||
private val uploadFile: UploadFile,
|
||||
private val fileSharer: FileSharer
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val selectedSpaceId = MutableStateFlow(NO_VALUE)
|
||||
|
@ -108,6 +117,62 @@ class AddToAnytypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onShareImages(uris: List<String>) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
delay(3000)
|
||||
val targetSpaceView = spaceViews.value.firstOrNull { view ->
|
||||
view.isSelected
|
||||
}
|
||||
val targetSpaceId = targetSpaceView?.obj?.targetSpaceId!!
|
||||
val paths = uris.mapNotNull { uri ->
|
||||
fileSharer.getPath(uri)
|
||||
}
|
||||
val files = mutableListOf<Id>()
|
||||
paths.forEach { path ->
|
||||
uploadFile.async(
|
||||
UploadFile.Params(
|
||||
path = path,
|
||||
space = SpaceId(targetSpaceId)
|
||||
)
|
||||
).onSuccess { obj ->
|
||||
files.add(obj)
|
||||
}
|
||||
}
|
||||
val startTime = System.currentTimeMillis()
|
||||
createPrefilledNote.async(
|
||||
CreatePrefilledNote.Params(
|
||||
text = "Here are your files",
|
||||
space = targetSpaceId,
|
||||
details = mapOf(
|
||||
Relations.ORIGIN to ObjectOrigin.SHARING_EXTENSION.code.toDouble()
|
||||
),
|
||||
attachments = files
|
||||
)
|
||||
).fold(
|
||||
onSuccess = { result ->
|
||||
sendAnalyticsObjectCreateEvent(
|
||||
analytics = analytics,
|
||||
objType = MarketplaceObjectTypeIds.NOTE,
|
||||
route = EventsDictionary.Routes.sharingExtension,
|
||||
startTime = startTime
|
||||
)
|
||||
if (targetSpaceId == spaceManager.get()) {
|
||||
navigation.emit(OpenObjectNavigation.OpenEditor(result))
|
||||
} else {
|
||||
with(commands) {
|
||||
emit(Command.ObjectAddToSpaceToast(targetSpaceView.obj.name))
|
||||
emit(Command.Dismiss)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure = {
|
||||
Timber.d(it, "Error while creating note")
|
||||
sendToast("Error while creating note: ${it.msg()}")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onCreateBookmark(url: String) {
|
||||
viewModelScope.launch {
|
||||
val targetSpaceView = spaceViews.value.firstOrNull { view ->
|
||||
|
@ -192,6 +257,32 @@ class AddToAnytypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onUploadImage(path: String) {
|
||||
Timber.d("Attempt to share image: $path")
|
||||
viewModelScope.launch {
|
||||
val targetSpaceView = spaceViews.value.firstOrNull { view ->
|
||||
view.isSelected
|
||||
}
|
||||
val targetSpaceId = targetSpaceView?.obj?.targetSpaceId!!
|
||||
val params = UploadFile.Params(
|
||||
path = path,
|
||||
space = SpaceId(targetSpaceId)
|
||||
)
|
||||
Timber.d("Uploading file with params: $params")
|
||||
uploadFile.async(params).fold(
|
||||
onSuccess = { obj: Id ->
|
||||
Timber.d("Successfully upload file")
|
||||
if (targetSpaceId == spaceManager.get()) {
|
||||
navigation.emit(OpenObjectNavigation.OpenEditor(obj))
|
||||
}
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while uploading file")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSelectSpaceClicked(view: SpaceView) {
|
||||
Timber.d("onSelectSpaceClicked: ${view.obj.targetSpaceId}")
|
||||
viewModelScope.launch {
|
||||
|
@ -225,7 +316,9 @@ class AddToAnytypeViewModel(
|
|||
private val getSpaceViews: GetSpaceViews,
|
||||
private val urlBuilder: UrlBuilder,
|
||||
private val awaitAccountStartManager: AwaitAccountStartManager,
|
||||
private val analytics: Analytics
|
||||
private val analytics: Analytics,
|
||||
private val uploadFile: UploadFile,
|
||||
private val fileSharer: FileSharer
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
|
@ -236,7 +329,9 @@ class AddToAnytypeViewModel(
|
|||
getSpaceViews = getSpaceViews,
|
||||
urlBuilder = urlBuilder,
|
||||
awaitAccountStartManager = awaitAccountStartManager,
|
||||
analytics = analytics
|
||||
analytics = analytics,
|
||||
uploadFile = uploadFile,
|
||||
fileSharer = fileSharer
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ private fun Context.deleteTemporaryFolder() {
|
|||
/**
|
||||
* Return /storage/emulated/0/Android/data/package/files/$TEMPORARY_DIRECTORY_NAME directory
|
||||
*/
|
||||
private fun Context.getExternalFilesDirTemp(): File? = getExternalFilesDir(TEMPORARY_DIRECTORY_NAME)
|
||||
fun Context.getExternalFilesDirTemp(): File? = getExternalFilesDir(TEMPORARY_DIRECTORY_NAME)
|
||||
|
||||
/**
|
||||
* Return /storage/emulated/0/Android/data/io.anytype.app/files/networkModeConfig directory
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.anytypeio.anytype.presentation.util.downloader
|
|||
|
||||
import android.content.Context
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
||||
|
@ -12,7 +13,7 @@ class DocumentFileShareDownloader(
|
|||
dispatchers: AppCoroutineDispatchers
|
||||
) : MiddlewareShareDownloader(context, uriFileProvider, dispatchers) {
|
||||
|
||||
override suspend fun downloadFile(hash: String, path: String) = repo.downloadFile(
|
||||
Command.DownloadFile(hash = hash, path = path)
|
||||
override suspend fun downloadFile(objectId: Id, path: String) = repo.downloadFile(
|
||||
Command.DownloadFile(objectId = objectId, path = path)
|
||||
)
|
||||
}
|
|
@ -2,7 +2,7 @@ package com.anytypeio.anytype.presentation.util.downloader
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.anytypeio.anytype.core_models.Hash
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import java.io.File
|
||||
|
@ -18,7 +18,7 @@ abstract class MiddlewareShareDownloader(
|
|||
) : ResultInteractor<MiddlewareShareDownloader.Params, MiddlewareShareDownloader.Response>(dispatchers.io) {
|
||||
|
||||
data class Params(
|
||||
val hash: Hash,
|
||||
val objectId: Id,
|
||||
val name: String
|
||||
)
|
||||
|
||||
|
@ -28,20 +28,20 @@ abstract class MiddlewareShareDownloader(
|
|||
)
|
||||
|
||||
/**
|
||||
* @param hash is a some middleware id
|
||||
* @param objectId id of Object File
|
||||
* @param path is local storage path to the file created
|
||||
* @return path to the file in the local storage
|
||||
* */
|
||||
abstract suspend fun downloadFile(hash: String, path: String): String
|
||||
abstract suspend fun downloadFile(objectId: Id, path: String): String
|
||||
|
||||
override suspend fun doWork(params: Params): Response {
|
||||
val cacheDir = context.cacheDir
|
||||
|
||||
require(cacheDir != null) { "Impossible to cache files!" }
|
||||
|
||||
val downloadFolder = File("${cacheDir.path}/${params.hash}").apply { mkdirs() }
|
||||
val downloadFolder = File("${cacheDir.path}/${params.objectId}").apply { mkdirs() }
|
||||
|
||||
val resultFilePath = "${cacheDir.path}/${params.hash}/${params.name}"
|
||||
val resultFilePath = "${cacheDir.path}/${params.objectId}/${params.name}"
|
||||
val resultFile = File(resultFilePath)
|
||||
|
||||
if (!resultFile.exists()) {
|
||||
|
@ -50,7 +50,12 @@ abstract class MiddlewareShareDownloader(
|
|||
if (tempDir.exists()) tempDir.deleteRecursively()
|
||||
tempDir.mkdirs()
|
||||
|
||||
val tempResult = File(downloadFile(params.hash, tempFileFolderPath))
|
||||
val tempResult = File(
|
||||
downloadFile(
|
||||
objectId = params.objectId,
|
||||
path = tempFileFolderPath
|
||||
)
|
||||
)
|
||||
|
||||
tempResult.renameTo(resultFile)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.anytypeio.anytype.analytics.base.Analytics
|
|||
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.Payload
|
||||
import com.anytypeio.anytype.core_models.Position
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
|
@ -398,6 +399,7 @@ open class EditorViewModelTest {
|
|||
fun setup() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
builder = UrlBuilder(gateway)
|
||||
stubNetworkMode()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -406,6 +408,12 @@ open class EditorViewModelTest {
|
|||
verifyNoInteractions(interceptEvents)
|
||||
}
|
||||
|
||||
fun stubNetworkMode() {
|
||||
getNetworkMode.stub {
|
||||
onBlocking { run(Unit) } doReturn NetworkModeConfig()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should start opening page when requested`() {
|
||||
val param = OpenPage.Params(root, true)
|
||||
|
@ -2568,7 +2576,7 @@ open class EditorViewModelTest {
|
|||
params = eq(
|
||||
MiddlewareShareDownloader.Params(
|
||||
name = file.content<Block.Content.File>().name.orEmpty(),
|
||||
hash = file.content<Block.Content.File>().hash.orEmpty(),
|
||||
objectId = file.content<Block.Content.File>().targetObjectId.orEmpty(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -2618,7 +2626,7 @@ open class EditorViewModelTest {
|
|||
|
||||
// TESTING
|
||||
|
||||
vm.startDownloadingFile(id = file.id)
|
||||
vm.startDownloadingFile(blockId = file.id)
|
||||
|
||||
runBlockingTest {
|
||||
verify(downloadFile, times(1)).invoke(
|
||||
|
@ -2626,7 +2634,7 @@ open class EditorViewModelTest {
|
|||
DownloadFile.Params(
|
||||
name = file.content<Block.Content.File>().name.orEmpty(),
|
||||
url = builder.file(
|
||||
hash = file.content<Block.Content.File>().hash
|
||||
path = file.content<Block.Content.File>().targetObjectId!!
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -3394,7 +3402,7 @@ open class EditorViewModelTest {
|
|||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.File(
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
type = Block.Content.File.Type.IMAGE,
|
||||
state = Block.Content.File.State.ERROR
|
||||
),
|
||||
|
@ -3469,7 +3477,7 @@ open class EditorViewModelTest {
|
|||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.File(
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = MockDataFactory.randomString(),
|
||||
type = Block.Content.File.Type.VIDEO,
|
||||
state = Block.Content.File.State.ERROR
|
||||
),
|
||||
|
@ -3587,7 +3595,8 @@ open class EditorViewModelTest {
|
|||
background = ThemeColor.DEFAULT,
|
||||
style = BlockView.Decoration.Style.Card
|
||||
)
|
||||
)
|
||||
),
|
||||
name = file.content<Block.Content.File>().name.orEmpty()
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class EditorErrorMessageTest : EditorPresentationTestSetup() {
|
|||
val file = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.File(
|
||||
hash = MockDataFactory.randomUuid(),
|
||||
targetObjectId = MockDataFactory.randomUuid(),
|
||||
type = Block.Content.File.Type.FILE,
|
||||
state = Block.Content.File.State.DONE
|
||||
),
|
||||
|
@ -69,7 +69,7 @@ class EditorErrorMessageTest : EditorPresentationTestSetup() {
|
|||
|
||||
// Launching operation that triggers a toast
|
||||
|
||||
vm.startDownloadingFile(id = file.id)
|
||||
vm.startDownloadingFile(blockId = file.id)
|
||||
|
||||
val subscription2 = launch { vm.toasts.collect { consumed.add(it) } }
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import com.anytypeio.anytype.core_models.StubTitle
|
|||
import com.anytypeio.anytype.core_models.ThemeColor
|
||||
import com.anytypeio.anytype.core_models.ext.content
|
||||
import com.anytypeio.anytype.core_utils.common.EventWrapper
|
||||
import com.anytypeio.anytype.presentation.BuildConfig
|
||||
import com.anytypeio.anytype.presentation.MockBlockFactory
|
||||
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
|
@ -21,6 +20,7 @@ import com.anytypeio.anytype.presentation.util.TXT
|
|||
import com.anytypeio.anytype.test_utils.MockDataFactory
|
||||
import com.jraska.livedata.test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
@ -48,6 +48,7 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
stubGetNetworkMode()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -543,15 +544,18 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `should open file when clicking on file when page is locked`() {
|
||||
fun `should open file when clicking on file when page is locked`() = runTest {
|
||||
|
||||
// SETUP
|
||||
|
||||
val fileBlockId = MockDataFactory.randomUuid()
|
||||
val targetObjectId = MockDataFactory.randomUuid()
|
||||
|
||||
val file = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
id = fileBlockId,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.File(
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = targetObjectId,
|
||||
type = Block.Content.File.Type.FILE,
|
||||
state = Block.Content.File.State.DONE
|
||||
),
|
||||
|
@ -565,17 +569,33 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
mapOf(Block.Fields.IS_LOCKED_KEY to true)
|
||||
),
|
||||
content = Block.Content.Smart,
|
||||
children = listOf(header.id, file.id)
|
||||
children = listOf(header.id, fileBlockId)
|
||||
),
|
||||
header,
|
||||
title,
|
||||
file
|
||||
)
|
||||
|
||||
val mimeType = "application/pdf"
|
||||
val fileName = "file.pdf"
|
||||
val fileSize = 1000.0
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(
|
||||
document = page
|
||||
document = page,
|
||||
details = Block.Details(
|
||||
mapOf(
|
||||
targetObjectId to Block.Fields(
|
||||
mapOf(
|
||||
Relations.ID to targetObjectId,
|
||||
Relations.FILE_MIME_TYPE to mimeType,
|
||||
Relations.NAME to fileName,
|
||||
Relations.SIZE_IN_BYTES to fileSize
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
@ -593,13 +613,13 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
mode = BlockView.Mode.READ
|
||||
),
|
||||
BlockView.Media.File(
|
||||
id = file.id,
|
||||
id = fileBlockId,
|
||||
mode = BlockView.Mode.READ,
|
||||
hash = file.content<Block.Content.File>().hash,
|
||||
mime = null,
|
||||
name = null,
|
||||
size = null,
|
||||
url = builder.file(file.content<Block.Content.File>().hash),
|
||||
targetObjectId = targetObjectId,
|
||||
mime = mimeType,
|
||||
name = fileName,
|
||||
size = fileSize.toLong(),
|
||||
url = builder.file(targetObjectId),
|
||||
decorations = listOf(
|
||||
BlockView.Decoration(
|
||||
background = ThemeColor.DEFAULT,
|
||||
|
@ -618,15 +638,14 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
|
||||
val testObserver = vm.commands.test()
|
||||
|
||||
vm.onClickListener(ListenerType.File.View(file.id))
|
||||
vm.onClickListener(ListenerType.File.View(fileBlockId))
|
||||
|
||||
// checking open-by-default-app command
|
||||
|
||||
testObserver.assertValue { value ->
|
||||
value is EventWrapper && value.peekContent() == Command.OpenFileByDefaultApp(
|
||||
id = file.id,
|
||||
uri = builder.file(file.content<Block.Content.File>().hash),
|
||||
mime = file.content<Block.Content.File>().mime.orEmpty()
|
||||
id = fileBlockId,
|
||||
uri = builder.file(targetObjectId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -636,11 +655,17 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
|
||||
// SETUP
|
||||
|
||||
val fileBlockId = MockDataFactory.randomUuid()
|
||||
val targetObjectId = MockDataFactory.randomUuid()
|
||||
val mimeType = "*/png"
|
||||
val fileName = "image.png"
|
||||
val fileSize = 1000.0
|
||||
|
||||
val picture = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
id = fileBlockId,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.File(
|
||||
hash = MockDataFactory.randomString(),
|
||||
targetObjectId = targetObjectId,
|
||||
type = Block.Content.File.Type.IMAGE,
|
||||
state = Block.Content.File.State.DONE
|
||||
),
|
||||
|
@ -664,7 +689,19 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(
|
||||
document = page
|
||||
document = page,
|
||||
details = Block.Details(
|
||||
mapOf(
|
||||
targetObjectId to Block.Fields(
|
||||
mapOf(
|
||||
Relations.ID to targetObjectId,
|
||||
Relations.FILE_MIME_TYPE to mimeType,
|
||||
Relations.NAME to fileName,
|
||||
Relations.SIZE_IN_BYTES to fileSize
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
@ -684,11 +721,11 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
BlockView.Media.Picture(
|
||||
id = picture.id,
|
||||
mode = BlockView.Mode.READ,
|
||||
hash = picture.content<Block.Content.File>().hash,
|
||||
mime = null,
|
||||
name = null,
|
||||
size = null,
|
||||
url = builder.image(picture.content<Block.Content.File>().hash),
|
||||
targetObjectId = targetObjectId,
|
||||
mime = mimeType,
|
||||
name = fileName,
|
||||
size = fileSize.toLong(),
|
||||
url = builder.image(targetObjectId),
|
||||
indent = 0,
|
||||
decorations = listOf(
|
||||
BlockView.Decoration(
|
||||
|
@ -715,7 +752,7 @@ class EditorLockPageTest : EditorPresentationTestSetup() {
|
|||
testObserver.assertValue { value ->
|
||||
value is EventWrapper && value.peekContent() == Command.OpenFullScreenImage(
|
||||
target = picture.id,
|
||||
url = builder.original(picture.content<Block.Content.File>().hash)
|
||||
url = builder.original(targetObjectId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
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.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.editor.editor.Markup
|
||||
|
@ -20,6 +23,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
private val urlBuilder: UrlBuilder get() = UrlBuilder(gateway)
|
||||
|
||||
private val targetObjectId : Id = "647tyhfgehf7ru"
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
|
@ -33,18 +38,28 @@ class MapperExtensionKtTest {
|
|||
val indent = MockDataFactory.randomInt()
|
||||
|
||||
val name = "name"
|
||||
val size = 10000L
|
||||
val mime = "*/txt"
|
||||
val hash = "647tyhfgehf7ru"
|
||||
val state = Block.Content.File.State.DONE
|
||||
val type = Block.Content.File.Type.FILE
|
||||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
targetObjectId to Block.Fields(
|
||||
mapOf(
|
||||
Relations.NAME to name,
|
||||
Relations.SIZE_IN_BYTES to 10000.0,
|
||||
Relations.FILE_MIME_TYPE to mime,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val block = Block.Content.File(
|
||||
name = name,
|
||||
size = size,
|
||||
size = 10000L,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
targetObjectId = targetObjectId,
|
||||
state = state,
|
||||
type = type
|
||||
|
||||
|
@ -53,15 +68,15 @@ class MapperExtensionKtTest {
|
|||
val expected = BlockView.Media.File(
|
||||
id = id,
|
||||
name = name,
|
||||
size = size,
|
||||
size = 10000L,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
targetObjectId = targetObjectId,
|
||||
mode = BlockView.Mode.EDIT,
|
||||
url = urlBuilder.video(hash),
|
||||
url = urlBuilder.video(targetObjectId),
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
|
||||
val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details)
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
@ -79,7 +94,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
val block = Block.Content.File(
|
||||
state = state,
|
||||
type = type
|
||||
type = type,
|
||||
targetObjectId = targetObjectId
|
||||
)
|
||||
|
||||
val expected =
|
||||
|
@ -102,8 +118,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
val block = Block.Content.File(
|
||||
state = state,
|
||||
type = type
|
||||
|
||||
type = type,
|
||||
targetObjectId = targetObjectId
|
||||
)
|
||||
|
||||
val expected = BlockView.Error.File(id = id, indent = indent, decorations = emptyList())
|
||||
|
@ -125,7 +141,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
val block = Block.Content.File(
|
||||
state = state,
|
||||
type = type
|
||||
type = type,
|
||||
targetObjectId = targetObjectId
|
||||
)
|
||||
|
||||
val expected = BlockView.Upload.File(id = id, indent = indent)
|
||||
|
@ -142,7 +159,7 @@ class MapperExtensionKtTest {
|
|||
val indent = MockDataFactory.randomInt()
|
||||
|
||||
val name = "name"
|
||||
val size = 10000L
|
||||
val size = 10000.0
|
||||
val mime = "image/jpeg"
|
||||
val hash = "647tyhfgehf7ru"
|
||||
val state = Block.Content.File.State.DONE
|
||||
|
@ -150,27 +167,36 @@ class MapperExtensionKtTest {
|
|||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val block = Block.Content.File(
|
||||
name = name,
|
||||
size = size,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
targetObjectId = targetObjectId,
|
||||
state = state,
|
||||
type = type
|
||||
|
||||
)
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
targetObjectId to Block.Fields(
|
||||
mapOf(
|
||||
Relations.NAME to name,
|
||||
Relations.SIZE_IN_BYTES to size,
|
||||
Relations.FILE_MIME_TYPE to mime,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expected = BlockView.Media.Picture(
|
||||
id = id,
|
||||
name = name,
|
||||
size = size,
|
||||
size = size.toLong(),
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
targetObjectId = targetObjectId,
|
||||
url = urlBuilder.image(hash),
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
|
||||
val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
|
||||
val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details)
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
@ -188,8 +214,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
val block = Block.Content.File(
|
||||
state = state,
|
||||
type = type
|
||||
|
||||
type = type,
|
||||
targetObjectId = targetObjectId
|
||||
)
|
||||
|
||||
val expected = BlockView.MediaPlaceholder.Picture(
|
||||
|
@ -215,8 +241,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
val block = Block.Content.File(
|
||||
state = state,
|
||||
type = type
|
||||
|
||||
type = type,
|
||||
targetObjectId = targetObjectId
|
||||
)
|
||||
|
||||
val expected = BlockView.Error.Picture(
|
||||
|
@ -243,7 +269,8 @@ class MapperExtensionKtTest {
|
|||
|
||||
val block = Block.Content.File(
|
||||
state = state,
|
||||
type = type
|
||||
type = type,
|
||||
targetObjectId = targetObjectId
|
||||
)
|
||||
|
||||
val expected = BlockView.Upload.Picture(id = id, indent = indent)
|
||||
|
@ -262,38 +289,47 @@ class MapperExtensionKtTest {
|
|||
val name = "name"
|
||||
val size = 10000L
|
||||
val mime = "video/mp4"
|
||||
val hash = "647tyhfgehf7ru"
|
||||
val targetObjectId = "647tyhfgehf7ru"
|
||||
val state = Block.Content.File.State.DONE
|
||||
val type = Block.Content.File.Type.VIDEO
|
||||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val block = Block.Content.File(
|
||||
name = name,
|
||||
size = size,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
targetObjectId = targetObjectId,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
targetObjectId to Block.Fields(
|
||||
mapOf(
|
||||
Relations.NAME to name,
|
||||
Relations.SIZE_IN_BYTES to 10000.0,
|
||||
Relations.FILE_MIME_TYPE to mime,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val expected = BlockView.Media.Video(
|
||||
id = id,
|
||||
name = name,
|
||||
size = size,
|
||||
mime = mime,
|
||||
hash = hash,
|
||||
url = urlBuilder.video(hash),
|
||||
targetObjectId = targetObjectId,
|
||||
url = urlBuilder.video(targetObjectId),
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
|
||||
val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
|
||||
val actual = block.toVideoView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList(), details)
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return video block view empty params`() {
|
||||
fun `should return video block error view when target object id is empty`() {
|
||||
|
||||
val id = MockDataFactory.randomUuid()
|
||||
|
||||
|
@ -304,22 +340,13 @@ class MapperExtensionKtTest {
|
|||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val block = Block.Content.File(
|
||||
name = null,
|
||||
size = null,
|
||||
mime = null,
|
||||
hash = null,
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
|
||||
)
|
||||
|
||||
val expected = BlockView.Media.Video(
|
||||
val expected = BlockView.Error.Video(
|
||||
id = id,
|
||||
name = null,
|
||||
size = null,
|
||||
mime = null,
|
||||
hash = null,
|
||||
url = urlBuilder.video(null),
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
|
@ -329,6 +356,90 @@ class MapperExtensionKtTest {
|
|||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return image block error view when target object id is empty`() {
|
||||
|
||||
val id = MockDataFactory.randomUuid()
|
||||
|
||||
val indent = MockDataFactory.randomInt()
|
||||
|
||||
val state = Block.Content.File.State.DONE
|
||||
val type = Block.Content.File.Type.IMAGE
|
||||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val block = Block.Content.File(
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
||||
val expected = BlockView.Error.Picture(
|
||||
id = id,
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
|
||||
val actual = block.toPictureView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return file block error view when target object id is empty`() {
|
||||
|
||||
val id = MockDataFactory.randomUuid()
|
||||
|
||||
val indent = MockDataFactory.randomInt()
|
||||
|
||||
val state = Block.Content.File.State.DONE
|
||||
val type = Block.Content.File.Type.FILE
|
||||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val block = Block.Content.File(
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
||||
val expected = BlockView.Error.File(
|
||||
id = id,
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
|
||||
val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return file block error view when target object id is empty for pdf`() {
|
||||
|
||||
val id = MockDataFactory.randomUuid()
|
||||
|
||||
val indent = MockDataFactory.randomInt()
|
||||
|
||||
val state = Block.Content.File.State.DONE
|
||||
val type = Block.Content.File.Type.PDF
|
||||
val mode = BlockView.Mode.EDIT
|
||||
|
||||
val block = Block.Content.File(
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
||||
val expected = BlockView.Error.File(
|
||||
id = id,
|
||||
indent = indent,
|
||||
decorations = emptyList()
|
||||
)
|
||||
|
||||
val actual = block.toFileView(id, urlBuilder, indent, mode, false, ThemeColor.DEFAULT, false, emptyList())
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return placeholder video block view`() {
|
||||
|
||||
|
@ -344,7 +455,7 @@ class MapperExtensionKtTest {
|
|||
name = null,
|
||||
size = null,
|
||||
mime = null,
|
||||
hash = null,
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
@ -375,7 +486,7 @@ class MapperExtensionKtTest {
|
|||
name = null,
|
||||
size = null,
|
||||
mime = null,
|
||||
hash = null,
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
@ -405,7 +516,7 @@ class MapperExtensionKtTest {
|
|||
name = null,
|
||||
size = null,
|
||||
mime = null,
|
||||
hash = null,
|
||||
targetObjectId = null,
|
||||
state = state,
|
||||
type = type
|
||||
)
|
||||
|
@ -435,7 +546,7 @@ class MapperExtensionKtTest {
|
|||
name = null,
|
||||
size = null,
|
||||
mime = null,
|
||||
hash = null,
|
||||
targetObjectId = null,
|
||||
state = null,
|
||||
type = type
|
||||
)
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.junit.Test
|
|||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.stub
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
@ -37,7 +36,7 @@ class ObjectWrapperExtensionsKtTest {
|
|||
|
||||
stubUrlBuilder(imageHash)
|
||||
|
||||
val result = obj.getImagePath(urlBuilder)
|
||||
val result = urlBuilder.image(obj.iconImage!!)
|
||||
|
||||
val expected = URL + imageHash
|
||||
|
||||
|
@ -47,87 +46,6 @@ class ObjectWrapperExtensionsKtTest {
|
|||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null image path from object wrapper when hash is null`() {
|
||||
|
||||
val imageHash: String? = null
|
||||
|
||||
val obj = ObjectWrapper.Basic(
|
||||
mapOf("iconImage" to imageHash)
|
||||
)
|
||||
|
||||
stubUrlBuilder(imageHash)
|
||||
|
||||
val result = obj.getImagePath(urlBuilder)
|
||||
|
||||
assertNull(actual = result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null image path from object wrapper when hash is empty`() {
|
||||
|
||||
val imageHash = ""
|
||||
|
||||
val obj = ObjectWrapper.Basic(
|
||||
mapOf("iconImage" to imageHash)
|
||||
)
|
||||
|
||||
stubUrlBuilder(imageHash)
|
||||
|
||||
val result = obj.getImagePath(urlBuilder)
|
||||
|
||||
assertNull(actual = result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null image path from object wrapper when hash is blank`() {
|
||||
|
||||
val imageHash = " "
|
||||
|
||||
val obj = ObjectWrapper.Basic(
|
||||
mapOf("iconImage" to imageHash)
|
||||
)
|
||||
|
||||
stubUrlBuilder(imageHash)
|
||||
|
||||
val result = obj.getImagePath(urlBuilder)
|
||||
|
||||
assertNull(actual = result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return proper emoji from object wrapper`() {
|
||||
|
||||
val emojiHash = "ycd79"
|
||||
|
||||
val obj = ObjectWrapper.Basic(
|
||||
mapOf("iconEmoji" to emojiHash)
|
||||
)
|
||||
|
||||
val result = obj.getEmojiPath()
|
||||
|
||||
val expected = emojiHash
|
||||
|
||||
assertEquals(
|
||||
expected = expected,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null emoji from object wrapper when emoji is null`() {
|
||||
|
||||
val emojiHash: String? = null
|
||||
|
||||
val obj = ObjectWrapper.Basic(
|
||||
mapOf("iconEmoji" to emojiHash)
|
||||
)
|
||||
|
||||
val result = obj.getEmojiPath()
|
||||
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null emoji from object wrapper when emoji is empty`() {
|
||||
|
||||
|
@ -137,7 +55,7 @@ class ObjectWrapperExtensionsKtTest {
|
|||
mapOf("iconEmoji" to emojiHash)
|
||||
)
|
||||
|
||||
val result = obj.getEmojiPath()
|
||||
val result = urlBuilder.image(obj.iconEmoji!!)
|
||||
|
||||
assertNull(result)
|
||||
}
|
||||
|
@ -151,7 +69,7 @@ class ObjectWrapperExtensionsKtTest {
|
|||
mapOf("iconEmoji" to emojiHash)
|
||||
)
|
||||
|
||||
val result = obj.getEmojiPath()
|
||||
val result = urlBuilder.image(obj.iconEmoji!!)
|
||||
|
||||
assertNull(result)
|
||||
}
|
||||
|
@ -226,15 +144,9 @@ class ObjectWrapperExtensionsKtTest {
|
|||
)
|
||||
}
|
||||
|
||||
fun stubUrlBuilder(hash: String?) {
|
||||
if (hash == null) {
|
||||
urlBuilder.stub {
|
||||
on { image(null) } doThrow RuntimeException("Should not happened")
|
||||
}
|
||||
} else {
|
||||
urlBuilder.stub {
|
||||
on { image(hash) } doReturn URL + hash
|
||||
}
|
||||
fun stubUrlBuilder(targetObjectId: String) {
|
||||
urlBuilder.stub {
|
||||
on { image(targetObjectId) } doReturn URL + targetObjectId
|
||||
}
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ message Change {
|
|||
|
||||
StoreSliceUpdate storeSliceUpdate = 109;
|
||||
OriginalCreatedTimestampSet originalCreatedTimestampSet = 110;
|
||||
SetFileInfo setFileInfo = 111;
|
||||
}
|
||||
reserved 102,103,104; // old unsupported relation changes
|
||||
}
|
||||
|
@ -151,4 +152,8 @@ message Change {
|
|||
message OriginalCreatedTimestampSet {
|
||||
int64 ts = 1;
|
||||
}
|
||||
|
||||
message SetFileInfo {
|
||||
model.FileInfo fileInfo = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2572,6 +2572,32 @@ message Rpc {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
message SpaceOffload {
|
||||
message Request {
|
||||
string spaceId = 1;
|
||||
}
|
||||
message Response {
|
||||
Error error = 1;
|
||||
int32 filesOffloaded = 2;
|
||||
uint64 bytesOffloaded = 3;
|
||||
|
||||
message Error {
|
||||
Code code = 1;
|
||||
string description = 2;
|
||||
|
||||
enum Code {
|
||||
NULL = 0;
|
||||
UNKNOWN_ERROR = 1;
|
||||
BAD_INPUT = 2;
|
||||
// ...
|
||||
NODE_NOT_STARTED = 103;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message ListOffload {
|
||||
message Request {
|
||||
repeated string onlyIds = 1; // empty means all
|
||||
|
@ -2605,12 +2631,13 @@ message Rpc {
|
|||
anytype.model.Block.Content.File.Type type = 3;
|
||||
bool disableEncryption = 4; // deprecated, has no affect, GO-1926
|
||||
anytype.model.Block.Content.File.Style style = 5;
|
||||
|
||||
google.protobuf.Struct details = 7; // additional details for file object
|
||||
}
|
||||
|
||||
message Response {
|
||||
Error error = 1;
|
||||
string hash = 2;
|
||||
string objectId = 2;
|
||||
google.protobuf.Struct details = 3;
|
||||
|
||||
message Error {
|
||||
Code code = 1;
|
||||
|
@ -2626,7 +2653,7 @@ message Rpc {
|
|||
}
|
||||
message Download {
|
||||
message Request {
|
||||
string hash = 1;
|
||||
string objectId = 1;
|
||||
string path = 2; // path to save file. Temp directory is used if empty
|
||||
}
|
||||
|
||||
|
@ -2942,7 +2969,7 @@ message Rpc {
|
|||
|
||||
message Response {
|
||||
Error error = 1;
|
||||
string hash = 2;
|
||||
string objectId = 2;
|
||||
|
||||
message Error {
|
||||
Code code = 1;
|
||||
|
|
|
@ -370,6 +370,7 @@ message Event {
|
|||
Name name = 6;
|
||||
Size size = 7;
|
||||
Style style = 8;
|
||||
TargetObjectId targetObjectId = 9;
|
||||
|
||||
message Name {
|
||||
string value = 1;
|
||||
|
@ -403,6 +404,9 @@ message Event {
|
|||
int64 value = 1;
|
||||
}
|
||||
|
||||
message TargetObjectId {
|
||||
string value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user