Feature | Create a bookmark from pasted url (#2074)

This commit is contained in:
Evgenii Kozlov 2022-02-01 02:39:07 +03:00 committed by GitHub
parent 4d806ab010
commit 03df82390d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 271 additions and 22 deletions

View File

@ -99,6 +99,7 @@ object EventsDictionary {
const val BLOCK_DOWNLOAD_FILE = "DownloadFile"
const val BLOCK_UPLOAD = "BlockUpload"
const val BLOCK_SETUP_BOOKMARK = "BlockBookmarkFetch"
const val BLOCK_CREATE_BOOKMARK = "BlockBookmarkCreateAndFetch"
const val BLOCK_PASTE = "BlockPaste"
const val BLOCK_COPY = "BlockCopy"
const val BLOCK_DIVIDER_UPDATE = "BlockListSetDivStyle"

View File

@ -6,7 +6,6 @@ import androidx.fragment.app.testing.launchFragmentInContainer
import com.anytypeio.anytype.R
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.*
import com.anytypeio.anytype.core_utils.tools.Counter
import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider
import com.anytypeio.anytype.domain.`object`.UpdateDetail
import com.anytypeio.anytype.domain.base.Either
@ -32,6 +31,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultEditorType
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.CreateBookmark
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.sets.FindObjectSetForType
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
@ -49,6 +49,7 @@ import com.anytypeio.anytype.presentation.editor.editor.pattern.DefaultPatternMa
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
import com.anytypeio.anytype.presentation.editor.selection.SelectionStateHolder
import com.anytypeio.anytype.presentation.editor.toggle.ToggleStateHolder
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.Dispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.emptyFlow
@ -73,6 +74,7 @@ open class EditorTestSetup {
lateinit var updateAlignment: UpdateAlignment
lateinit var replaceBlock: ReplaceBlock
lateinit var setupBookmark: SetupBookmark
lateinit var createBookmark: CreateBookmark
lateinit var uploadBlock: UploadBlock
lateinit var splitBlock: SplitBlock
lateinit var createPage: CreatePage
@ -82,6 +84,9 @@ open class EditorTestSetup {
lateinit var updateDetail: UpdateDetail
lateinit var getCompatibleObjectTypes: GetCompatibleObjectTypes
@Mock
lateinit var copyFileToCacheDirectory: CopyFileToCacheDirectory
@Mock
lateinit var openPage: OpenPage
@Mock
@ -232,6 +237,7 @@ open class EditorTestSetup {
getDefaultEditorType = GetDefaultEditorType(userSettingsRepository)
createObjectSet = CreateObjectSet(repo)
findObjectSetForType = FindObjectSetForType(repo)
createBookmark = CreateBookmark(repo)
TestEditorFragment.testViewModelFactory = EditorViewModelFactory(
openPage = openPage,
@ -247,7 +253,6 @@ open class EditorTestSetup {
urlBuilder = urlBuilder,
renderer = DefaultBlockViewRenderer(
urlBuilder = urlBuilder,
counter = Counter.Default(),
toggleStateHolder = ToggleStateHolder.Default(),
coverImageHashProvider = coverImageHashProvider
),
@ -290,7 +295,8 @@ open class EditorTestSetup {
turnIntoDocument = turnIntoDocument,
turnIntoStyle = turnIntoStyle,
updateBlocksMark = updateBlocksMark,
setObjectType = setObjectType
setObjectType = setObjectType,
createBookmark = createBookmark
),
createNewDocument = createNewDocument,
interceptThreadStatus = interceptThreadStatus,
@ -303,7 +309,8 @@ open class EditorTestSetup {
searchObjects = getSearchObjects,
getDefaultEditorType = getDefaultEditorType,
createObjectSet = createObjectSet,
findObjectSetForType = findObjectSetForType
findObjectSetForType = findObjectSetForType,
copyFileToCacheDirectory = copyFileToCacheDirectory
)
}

View File

@ -26,6 +26,7 @@ import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvid
import com.anytypeio.anytype.presentation.sets.ObjectSet
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
import com.anytypeio.anytype.presentation.sets.RelationValueDVViewModel
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.ui.relations.RelationValueBaseFragment
import com.anytypeio.anytype.utils.*
@ -52,6 +53,9 @@ class DisplayRelationObjectValueTest {
@Mock
lateinit var gateway: Gateway
@Mock
lateinit var copyFileToCacheDirectory: CopyFileToCacheDirectory
private lateinit var addRelationOption: AddDataViewRelationOption
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
private lateinit var removeStatusFromDataViewRecord: RemoveStatusFromDataViewRecord
@ -95,9 +99,9 @@ class DisplayRelationObjectValueTest {
removeTagFromRecord = removeTagFromDataViewRecord,
removeStatusFromDataViewRecord = removeStatusFromDataViewRecord,
urlBuilder = urlBuilder,
dispatcher = dispatcher,
updateDataViewRecord = updateDataViewRecord,
addFileToRecord = addFileToRecord
addFileToRecord = addFileToRecord,
copyFileToCache = copyFileToCacheDirectory
)
}

View File

@ -27,6 +27,7 @@ import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvid
import com.anytypeio.anytype.presentation.sets.ObjectSet
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
import com.anytypeio.anytype.presentation.sets.RelationValueDVViewModel
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.ui.relations.RelationValueBaseFragment
import com.anytypeio.anytype.utils.CoroutinesTestRule
@ -55,6 +56,9 @@ class DisplayRelationStatusValueTest {
@Mock
lateinit var gateway: Gateway
@Mock
lateinit var copyFileToCacheDirectory: CopyFileToCacheDirectory
private lateinit var addRelationOption: AddDataViewRelationOption
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
private lateinit var removeStatusFromDataViewRecord: RemoveStatusFromDataViewRecord
@ -98,9 +102,9 @@ class DisplayRelationStatusValueTest {
removeTagFromRecord = removeTagFromDataViewRecord,
removeStatusFromDataViewRecord = removeStatusFromDataViewRecord,
urlBuilder = urlBuilder,
dispatcher = dispatcher,
updateDataViewRecord = updateDataViewRecord,
addFileToRecord = addFileToRecord
addFileToRecord = addFileToRecord,
copyFileToCache = copyFileToCacheDirectory
)
}

View File

@ -27,6 +27,7 @@ import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvid
import com.anytypeio.anytype.presentation.sets.ObjectSet
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
import com.anytypeio.anytype.presentation.sets.RelationValueDVViewModel
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.ui.relations.RelationValueBaseFragment
import com.anytypeio.anytype.utils.CoroutinesTestRule
@ -55,6 +56,9 @@ class DisplayRelationTagValueTest {
@Mock
lateinit var dispatcher: Dispatcher<Payload>
@Mock
lateinit var copyFileToCacheDirectory: CopyFileToCacheDirectory
private lateinit var addRelationOption: AddDataViewRelationOption
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
private lateinit var removeStatusFromDataViewRecord: RemoveStatusFromDataViewRecord
@ -98,9 +102,9 @@ class DisplayRelationTagValueTest {
removeTagFromRecord = removeTagFromDataViewRecord,
removeStatusFromDataViewRecord = removeStatusFromDataViewRecord,
urlBuilder = urlBuilder,
dispatcher = dispatcher,
updateDataViewRecord = updateDataViewRecord,
addFileToRecord = addFileToRecord
addFileToRecord = addFileToRecord,
copyFileToCache = copyFileToCacheDirectory
)
}

View File

@ -24,6 +24,7 @@ import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvid
import com.anytypeio.anytype.presentation.sets.ObjectSet
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
import com.anytypeio.anytype.presentation.sets.RelationValueDVViewModel
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.ui.relations.RelationValueBaseFragment
import com.anytypeio.anytype.utils.*
@ -51,6 +52,9 @@ class EditRelationTagValueTest {
@Mock
lateinit var dispatcher: Dispatcher<Payload>
@Mock
lateinit var copyFileToCacheDirectory: CopyFileToCacheDirectory
private lateinit var addRelationOption: AddDataViewRelationOption
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
private lateinit var removeStatusFromDataViewRecord: RemoveStatusFromDataViewRecord
@ -94,9 +98,9 @@ class EditRelationTagValueTest {
removeTagFromRecord = removeTagFromDataViewRecord,
removeStatusFromDataViewRecord = removeStatusFromDataViewRecord,
urlBuilder = urlBuilder,
dispatcher = dispatcher,
updateDataViewRecord = updateDataViewRecord,
addFileToRecord = addFileToRecord
addFileToRecord = addFileToRecord,
copyFileToCache = copyFileToCacheDirectory
)
}

View File

@ -34,6 +34,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultEditorType
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.CreateBookmark
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.relations.AddFileToObject
import com.anytypeio.anytype.domain.sets.FindObjectSetForType
@ -237,6 +238,7 @@ object EditorSessionModule {
updateFields: UpdateFields,
updateAlignment: UpdateAlignment,
setupBookmark: SetupBookmark,
createBookmark: CreateBookmark,
turnIntoDocument: TurnIntoDocument,
setObjectType: SetObjectType,
matcher: DefaultPatternMatcher,
@ -277,6 +279,7 @@ object EditorSessionModule {
updateText = updateText,
updateAlignment = updateAlignment,
setupBookmark = setupBookmark,
createBookmark = createBookmark,
move = move,
paste = paste,
copy = copy,
@ -589,6 +592,15 @@ object EditorUseCaseModule {
repo = repo
)
@JvmStatic
@Provides
@PerScreen
fun provideCreateBookmarkUseCase(
repo: BlockRepository
): CreateBookmark = CreateBookmark(
repo = repo
)
@JvmStatic
@Provides
@PerScreen

View File

@ -49,6 +49,7 @@ import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Position
import com.anytypeio.anytype.core_models.SyncStatus
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_models.ext.getFirstLinkOrObjectMarkupParam
import com.anytypeio.anytype.core_models.ext.getSubstring
import com.anytypeio.anytype.core_ui.extensions.addTextFromSelectedStart
@ -119,7 +120,6 @@ import kotlinx.coroutines.flow.*
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.ArrayList
import javax.inject.Inject
import kotlin.math.abs
@ -1645,6 +1645,10 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
}
}
override fun onUrlPasted(url: Url) {
vm.onUrlPasted(url)
}
private fun hideKeyboard() {
Timber.d("Hiding keyboard")
hideSoftInput()

View File

@ -279,6 +279,20 @@ sealed class Command {
val url: String
)
/**
* Command for creating a bookmark block from [url]
* @property context id of the context
* @property target id of the target block (future bookmark block)
* @property url bookmark url
* @property [position] position relative to [target] block
*/
data class CreateBookmark(
val context: Id,
val target: Id,
val url: String,
val position: Position
)
/**
* Command for undoing latest changes in document
* @property context id of the context

View File

@ -1,8 +1,11 @@
package com.anytypeio.anytype.core_ui.tools
import com.anytypeio.anytype.core_models.Url
interface ClipboardInterceptor {
fun onClipboardAction(action: Action)
fun onUrlPasted(url: Url)
sealed class Action {
data class Copy(val selection: IntRange) : Action()

View File

@ -2,6 +2,7 @@ package com.anytypeio.anytype.core_ui.widgets.text
import android.R.id.copy
import android.R.id.paste
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Canvas
import android.text.InputType
@ -9,6 +10,7 @@ import android.text.Spanned
import android.text.TextWatcher
import android.text.util.Linkify
import android.util.AttributeSet
import android.util.Patterns
import android.view.DragEvent
import android.view.KeyEvent
import android.view.MotionEvent
@ -16,6 +18,7 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.graphics.withTranslation
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.features.editor.EditorTouchProcessor
import com.anytypeio.anytype.core_ui.tools.*
@ -204,11 +207,24 @@ class TextInputWidget : AppCompatEditText {
when (id) {
paste -> {
if (clipboardInterceptor != null) {
clipboardInterceptor?.onClipboardAction(
ClipboardInterceptor.Action.Paste(
selection = selectionStart..selectionEnd
if (editableText.isNotEmpty()) {
clipboardInterceptor?.onClipboardAction(
ClipboardInterceptor.Action.Paste(
selection = selectionStart..selectionEnd
)
)
)
} else {
val url = parseUrlFromPastedText()
if (url == null) {
clipboardInterceptor?.onClipboardAction(
ClipboardInterceptor.Action.Paste(
selection = selectionStart..selectionEnd
)
)
} else {
clipboardInterceptor?.onUrlPasted(url = url)
}
}
consumed = true
}
}
@ -231,6 +247,22 @@ class TextInputWidget : AppCompatEditText {
}
}
private fun parseUrlFromPastedText(): Url? {
val mng = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = mng.primaryClip
return if (clip != null && clip.itemCount > 0) {
val txt = clip.getItemAt(0).text
val matcher = Patterns.WEB_URL.matcher(txt)
if (matcher.matches()) {
txt.toString()
} else {
null
}
} else {
null
}
}
override fun onDraw(canvas: Canvas?) {
// need to draw bg first so that text can be on top during super.onDraw()
if (text is Spanned && layout != null) {

View File

@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.features.editor.BlockAdapter
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil.Companion.BACKGROUND_COLOR_CHANGED
@ -70,6 +71,7 @@ class BlockAdapterTest {
private val clipboardInterceptor : ClipboardInterceptor = object: ClipboardInterceptor {
override fun onClipboardAction(action: ClipboardInterceptor.Action) {}
override fun onUrlPasted(url: Url) {}
}
@Test

View File

@ -7,6 +7,7 @@ import android.text.Spannable
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.common.Span
import com.anytypeio.anytype.core_ui.features.editor.BlockAdapter
import com.anytypeio.anytype.core_ui.features.editor.BlockViewDiffUtil
@ -35,6 +36,7 @@ class HeaderBlockTest {
private val context: Context = ApplicationProvider.getApplicationContext()
private val clipboardInterceptor: ClipboardInterceptor = object : ClipboardInterceptor {
override fun onClipboardAction(action: ClipboardInterceptor.Action) = Unit
override fun onUrlPasted(url: Url) {}
}
@Test

View File

@ -8,9 +8,9 @@ import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.common.Span
import com.anytypeio.anytype.core_ui.features.editor.BlockAdapter
import com.anytypeio.anytype.core_ui.features.editor.BlockViewHolder
import com.anytypeio.anytype.core_ui.features.editor.EditorDragAndDropListener
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Highlight
import com.anytypeio.anytype.core_ui.tools.ClipboardInterceptor
@ -33,6 +33,7 @@ class HighlightingBlockTest {
private val clipboardInterceptor: ClipboardInterceptor = object : ClipboardInterceptor {
override fun onClipboardAction(action: ClipboardInterceptor.Action) = Unit
override fun onUrlPasted(url: Url) {}
}
@Test

View File

@ -6,6 +6,7 @@ import android.text.Editable
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.MockDataFactory
import com.anytypeio.anytype.core_ui.features.editor.holders.text.*
import com.anytypeio.anytype.core_ui.tools.ClipboardInterceptor
@ -34,6 +35,7 @@ class BlockAdapterCursorBindingTest {
private val clipboardInterceptor: ClipboardInterceptor = object : ClipboardInterceptor {
override fun onClipboardAction(action: ClipboardInterceptor.Action) {}
override fun onUrlPasted(url: Url) {}
}
@Test

View File

@ -3,14 +3,16 @@ package com.anytypeio.anytype.core_ui.features.editor
import android.content.Context
import android.text.Editable
import androidx.test.core.app.ApplicationProvider
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.tools.ClipboardInterceptor
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import java.util.*
open class BlockAdapterTestSetup {
val clipboardInterceptor: ClipboardInterceptor = object: ClipboardInterceptor {
private val clipboardInterceptor: ClipboardInterceptor = object: ClipboardInterceptor {
override fun onClipboardAction(action: ClipboardInterceptor.Action) {}
override fun onUrlPasted(url: Url) {}
}
val context: Context = ApplicationProvider.getApplicationContext()

View File

@ -171,6 +171,10 @@ class BlockDataRepository(
command: Command.SetupBookmark
): Payload = factory.remote.setupBookmark(command)
override suspend fun createBookmark(
command: Command.CreateBookmark
): Payload = factory.remote.createBookmark(command)
override suspend fun uploadBlock(command: Command.UploadBlock): Payload =
factory.remote.uploadBlock(command)

View File

@ -40,6 +40,7 @@ interface BlockDataStore {
suspend fun removeDocumentCover(ctx: String): Payload
suspend fun removeDocumentIcon(ctx: Id): Payload
suspend fun setupBookmark(command: Command.SetupBookmark): Payload
suspend fun createBookmark(command: Command.CreateBookmark): Payload
suspend fun undo(command: Command.Undo): Payload
suspend fun redo(command: Command.Redo): Payload
suspend fun turnIntoDocument(command: Command.TurnIntoDocument): List<Id>

View File

@ -40,6 +40,7 @@ interface BlockRemote {
suspend fun removeDocumentIcon(ctx: Id): Payload
suspend fun uploadBlock(command: Command.UploadBlock): Payload
suspend fun setupBookmark(command: Command.SetupBookmark) : Payload
suspend fun createBookmark(command: Command.CreateBookmark): Payload
suspend fun undo(command: Command.Undo) : Payload
suspend fun redo(command: Command.Redo) : Payload
suspend fun turnIntoDocument(command: Command.TurnIntoDocument): List<Id>

View File

@ -129,6 +129,10 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
command: Command.SetupBookmark
): Payload = remote.setupBookmark(command)
override suspend fun createBookmark(
command: Command.CreateBookmark
): Payload = remote.createBookmark(command)
override suspend fun undo(command: Command.Undo) = remote.undo(command)
override suspend fun redo(command: Command.Redo) = remote.redo(command)

View File

@ -95,6 +95,7 @@ interface BlockRepository {
suspend fun removeDocumentIcon(ctx: Id): Payload
suspend fun setupBookmark(command: Command.SetupBookmark): Payload
suspend fun createBookmark(command: Command.CreateBookmark): Payload
suspend fun undo(command: Command.Undo): Undo.Result
suspend fun redo(command: Command.Redo): Redo.Result

View File

@ -0,0 +1,46 @@
package com.anytypeio.anytype.domain.page.bookmark
import com.anytypeio.anytype.core_models.Command
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_models.Position
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.base.Either
import com.anytypeio.anytype.domain.block.repo.BlockRepository
/**
* Use-case for creating a bookmark block from url.
*/
class CreateBookmark(
private val repo: BlockRepository
) : BaseUseCase<Payload, CreateBookmark.Params>() {
override suspend fun run(params: Params) = try {
repo.createBookmark(
command = Command.CreateBookmark(
context = params.context,
target = params.target,
url = params.url,
position = params.position
)
).let {
Either.Right(it)
}
} catch (t: Throwable) {
Either.Left(t)
}
/**
* Params for creating a bookmark block from [url]
* @property context id of the context
* @property target id of the target block (future bookmark block)
* @property url bookmark url
* @property [position] positon relative to [target] block
*/
data class Params(
val context: Id,
val target: Id,
val url: String,
val position: Position
)
}

View File

@ -145,6 +145,10 @@ class BlockMiddleware(
command: Command.SetupBookmark
): Payload = middleware.setupBookmark(command)
override suspend fun createBookmark(
command: Command.CreateBookmark
): Payload = middleware.createAndSetupBookmark(command)
override suspend fun undo(
command: Command.Undo
): Payload = middleware.undo(command)

View File

@ -728,6 +728,21 @@ class Middleware(
return response.event.toPayload()
}
@Throws(Exception::class)
fun createAndSetupBookmark(command: Command.CreateBookmark): Payload {
val request: Rpc.Block.Bookmark.CreateAndFetch.Request = Rpc.Block.Bookmark.CreateAndFetch.Request(
contextId = command.context,
targetId = command.target,
url = command.url,
position = command.position.toMiddlewareModel()
)
if (BuildConfig.DEBUG) logRequest(request)
val response = service.blockBookmarkCreateAndFetch(request)
if (BuildConfig.DEBUG) logResponse(response)
return response.event.toPayload()
}
@Throws(Exception::class)
fun undo(command: Command.Undo): Payload {
val request = Rpc.Block.Undo.Request(contextId = command.context)

View File

@ -84,6 +84,9 @@ interface MiddlewareService {
@Throws(Exception::class)
fun blockBookmarkFetch(request: Block.Bookmark.Fetch.Request): Block.Bookmark.Fetch.Response
@Throws(Exception::class)
fun blockBookmarkCreateAndFetch(request: Block.Bookmark.CreateAndFetch.Request): Block.Bookmark.CreateAndFetch.Response
@Throws(Exception::class)
fun blockUpload(request: Block.Upload.Request): Block.Upload.Response

View File

@ -1,7 +1,6 @@
package com.anytypeio.anytype.middleware.service
import anytype.Rpc.*
import anytype.Rpc.Config
import com.anytypeio.anytype.data.auth.exception.BackwardCompatilityNotSupportedException
import com.anytypeio.anytype.data.auth.exception.NotFoundObjectException
import com.anytypeio.anytype.data.auth.exception.UndoRedoExhaustedException
@ -314,6 +313,19 @@ class MiddlewareServiceImplementation : MiddlewareService {
}
}
override fun blockBookmarkCreateAndFetch(request: Block.Bookmark.CreateAndFetch.Request): Block.Bookmark.CreateAndFetch.Response {
val encoded = Service.blockBookmarkCreateAndFetch(
Block.Bookmark.CreateAndFetch.Request.ADAPTER.encode(request)
)
val response = Block.Bookmark.CreateAndFetch.Response.ADAPTER.decode(encoded)
val error = response.error
if (error != null && error.code != Block.Bookmark.CreateAndFetch.Response.Error.Code.NULL) {
throw Exception(error.description)
} else {
return response
}
}
override fun blockUpload(request: Block.Upload.Request): Block.Upload.Response {
val encoded = Service.blockUpload(Block.Upload.Request.ADAPTER.encode(request))
val response = Block.Upload.Response.ADAPTER.decode(encoded)

View File

@ -3132,6 +3132,22 @@ class EditorViewModel(
}
}
fun onUrlPasted(url: Url) {
val focus = orchestrator.stores.focus.current()
if (!focus.isEmpty) {
viewModelScope.launch {
orchestrator.proxies.intents.send(
Intent.Bookmark.CreateBookmark(
context = context,
target = focus.id,
position = Position.TOP,
url = url
)
)
}
}
}
fun onClickListener(clicked: ListenerType) {
Timber.d("onClickListener, clicked:[$clicked]")
if (mode is EditorMode.Styling) {

View File

@ -180,12 +180,17 @@ sealed class Intent {
}
sealed class Bookmark : Intent() {
class SetupBookmark(
val context: Id,
val target: Id,
val url: String
) : Bookmark()
class CreateBookmark(
val context: Id,
val target: Id,
val url: String,
val position: Position
) : Bookmark()
}
sealed class Divider : Intent() {

View File

@ -4,6 +4,7 @@ import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_BACKGROUND_COLOR
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_COPY
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_CREATE
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_CREATE_BOOKMARK
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_DIVIDER_UPDATE
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_DOWNLOAD_FILE
import com.anytypeio.anytype.analytics.base.EventsDictionary.BLOCK_DUPLICATE
@ -42,6 +43,7 @@ import com.anytypeio.anytype.domain.editor.Editor.Focus
import com.anytypeio.anytype.domain.page.Redo
import com.anytypeio.anytype.domain.page.Undo
import com.anytypeio.anytype.domain.page.UpdateTitle
import com.anytypeio.anytype.domain.page.bookmark.CreateBookmark
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.presentation.editor.Editor
import com.anytypeio.anytype.presentation.extension.getAnalyticsEvent
@ -68,6 +70,7 @@ class Orchestrator(
private val updateAlignment: UpdateAlignment,
private val uploadBlock: UploadBlock,
private val setupBookmark: SetupBookmark,
private val createBookmark: CreateBookmark,
private val turnIntoDocument: TurnIntoDocument,
private val updateFields: UpdateFields,
private val move: Move,
@ -664,6 +667,32 @@ class Orchestrator(
}
)
}
is Intent.Bookmark.CreateBookmark -> {
val startTime = System.currentTimeMillis()
createBookmark(
params = CreateBookmark.Params(
context = intent.context,
target = intent.target,
url = intent.url,
position = intent.position
)
).proceed(
failure = { throwable ->
proxies.errors.send(throwable)
},
success = { payload ->
val event = EventAnalytics.Anytype(
name = BLOCK_CREATE_BOOKMARK,
props = Props.empty(),
duration = EventAnalytics.Duration(
start = startTime,
middleware = System.currentTimeMillis()
)
)
defaultPayloadWithEvent(Pair(payload, event))
}
)
}
is Intent.Clipboard.Paste -> {
val startTime = System.currentTimeMillis()
paste(

View File

@ -25,6 +25,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultEditorType
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.CreateBookmark
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.sets.FindObjectSetForType
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
@ -166,6 +167,9 @@ open class EditorViewModelTest {
@Mock
lateinit var setupBookmark: SetupBookmark
@Mock
lateinit var createBookmark: CreateBookmark
@Mock
lateinit var createDocument: CreateDocument
@ -3964,6 +3968,7 @@ open class EditorViewModelTest {
),
updateAlignment = updateAlignment,
setupBookmark = setupBookmark,
createBookmark = createBookmark,
paste = paste,
copy = copy,
move = move,
@ -3973,7 +3978,7 @@ open class EditorViewModelTest {
setRelationKey = setRelationKey,
turnIntoStyle = turnIntoStyle,
updateBlocksMark = updateBlocksMark,
setObjectType = setObjectType
setObjectType = setObjectType,
),
dispatcher = Dispatcher.Default(),
detailModificationManager = InternalDetailModificationManager(storage.details),

View File

@ -24,6 +24,7 @@ import com.anytypeio.anytype.domain.launch.GetDefaultEditorType
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.SetObjectIsArchived
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.CreateBookmark
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.sets.FindObjectSetForType
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
@ -139,6 +140,9 @@ open class EditorPresentationTestSetup {
@Mock
lateinit var setupBookmark: SetupBookmark
@Mock
lateinit var createBookmark: CreateBookmark
@Mock
lateinit var createDocument: CreateDocument
@ -242,6 +246,7 @@ open class EditorPresentationTestSetup {
),
updateAlignment = updateAlignment,
setupBookmark = setupBookmark,
createBookmark = createBookmark,
paste = paste,
copy = copy,
move = move,