diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt
index d6f00ea538..7564ecda68 100644
--- a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt
+++ b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt
@@ -18,7 +18,6 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.clipboard.Clipboard
import com.anytypeio.anytype.domain.clipboard.Copy
import com.anytypeio.anytype.domain.clipboard.Paste
-import com.anytypeio.anytype.domain.config.FlavourConfigProvider
import com.anytypeio.anytype.domain.config.Gateway
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.cover.RemoveDocCover
@@ -34,7 +33,6 @@ 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.SetupBookmark
-import com.anytypeio.anytype.domain.page.navigation.GetListPages
import com.anytypeio.anytype.domain.sets.FindObjectSetForType
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
import com.anytypeio.anytype.domain.status.ThreadStatusChannel
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/LinkToObjectOrWebDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/LinkToObjectOrWebDi.kt
index feb68e84c1..5dfb4b8781 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/LinkToObjectOrWebDi.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/LinkToObjectOrWebDi.kt
@@ -7,8 +7,6 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.linking.LinkToObjectOrWebViewModelFactory
-import com.anytypeio.anytype.presentation.linking.LinkToObjectViewModelFactory
-import com.anytypeio.anytype.ui.linking.LinkToObjectFragment
import com.anytypeio.anytype.ui.linking.LinkToObjectOrWebPagesFragment
import dagger.Module
import dagger.Provides
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt
index e0fd2bbfc7..de3a7c07a8 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt
@@ -95,7 +95,9 @@ import com.anytypeio.anytype.ui.editor.modals.actions.BlockActionToolbarFactory
import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuBaseFragment.DocumentMenuActionReceiver
import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuFragment
import com.anytypeio.anytype.ui.linking.LinkToObjectFragment
+import com.anytypeio.anytype.ui.linking.LinkToObjectOrWebPagesFragment.Companion.LINK_TO_OBJ_OR_WEB_NAME_KEY
import com.anytypeio.anytype.ui.linking.LinkToObjectOrWebPagesFragment.Companion.LINK_TO_OBJ_OR_WEB_REQUEST_KEY
+import com.anytypeio.anytype.ui.linking.LinkToObjectOrWebPagesFragment.Companion.LINK_TO_OBJ_OR_WEB_ID_KEY
import com.anytypeio.anytype.ui.linking.LinkToObjectOrWebPagesFragment.Companion.LINK_TO_OBJ_OR_WEB_URL_KEY
import com.anytypeio.anytype.ui.linking.OnLinkToAction
import com.anytypeio.anytype.ui.moving.MoveToFragment
@@ -428,7 +430,12 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
}
setFragmentResultListener(LINK_TO_OBJ_OR_WEB_REQUEST_KEY) {_, bundle ->
val url = bundle.getString(LINK_TO_OBJ_OR_WEB_URL_KEY)
- vm.onUriSelectedForTextSelection(url)
+ if (url != null) vm.proceedToAddUriToTextAsLink(url)
+ val name = bundle.getString(LINK_TO_OBJ_OR_WEB_NAME_KEY)
+ if (name != null) vm.proceedToCreateObjectAndAddToTextAsLink(name)
+ val id = bundle.getString(LINK_TO_OBJ_OR_WEB_ID_KEY)
+ if (id != null) vm.proceedToAddObjectToTextAsLink(id)
+ Timber.d("FragmentResultListener, request:[$LINK_TO_OBJ_OR_WEB_REQUEST_KEY], url:[$url], name:[$name], id:[$id]")
}
pickiT = PickiT(requireContext(), this, requireActivity())
setupOnBackPressedDispatcher()
@@ -576,11 +583,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
.onEach { type -> vm.onStyleToolbarMarkupAction(type, null) }
.launchIn(lifecycleScope)
- setMarkupUrlToolbar
- .onApply()
- .onEach { vm.onUriSelectedForTextSelection(it) }
- .launchIn(lifecycleScope)
-
blockActionToolbar.actionListener = { action -> vm.onMultiSelectAction(action) }
markupColorToolbar.onColorClickedListener = { color ->
@@ -597,10 +599,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
}
}
- blocker.clicks()
- .onEach { vm.onBlockerClicked() }
- .launchIn(lifecycleScope)
-
// topToolbar.back.clicks().onEach {
// hideSoftInput()
// vm.onBackButtonPressed()
@@ -1057,6 +1055,9 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
R.id.action_pageScreen_to_linkToObjectOrWebPagesFragment
)
}
+ Command.ShowKeyboard -> {
+ recycler.findFocus()?.focusAndShowKeyboard()
+ }
}
}
}
@@ -1224,18 +1225,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
setMainMarkupToolbarState(state)
- state.markupUrlToolbar.apply {
- if (isVisible) {
- setMarkupUrlToolbar.visible()
- setMarkupUrlToolbar.takeFocus()
- setMarkupUrlToolbar.bind(state.markupMainToolbar.style?.markupUrl)
- blocker.visible()
- } else {
- setMarkupUrlToolbar.invisible()
- blocker.invisible()
- }
- }
-
state.multiSelect.apply {
val behavior = BottomSheetBehavior.from(blockActionToolbar)
if (isVisible) {
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/linking/LinkToObjectOrWebPagesFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/linking/LinkToObjectOrWebPagesFragment.kt
index afa3175f03..75de47b977 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/linking/LinkToObjectOrWebPagesFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/linking/LinkToObjectOrWebPagesFragment.kt
@@ -26,6 +26,7 @@ import com.anytypeio.anytype.ui.search.ObjectSearchFragment
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.android.synthetic.main.fragment_link_to_object_or_web.*
import kotlinx.coroutines.launch
+import timber.log.Timber
import javax.inject.Inject
class LinkToObjectOrWebPagesFragment() : BaseBottomSheetFragment() {
@@ -99,6 +100,7 @@ class LinkToObjectOrWebPagesFragment() : BaseBottomSheetFragment() {
}
private fun execute(command: LinkToObjectOrWebViewModel.Command) {
+ Timber.d("execute, command:[$command]")
when (command) {
LinkToObjectOrWebViewModel.Command.Exit -> {
hideSoftInput()
@@ -110,6 +112,18 @@ class LinkToObjectOrWebPagesFragment() : BaseBottomSheetFragment() {
hideSoftInput()
dismiss()
}
+ is LinkToObjectOrWebViewModel.Command.SetObjectLink -> {
+ val bundle = bundleOf(LINK_TO_OBJ_OR_WEB_ID_KEY to command.target)
+ setFragmentResult(LINK_TO_OBJ_OR_WEB_REQUEST_KEY, bundle)
+ hideSoftInput()
+ dismiss()
+ }
+ is LinkToObjectOrWebViewModel.Command.CreateObject -> {
+ val bundle = bundleOf(LINK_TO_OBJ_OR_WEB_NAME_KEY to command.name)
+ setFragmentResult(LINK_TO_OBJ_OR_WEB_REQUEST_KEY, bundle)
+ hideSoftInput()
+ dismiss()
+ }
}
}
@@ -150,5 +164,7 @@ class LinkToObjectOrWebPagesFragment() : BaseBottomSheetFragment() {
companion object {
const val LINK_TO_OBJ_OR_WEB_REQUEST_KEY = "link-to-object-or-web.request"
const val LINK_TO_OBJ_OR_WEB_URL_KEY = "link-to-object-or-web.url.key"
+ const val LINK_TO_OBJ_OR_WEB_ID_KEY = "link-to-object-or-web.id.key"
+ const val LINK_TO_OBJ_OR_WEB_NAME_KEY = "link-to-object-or-web.name.key"
}
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_editor.xml b/app/src/main/res/layout/fragment_editor.xml
index bd3266a6b8..0449cfba9f 100644
--- a/app/src/main/res/layout/fragment_editor.xml
+++ b/app/src/main/res/layout/fragment_editor.xml
@@ -89,15 +89,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
-
-
-
-
()
+ this.forEach { mark ->
+ if (!mark.isClickableMark()) {
+ result.add(mark)
+ } else {
+ if (mark.rangeIntersection(newMark.range) == NO_RANGE_INTERSECTION) {
+ result.add(mark)
+ }
+ }
+ }
+ result.add(newMark)
+ return result.toList()
+}
+
fun Marks.sortByType(): Marks {
return this.sortedBy { it.type.ordinal }
}
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/ControlPanelMachine.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/ControlPanelMachine.kt
index 240376f292..6bcdde1e88 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/ControlPanelMachine.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/ControlPanelMachine.kt
@@ -146,8 +146,6 @@ sealed class ControlPanelMachine {
object OnMarkupColorToggleClicked : MarkupToolbar()
object OnMarkupHighlightToggleClicked : MarkupToolbar()
object OnMarkupToolbarUrlClicked : MarkupToolbar()
- object OnMarkupUrlSet : MarkupToolbar()
- object OnBlockerClicked : MarkupToolbar()
}
/**
@@ -378,24 +376,7 @@ sealed class ControlPanelMachine {
markupColorToolbar = state.markupColorToolbar.copy(
isVisible = false
),
- markupMainToolbar = state.markupMainToolbar.copy(),
- markupUrlToolbar = state.markupUrlToolbar.copy(
- isVisible = true
- )
- )
- }
- is Event.MarkupToolbar.OnMarkupUrlSet -> {
- state.copy(
- markupUrlToolbar = state.markupUrlToolbar.copy(
- isVisible = false
- )
- )
- }
- is Event.MarkupToolbar.OnBlockerClicked -> {
- state.copy(
- markupUrlToolbar = state.markupUrlToolbar.copy(
- isVisible = false
- )
+ markupMainToolbar = state.markupMainToolbar.copy()
)
}
is Event.OnMarkupTextColorSelected -> state.copy()
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt
index db0a2184b8..883fc6af63 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt
@@ -345,22 +345,10 @@ class EditorViewModel(
.onEach { (action, textSelection) ->
val range = textSelection.selection
if (textSelection.isNotEmpty && range != null && range.first != range.last) {
- if (action.type == Markup.Type.LINK) {
- val block = blocks.first { it.id == textSelection.id }
- stateData.value = ViewState.OpenLinkScreen(
- pageId = context,
- block = block,
- range = IntRange(
- start = range.first,
- endInclusive = range.last.dec()
- )
- )
- } else {
- applyMarkup(
- selection = Pair(textSelection.id, range),
- action = action
- )
- }
+ applyMarkup(
+ selection = Pair(textSelection.id, range),
+ action = action
+ )
}
}
.launchIn(viewModelScope)
@@ -4477,29 +4465,8 @@ class EditorViewModel(
//region MARKUP TOOLBAR
fun onMarkupUrlClicked() {
-
Timber.d("onMarkupUrlClicked, ")
-
val target = orchestrator.stores.focus.current().id
- val selection = orchestrator.stores.textSelection.current().selection!!
-
- pending.add(
- Restore.Selection(
- target = target,
- range = selection
- )
- )
-
- val update = views.map { view ->
- if (view.id == target) {
- view.setGhostEditorSelection(selection)
- } else {
- view
- }
- }
-
- viewModelScope.launch { orchestrator.stores.views.update(update) }
- viewModelScope.launch { renderCommand.send(Unit) }
dispatch(
Command.OpenLinkToObjectOrWebScreen(
target = target
@@ -4507,55 +4474,6 @@ class EditorViewModel(
)
}
- fun onUriSelectedForTextSelection(uri: String?) {
- Timber.d("onSetLink, url:[$uri]")
- if (uri == null) {
- Timber.e("Can't set nullable url link")
- return
- }
- val range = orchestrator.stores.textSelection.current().selection
- if (range != null) {
- val target = orchestrator.stores.focus.current().id
- restore.add(pending.poll())
- if (uri.isNotEmpty())
- applyLinkMarkup(
- blockId = target,
- link = uri,
- range = range.first..range.last.dec()
- )
- else
- onUnlinkPressed(
- blockId = target,
- range = range.first..range.last.dec()
- )
- controlPanelInteractor.onEvent(
- event = ControlPanelMachine.Event.MarkupToolbar.OnMarkupUrlSet
- )
- }
- }
-
- fun onBlockerClicked() {
- Timber.d("onBlockerClicked, ")
- val target = orchestrator.stores.focus.current().id
- val update = views.map { view ->
- if (view.id == target) {
- view.setGhostEditorSelection(null).apply {
- if (this is Focusable) {
- isFocused = true
- }
- }
- } else {
- view
- }
- }
- restore.add(pending.poll())
- viewModelScope.launch { orchestrator.stores.views.update(update) }
- viewModelScope.launch { renderCommand.send(Unit) }
- controlPanelInteractor.onEvent(
- event = ControlPanelMachine.Event.MarkupToolbar.OnBlockerClicked
- )
- }
-
fun onUnlinkPressed(blockId: String, range: IntRange) {
Timber.d("onUnlinkPressed, blockId:[$blockId] range:[$range]")
@@ -5378,4 +5296,66 @@ class EditorViewModel(
)
}
}
+
+ //region ADD URI OR OBJECT ID TO SELECTED TEXT
+ fun proceedToCreateObjectAndAddToTextAsLink(name: String) {
+ Timber.d("proceedToCreateObjectAndAddToTextAsLink, name:[$name]")
+ viewModelScope.launch {
+ getDefaultEditorType.invoke(Unit).proceed(
+ failure = { Timber.e(it, "Error while getting default object type") },
+ success = { response ->
+ createObjectAddProceedToAddToTextAsLink(
+ name = name,
+ type = response.type
+ )
+ }
+ )
+ }
+ }
+
+ private suspend fun createObjectAddProceedToAddToTextAsLink(name: String, type: String?) {
+ val params = CreateNewDocument.Params(name, type)
+ createNewDocument.invoke(params).process(
+ failure = { Timber.e(it, "Error while creating new page with params: $params") },
+ success = { result -> proceedToAddObjectToTextAsLink(id = result.id) }
+ )
+ }
+
+ fun proceedToAddObjectToTextAsLink(id: Id) {
+ Timber.d("proceedToAddObjectToTextAsLink, target:[$id]")
+ val range = orchestrator.stores.textSelection.current().selection
+ if (range != null) {
+ dispatch(Command.ShowKeyboard)
+ viewModelScope.launch {
+ markupActionPipeline.send(
+ MarkupAction(
+ type = Markup.Type.OBJECT,
+ param = id
+ )
+ )
+ }
+ }
+ }
+
+ fun proceedToAddUriToTextAsLink(uri: String) {
+ Timber.d("proceedToAddUriToTextAsLink, uri:[$uri]")
+ val range = orchestrator.stores.textSelection.current().selection
+ if (range != null) {
+ val target = orchestrator.stores.focus.current().id
+ if (uri.isNotEmpty())
+ applyLinkMarkup(
+ blockId = target,
+ link = uri,
+ range = range.first..range.last.dec()
+ )
+ else
+ onUnlinkPressed(
+ blockId = target,
+ range = range.first..range.last.dec()
+ )
+ } else {
+ Timber.e("Can't add uri to text, range is null")
+ }
+ }
+ //endregion
}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt
index 8dc3fb474c..18cb41c37d 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt
@@ -50,6 +50,7 @@ sealed class Command {
object PopBackStack : Command()
+ object ShowKeyboard : Command()
object CloseKeyboard : Command()
object ClearSearchInput : Command()
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Transformation.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Transformation.kt
index d51f351994..9df33d9703 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Transformation.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Transformation.kt
@@ -2,8 +2,10 @@ package com.anytypeio.anytype.presentation.editor.editor
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Block.Content.Text.Mark
+import com.anytypeio.anytype.core_models.ext.addClickableMark
import com.anytypeio.anytype.core_models.ext.addMark
import com.anytypeio.anytype.core_models.ext.content
+import com.anytypeio.anytype.core_models.ext.sortByType
import com.anytypeio.anytype.presentation.editor.model.TextUpdate
fun Block.updateText(update: TextUpdate): Block {
@@ -41,7 +43,13 @@ fun Block.markup(
param = param
)
- val marks = content.marks.addMark(new)
+ return copy(content = content.addMarkToContent(new))
+}
- return copy(content = content.copy(marks = marks))
+fun Block.Content.Text.addMarkToContent(mark: Mark): Block.Content.Text {
+ return if (mark.isClickableMark()) {
+ this.copy(marks = marks.addClickableMark(mark).sortByType())
+ } else {
+ this.copy(marks = marks.addMark(mark))
+ }
}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/control/ControlPanelState.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/control/ControlPanelState.kt
index 144ca90324..14fb73f6db 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/control/ControlPanelState.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/control/ControlPanelState.kt
@@ -23,7 +23,6 @@ data class ControlPanelState(
val styleExtraToolbar: Toolbar.Styling.Other = Toolbar.Styling.Other(),
val styleColorToolbar: Toolbar.Styling.Color = Toolbar.Styling.Color(),
val markupMainToolbar: Toolbar.MarkupMainToolbar = Toolbar.MarkupMainToolbar.reset(),
- val markupUrlToolbar: Toolbar.MarkupUrlToolbar = Toolbar.MarkupUrlToolbar(),
val markupColorToolbar: Toolbar.MarkupColorToolbar = Toolbar.MarkupColorToolbar(),
val multiSelect: Toolbar.MultiSelect,
val mentionToolbar: Toolbar.MentionToolbar,
@@ -86,19 +85,6 @@ data class ControlPanelState(
override val isVisible: Boolean = false
) : Toolbar()
- /**
- * TODO Markup toolbar allowing user-interface for markup operations.
- * @property isVisible defines whether the toolbar is visible or not
- */
- data class MarkupUrlToolbar(
- override val isVisible: Boolean = false,
- val url: String? = null
- ) : Toolbar() {
- companion object {
- fun reset() = MarkupUrlToolbar()
- }
- }
-
/**
* Basic color toolbar state.
* @property isVisible defines whether the toolbar is visible or not
@@ -283,7 +269,6 @@ data class ControlPanelState(
markupMainToolbar = Toolbar.MarkupMainToolbar(
isVisible = false
),
- markupUrlToolbar = Toolbar.MarkupUrlToolbar(),
markupColorToolbar = Toolbar.MarkupColorToolbar(),
multiSelect = Toolbar.MultiSelect(
isVisible = false,
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt
index 963dfe2a88..fe4ff00520 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt
@@ -53,15 +53,19 @@ class LinkToObjectOrWebViewModel(
}
fun onClicked(item: LinkToItemView) {
+ Timber.d("onClicked, item:[$item] ")
viewModelScope.launch {
when (item) {
- is LinkToItemView.CreateObject -> TODO()
- is LinkToItemView.Object -> TODO()
- LinkToItemView.Subheading.Objects -> TODO()
- LinkToItemView.Subheading.Web -> TODO()
+ is LinkToItemView.CreateObject -> {
+ commands.emit(Command.CreateObject(item.title))
+ }
+ is LinkToItemView.Object -> {
+ commands.emit(Command.SetObjectLink(item.id))
+ }
is LinkToItemView.WebItem -> {
commands.emit(Command.SetWebLink(item.url))
}
+ else -> Unit
}
}
}
@@ -95,7 +99,7 @@ class LinkToObjectOrWebViewModel(
}
}
- fun setObjects(data: List) {
+ private fun setObjects(data: List) {
objects.value = data.filter {
SupportedLayouts.layouts.contains(it.layout)
}
@@ -105,10 +109,6 @@ class LinkToObjectOrWebViewModel(
userInput.value = searchText
}
- fun onObjectClicked(target: Id, layout: ObjectType.Layout?) {
- //todo will be fixed in next PR
- }
-
private fun proceedWithNewFilter(filter: String) {
if (filter.isEmpty()) {
onEmptyFilterState()
@@ -172,6 +172,8 @@ class LinkToObjectOrWebViewModel(
sealed class Command {
object Exit : Command()
data class SetWebLink(val url: String) : Command()
+ data class SetObjectLink(val target: Id) : Command()
+ data class CreateObject(val name: String) : Command()
}
sealed class ViewState {
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMarkupObjectTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMarkupObjectTest.kt
new file mode 100644
index 0000000000..ee4631a087
--- /dev/null
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorMarkupObjectTest.kt
@@ -0,0 +1,472 @@
+package com.anytypeio.anytype.presentation.editor.editor
+
+import MockDataFactory
+import android.util.Log
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.anytypeio.anytype.core_models.Block
+import com.anytypeio.anytype.core_models.ObjectType.Companion.PAGE_URL
+import com.anytypeio.anytype.core_models.SmartBlockType
+import com.anytypeio.anytype.core_models.ext.content
+import com.anytypeio.anytype.presentation.MockTypicalDocumentFactory
+import com.anytypeio.anytype.presentation.editor.EditorViewModel
+import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
+import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
+import com.anytypeio.anytype.presentation.util.TXT
+import com.jraska.livedata.test
+import net.lachlanmckee.timberjunit.TimberTestRule
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.MockitoAnnotations
+import kotlin.test.assertEquals
+
+class EditorMarkupObjectTest : EditorPresentationTestSetup() {
+
+ @get:Rule
+ val rule = InstantTaskExecutorRule()
+
+ @get:Rule
+ val coroutineTestRule = CoroutinesTestRule()
+
+ @get:Rule
+ val timberTestRule: TimberTestRule = TimberTestRule.builder()
+ .minPriority(Log.DEBUG)
+ .showThread(true)
+ .showTimestamp(false)
+ .onlyLogWhenTestFails(true)
+ .build()
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.openMocks(this)
+ }
+
+ @After
+ fun after() {
+ coroutineTestRule.advanceTime(EditorViewModel.TEXT_CHANGES_DEBOUNCE_DURATION)
+ }
+
+ @Test
+ fun `should add object markup to text`() {
+ val title = MockTypicalDocumentFactory.title
+ val header = MockTypicalDocumentFactory.header
+ val block = Block(
+ id = MockDataFactory.randomUuid(),
+ fields = Block.Fields(emptyMap()),
+ content = Block.Content.Text(
+ text = "Start Foobar End",
+ marks = emptyList(),
+ style = Block.Content.Text.Style.P
+ ),
+ children = emptyList()
+ )
+
+ val page = Block(
+ id = root,
+ fields = Block.Fields(emptyMap()),
+ content = Block.Content.Smart(SmartBlockType.PAGE),
+ children = listOf(header.id, block.id)
+ )
+
+ val doc = listOf(page, header, title, block)
+
+ stubInterceptEvents()
+ stubInterceptThreadStatus()
+ stubGetObjectTypes(objectTypes = listOf())
+ stubOpenDocument(
+ document = doc,
+ details = Block.Details(),
+ relations = listOf()
+ )
+ stubUpdateText()
+
+ val vm = buildViewModel()
+ val linkObject = MockDataFactory.randomString()
+
+ //TESTING
+ vm.apply {
+ onStart(root)
+ onBlockFocusChanged(
+ id = block.id,
+ hasFocus = true
+ )
+ onSelectionChanged(
+ id = block.id,
+ selection = IntRange(6, 12)
+ )
+ proceedToAddObjectToTextAsLink(id = linkObject)
+ }
+
+ vm.state.test().apply {
+ assertValue(
+ ViewState.Success(
+ blocks = listOf(
+ BlockView.Title.Basic(
+ id = title.id,
+ isFocused = false,
+ text = title.content().text,
+ mode = BlockView.Mode.EDIT
+ ),
+ BlockView.Text.Paragraph(
+ id = block.id,
+ cursor = null,
+ isSelected = false,
+ isFocused = true,
+ marks = listOf(
+ Markup.Mark(
+ from = 6,
+ to = 12,
+ type = Markup.Type.OBJECT,
+ param = linkObject
+ )
+ ),
+ backgroundColor = null,
+ color = null,
+ indent = 0,
+ text = "Start Foobar End",
+ mode = BlockView.Mode.EDIT
+ )
+ )
+ )
+ )
+ }
+ }
+
+ @Test
+ fun `should add object markup to text end remove all clicked marks in range`() {
+ val title = MockTypicalDocumentFactory.title
+ val header = MockTypicalDocumentFactory.header
+ val linkObject = MockDataFactory.randomUuid()
+ val linkWeb = MockDataFactory.randomString()
+ val linkMention = MockDataFactory.randomUuid()
+
+ val block = Block(
+ id = MockDataFactory.randomUuid(),
+ fields = Block.Fields(emptyMap()),
+ content = Block.Content.Text(
+ text = "Start Link Object Mention End",
+ marks = listOf(
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 0,
+ endInclusive = 5
+ ),
+ type = Block.Content.Text.Mark.Type.BOLD
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 6,
+ endInclusive = 10
+ ),
+ type = Block.Content.Text.Mark.Type.LINK,
+ param = linkWeb
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 6,
+ endInclusive = 10
+ ),
+ type = Block.Content.Text.Mark.Type.BOLD
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 11,
+ endInclusive = 17
+ ),
+ type = Block.Content.Text.Mark.Type.OBJECT,
+ param = linkObject
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 18,
+ endInclusive = 25
+ ),
+ type = Block.Content.Text.Mark.Type.MENTION,
+ param = linkMention
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 18,
+ endInclusive = 25
+ ),
+ type = Block.Content.Text.Mark.Type.TEXT_COLOR,
+ param = "#000"
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 26,
+ endInclusive = 29
+ ),
+ type = Block.Content.Text.Mark.Type.ITALIC
+ )
+ ),
+ style = Block.Content.Text.Style.P
+ ),
+ children = emptyList()
+ )
+
+ val page = Block(
+ id = root,
+ fields = Block.Fields(emptyMap()),
+ content = Block.Content.Smart(SmartBlockType.PAGE),
+ children = listOf(header.id, block.id)
+ )
+
+ val doc = listOf(page, header, title, block)
+
+ stubInterceptEvents()
+ stubInterceptThreadStatus()
+ stubGetObjectTypes(objectTypes = listOf())
+ stubOpenDocument(
+ document = doc,
+ details = Block.Details(),
+ relations = listOf()
+ )
+ stubUpdateText()
+
+ val vm = buildViewModel()
+ val linkNew = MockDataFactory.randomString()
+
+ //TESTING
+ vm.apply {
+ onStart(root)
+ onBlockFocusChanged(
+ id = block.id,
+ hasFocus = true
+ )
+ onSelectionChanged(
+ id = block.id,
+ selection = IntRange(6, 25)
+ )
+ proceedToAddObjectToTextAsLink(id = linkNew)
+ }
+
+ val expected = ViewState.Success(
+ blocks = listOf(
+ BlockView.Title.Basic(
+ id = title.id,
+ isFocused = false,
+ text = title.content().text,
+ mode = BlockView.Mode.EDIT
+ ),
+ BlockView.Text.Paragraph(
+ id = block.id,
+ cursor = null,
+ isSelected = false,
+ isFocused = true,
+ marks = listOf(
+ Markup.Mark(
+ from = 26,
+ to = 29,
+ type = Markup.Type.ITALIC
+ ),
+ Markup.Mark(
+ from = 0,
+ to = 5,
+ type = Markup.Type.BOLD
+ ),
+ Markup.Mark(
+ from = 6,
+ to = 10,
+ type = Markup.Type.BOLD
+ ),
+ Markup.Mark(
+ from = 18,
+ to = 25,
+ type = Markup.Type.TEXT_COLOR,
+ param = "#000"
+ ),
+ Markup.Mark(
+ from = 6,
+ to = 25,
+ type = Markup.Type.OBJECT,
+ param = linkNew
+ ),
+
+ ),
+ backgroundColor = null,
+ color = null,
+ indent = 0,
+ text = "Start Link Object Mention End",
+ mode = BlockView.Mode.EDIT
+ )
+ )
+ )
+
+ val actual = vm.state.value
+ assertEquals(expected, actual)
+ }
+
+ @Test
+ fun `should create object and add markup to text end remove all clicked marks in range`() {
+ val title = MockTypicalDocumentFactory.title
+ val header = MockTypicalDocumentFactory.header
+ val linkObject = MockDataFactory.randomUuid()
+ val linkWeb = MockDataFactory.randomString()
+ val linkMention = MockDataFactory.randomUuid()
+
+ val block = Block(
+ id = MockDataFactory.randomUuid(),
+ fields = Block.Fields(emptyMap()),
+ content = Block.Content.Text(
+ text = "Start Link Object Mention End",
+ marks = listOf(
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 0,
+ endInclusive = 5
+ ),
+ type = Block.Content.Text.Mark.Type.BOLD
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 6,
+ endInclusive = 10
+ ),
+ type = Block.Content.Text.Mark.Type.LINK,
+ param = linkWeb
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 6,
+ endInclusive = 10
+ ),
+ type = Block.Content.Text.Mark.Type.BOLD
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 11,
+ endInclusive = 17
+ ),
+ type = Block.Content.Text.Mark.Type.OBJECT,
+ param = linkObject
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 18,
+ endInclusive = 25
+ ),
+ type = Block.Content.Text.Mark.Type.MENTION,
+ param = linkMention
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 18,
+ endInclusive = 25
+ ),
+ type = Block.Content.Text.Mark.Type.TEXT_COLOR,
+ param = "#000"
+ ),
+ Block.Content.Text.Mark(
+ range = IntRange(
+ start = 26,
+ endInclusive = 29
+ ),
+ type = Block.Content.Text.Mark.Type.ITALIC
+ )
+ ),
+ style = Block.Content.Text.Style.P
+ ),
+ children = emptyList()
+ )
+
+ val page = Block(
+ id = root,
+ fields = Block.Fields(emptyMap()),
+ content = Block.Content.Smart(SmartBlockType.PAGE),
+ children = listOf(header.id, block.id)
+ )
+
+ val doc = listOf(page, header, title, block)
+
+ stubInterceptEvents()
+ stubInterceptThreadStatus()
+ stubGetObjectTypes(objectTypes = listOf())
+ stubOpenDocument(
+ document = doc,
+ details = Block.Details(),
+ relations = listOf()
+ )
+ stubUpdateText()
+ val vm = buildViewModel()
+ val linkNew = MockDataFactory.randomString()
+
+ //TESTING
+ val newObjectType = PAGE_URL
+ val newObjectId = MockDataFactory.randomString()
+ val newObjectName = MockDataFactory.randomString()
+ stubCreateNewDocument(
+ name = newObjectName,
+ type = newObjectType,
+ id = newObjectId
+ )
+ stubGetDefaultObjectType(type = newObjectType)
+ vm.apply {
+ onStart(root)
+ onBlockFocusChanged(
+ id = block.id,
+ hasFocus = true
+ )
+ onSelectionChanged(
+ id = block.id,
+ selection = IntRange(6, 25)
+ )
+ proceedToCreateObjectAndAddToTextAsLink(name = newObjectName)
+ }
+
+ val expected = ViewState.Success(
+ blocks = listOf(
+ BlockView.Title.Basic(
+ id = title.id,
+ isFocused = false,
+ text = title.content().text,
+ mode = BlockView.Mode.EDIT
+ ),
+ BlockView.Text.Paragraph(
+ id = block.id,
+ cursor = null,
+ isSelected = false,
+ isFocused = true,
+ marks = listOf(
+ Markup.Mark(
+ from = 26,
+ to = 29,
+ type = Markup.Type.ITALIC
+ ),
+ Markup.Mark(
+ from = 0,
+ to = 5,
+ type = Markup.Type.BOLD
+ ),
+ Markup.Mark(
+ from = 6,
+ to = 10,
+ type = Markup.Type.BOLD
+ ),
+ Markup.Mark(
+ from = 18,
+ to = 25,
+ type = Markup.Type.TEXT_COLOR,
+ param = "#000"
+ ),
+ Markup.Mark(
+ from = 6,
+ to = 25,
+ type = Markup.Type.OBJECT,
+ param = newObjectId
+ ),
+ ),
+ backgroundColor = null,
+ color = null,
+ indent = 0,
+ text = "Start Link Object Mention End",
+ mode = BlockView.Mode.EDIT
+ )
+ )
+ )
+
+ val actual = vm.state.value
+ assertEquals(expected, actual)
+ }
+}
\ No newline at end of file
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt
index f9bfa989dd..1b3ff0ade1 100644
--- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt
@@ -535,4 +535,12 @@ open class EditorPresentationTestSetup {
onBlocking { invoke(Unit) } doReturn Either.Right(GetDefaultEditorType.Response(type, name))
}
}
+
+ fun stubCreateNewDocument(name: String, type: String, id: String) {
+ val params = CreateNewDocument.Params(name, type)
+ val result = CreateNewDocument.Result(id, name, null)
+ createNewDocument.stub {
+ onBlocking { invoke(params) } doReturn Either.Right(result)
+ }
+ }
}
\ No newline at end of file