mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Epic with sets and relations + new app flavors (stable, experimental) (#1048)
This commit is contained in:
parent
4f540aa356
commit
31d820c4dd
911 changed files with 51701 additions and 3827 deletions
|
@ -63,6 +63,7 @@ object EventsDictionary {
|
|||
const val ACCOUNT_STOP = "AccountStop"
|
||||
|
||||
const val PAGE_CREATE = "BlockCreatePage"
|
||||
const val OBJECT_CREATE = "BlockCreateObject"
|
||||
const val PAGE_MENTION_CREATE = "PageCreate"
|
||||
|
||||
const val BLOCK_CREATE = "BlockCreate"
|
||||
|
|
|
@ -49,10 +49,40 @@ android {
|
|||
}
|
||||
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
debuggable true
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions 'default'
|
||||
productFlavors {
|
||||
stable {
|
||||
dimension 'default'
|
||||
}
|
||||
experimental{
|
||||
dimension 'default'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
stable {
|
||||
java {
|
||||
srcDirs 'src/stable/java'
|
||||
}
|
||||
res {
|
||||
srcDirs 'src/stable/res'
|
||||
}
|
||||
}
|
||||
experimental {
|
||||
java {
|
||||
srcDirs 'src/experimental/java'
|
||||
}
|
||||
res {
|
||||
srcDirs 'src/experimental/res'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
|
@ -74,6 +104,7 @@ ext {
|
|||
dependencies {
|
||||
|
||||
implementation project(':domain')
|
||||
implementation project(':core-models')
|
||||
implementation project(':data')
|
||||
implementation project(':device')
|
||||
implementation project(':persistence')
|
||||
|
@ -135,6 +166,7 @@ dependencies {
|
|||
implementation applicationDependencies.exoPlayer
|
||||
|
||||
implementation analyticsDependencies.amplitude
|
||||
implementation analyticsDependencies.okhttp
|
||||
|
||||
implementation applicationDependencies.blurry
|
||||
implementation applicationDependencies.shimmerLayout
|
||||
|
@ -158,7 +190,10 @@ dependencies {
|
|||
androidTestImplementation unitTestDependencies.kotlinTest
|
||||
androidTestImplementation acceptanceTesting.testRules
|
||||
androidTestImplementation acceptanceTesting.disableAnimation
|
||||
androidTestImplementation unitTestDependencies.coroutineTesting
|
||||
|
||||
androidTestImplementation(unitTestDependencies.coroutineTesting) {
|
||||
exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug"
|
||||
}
|
||||
|
||||
debugImplementation acceptanceTesting.fragmentTesting
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version.versionMajor=0
|
||||
version.versionMinor=1
|
||||
version.versionPatch=7
|
||||
version.versionPatch=6
|
||||
|
|
|
@ -11,6 +11,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.domain.auth.interactor.StartAccount
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.device.PathProvider
|
||||
|
@ -50,6 +51,9 @@ class SetupSelectedAccountTest {
|
|||
@Mock
|
||||
lateinit var authRepository: AuthRepository
|
||||
|
||||
@Mock
|
||||
lateinit var analytics: Analytics
|
||||
|
||||
@Mock
|
||||
lateinit var pathProvider: PathProvider
|
||||
|
||||
|
@ -62,7 +66,8 @@ class SetupSelectedAccountTest {
|
|||
TestSetupSelectedAccountFragment.testViewModelFactory =
|
||||
SetupSelectedAccountViewModelFactory(
|
||||
startAccount = startAccount,
|
||||
pathProvider = pathProvider
|
||||
pathProvider = pathProvider,
|
||||
analytics = analytics
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,16 +14,13 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.data.auth.model.ClipEntity
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.block.model.Command
|
||||
import com.anytypeio.anytype.domain.clipboard.Paste
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.PageViewModel
|
||||
import com.anytypeio.anytype.ui.page.PageFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
|
@ -190,7 +187,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
}
|
||||
|
||||
repo.stub {
|
||||
onBlocking { paste(any()) } doReturn Paste.Response(
|
||||
onBlocking { paste(any()) } doReturn Response.Clipboard.Paste(
|
||||
cursor = 6,
|
||||
payload = Payload(
|
||||
context = root,
|
||||
|
@ -202,6 +199,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
}
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus( )
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
|
@ -209,7 +207,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
|
||||
// TESTING
|
||||
|
||||
val target = onView(withRecyclerView(R.id.recycler).atPositionOnView(1, view))
|
||||
val target = onView(withRecyclerView(R.id.recycler).atPositionOnView(0, view))
|
||||
|
||||
// Click to open action mode
|
||||
|
||||
|
@ -229,7 +227,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
}
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val item = fragment.recycler.getChildAt(0)
|
||||
item.findViewById<TextInputWidget>(view).apply {
|
||||
assertEquals(expected = result.length, actual = selectionStart)
|
||||
assertEquals(expected = result.length, actual = selectionEnd)
|
||||
|
@ -255,6 +253,8 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
advance(PageViewModel.TEXT_CHANGES_DEBOUNCE_DURATION)
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
@ -464,7 +464,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
}
|
||||
|
||||
repo.stub {
|
||||
onBlocking { paste(any()) } doReturn Paste.Response(
|
||||
onBlocking { paste(any()) } doReturn Response.Clipboard.Paste(
|
||||
cursor = -1,
|
||||
payload = Payload(
|
||||
context = root,
|
||||
|
@ -476,6 +476,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
}
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
|
@ -483,7 +484,7 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
|
||||
// TESTING
|
||||
|
||||
val target = onView(withRecyclerView(R.id.recycler).atPositionOnView(1, targetBlockView))
|
||||
val target = onView(withRecyclerView(R.id.recycler).atPositionOnView(0, targetBlockView))
|
||||
|
||||
// Click to open action mode
|
||||
|
||||
|
@ -517,21 +518,21 @@ class ClipboardTesting : EditorTestSetup() {
|
|||
)
|
||||
}
|
||||
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(1, targetBlockView)).apply {
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(0, targetBlockView)).apply {
|
||||
check(matches(withText(text)))
|
||||
}
|
||||
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(2, firstPastedBlockView)).apply {
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(1, firstPastedBlockView)).apply {
|
||||
check(matches(withText(pasted.first)))
|
||||
}
|
||||
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(3, secondPastedBlockView)).apply {
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(2, secondPastedBlockView)).apply {
|
||||
check(matches(withText(pasted.second)))
|
||||
check(matches(hasFocus()))
|
||||
}
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(3)
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
item.findViewById<TextInputWidget>(secondPastedBlockView).apply {
|
||||
assertEquals(expected = pasted.second.length, actual = selectionStart)
|
||||
assertEquals(expected = pasted.second.length, actual = selectionEnd)
|
||||
|
|
|
@ -11,13 +11,13 @@ import androidx.test.espresso.matcher.ViewMatchers
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.Position
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.block.model.Position
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
@ -171,6 +171,7 @@ class CreateBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
stubCreateBlocks(params, new, events)
|
||||
|
@ -180,7 +181,7 @@ class CreateBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = Espresso.onView(
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -196,13 +197,13 @@ class CreateBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(createBlock, times(1)) { invoke(params) }
|
||||
|
||||
Espresso.onView(
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("")))
|
||||
}
|
||||
|
||||
Espresso.onView(
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(2, R.id.textContent)
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(1, R.id.textContent)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -211,7 +212,7 @@ class CreateBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position at block B
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
item.findViewById<TextInputWidget>(R.id.textContent).apply {
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
package com.anytypeio.anytype.features.editor
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Position
|
||||
import com.anytypeio.anytype.core_models.ext.content
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.emojifier.data.DefaultDocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.UiBlock
|
||||
import com.anytypeio.anytype.ui.page.PageFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class CreateRelationBlockTesting : EditorTestSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val args = bundleOf(PageFragment.ID_KEY to root)
|
||||
|
||||
private val defaultDetails = Block.Details(
|
||||
mapOf(
|
||||
root to Block.Fields(
|
||||
mapOf(
|
||||
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private val title = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "CreateRelationBlockTesting",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
private val header = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Layout(
|
||||
type = Block.Content.Layout.Type.HEADER
|
||||
),
|
||||
fields = Block.Fields.empty(),
|
||||
children = listOf(title.id)
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldAddNewRelationBlockPlaceholderWithOnCreateAfterOnAddRelationCommand() {
|
||||
|
||||
val new = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.RelationBlock(
|
||||
key = null
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val paragraph = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = "Foo",
|
||||
marks = emptyList(),
|
||||
style = Block.Content.Text.Style.P
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, paragraph.id)
|
||||
)
|
||||
|
||||
val document = listOf(page, header, title, paragraph)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document, defaultDetails)
|
||||
stubCreateBlock(
|
||||
params = CreateBlock.Params(
|
||||
context = root,
|
||||
target = paragraph.id,
|
||||
position = Position.BOTTOM,
|
||||
prototype = Block.Prototype.Relation("")
|
||||
),
|
||||
events = listOf(
|
||||
Event.Command.UpdateStructure(
|
||||
context = root,
|
||||
id = root,
|
||||
children = page.children + listOf(new.id)
|
||||
),
|
||||
Event.Command.AddBlock(
|
||||
context = root,
|
||||
blocks = listOf(new)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
val fragment = launchFragment(args)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.title).checkHasText(title.content<Block.Content.Text>().text)
|
||||
onItemView(
|
||||
1,
|
||||
R.id.textContent
|
||||
).checkHasText(paragraph.content<Block.Content.Text>().text)
|
||||
}
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(1, R.id.textContent).perform(click())
|
||||
}
|
||||
|
||||
Thread.sleep(200)
|
||||
|
||||
fragment.onFragment { fr ->
|
||||
fr.onAddBlockClicked(UiBlock.RELATION)
|
||||
}
|
||||
|
||||
Thread.sleep(200)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
checkIsRecyclerSize(3)
|
||||
onItemView(0, R.id.title).checkHasText(title.content<Block.Content.Text>().text)
|
||||
onItemView(
|
||||
1,
|
||||
R.id.textContent
|
||||
).checkHasText(paragraph.content<Block.Content.Text>().text)
|
||||
onItemView(2, R.id.tvPlaceholder).checkHasText(R.string.set_new_relation)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldAddNewRelationBlockPlaceholderWithOnCreateAfterOnAddRelationCommandAfterTitle() {
|
||||
|
||||
val new = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.RelationBlock(
|
||||
key = null
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id)
|
||||
)
|
||||
|
||||
val document = listOf(page, header, title)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document, defaultDetails)
|
||||
stubCreateBlock(
|
||||
params = CreateBlock.Params(
|
||||
context = root,
|
||||
target = title.id,
|
||||
position = Position.BOTTOM,
|
||||
prototype = Block.Prototype.Relation("")
|
||||
),
|
||||
events = listOf(
|
||||
Event.Command.UpdateStructure(
|
||||
context = root,
|
||||
id = root,
|
||||
children = page.children + listOf(new.id)
|
||||
),
|
||||
Event.Command.AddBlock(
|
||||
context = root,
|
||||
blocks = listOf(new)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
val fragment = launchFragment(args)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
checkIsRecyclerSize(1)
|
||||
onItemView(0, R.id.title).checkHasText(title.content<Block.Content.Text>().text)
|
||||
}
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.title).perform(click())
|
||||
}
|
||||
|
||||
Thread.sleep(200)
|
||||
|
||||
fragment.onFragment { fr ->
|
||||
fr.onAddBlockClicked(UiBlock.RELATION)
|
||||
}
|
||||
|
||||
Thread.sleep(100)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.title).checkHasText(title.content<Block.Content.Text>().text)
|
||||
onItemView(1, R.id.tvPlaceholder).checkHasText(R.string.set_new_relation)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldAddNewRelationBlockPlaceholderWithOnReplaceAfterOnAddRelationCommand() {
|
||||
|
||||
val new = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.RelationBlock(
|
||||
key = null
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val paragraph = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
fields = Block.Fields.empty(),
|
||||
children = emptyList(),
|
||||
content = Block.Content.Text(
|
||||
text = "",
|
||||
marks = emptyList(),
|
||||
style = Block.Content.Text.Style.P
|
||||
)
|
||||
)
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = listOf(header.id, paragraph.id)
|
||||
)
|
||||
|
||||
val document = listOf(page, header, title, paragraph)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document, defaultDetails)
|
||||
stubReplaceBlock(
|
||||
command = Command.Replace(
|
||||
context = root,
|
||||
target = paragraph.id,
|
||||
prototype = Block.Prototype.Relation("")
|
||||
),
|
||||
events = listOf(
|
||||
Event.Command.UpdateStructure(
|
||||
context = root,
|
||||
id = root,
|
||||
children = listOf(page.id, header.id, new.id)
|
||||
),
|
||||
Event.Command.AddBlock(
|
||||
context = root,
|
||||
blocks = listOf(new)
|
||||
),
|
||||
Event.Command.DeleteBlock(
|
||||
context = root,
|
||||
targets = listOf(paragraph.id)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
val fragment = launchFragment(args)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.title).checkHasText(title.content<Block.Content.Text>().text)
|
||||
onItemView(1, R.id.textContent).checkHasText("")
|
||||
}
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(1, R.id.textContent).perform(click())
|
||||
}
|
||||
|
||||
Thread.sleep(200)
|
||||
|
||||
fragment.onFragment { fr ->
|
||||
fr.onAddBlockClicked(UiBlock.RELATION)
|
||||
}
|
||||
|
||||
Thread.sleep(100)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.title).checkHasText(title.content<Block.Content.Text>().text)
|
||||
onItemView(1, R.id.tvPlaceholder).checkHasText(R.string.set_new_relation)
|
||||
}
|
||||
}
|
||||
|
||||
// STUBBING & SETUP
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestPageFragment> {
|
||||
return launchFragmentInContainer<TestPageFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves coroutines clock time.
|
||||
*/
|
||||
private fun advance(millis: Long) {
|
||||
coroutineTestRule.advanceTime(millis)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,12 +12,12 @@ import androidx.test.espresso.matcher.ViewMatchers
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.interactor.UnlinkBlocks
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
@ -322,6 +322,7 @@ class DeleteBlockTesting : EditorTestSetup() {
|
|||
|
||||
stubInterceptEvents()
|
||||
stubOpenDocument(document)
|
||||
stubInterceptThreadStatus()
|
||||
stubUpdateText()
|
||||
|
||||
stubUnlinkBlocks(params, events)
|
||||
|
@ -331,7 +332,7 @@ class DeleteBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = Espresso.onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -347,7 +348,7 @@ class DeleteBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(unlinkBlocks, times(1)) { invoke(params) }
|
||||
|
||||
Espresso.onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, firstViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, firstViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -356,7 +357,7 @@ class DeleteBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val item = fragment.recycler.getChildAt(0)
|
||||
val view = item.findViewById<TextInputWidget>(firstViewId)
|
||||
assertEquals(
|
||||
expected = 3,
|
||||
|
@ -567,8 +568,6 @@ class DeleteBlockTesting : EditorTestSetup() {
|
|||
|
||||
Thread.sleep(100)
|
||||
|
||||
|
||||
|
||||
val target = Espresso.onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, firstViewId)
|
||||
)
|
||||
|
|
|
@ -11,12 +11,15 @@ import androidx.test.espresso.matcher.ViewMatchers.*
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_ui.features.page.BlockViewHolder
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.BlockSplitMode
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Checkbox
|
||||
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Numbered
|
||||
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Toggle
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.block.model.Command
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
@ -122,7 +125,7 @@ class EditorIntegrationTesting : EditorTestSetup() {
|
|||
onView(withRecyclerView(R.id.recycler).atPositionOnView(6, R.id.bulletedListContent))
|
||||
.check(matches(withText(BLOCK_BULLET.content.asText().text)))
|
||||
|
||||
R.id.recycler.scrollTo<BlockViewHolder.Numbered>(7)
|
||||
R.id.recycler.scrollTo<Numbered>(7)
|
||||
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(7, R.id.numberedListContent))
|
||||
.check(matches(withText(BLOCK_NUMBERED_1.content.asText().text)))
|
||||
|
@ -130,12 +133,12 @@ class EditorIntegrationTesting : EditorTestSetup() {
|
|||
onView(withRecyclerView(R.id.recycler).atPositionOnView(7, R.id.number))
|
||||
.check(matches(withText("1.")))
|
||||
|
||||
R.id.recycler.scrollTo<BlockViewHolder.Toggle>(8)
|
||||
R.id.recycler.scrollTo<Toggle>(8)
|
||||
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(8, R.id.toggleContent))
|
||||
.check(matches(withText(BLOCK_TOGGLE.content.asText().text)))
|
||||
|
||||
R.id.recycler.scrollTo<BlockViewHolder.Checkbox>(9)
|
||||
R.id.recycler.scrollTo<Checkbox>(9)
|
||||
|
||||
onView(withRecyclerView(R.id.recycler).atPositionOnView(9, R.id.checkboxContent))
|
||||
.check(matches(withText(BLOCK_CHECKBOX.content.asText().text)))
|
||||
|
@ -300,8 +303,9 @@ class EditorIntegrationTesting : EditorTestSetup() {
|
|||
val command = Command.Split(
|
||||
context = root,
|
||||
target = paragraph.id,
|
||||
index = 3,
|
||||
style = Block.Content.Text.Style.P
|
||||
style = Block.Content.Text.Style.P,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
range = 3..3
|
||||
)
|
||||
|
||||
stubSplitBlocks(
|
||||
|
|
|
@ -9,15 +9,15 @@ import androidx.test.espresso.action.ViewActions
|
|||
import androidx.test.espresso.assertion.ViewAssertions
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.Position
|
||||
import com.anytypeio.anytype.core_models.ext.content
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.interactor.CreateBlock
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateTextStyle
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.block.model.Position
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.domain.ext.content
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
@ -146,6 +146,7 @@ class ListBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
stubCreateBlocks(params, new, events)
|
||||
|
@ -155,7 +156,7 @@ class ListBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = Espresso.onView(
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(1, view)
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(0, view)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -177,13 +178,13 @@ class ListBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(createBlock, times(1)) { invoke(params) }
|
||||
|
||||
Espresso.onView(
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(1, view)
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(0, view)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText(a.content<Block.Content.Text>().text)))
|
||||
}
|
||||
|
||||
Espresso.onView(
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(2, view)
|
||||
TestUtils.withRecyclerView(R.id.recycler).atPositionOnView(1, view)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -192,7 +193,7 @@ class ListBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position at block B
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
item.findViewById<TextInputWidget>(view).apply {
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
|
|
@ -12,12 +12,12 @@ import androidx.test.espresso.matcher.ViewMatchers
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.interactor.MergeBlocks
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
@ -241,6 +241,7 @@ class MergeBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
stubMergelocks(
|
||||
|
@ -253,7 +254,7 @@ class MergeBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = Espresso.onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -263,7 +264,7 @@ class MergeBlockTesting : EditorTestSetup() {
|
|||
// Set cursor at the beginning of B
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
view.setSelection(0)
|
||||
}
|
||||
|
@ -282,7 +283,7 @@ class MergeBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(mergeBlocks, times(1)) { invoke(params) }
|
||||
|
||||
Espresso.onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("FooBar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -291,7 +292,7 @@ class MergeBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val item = fragment.recycler.getChildAt(0)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 3,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
|
|
@ -11,10 +11,11 @@ import androidx.test.espresso.matcher.ViewMatchers
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.BlockSplitMode
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.Event
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.block.model.Command
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.features.editor.base.EditorTestSetup
|
||||
import com.anytypeio.anytype.features.editor.base.TestPageFragment
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
|
@ -26,7 +27,6 @@ import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
|||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verifyBlocking
|
||||
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
||||
import kotlinx.android.synthetic.main.fragment_page.*
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
|
@ -49,86 +49,6 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldNotSplitTitle() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val args = bundleOf(PageFragment.ID_KEY to root)
|
||||
|
||||
val title = "Indivisible title"
|
||||
|
||||
val page = Block(
|
||||
id = root,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.PAGE
|
||||
),
|
||||
children = emptyList()
|
||||
)
|
||||
|
||||
val document = listOf(page)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenDocument(
|
||||
document = document,
|
||||
details = Block.Details(
|
||||
mapOf(
|
||||
root to Block.Fields(
|
||||
mapOf("name" to title)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val scenario = launchFragment(args)
|
||||
|
||||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, R.id.title)
|
||||
)
|
||||
|
||||
// Set cursor programmatically
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
fragment.recycler.findViewById<TextInputWidget>(R.id.title).setSelection(3)
|
||||
}
|
||||
|
||||
// Press ENTER
|
||||
|
||||
target.perform(ViewActions.pressImeActionButton())
|
||||
|
||||
// Check results
|
||||
|
||||
verifyZeroInteractions(updateText)
|
||||
verifyZeroInteractions(repo)
|
||||
|
||||
target.apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText(title)))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
}
|
||||
|
||||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(0)
|
||||
val view = item.findViewById<TextInputWidget>(R.id.title)
|
||||
assertEquals(
|
||||
expected = 3,
|
||||
actual = view.selectionStart
|
||||
)
|
||||
assertEquals(
|
||||
expected = 3,
|
||||
actual = view.selectionEnd
|
||||
)
|
||||
}
|
||||
|
||||
// Release pending coroutines
|
||||
|
||||
advance(PageViewModel.TEXT_CHANGES_DEBOUNCE_DURATION)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSplitParagraph() {
|
||||
|
||||
|
@ -191,13 +111,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
range = 3..3,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -214,7 +136,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -244,13 +166,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -259,7 +181,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -338,13 +260,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -361,7 +285,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -391,13 +315,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -406,7 +330,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -485,13 +409,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -508,7 +434,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -538,13 +464,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -553,7 +479,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -632,13 +558,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -655,7 +583,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -683,13 +611,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -698,7 +626,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -777,13 +705,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -800,7 +730,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -828,13 +758,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -843,7 +773,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -922,13 +852,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -973,13 +905,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -988,7 +920,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -1067,13 +999,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -1090,7 +1024,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -1116,13 +1050,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -1131,7 +1065,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -1210,13 +1144,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -1233,7 +1169,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -1259,13 +1195,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -1274,7 +1210,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
@ -1353,13 +1289,15 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubInterceptThreadStatus()
|
||||
stubOpenDocument(document)
|
||||
stubUpdateText()
|
||||
|
||||
val command = Command.Split(
|
||||
context = root,
|
||||
target = block.id,
|
||||
index = 3,
|
||||
range = 3..3,
|
||||
mode = BlockSplitMode.BOTTOM,
|
||||
style = style
|
||||
)
|
||||
|
||||
|
@ -1376,7 +1314,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// TESTING
|
||||
|
||||
val target = onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
)
|
||||
|
||||
target.apply {
|
||||
|
@ -1402,13 +1340,13 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
verifyBlocking(repo, times(1)) { split(command) }
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(0, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Foo")))
|
||||
}
|
||||
|
||||
onView(
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(2, targetViewId)
|
||||
withRecyclerView(R.id.recycler).atPositionOnView(1, targetViewId)
|
||||
).apply {
|
||||
check(ViewAssertions.matches(ViewMatchers.withText("Bar")))
|
||||
check(ViewAssertions.matches(ViewMatchers.hasFocus()))
|
||||
|
@ -1417,7 +1355,7 @@ class SplitBlockTesting : EditorTestSetup() {
|
|||
// Check cursor position
|
||||
|
||||
scenario.onFragment { fragment ->
|
||||
val item = fragment.recycler.getChildAt(2)
|
||||
val item = fragment.recycler.getChildAt(1)
|
||||
val view = item.findViewById<TextInputWidget>(targetViewId)
|
||||
assertEquals(
|
||||
expected = 0,
|
||||
|
|
|
@ -1,36 +1,44 @@
|
|||
package com.anytypeio.anytype.features.editor.base
|
||||
|
||||
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`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.base.Result
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.*
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.domain.block.model.Command
|
||||
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.common.Id
|
||||
import com.anytypeio.anytype.domain.config.Config
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.cover.RemoveDocCover
|
||||
import com.anytypeio.anytype.domain.cover.SetDocCoverImage
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetRelationKey
|
||||
import com.anytypeio.anytype.domain.download.DownloadFile
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.anytypeio.anytype.domain.event.model.Event
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.domain.icon.DocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
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.status.InterceptThreadStatus
|
||||
import com.anytypeio.anytype.domain.status.ThreadStatusChannel
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.DocumentExternalEventReducer
|
||||
import com.anytypeio.anytype.presentation.page.Editor
|
||||
import com.anytypeio.anytype.presentation.page.PageViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.page.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.presentation.page.editor.Interactor
|
||||
import com.anytypeio.anytype.presentation.page.editor.InternalDetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.editor.Orchestrator
|
||||
import com.anytypeio.anytype.presentation.page.editor.Proxy
|
||||
import com.anytypeio.anytype.presentation.page.editor.pattern.DefaultPatternMatcher
|
||||
import com.anytypeio.anytype.presentation.page.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.page.selection.SelectionStateHolder
|
||||
import com.anytypeio.anytype.presentation.page.toggle.ToggleStateHolder
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
|
@ -42,6 +50,7 @@ import org.mockito.MockitoAnnotations
|
|||
|
||||
open class EditorTestSetup {
|
||||
|
||||
lateinit var createObject: CreateObject
|
||||
lateinit var archiveDocument: ArchiveDocument
|
||||
lateinit var createDocument: CreateDocument
|
||||
lateinit var downloadFile: DownloadFile
|
||||
|
@ -58,11 +67,14 @@ open class EditorTestSetup {
|
|||
lateinit var createPage: CreatePage
|
||||
lateinit var updateBackgroundColor: UpdateBackgroundColor
|
||||
lateinit var move: Move
|
||||
lateinit var setRelationKey: SetRelationKey
|
||||
lateinit var updateDetail: UpdateDetail
|
||||
|
||||
|
||||
@Mock
|
||||
lateinit var openPage: OpenPage
|
||||
@Mock
|
||||
lateinit var closePage: ClosePage
|
||||
lateinit var closePage: CloseBlock
|
||||
@Mock
|
||||
lateinit var updateText: UpdateText
|
||||
@Mock
|
||||
|
@ -77,25 +89,56 @@ open class EditorTestSetup {
|
|||
lateinit var getListPages: GetListPages
|
||||
@Mock
|
||||
lateinit var duplicateBlock: DuplicateBlock
|
||||
|
||||
@Mock
|
||||
lateinit var updateTextStyle: UpdateTextStyle
|
||||
|
||||
@Mock
|
||||
lateinit var updateTextColor: UpdateTextColor
|
||||
|
||||
@Mock
|
||||
lateinit var updateLinkMarks: UpdateLinkMarks
|
||||
|
||||
@Mock
|
||||
lateinit var removeLinkMark: RemoveLinkMark
|
||||
|
||||
@Mock
|
||||
lateinit var mergeBlocks: MergeBlocks
|
||||
|
||||
lateinit var createNewDocument: CreateNewDocument
|
||||
lateinit var interceptThreadStatus: InterceptThreadStatus
|
||||
|
||||
lateinit var setDocCoverImage: SetDocCoverImage
|
||||
lateinit var removeDocCover: RemoveDocCover
|
||||
|
||||
lateinit var updateFields: UpdateFields
|
||||
lateinit var turnIntoDocument: TurnIntoDocument
|
||||
lateinit var turnIntoStyle: TurnIntoStyle
|
||||
|
||||
@Mock
|
||||
lateinit var updateDivider: UpdateDivider
|
||||
|
||||
@Mock
|
||||
lateinit var uriMatcher: Clipboard.UriMatcher
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var coverImageHashProvider: CoverImageHashProvider
|
||||
|
||||
@Mock
|
||||
lateinit var clipboard: Clipboard
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
@Mock
|
||||
lateinit var analytics: Analytics
|
||||
|
||||
@Mock
|
||||
lateinit var threadStatusChannel: ThreadStatusChannel
|
||||
|
||||
@Mock
|
||||
lateinit var documentEmojiIconProvider: DocumentEmojiIconProvider
|
||||
|
||||
|
@ -107,9 +150,11 @@ open class EditorTestSetup {
|
|||
profile = MockDataFactory.randomUuid()
|
||||
)
|
||||
|
||||
private val urlBuilder = UrlBuilder(
|
||||
config = config
|
||||
)
|
||||
private val urlBuilder by lazy {
|
||||
UrlBuilder(
|
||||
gateway = gateway
|
||||
)
|
||||
}
|
||||
|
||||
private val intents = Proxy.Intents()
|
||||
|
||||
|
@ -133,6 +178,12 @@ open class EditorTestSetup {
|
|||
updateAlignment = UpdateAlignment(repo)
|
||||
updateTitle = UpdateTitle(repo)
|
||||
uploadBlock = UploadBlock(repo)
|
||||
createObject = CreateObject(repo, documentEmojiIconProvider)
|
||||
setRelationKey = SetRelationKey(repo)
|
||||
turnIntoDocument = TurnIntoDocument(repo)
|
||||
updateFields = UpdateFields(repo)
|
||||
createNewDocument = CreateNewDocument(repo, documentEmojiIconProvider)
|
||||
interceptThreadStatus = InterceptThreadStatus(channel = threadStatusChannel)
|
||||
downloadFile = DownloadFile(
|
||||
downloader = mock(),
|
||||
context = Dispatchers.Main
|
||||
|
@ -151,6 +202,11 @@ open class EditorTestSetup {
|
|||
|
||||
updateBackgroundColor = UpdateBackgroundColor(repo)
|
||||
|
||||
setDocCoverImage = SetDocCoverImage(repo)
|
||||
removeDocCover = RemoveDocCover(repo)
|
||||
turnIntoStyle = TurnIntoStyle(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
|
||||
TestPageFragment.testViewModelFactory = PageViewModelFactory(
|
||||
openPage = openPage,
|
||||
closePage = closePage,
|
||||
|
@ -158,6 +214,7 @@ open class EditorTestSetup {
|
|||
updateLinkMarks = updateLinkMarks,
|
||||
removeLinkMark = removeLinkMark,
|
||||
createPage = createPage,
|
||||
createObject = createObject,
|
||||
documentEventReducer = DocumentExternalEventReducer(),
|
||||
archiveDocument = archiveDocument,
|
||||
createDocument = createDocument,
|
||||
|
@ -165,10 +222,11 @@ open class EditorTestSetup {
|
|||
renderer = DefaultBlockViewRenderer(
|
||||
urlBuilder = urlBuilder,
|
||||
counter = Counter.Default(),
|
||||
toggleStateHolder = ToggleStateHolder.Default()
|
||||
toggleStateHolder = ToggleStateHolder.Default(),
|
||||
coverImageHashProvider = coverImageHashProvider
|
||||
),
|
||||
getListPages = getListPages,
|
||||
interactor = Orchestrator(
|
||||
orchestrator = Orchestrator(
|
||||
createBlock = createBlock,
|
||||
splitBlock = splitBlock,
|
||||
unlinkBlocks = unlinkBlocks,
|
||||
|
@ -188,6 +246,7 @@ open class EditorTestSetup {
|
|||
updateTextColor = updateTextColor,
|
||||
replaceBlock = replaceBlock,
|
||||
setupBookmark = setupBookmark,
|
||||
setRelationKey = setRelationKey,
|
||||
memory = Editor.Memory(
|
||||
selections = SelectionStateHolder.Default()
|
||||
),
|
||||
|
@ -199,8 +258,21 @@ open class EditorTestSetup {
|
|||
matcher = DefaultPatternMatcher()
|
||||
),
|
||||
uploadBlock = uploadBlock,
|
||||
move = move
|
||||
)
|
||||
move = move,
|
||||
analytics = analytics,
|
||||
updateDivider = updateDivider,
|
||||
updateFields = updateFields,
|
||||
turnIntoDocument = turnIntoDocument,
|
||||
turnIntoStyle = turnIntoStyle
|
||||
),
|
||||
createNewDocument = createNewDocument,
|
||||
interceptThreadStatus = interceptThreadStatus,
|
||||
analytics = analytics,
|
||||
dispatcher = Dispatcher.Default(),
|
||||
setDocCoverImage = setDocCoverImage,
|
||||
removeDocCover = removeDocCover,
|
||||
detailModificationManager = InternalDetailModificationManager(stores.details),
|
||||
updateDetail = updateDetail
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -210,24 +282,36 @@ open class EditorTestSetup {
|
|||
|
||||
fun stubInterceptEvents() {
|
||||
interceptEvents.stub {
|
||||
onBlocking { build() } doReturn emptyFlow()
|
||||
onBlocking { build(any()) } doReturn emptyFlow()
|
||||
}
|
||||
}
|
||||
|
||||
fun stubInterceptThreadStatus(
|
||||
params: InterceptThreadStatus.Params = InterceptThreadStatus.Params(ctx = root)
|
||||
) {
|
||||
interceptThreadStatus.stub {
|
||||
onBlocking { build(params) } doReturn emptyFlow()
|
||||
}
|
||||
}
|
||||
|
||||
fun stubOpenDocument(
|
||||
document: List<Block>,
|
||||
details: Block.Details = Block.Details()
|
||||
details: Block.Details = Block.Details(),
|
||||
relations: List<Relation> = emptyList()
|
||||
) {
|
||||
openPage.stub {
|
||||
onBlocking { invoke(any()) } doReturn Either.Right(
|
||||
Payload(
|
||||
context = root,
|
||||
events = listOf(
|
||||
Event.Command.ShowBlock(
|
||||
context = root,
|
||||
root = root,
|
||||
details = details,
|
||||
blocks = document
|
||||
Result.Success(
|
||||
Payload(
|
||||
context = root,
|
||||
events = listOf(
|
||||
Event.Command.ShowBlock(
|
||||
context = root,
|
||||
root = root,
|
||||
details = details,
|
||||
blocks = document,
|
||||
relations = relations
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -235,6 +319,31 @@ open class EditorTestSetup {
|
|||
}
|
||||
}
|
||||
|
||||
fun stubCreateBlock(
|
||||
params: CreateBlock.Params,
|
||||
events: List<Event.Command>
|
||||
) {
|
||||
createBlock.stub {
|
||||
onBlocking { invoke(params) } doReturn Either.Right(
|
||||
Pair(
|
||||
MockDataFactory.randomUuid(),
|
||||
Payload(context = root, events = events)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun stubReplaceBlock(
|
||||
command: Command.Replace,
|
||||
events: List<Event.Command>
|
||||
) {
|
||||
repo.stub {
|
||||
onBlocking {
|
||||
replace(command = command)
|
||||
} doReturn Pair(command.context, Payload(command.context, events))
|
||||
}
|
||||
}
|
||||
|
||||
fun stubSplitBlocks(
|
||||
command: Command.Split,
|
||||
new: Id,
|
||||
|
|
|
@ -19,7 +19,9 @@ import com.anytypeio.anytype.emojifier.data.EmojiProvider
|
|||
import com.anytypeio.anytype.emojifier.suggest.EmojiSuggester
|
||||
import com.anytypeio.anytype.emojifier.suggest.model.EmojiModel
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.picker.DocumentEmojiIconPickerViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import kotlinx.android.synthetic.main.fragment_page_icon_picker.*
|
||||
|
@ -35,6 +37,9 @@ import kotlin.test.assertEquals
|
|||
@LargeTest
|
||||
class DocumentEmojiPickerFragmentTest {
|
||||
|
||||
@Mock
|
||||
lateinit var detailModificationManager: DetailModificationManager
|
||||
|
||||
@Mock
|
||||
lateinit var suggester: EmojiSuggester
|
||||
|
||||
|
@ -54,7 +59,9 @@ class DocumentEmojiPickerFragmentTest {
|
|||
DocumentEmojiIconPickerViewModelFactory(
|
||||
emojiProvider = provider,
|
||||
emojiSuggester = suggester,
|
||||
setEmojiIcon = setEmojiIcon
|
||||
setEmojiIcon = setEmojiIcon,
|
||||
dispatcher = Dispatcher.Default(),
|
||||
details = detailModificationManager
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,606 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddStatusToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.relations.AddObjectRelationOption
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.relations.AddObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.relations.AddObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class AddRelationStatusValueTest {
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
private lateinit var addRelationOption: AddDataViewRelationOption
|
||||
private lateinit var addObjectRelationOption: AddObjectRelationOption
|
||||
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
|
||||
private lateinit var addTagToDataViewRecord: AddTagToDataViewRecord
|
||||
private lateinit var addStatusToDataViewRecord: AddStatusToDataViewRecord
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
private lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val ctx = MockDataFactory.randomUuid()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
addRelationOption = AddDataViewRelationOption(repo)
|
||||
addTagToDataViewRecord = AddTagToDataViewRecord(repo)
|
||||
addObjectRelationOption = AddObjectRelationOption(repo)
|
||||
addStatusToDataViewRecord = AddStatusToDataViewRecord(repo)
|
||||
removeTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestAddObjectSetObjectRelationValueFragment.testVmFactory = AddObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session),
|
||||
details = object : ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
},
|
||||
types = object : ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
},
|
||||
addDataViewRelationOption = addRelationOption,
|
||||
addTagToDataViewRecord = addTagToDataViewRecord,
|
||||
addStatusToDataViewRecord = addStatusToDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldStartCreatingDataViewOptionWhenTypeAndButtonClicked() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = emptyList()
|
||||
)
|
||||
|
||||
val obj = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to obj,
|
||||
relation.key to emptyList<Id>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
repo.stub {
|
||||
onBlocking {
|
||||
addDataViewRelationOption(
|
||||
ctx = any(),
|
||||
dataview = any(),
|
||||
relation = any(),
|
||||
color = any(),
|
||||
name = any(),
|
||||
record = any()
|
||||
)
|
||||
} doReturn Pair(
|
||||
Payload(
|
||||
context = ctx,
|
||||
events = emptyList()
|
||||
),
|
||||
MockDataFactory.randomUuid()
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to obj
|
||||
)
|
||||
)
|
||||
|
||||
// Creating name for a new option
|
||||
|
||||
R.id.filterInput.type("In progress")
|
||||
|
||||
val btn = R.id.recycler.rVMatcher().onItemView(0, R.id.tvCreateOptionValue)
|
||||
|
||||
btn.checkHasText("Create option \"In progress\"")
|
||||
|
||||
// Pressing button, in order to trigger request.
|
||||
|
||||
btn.performClick()
|
||||
|
||||
// Verifying that the request is made.
|
||||
|
||||
verifyBlocking(repo, times(1)) {
|
||||
addDataViewRelationOption(
|
||||
ctx = any(),
|
||||
dataview = any(),
|
||||
relation = any(),
|
||||
color = any(),
|
||||
name = any(),
|
||||
record = any()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addButtonShouldNotBeVisible() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = emptyList()
|
||||
)
|
||||
|
||||
val obj = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to obj,
|
||||
relation.key to emptyList<Id>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
repo.stub {
|
||||
onBlocking {
|
||||
addDataViewRelationOption(
|
||||
ctx = any(),
|
||||
dataview = any(),
|
||||
relation = any(),
|
||||
color = any(),
|
||||
name = any(),
|
||||
record = any()
|
||||
)
|
||||
} doReturn Pair(
|
||||
Payload(
|
||||
context = ctx,
|
||||
events = emptyList()
|
||||
),
|
||||
MockDataFactory.randomUuid()
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to obj
|
||||
)
|
||||
)
|
||||
|
||||
R.id.btnAdd.matchView().checkIsNotDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderOnlyStatusesWhichRelationValueDoesNotContain() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1Color = ThemeColor.values().random()
|
||||
val option2Color = ThemeColor.values().random()
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = option1Color.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Done",
|
||||
color = option2Color.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Development",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id, option3.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
R.id.recycler.rVMatcher().apply {
|
||||
onItemView(0, R.id.tvStatusName).checkHasText(option1.text)
|
||||
onItemView(0, R.id.tvStatusName).checkHasTextColor(option1Color.text)
|
||||
checkIsRecyclerSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun statusesShouldBeInTheListWhenTypingToCreateNewOption() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In Testing",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Done",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Development",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to emptyList<String>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Typing name for a new option
|
||||
|
||||
R.id.filterInput.type("Backlog")
|
||||
|
||||
// Checking that not only create-option view button, but also tags are visible
|
||||
|
||||
R.id.recycler.rVMatcher().apply {
|
||||
onItemView(0, R.id.tvCreateOptionValue).checkHasText("Create option \"Backlog\"")
|
||||
onItemView(1, R.id.tvStatusName).checkHasText(option1.text)
|
||||
onItemView(2, R.id.tvStatusName).checkHasText(option2.text)
|
||||
onItemView(3, R.id.tvStatusName).checkHasText(option3.text)
|
||||
checkIsRecyclerSize(4)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRequestAddingStatusToDataViewRecordWhenStatusClicked() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Testing",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Development",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to emptyList<String>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
// Selecting the first two tags
|
||||
|
||||
R.id.recycler.rVMatcher().onItemView(1, R.id.tvStatusName).performClick()
|
||||
|
||||
// Veryfying UI
|
||||
|
||||
verifyBlocking(repo, times(1)) {
|
||||
updateDataViewRecord(
|
||||
context = ctx,
|
||||
target = dv.id,
|
||||
record = target,
|
||||
values = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestAddObjectSetObjectRelationValueFragment> {
|
||||
return launchFragmentInContainer<TestAddObjectSetObjectRelationValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,532 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddStatusToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.relations.AddObjectRelationOption
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.relations.AddObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.relations.AddObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class AddRelationTagValueTest {
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
private lateinit var addRelationOption: AddDataViewRelationOption
|
||||
private lateinit var addObjectRelationOption: AddObjectRelationOption
|
||||
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
|
||||
private lateinit var addTagToDataViewRecord: AddTagToDataViewRecord
|
||||
private lateinit var addStatusToDataViewRecord: AddStatusToDataViewRecord
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
private lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val ctx = MockDataFactory.randomUuid()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
addRelationOption = AddDataViewRelationOption(repo)
|
||||
addTagToDataViewRecord = AddTagToDataViewRecord(repo)
|
||||
addObjectRelationOption = AddObjectRelationOption(repo)
|
||||
addStatusToDataViewRecord = AddStatusToDataViewRecord(repo)
|
||||
removeTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestAddObjectSetObjectRelationValueFragment.testVmFactory = AddObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session),
|
||||
details = object : ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
},
|
||||
types = object : ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
},
|
||||
addDataViewRelationOption = addRelationOption,
|
||||
addTagToDataViewRecord = addTagToDataViewRecord,
|
||||
addStatusToDataViewRecord = addStatusToDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldStartCreatingDataViewOptionWhenTypeAndButtonClicked() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = emptyList()
|
||||
)
|
||||
|
||||
val obj = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to obj,
|
||||
relation.key to emptyList<Id>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
repo.stub {
|
||||
onBlocking {
|
||||
addDataViewRelationOption(
|
||||
ctx = any(),
|
||||
dataview = any(),
|
||||
relation = any(),
|
||||
color = any(),
|
||||
name = any(),
|
||||
record = any()
|
||||
)
|
||||
} doReturn Pair(
|
||||
Payload(
|
||||
context = ctx,
|
||||
events = emptyList()
|
||||
),
|
||||
MockDataFactory.randomUuid()
|
||||
)
|
||||
}
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to obj
|
||||
)
|
||||
)
|
||||
|
||||
// Creating name for a new option
|
||||
|
||||
R.id.filterInput.type("Writer")
|
||||
|
||||
val btn = R.id.recycler.rVMatcher().onItemView(0, R.id.tvCreateOptionValue)
|
||||
|
||||
btn.checkHasText("Create option \"Writer\"")
|
||||
|
||||
// Pressing button, in order to trigger request.
|
||||
|
||||
btn.performClick()
|
||||
|
||||
// Verifying that the request is made.
|
||||
|
||||
verifyBlocking(repo, times(1)) {
|
||||
addDataViewRelationOption(
|
||||
ctx = any(),
|
||||
dataview = any(),
|
||||
relation = any(),
|
||||
color = any(),
|
||||
name = any(),
|
||||
record = any()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderOnlyTagsWhichRelationValueDoesNotContain() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1Color = ThemeColor.values().random()
|
||||
val option2Color = ThemeColor.values().random()
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = option1Color.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = option2Color.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id, option3.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
R.id.recycler.rVMatcher().apply {
|
||||
onItemView(0, R.id.tvTagName).checkHasText(option1.text)
|
||||
onItemView(0, R.id.tvTagName).checkHasTextColor(option1Color.text)
|
||||
checkIsRecyclerSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tagsShouldBeInTheListWhenTypingToCreateNewOption() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to emptyList<String>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Typing name for a new option
|
||||
|
||||
R.id.filterInput.type("Writer")
|
||||
|
||||
// Checking that not only create-option view button, but also tags are visible
|
||||
|
||||
R.id.recycler.rVMatcher().apply {
|
||||
onItemView(0, R.id.tvCreateOptionValue).checkHasText("Create option \"Writer\"")
|
||||
onItemView(1, R.id.tvTagName).checkHasText(option1.text)
|
||||
onItemView(2, R.id.tvTagName).checkHasText(option2.text)
|
||||
onItemView(3, R.id.tvTagName).checkHasText(option3.text)
|
||||
checkIsRecyclerSize(4)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSelectFirstTwoTagsUpdateCounterAndRequestAddingThisTagToDataViewRecord() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = ThemeColor.values().random().title
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to emptyList<String>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
AddObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
AddObjectRelationValueFragment.RELATION_KEY to relation.key,
|
||||
AddObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
AddObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
AddObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
// Selecting the first two tags
|
||||
|
||||
R.id.recycler.rVMatcher().apply {
|
||||
onItemView(0, R.id.tvTagName).performClick()
|
||||
onItemView(1, R.id.tvTagName).performClick()
|
||||
}
|
||||
|
||||
// Clicking twice on the last tag, in order to check select / unselect logic.
|
||||
|
||||
R.id.recycler.rVMatcher().apply {
|
||||
onItemView(2, R.id.tvTagName).performClick()
|
||||
onItemView(2, R.id.tvTagName).performClick()
|
||||
}
|
||||
|
||||
// Veryfying UI
|
||||
|
||||
R.id.tvSelectionCounter.matchView().checkHasText("2")
|
||||
|
||||
R.id.btnAdd.performClick()
|
||||
|
||||
verifyBlocking(repo, times(1)) {
|
||||
updateDataViewRecord(
|
||||
context = ctx,
|
||||
target = dv.id,
|
||||
record = target,
|
||||
values = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option1.id, option2.id)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestAddObjectSetObjectRelationValueFragment> {
|
||||
return launchFragmentInContainer<TestAddObjectSetObjectRelationValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,447 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectRelationTextValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationTextValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class DisplayObjectRelationTextValueTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
val root = MockDataFactory.randomUuid()
|
||||
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
TestObjectRelationTextValueFragment.testVmFactory = ObjectRelationTextValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetDescriptionTextAndNotDisplayActionButton() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Architect"
|
||||
val valueText = "Filippo Brunelleschi"
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.SHORT_TEXT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueText
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationTextValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationTextValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationTextValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationTextValueFragment.FLOW_KEY to ObjectRelationTextValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
onView(withId(R.id.textInputField)).apply {
|
||||
check(matches(withText(valueText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.tvRelationHeader)).apply {
|
||||
check(matches(withText(relationText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAction)).apply {
|
||||
check(matches(not(isDisplayed())))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetNumberTextAndNotDisplayActionButton() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Year"
|
||||
val valueText = "1446"
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.NUMBER,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueText
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationTextValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationTextValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationTextValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationTextValueFragment.FLOW_KEY to ObjectRelationTextValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
onView(withId(R.id.textInputField)).apply {
|
||||
check(matches(withText(valueText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.tvRelationHeader)).apply {
|
||||
check(matches(withText(relationText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAction)).apply {
|
||||
check(matches(not(isDisplayed())))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetPhoneTextAndDisplayActionButton() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Phone number"
|
||||
val valueText = "+ 124242423423"
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.PHONE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueText
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationTextValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationTextValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationTextValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationTextValueFragment.FLOW_KEY to ObjectRelationTextValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
onView(withId(R.id.textInputField)).apply {
|
||||
check(matches(withText(valueText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.tvRelationHeader)).apply {
|
||||
check(matches(withText(relationText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAction)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetEmailTextAndDisplayActionButton() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Email"
|
||||
val valueText = "foo.bar@foobar.com"
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.EMAIL,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueText
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationTextValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationTextValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationTextValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationTextValueFragment.FLOW_KEY to ObjectRelationTextValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
onView(withId(R.id.textInputField)).apply {
|
||||
check(matches(withText(valueText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.tvRelationHeader)).apply {
|
||||
check(matches(withText(relationText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAction)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetUrlTextAndDisplayActionButton() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Url"
|
||||
val valueText = "https://anytype.io"
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.URL,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueText
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationTextValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationTextValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationTextValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationTextValueFragment.FLOW_KEY to ObjectRelationTextValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
onView(withId(R.id.textInputField)).apply {
|
||||
check(matches(withText(valueText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.tvRelationHeader)).apply {
|
||||
check(matches(withText(relationText)))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAction)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectRelationTextValueFragment> {
|
||||
return launchFragmentInContainer<TestObjectRelationTextValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,640 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class DisplayRelationObjectValueTest {
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
private lateinit var addRelationOption: AddDataViewRelationOption
|
||||
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
|
||||
private lateinit var addTagToDataViewRecord: AddTagToDataViewRecord
|
||||
private lateinit var updateDataViewRecord: UpdateDataViewRecord
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
private lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
addRelationOption = AddDataViewRelationOption(repo)
|
||||
addTagToDataViewRecord = AddTagToDataViewRecord(repo)
|
||||
removeTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo)
|
||||
updateDataViewRecord = UpdateDataViewRecord(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestObjectSetObjectRelationValueFragment.testVmFactory = ObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session),
|
||||
details = object: ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
},
|
||||
types = object: ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
},
|
||||
removeTagFromRecord = removeTagFromDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewRecord = updateDataViewRecord
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayEditButtonAndPlusButton() {
|
||||
// SETUP
|
||||
|
||||
val relation = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation to emptyList<Id>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relation,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relation,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Checking that the buttons are invisible
|
||||
|
||||
onView(withId(R.id.btnEditOrDone)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAddValue)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetRelationName() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Object"
|
||||
|
||||
val relation = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation to emptyList<Id>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relation,
|
||||
isMulti = true,
|
||||
name = name,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relation,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Checking that the name is set
|
||||
|
||||
onView(withId(R.id.tvTagOrStatusRelationHeader)).apply {
|
||||
check(matches(withText(name)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderEmptyState() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Object"
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val targetId = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to targetId,
|
||||
relationId to emptyList<Id>()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationId,
|
||||
name = name,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationId,
|
||||
ObjectRelationValueFragment.TARGET_KEY to targetId
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvEmptyMessage)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderTwoObjectsWithNames() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "Cast"
|
||||
val object1Name = "Charlie Chaplin"
|
||||
val object1Id = MockDataFactory.randomUuid()
|
||||
val object2Name = "Jean-Pierre Léaud"
|
||||
val object2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val objectType1 = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Director",
|
||||
relations = emptyList(),
|
||||
emoji = "",
|
||||
layout = ObjectType.Layout.values().random(),
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val objectType2 = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Actor",
|
||||
relations = emptyList(),
|
||||
emoji = "",
|
||||
layout = ObjectType.Layout.values().random(),
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val recordId = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to recordId,
|
||||
relationId to listOf(object1Id, object2Id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
),
|
||||
details = mapOf(
|
||||
object1Id to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to object1Name,
|
||||
Block.Fields.TYPE_KEY to objectType1.url,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
),
|
||||
object2Id to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to object2Name,
|
||||
Block.Fields.TYPE_KEY to objectType2.url,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
)
|
||||
),
|
||||
objectTypes = listOf(objectType1, objectType2)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationId,
|
||||
ObjectRelationValueFragment.TARGET_KEY to recordId
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvTitle)).apply {
|
||||
check(matches(withText(object1Name)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvSubtitle)).apply {
|
||||
check(matches(withText(objectType1.name)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.tvTitle)).apply {
|
||||
check(matches(withText(object2Name)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.tvSubtitle)).apply {
|
||||
check(matches(withText(objectType2.name)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderTwoObjectsWithoutObjectTypes() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "Cast"
|
||||
val object1Name = "Charlie Chaplin"
|
||||
val object1Id = MockDataFactory.randomUuid()
|
||||
val object2Name = "Jean-Pierre Léaud"
|
||||
val object2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val recordId = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to recordId,
|
||||
relationId to listOf(object1Id, object2Id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
),
|
||||
details = mapOf(
|
||||
object1Id to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to object1Name,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
),
|
||||
object2Id to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to object2Name,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
)
|
||||
),
|
||||
objectTypes = listOf()
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationId,
|
||||
ObjectRelationValueFragment.TARGET_KEY to recordId
|
||||
)
|
||||
)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvTitle).checkHasText(object1Name)
|
||||
onItemView(0, R.id.tvSubtitle).checkHasText(R.string.unknown_object_type)
|
||||
onItemView(1, R.id.tvTitle).checkHasText(object2Name)
|
||||
onItemView(1, R.id.tvSubtitle).checkHasText(R.string.unknown_object_type)
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderProfileObjectWithNameAndInitial() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "Writers"
|
||||
val object1Name = "Virginia Woolf"
|
||||
val object1Id = MockDataFactory.randomUuid()
|
||||
val object2Name = "Réné-Auguste Chateaubriand"
|
||||
val object2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val objectType1 = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Writer",
|
||||
relations = emptyList(),
|
||||
emoji = "",
|
||||
layout = ObjectType.Layout.PROFILE,
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val objectType2 = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Writer",
|
||||
relations = emptyList(),
|
||||
emoji = "",
|
||||
layout = ObjectType.Layout.PROFILE,
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val recordId = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to recordId,
|
||||
relationId to listOf(object1Id, object2Id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
),
|
||||
details = mapOf(
|
||||
object1Id to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to object1Name,
|
||||
Block.Fields.TYPE_KEY to objectType1.url
|
||||
)
|
||||
),
|
||||
object2Id to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to object2Name,
|
||||
Block.Fields.TYPE_KEY to objectType2.url
|
||||
)
|
||||
)
|
||||
),
|
||||
objectTypes = listOf(objectType1, objectType2)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationId,
|
||||
ObjectRelationValueFragment.TARGET_KEY to recordId
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.initial)).apply {
|
||||
check(matches(withText(object1Name.first().toString())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.initial)).apply {
|
||||
check(matches(withText(object2Name.first().toString())))
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectSetObjectRelationValueFragment> {
|
||||
return launchFragmentInContainer<TestObjectSetObjectRelationValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
import com.anytypeio.anytype.utils.WithTextColor
|
||||
import com.anytypeio.anytype.utils.WithTextColorRes
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class DisplayRelationStatusValueTest {
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
private lateinit var addRelationOption: AddDataViewRelationOption
|
||||
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
|
||||
private lateinit var addTagToDataViewRecord: AddTagToDataViewRecord
|
||||
private lateinit var updateDataViewRecord: UpdateDataViewRecord
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
private lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
addRelationOption = AddDataViewRelationOption(repo)
|
||||
addTagToDataViewRecord = AddTagToDataViewRecord(repo)
|
||||
updateDataViewRecord = UpdateDataViewRecord(repo)
|
||||
removeTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestObjectSetObjectRelationValueFragment.testVmFactory = ObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session),
|
||||
details = object: ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
},
|
||||
types = object: ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
},
|
||||
removeTagFromRecord = removeTagFromDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewRecord = updateDataViewRecord
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayEditButtonAndPlusButton() {
|
||||
// SETUP
|
||||
|
||||
val relation = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relation,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
format = Relation.Format.STATUS,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relation,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Checking that the buttons are invisible
|
||||
|
||||
onView(withId(R.id.btnEditOrDone)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAddValue)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetRelationName() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Status"
|
||||
|
||||
val relation = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relation,
|
||||
isMulti = true,
|
||||
name = name,
|
||||
format = Relation.Format.STATUS,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relation,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Checking that the name is set
|
||||
|
||||
onView(withId(R.id.tvTagOrStatusRelationHeader)).apply {
|
||||
check(matches(withText(name)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderStatusFromDV() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1Color = ThemeColor.values().random()
|
||||
val option2Color = ThemeColor.values().random()
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = option1Color.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Done",
|
||||
color = option2Color.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Todo",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvStatusName)).apply {
|
||||
check(matches(withText(option2.text)))
|
||||
check(matches(WithTextColor(option2Color.text)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderStatusWithDefaultColor() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option1.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvStatusName)).apply {
|
||||
check(matches(WithTextColorRes(R.color.default_filter_tag_text_color)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderEmptyState() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Done",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Todo",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvEmptyMessage)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectSetObjectRelationValueFragment> {
|
||||
return launchFragmentInContainer<TestObjectSetObjectRelationValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,518 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
import com.anytypeio.anytype.utils.WithTextColor
|
||||
import com.anytypeio.anytype.utils.WithTextColorRes
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.hamcrest.core.IsNot.not
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class DisplayRelationTagValueTest {
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
private lateinit var addRelationOption: AddDataViewRelationOption
|
||||
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
|
||||
private lateinit var addTagToDataViewRecord: AddTagToDataViewRecord
|
||||
private lateinit var updateDataViewRecord: UpdateDataViewRecord
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
private lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
addRelationOption = AddDataViewRelationOption(repo)
|
||||
addTagToDataViewRecord = AddTagToDataViewRecord(repo)
|
||||
removeTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo)
|
||||
updateDataViewRecord = UpdateDataViewRecord(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestObjectSetObjectRelationValueFragment.testVmFactory = ObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session),
|
||||
details = object: ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
},
|
||||
types = object: ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
},
|
||||
removeTagFromRecord = removeTagFromDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewRecord = updateDataViewRecord
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayEditButtonAndPlusButton() {
|
||||
// SETUP
|
||||
|
||||
val relation = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relation,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
format = Relation.Format.TAG,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relation,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Checking that the buttons are invisible
|
||||
|
||||
onView(withId(R.id.btnEditOrDone)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
onView(withId(R.id.btnAddValue)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetRelationName() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Tag"
|
||||
|
||||
val relation = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relation,
|
||||
isMulti = true,
|
||||
name = name,
|
||||
format = Relation.Format.TAG,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relation,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
// Checking that the name is set
|
||||
|
||||
onView(withId(R.id.tvTagOrStatusRelationHeader)).apply {
|
||||
check(matches(withText(name)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderTwoLastTagsFromDvWithFilterContainerInvisible() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1Color = ThemeColor.values().random()
|
||||
val option2Color = ThemeColor.values().random()
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = option1Color.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = option2Color.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id, option3.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(withId(R.id.filterInputContainer)).apply {
|
||||
check(matches(not(isDisplayed())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvTagName)).apply {
|
||||
check(matches(withText(option2.text)))
|
||||
check(matches(WithTextColor(option2Color.text)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.tvTagName)).apply {
|
||||
check(matches(withText(option3.text)))
|
||||
check(matches(WithTextColorRes(R.color.default_filter_tag_text_color)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderOnlyOneTagWithDefaultColor() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option1.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvTagName)).apply {
|
||||
check(matches(WithTextColorRes(R.color.default_filter_tag_text_color)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderEmptyState() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "TAG1",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "TAG 2",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "TAG 3",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to root,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.recycler)
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvEmptyMessage)).apply {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectSetObjectRelationValueFragment> {
|
||||
return launchFragmentInContainer<TestObjectSetObjectRelationValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verifyBlocking
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class EditRelationTagValueTest {
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
private lateinit var addRelationOption: AddDataViewRelationOption
|
||||
private lateinit var removeTagFromDataViewRecord: RemoveTagFromDataViewRecord
|
||||
private lateinit var updateDataViewRecord: UpdateDataViewRecord
|
||||
private lateinit var addTagToDataViewRecord: AddTagToDataViewRecord
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
private lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
private val ctx = MockDataFactory.randomUuid()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
addRelationOption = AddDataViewRelationOption(repo)
|
||||
addTagToDataViewRecord = AddTagToDataViewRecord(repo)
|
||||
removeTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo)
|
||||
updateDataViewRecord = UpdateDataViewRecord(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestObjectSetObjectRelationValueFragment.testVmFactory = ObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session),
|
||||
details = object : ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
},
|
||||
types = object : ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
},
|
||||
removeTagFromRecord = removeTagFromDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewRecord = updateDataViewRecord
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderTwoTagsInReadThenInEditMode() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1Color = ThemeColor.values().random()
|
||||
val option2Color = ThemeColor.values().random()
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = option1Color.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = option2Color.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id, option3.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
val editOrDoneBtn = R.id.btnEditOrDone.matchView()
|
||||
|
||||
editOrDoneBtn.checkHasText(R.string.edit)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvTagName).checkHasText(option2.text)
|
||||
onItemView(0, R.id.tvTagName).checkHasTextColor(option2Color.text)
|
||||
onItemView(0, R.id.btnRemoveTag).checkIsNotDisplayed()
|
||||
onItemView(0, R.id.btnDragAndDropTag).checkIsNotDisplayed()
|
||||
onItemView(1, R.id.tvTagName).checkHasText(option3.text)
|
||||
onItemView(1, R.id.btnRemoveTag).checkIsNotDisplayed()
|
||||
onItemView(1, R.id.btnDragAndDropTag).checkIsNotDisplayed()
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
|
||||
editOrDoneBtn.performClick()
|
||||
|
||||
editOrDoneBtn.checkHasText(R.string.done)
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvTagName).checkHasText(option2.text)
|
||||
onItemView(0, R.id.tvTagName).checkHasTextColor(option2Color.text)
|
||||
onItemView(0, R.id.btnRemoveTag).checkIsDisplayed()
|
||||
onItemView(0, R.id.btnDragAndDropTag).checkIsDisplayed()
|
||||
onItemView(1, R.id.tvTagName).checkHasText(option3.text)
|
||||
onItemView(1, R.id.btnRemoveTag).checkIsDisplayed()
|
||||
onItemView(1, R.id.btnDragAndDropTag).checkIsDisplayed()
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRequestRemovingLastTagWhenRemoveButtonPressed() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val option1Color = ThemeColor.values().random()
|
||||
val option2Color = ThemeColor.values().random()
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = option1Color.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = option2Color.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = ""
|
||||
)
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id, option3.id)
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(
|
||||
Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = "Roles",
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationValueFragment.CTX_KEY to ctx,
|
||||
ObjectRelationValueFragment.DATAVIEW_KEY to dv.id,
|
||||
ObjectRelationValueFragment.VIEWER_KEY to viewer.id,
|
||||
ObjectRelationValueFragment.RELATION_KEY to relationKey,
|
||||
ObjectRelationValueFragment.TARGET_KEY to target
|
||||
)
|
||||
)
|
||||
|
||||
R.id.btnEditOrDone.performClick()
|
||||
|
||||
val rvMatcher = R.id.recycler.rVMatcher()
|
||||
|
||||
rvMatcher.onItemView(1, R.id.btnRemoveTag).performClick()
|
||||
|
||||
verifyBlocking(repo, times(1)) {
|
||||
updateDataViewRecord(
|
||||
context = ctx,
|
||||
target = dv.id,
|
||||
record = target,
|
||||
values = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to listOf(option2.id)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectSetObjectRelationValueFragment> {
|
||||
return launchFragmentInContainer<TestObjectSetObjectRelationValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,590 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.core_utils.ext.timeInSecondsFormat
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectRelationDateValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.TIME_FORMAT_DEFAULT
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationDateValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.*
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectRelationDateValueTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
val root = MockDataFactory.randomUuid()
|
||||
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val session = ObjectSetSession()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
TestObjectRelationDateValueFragment.testVmFactory =
|
||||
ObjectRelationDateValueViewModel.Factory(
|
||||
relations = DataViewObjectRelationProvider(state),
|
||||
values = DataViewObjectValueProvider(state, session)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetNullDateValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val valueDate: Long? = null
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetTodayDateValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val valueDate: Long = System.currentTimeMillis() / 1000
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(isDisplayed()))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetTomorrowDateValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val calendar = Calendar.getInstance().apply { add(Calendar.DATE, 1) }
|
||||
val valueDate: Long = calendar.timeInMillis / 1000
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetYesterdayDateValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val calendar = Calendar.getInstance().apply { add(Calendar.DATE, -1) }
|
||||
val valueDate: Long = calendar.timeInMillis / 1000
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetExactDayDateValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val calendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, 45) }
|
||||
val valueDate: Long = calendar.timeInMillis / 1000
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
val exactDateFormat = valueDate.timeInSecondsFormat(TIME_FORMAT_DEFAULT)
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText(exactDateFormat)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetExactDayDateValueAndThenUpdateWithDatePicker() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val calendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, 45) }
|
||||
val valueDate: Long = calendar.timeInMillis / 1000
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val fragment = launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
val exactDateFormat = valueDate.timeInSecondsFormat(TIME_FORMAT_DEFAULT)
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText(exactDateFormat)))
|
||||
|
||||
val dateUpdate = Calendar.getInstance().apply { add(Calendar.DATE, 17) }
|
||||
val valueUpdate: Long = dateUpdate.timeInMillis / 1000
|
||||
fragment.onFragment {
|
||||
it.onPickDate(valueUpdate)
|
||||
}
|
||||
|
||||
val updatedDateFormat = valueUpdate.timeInSecondsFormat(TIME_FORMAT_DEFAULT)
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText(updatedDateFormat)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSetExactDayDateValueAndThenUpdateToTodayTomorrowAndYesterday() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationText = "Birth date"
|
||||
val calendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, 45) }
|
||||
val valueDate: Long = calendar.timeInMillis / 1000
|
||||
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
name = relationText,
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relation.key to valueDate
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val fragment = launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationDateValueFragment.CONTEXT_ID to root,
|
||||
ObjectRelationDateValueFragment.RELATION_ID to relation.key,
|
||||
ObjectRelationDateValueFragment.OBJECT_ID to target,
|
||||
ObjectRelationDateValueFragment.FLOW_KEY to ObjectRelationDateValueFragment.FLOW_DATAVIEW
|
||||
)
|
||||
)
|
||||
|
||||
val exactDateFormat = valueDate.timeInSecondsFormat(TIME_FORMAT_DEFAULT)
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText(exactDateFormat)))
|
||||
|
||||
fragment.onFragment { it.vm.onTodayClicked() }
|
||||
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
|
||||
fragment.onFragment { it.vm.onTomorrowClicked() }
|
||||
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
|
||||
fragment.onFragment { it.vm.onYesterdayClicked() }
|
||||
|
||||
onView(withId(R.id.ivTomorrowCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivTodayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.ivYesterdayCheck)).check(matches((isDisplayed())))
|
||||
onView(withId(R.id.ivExactDayCheck)).check(matches(not(isDisplayed())))
|
||||
onView(withId(R.id.tvDate)).check(matches(withText("")))
|
||||
}
|
||||
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectRelationDateValueFragment> {
|
||||
return launchFragmentInContainer<TestObjectRelationDateValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,631 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.core_utils.ext.toTimeSeconds
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.ObjectRelationList
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.page.Editor
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationListViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.sets.MONTH_DAY_AND_YEAR
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectRelationListTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
@Mock
|
||||
lateinit var detailModificationManager: DetailModificationManager
|
||||
|
||||
private lateinit var objectRelationList: ObjectRelationList
|
||||
private lateinit var updateDetail: UpdateDetail
|
||||
|
||||
private val ctx = MockDataFactory.randomUuid()
|
||||
private val storage = Editor.Storage()
|
||||
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
objectRelationList = ObjectRelationList(repo)
|
||||
updateDetail = UpdateDetail(repo)
|
||||
TestObjectRelationListFragment.testVmFactory = ObjectRelationListViewModelFactory(
|
||||
stores = storage,
|
||||
urlBuilder = urlBuilder,
|
||||
objectRelationList = objectRelationList,
|
||||
dispatcher = dispatcher,
|
||||
detailModificationManager = detailModificationManager,
|
||||
updateDetail = updateDetail
|
||||
)
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun shouldThrowAnExceptionIfArgsNotProvided() {
|
||||
launchFragment(bundleOf())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayOneRelationWithoutValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Description"
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(
|
||||
listOf(relation)
|
||||
)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasText("")
|
||||
checkIsRecyclerSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayOnlyFirstRelationBecauseSecondIsHidden() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name1 = "Description"
|
||||
val name2 = "Identifier"
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
isHidden = true,
|
||||
name = name1
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name2
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(
|
||||
listOf(relation1, relation2)
|
||||
)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name2)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasText("")
|
||||
checkIsRecyclerSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayTwoRelationsWithoutValue() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name1 = "Description"
|
||||
val name2 = "Comment"
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name1
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name2
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(
|
||||
listOf(relation1, relation2)
|
||||
)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name1)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasText("")
|
||||
onItemView(1, R.id.tvRelationTitle).checkHasText(name2)
|
||||
onItemView(1, R.id.tvRelationValue).checkHasText("")
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayTwoRelationsWithValues() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name1 = "Description"
|
||||
val name2 = "Comment"
|
||||
val value1 = "A mountain is an elevated portion of the Earth's crust, generally with steep sides that show significant exposed bedrock."
|
||||
val value2 = "We've never seen that mountain before."
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name1
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.LONG_TEXT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name2
|
||||
)
|
||||
|
||||
val relations = listOf(relation1, relation2)
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
relation1.key to value1,
|
||||
relation2.key to value2,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(relations)
|
||||
storage.details.update(details)
|
||||
}
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name1)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasText(value1)
|
||||
onItemView(1, R.id.tvRelationTitle).checkHasText(name2)
|
||||
onItemView(1, R.id.tvRelationValue).checkHasText(value2)
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayTwoObjectRelationsWithNameAndAvatarInitials() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name1 = "Assignee"
|
||||
val target1: Id = MockDataFactory.randomUuid()
|
||||
val username1 = "Konstantin"
|
||||
|
||||
val name2 = "Created by"
|
||||
val target2: Id = MockDataFactory.randomUuid()
|
||||
val username2 = "Roman"
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name1
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name2
|
||||
)
|
||||
|
||||
val relations = listOf(relation1, relation2)
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
relation1.key to target1,
|
||||
relation2.key to target2,
|
||||
)
|
||||
),
|
||||
target1 to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to username1
|
||||
)
|
||||
),
|
||||
target2 to Block.Fields(
|
||||
mapOf(
|
||||
Block.Fields.NAME_KEY to username2
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(relations)
|
||||
storage.details.update(details)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name1)
|
||||
onItemView(0, R.id.obj0).check(matches(hasDescendant(withText(username1))))
|
||||
onItemView(1, R.id.tvRelationTitle).checkHasText(name2)
|
||||
onItemView(1, R.id.obj0).check(matches(hasDescendant(withText(username2))))
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayTwoDateRelations() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val format = SimpleDateFormat(MONTH_DAY_AND_YEAR, Locale.US)
|
||||
|
||||
val name1 = "Date of birth"
|
||||
val date1 = System.currentTimeMillis()
|
||||
val date1Screen = format.format(Date(date1))
|
||||
|
||||
val name2 = "Last modified at"
|
||||
val date2 = System.currentTimeMillis()
|
||||
val date2Screen = format.format(Date(date2))
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name1,
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.DATE,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name2
|
||||
)
|
||||
|
||||
val relations = listOf(relation1, relation2)
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
relation1.key to date1.toTimeSeconds(),
|
||||
relation2.key to date2.toTimeSeconds(),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(relations)
|
||||
storage.details.update(details)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name1)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasText(date1Screen)
|
||||
onItemView(1, R.id.tvRelationTitle).checkHasText(name2)
|
||||
onItemView(1, R.id.tvRelationValue).checkHasText(date2Screen)
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayTwoStatusRelations() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val color1 = ThemeColor.RED
|
||||
val color2 = ThemeColor.TEAL
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = color1.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Done",
|
||||
color = color2.title
|
||||
)
|
||||
|
||||
val name1 = "Status 1"
|
||||
val name2 = "Status 2"
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.STATUS,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name1,
|
||||
selections = listOf(option1)
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.STATUS,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name2,
|
||||
selections = listOf(option2)
|
||||
)
|
||||
|
||||
val relations = listOf(relation1, relation2)
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
relation1.key to option1.id,
|
||||
relation2.key to option2.id,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(relations)
|
||||
storage.details.update(details)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name1)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasText(option1.text)
|
||||
onItemView(0, R.id.tvRelationValue).checkHasTextColor(color1.text)
|
||||
onItemView(1, R.id.tvRelationTitle).checkHasText(name2)
|
||||
onItemView(1, R.id.tvRelationValue).checkHasText(option2.text)
|
||||
onItemView(1, R.id.tvRelationValue).checkHasTextColor(color2.text)
|
||||
checkIsRecyclerSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayFourTagRelations() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val color1 = ThemeColor.RED
|
||||
val color2 = ThemeColor.TEAL
|
||||
val color3 = ThemeColor.ICE
|
||||
val color4 = ThemeColor.PURPLE
|
||||
|
||||
val name = "Role"
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Essayist",
|
||||
color = color1.title
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Journalist",
|
||||
color = color2.title
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Politik",
|
||||
color = color3.title
|
||||
)
|
||||
|
||||
val option4 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Critic",
|
||||
color = color4.title
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.TAG,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name,
|
||||
selections = listOf(option1, option2, option3, option4)
|
||||
)
|
||||
|
||||
val relations = listOf(relation)
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
relation.key to listOf(option1.id, option2.id, option3.id, option4.id)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(relations)
|
||||
storage.details.update(details)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name)
|
||||
onItemView(0, R.id.tag0).check(matches((withText(option1.text))))
|
||||
onItemView(0, R.id.tag1).check(matches((withText(option2.text))))
|
||||
onItemView(0, R.id.tag2).check(matches((withText(option3.text))))
|
||||
onItemView(0, R.id.tag3).check(matches((withText(option4.text))))
|
||||
checkIsRecyclerSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayTwoFileRelations() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Attachement"
|
||||
|
||||
val relation = Relation(
|
||||
key = MockDataFactory.randomUuid(),
|
||||
format = Relation.Format.FILE,
|
||||
source = Relation.Source.values().random(),
|
||||
name = name,
|
||||
selections = emptyList()
|
||||
)
|
||||
|
||||
val relations = listOf(relation)
|
||||
|
||||
val file1 = MockDataFactory.randomUuid()
|
||||
val file2 = MockDataFactory.randomUuid()
|
||||
|
||||
val details = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
relation.key to listOf(file1, file2)
|
||||
)
|
||||
),
|
||||
file1 to Block.Fields(
|
||||
mapOf(
|
||||
"name" to "Document",
|
||||
"ext" to "pdf",
|
||||
"mime" to "application/pdf"
|
||||
)
|
||||
),
|
||||
file2 to Block.Fields(
|
||||
mapOf(
|
||||
"name" to "Image",
|
||||
"ext" to "jpg",
|
||||
"mime" to "image/jpeg"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
runBlocking {
|
||||
storage.relations.update(relations)
|
||||
storage.details.update(details)
|
||||
}
|
||||
|
||||
launchFragment(bundleOf(
|
||||
ObjectRelationListFragment.ARG_CTX to ctx,
|
||||
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST
|
||||
))
|
||||
|
||||
// TESTING
|
||||
|
||||
with(R.id.recycler.rVMatcher()) {
|
||||
onItemView(0, R.id.tvRelationTitle).checkHasText(name)
|
||||
onItemView(0, R.id.file0).check(matches(hasDescendant(withText("Document"))))
|
||||
onItemView(0, R.id.file1).check(matches(hasDescendant(withText("Image"))))
|
||||
checkIsRecyclerSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestObjectRelationListFragment> {
|
||||
return launchFragmentInContainer<TestObjectRelationListFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import com.anytypeio.anytype.presentation.relations.AddObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.ui.relations.AddObjectSetObjectRelationValueFragment
|
||||
|
||||
class TestAddObjectSetObjectRelationValueFragment : AddObjectSetObjectRelationValueFragment() {
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
override fun proceedWithExiting() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: AddObjectSetObjectRelationValueViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectRelationDateValueViewModel
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationDateValueFragment
|
||||
|
||||
class TestObjectRelationDateValueFragment: ObjectRelationDateValueFragment() {
|
||||
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: ObjectRelationDateValueViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationListViewModelFactory
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
|
||||
|
||||
class TestObjectRelationListFragment : ObjectRelationListFragment() {
|
||||
override fun injectDependencies() {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: ObjectRelationListViewModelFactory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectRelationTextValueViewModel
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationTextValueFragment
|
||||
|
||||
class TestObjectRelationTextValueFragment : ObjectRelationTextValueFragment() {
|
||||
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: ObjectRelationTextValueViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.anytypeio.anytype.features.relations
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectSetObjectRelationValueFragment
|
||||
|
||||
class TestObjectSetObjectRelationValueFragment : ObjectSetObjectRelationValueFragment() {
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: ObjectSetObjectRelationValueViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import com.anytypeio.anytype.utils.checkHasText
|
||||
import com.anytypeio.anytype.utils.checkIsRecyclerSize
|
||||
import com.anytypeio.anytype.utils.onItemView
|
||||
import com.anytypeio.anytype.utils.rVMatcher
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectSetGridColumnRenderingTest : TestObjectSetSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
override val title: Block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "Data View UI Testing",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderAllColumnHeaderNamesBasedOnViewerRelations() {
|
||||
|
||||
val type = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
emoji = MockDataFactory.randomString(),
|
||||
layout = ObjectType.Layout.PAGE,
|
||||
relations = emptyList(),
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Description",
|
||||
format = Relation.Format.SHORT_TEXT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Year",
|
||||
format = Relation.Format.NUMBER,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation3 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Phone",
|
||||
format = Relation.Format.PHONE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation4 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Website",
|
||||
format = Relation.Format.URL,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation5 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Email",
|
||||
format = Relation.Format.EMAIL,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = "Default Grid View",
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
DVViewerRelation(
|
||||
key = relation1.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation2.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation3.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation4.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation5.key,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation1, relation2, relation3, relation4, relation5),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSetWithRecord(
|
||||
set = set,
|
||||
relations = listOf(relation1, relation2, relation3, relation4, relation5),
|
||||
details = defaultDetails,
|
||||
viewer = viewer.id,
|
||||
dataview = dataview.id,
|
||||
records = emptyList(),
|
||||
total = 1,
|
||||
objectTypes = listOf(type)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
with(R.id.rvHeader.rVMatcher()) {
|
||||
// There should be 5 column headers + 1 plus button
|
||||
checkIsRecyclerSize(6)
|
||||
onItemView(0, R.id.cellText).checkHasText(relation1.name)
|
||||
onItemView(1, R.id.cellText).checkHasText(relation2.name)
|
||||
onItemView(2, R.id.cellText).checkHasText(relation3.name)
|
||||
onItemView(3, R.id.cellText).checkHasText(relation4.name)
|
||||
onItemView(4, R.id.cellText).checkHasText(relation5.name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.test.espresso.assertion.ViewAssertions
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.emojifier.data.DefaultDocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import com.anytypeio.anytype.utils.checkHasText
|
||||
import com.anytypeio.anytype.utils.checkIsRecyclerSize
|
||||
import com.anytypeio.anytype.utils.onItemView
|
||||
import com.anytypeio.anytype.utils.rVMatcher
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectSetGridFileCellRenderingTest : TestObjectSetSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
override val title: Block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "Data View UI Testing",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderTwoFilesInTwoRecords() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "Files"
|
||||
val file1Name = "CharlieChaplin"
|
||||
val file1Id = MockDataFactory.randomUuid()
|
||||
val file1Ext = "txt"
|
||||
val file2Name = "Jean-PierreLéaud"
|
||||
val file2Id = MockDataFactory.randomUuid()
|
||||
val file2Ext = "jpeg"
|
||||
|
||||
val objectType = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Movie",
|
||||
relations = emptyList(),
|
||||
emoji = MockDataFactory.randomString(),
|
||||
layout = ObjectType.Layout.PROFILE,
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val record1Id = MockDataFactory.randomUuid()
|
||||
val record2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val record1: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to record1Id,
|
||||
ObjectSetConfig.NAME_KEY to "The Great Dictator",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to file1Id
|
||||
)
|
||||
|
||||
val record2: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to record2Id,
|
||||
ObjectSetConfig.NAME_KEY to "Les Quatre Cents Coups",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to file2Id
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.FILE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
DVViewerRelation(
|
||||
key = relation.key,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val details = Block.Details(
|
||||
details = defaultDetails.details + mapOf(
|
||||
file1Id to Block.Fields(
|
||||
mapOf(
|
||||
ObjectSetConfig.NAME_KEY to file1Name,
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
"fileExt" to file1Ext
|
||||
)
|
||||
),
|
||||
file2Id to Block.Fields(
|
||||
mapOf(
|
||||
ObjectSetConfig.NAME_KEY to file2Name,
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
"fileExt" to file2Ext
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSetWithRecord(
|
||||
set = set,
|
||||
relations = listOf(relation),
|
||||
details = details,
|
||||
viewer = viewer.id,
|
||||
dataview = dataview.id,
|
||||
records = listOf(record1, record2),
|
||||
total = 1,
|
||||
objectTypes = listOf(objectType)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
with(R.id.rvRows.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.tvTitle).checkHasText("The Great Dictator")
|
||||
onItemView(0, R.id.file0).check(
|
||||
ViewAssertions.matches(
|
||||
ViewMatchers.hasDescendant(
|
||||
ViewMatchers.withText(file1Name)
|
||||
)
|
||||
)
|
||||
)
|
||||
onItemView(1, R.id.tvTitle).checkHasText("Les Quatre Cents Coups")
|
||||
onItemView(1, R.id.file0).check(
|
||||
ViewAssertions.matches(
|
||||
ViewMatchers.hasDescendant(
|
||||
ViewMatchers.withText(file2Name)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.emojifier.data.DefaultDocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import com.anytypeio.anytype.utils.checkHasText
|
||||
import com.anytypeio.anytype.utils.checkIsRecyclerSize
|
||||
import com.anytypeio.anytype.utils.onItemView
|
||||
import com.anytypeio.anytype.utils.rVMatcher
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectSetGridObjectCellRenderingTest : TestObjectSetSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
override val title: Block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "Data View UI Testing",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderOneHumanObjectFromEachOfTwoRecords() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "Starring"
|
||||
val object1Name = "Charlie Chaplin"
|
||||
val object1Id = MockDataFactory.randomUuid()
|
||||
val object2Name = "Jean-Pierre Léaud"
|
||||
val object2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val objectType = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Movie",
|
||||
relations = emptyList(),
|
||||
emoji = MockDataFactory.randomString(),
|
||||
layout = ObjectType.Layout.PROFILE,
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val record1Id = MockDataFactory.randomUuid()
|
||||
val record2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val record1: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to record1Id,
|
||||
ObjectSetConfig.NAME_KEY to "The Great Dictator",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to object1Id
|
||||
)
|
||||
|
||||
val record2: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to record2Id,
|
||||
ObjectSetConfig.NAME_KEY to "Les Quatre Cents Coups",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to object2Id
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
DVViewerRelation(
|
||||
key = relation.key,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val details = Block.Details(
|
||||
details = defaultDetails.details + mapOf(
|
||||
object1Id to Block.Fields(
|
||||
mapOf(
|
||||
ObjectSetConfig.NAME_KEY to object1Name,
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
),
|
||||
object2Id to Block.Fields(
|
||||
mapOf(
|
||||
ObjectSetConfig.NAME_KEY to object2Name,
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSetWithRecord(
|
||||
set = set,
|
||||
relations = listOf(relation),
|
||||
details = details,
|
||||
viewer = viewer.id,
|
||||
dataview = dataview.id,
|
||||
records = listOf(record1, record2),
|
||||
total = 1,
|
||||
objectTypes = listOf(objectType)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
with(R.id.rvRows.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.tvTitle).checkHasText("The Great Dictator")
|
||||
onItemView(0, R.id.object0).check(matches(hasDescendant(withText(object1Name))))
|
||||
onItemView(1, R.id.tvTitle).checkHasText("Les Quatre Cents Coups")
|
||||
onItemView(1, R.id.object0).check(matches(hasDescendant(withText(object2Name))))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderTwoHumanObjectsFromOneRecord() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "Starring"
|
||||
val object1Name = "Maurice Ronet"
|
||||
val object1Id = MockDataFactory.randomUuid()
|
||||
val object2Name = "Jeanne Moreau"
|
||||
val object2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val objectType = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Movie",
|
||||
relations = emptyList(),
|
||||
emoji = MockDataFactory.randomString(),
|
||||
layout = ObjectType.Layout.PROFILE,
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val recordId = MockDataFactory.randomUuid()
|
||||
|
||||
val record1: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to recordId,
|
||||
ObjectSetConfig.NAME_KEY to "Le Feu Follet",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to listOf(object1Id, object2Id)
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.OBJECT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
DVViewerRelation(
|
||||
key = relation.key,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val details = Block.Details(
|
||||
details = defaultDetails.details + mapOf(
|
||||
object1Id to Block.Fields(
|
||||
mapOf(
|
||||
ObjectSetConfig.NAME_KEY to object1Name,
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
),
|
||||
object2Id to Block.Fields(
|
||||
mapOf(
|
||||
ObjectSetConfig.NAME_KEY to object2Name,
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
"iconEmoji" to "👤"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSetWithRecord(
|
||||
set = set,
|
||||
relations = listOf(relation),
|
||||
details = details,
|
||||
viewer = viewer.id,
|
||||
dataview = dataview.id,
|
||||
records = listOf(record1),
|
||||
total = 1,
|
||||
objectTypes = listOf(objectType)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
with(R.id.rvRows.rVMatcher()) {
|
||||
checkIsRecyclerSize(1)
|
||||
onItemView(0, R.id.tvTitle).checkHasText("Le Feu Follet")
|
||||
onItemView(0, R.id.object0).check(matches(hasDescendant(withText(object1Name))))
|
||||
onItemView(0, R.id.object1).check(matches(hasDescendant(withText(object2Name))))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.emojifier.data.DefaultDocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import com.anytypeio.anytype.utils.*
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectSetGridPrimitiveRelationTest : TestObjectSetSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
override val title: Block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "Data View UI Testing",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderAllObjectPrimitiveRelationsValuesFromTwoRecords() {
|
||||
|
||||
val type = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
emoji = MockDataFactory.randomString(),
|
||||
layout = ObjectType.Layout.PAGE,
|
||||
relations = emptyList(),
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relation1 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Description",
|
||||
format = Relation.Format.SHORT_TEXT,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation2 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Year",
|
||||
format = Relation.Format.NUMBER,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation3 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Phone",
|
||||
format = Relation.Format.PHONE,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation4 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Website",
|
||||
format = Relation.Format.URL,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val relation5 = Relation(
|
||||
key = MockDataFactory.randomString(),
|
||||
name = "Email",
|
||||
format = Relation.Format.EMAIL,
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val object1value1 = "Operating environment for the new Internet"
|
||||
val object1value2 = "2021"
|
||||
val object1value3 = "+00000000000"
|
||||
val object1value4 = "https://anytype.io/"
|
||||
val object1value5 = "team@anytype.io"
|
||||
|
||||
val object2value1 = "A peer-to-peer hypermedia protocol designed to make the web faster, safer, and more open."
|
||||
val object2value2 = "2021"
|
||||
val object2value3 = "+00000000000"
|
||||
val object2value4 = "https://ipfs.io/"
|
||||
val object2value5 = "team@ipfs.io"
|
||||
|
||||
val record1 = mapOf(
|
||||
ObjectSetConfig.ID_KEY to MockDataFactory.randomUuid(),
|
||||
ObjectSetConfig.TYPE_KEY to type.url,
|
||||
ObjectSetConfig.NAME_KEY to "Anytype",
|
||||
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
relation1.key to object1value1,
|
||||
relation2.key to object1value2,
|
||||
relation3.key to object1value3,
|
||||
relation4.key to object1value4,
|
||||
relation5.key to object1value5,
|
||||
)
|
||||
|
||||
val record2 = mapOf(
|
||||
ObjectSetConfig.ID_KEY to MockDataFactory.randomUuid(),
|
||||
ObjectSetConfig.TYPE_KEY to type.url,
|
||||
ObjectSetConfig.NAME_KEY to "IPFS",
|
||||
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
relation1.key to object2value1,
|
||||
relation2.key to object2value2,
|
||||
relation3.key to object2value3,
|
||||
relation4.key to object2value4,
|
||||
relation5.key to object2value5,
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = "Default Grid View",
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
DVViewerRelation(
|
||||
key = relation1.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation2.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation3.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation4.key,
|
||||
isVisible = true
|
||||
),
|
||||
DVViewerRelation(
|
||||
key = relation5.key,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation1, relation2, relation3, relation4, relation5),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSetWithRecord(
|
||||
set = set,
|
||||
relations = listOf(relation1, relation2, relation3, relation4, relation5),
|
||||
details = defaultDetails,
|
||||
viewer = viewer.id,
|
||||
dataview = dataview.id,
|
||||
records = listOf(record1, record2),
|
||||
total = 1,
|
||||
objectTypes = listOf(type)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
with(R.id.rvRows.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
|
||||
onItemView(0, R.id.rowCellRecycler)
|
||||
.checkHasChildViewCount(5)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 0,
|
||||
text = object1value1,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 1,
|
||||
text = object1value2,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 2,
|
||||
text = object1value3,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 3,
|
||||
text = object1value4,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 4,
|
||||
text = object1value5,
|
||||
target = R.id.tvText
|
||||
)
|
||||
|
||||
onItemView(0, R.id.tvTitle).checkHasText("Anytype")
|
||||
|
||||
onItemView(1, R.id.rowCellRecycler)
|
||||
.checkHasChildViewCount(5)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 0,
|
||||
text = object2value1,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 1,
|
||||
text = object2value2,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 2,
|
||||
text = object2value3,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 3,
|
||||
text = object2value4,
|
||||
target = R.id.tvText
|
||||
)
|
||||
.checkHasChildViewWithText(
|
||||
pos = 4,
|
||||
text = object2value5,
|
||||
target = R.id.tvText
|
||||
)
|
||||
|
||||
onItemView(1, R.id.tvTitle).checkHasText("IPFS")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.test.espresso.assertion.ViewAssertions
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.emojifier.data.DefaultDocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import com.anytypeio.anytype.utils.checkHasText
|
||||
import com.anytypeio.anytype.utils.checkIsRecyclerSize
|
||||
import com.anytypeio.anytype.utils.onItemView
|
||||
import com.anytypeio.anytype.utils.rVMatcher
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectSetGridTagCellRenderingTest : TestObjectSetSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
override val title: Block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "Data View UI Testing",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderOneSameTagAndTwoDifferentTagsOfTwoRecords() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val relationName = "FilmTags"
|
||||
val tag1Name = "Silent film"
|
||||
val tag1Id = MockDataFactory.randomUuid()
|
||||
val tag2Name = "Sound film"
|
||||
val tag2Id = MockDataFactory.randomUuid()
|
||||
val tag3Name = "Director"
|
||||
val tag3Id = MockDataFactory.randomUuid()
|
||||
|
||||
val objectType = ObjectType(
|
||||
url = MockDataFactory.randomUuid(),
|
||||
name = "Film",
|
||||
relations = emptyList(),
|
||||
emoji = MockDataFactory.randomString(),
|
||||
layout = ObjectType.Layout.PAGE,
|
||||
description = "",
|
||||
isHidden = false
|
||||
)
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val record1Id = MockDataFactory.randomUuid()
|
||||
val record2Id = MockDataFactory.randomUuid()
|
||||
|
||||
val record1: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to record1Id,
|
||||
ObjectSetConfig.NAME_KEY to "The Face on the Bar Room Floor",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to listOf(tag1Id, tag3Id)
|
||||
)
|
||||
|
||||
val record2: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to record2Id,
|
||||
ObjectSetConfig.NAME_KEY to "The Great Dictator",
|
||||
ObjectSetConfig.EMOJI_KEY to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
|
||||
ObjectSetConfig.TYPE_KEY to objectType.url,
|
||||
relationId to listOf(tag2Id, tag3Id)
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationId,
|
||||
name = relationName,
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(
|
||||
Relation.Option(id = tag1Id, text = tag1Name, color = "blue"),
|
||||
Relation.Option(id = tag2Id, text = tag2Name, color = "red"),
|
||||
Relation.Option(id = tag3Id, text = tag3Name, color = "black"),
|
||||
Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = MockDataFactory.randomString(),
|
||||
color = "black"
|
||||
)
|
||||
),
|
||||
source = Relation.Source.values().random()
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
DVViewerRelation(
|
||||
key = relation.key,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val details = Block.Details()
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSetWithRecord(
|
||||
set = set,
|
||||
relations = listOf(relation),
|
||||
details = details,
|
||||
viewer = viewer.id,
|
||||
dataview = dataview.id,
|
||||
records = listOf(record1, record2),
|
||||
total = 1,
|
||||
objectTypes = listOf(objectType)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
with(R.id.rvRows.rVMatcher()) {
|
||||
checkIsRecyclerSize(2)
|
||||
onItemView(0, R.id.tvTitle).checkHasText("The Face on the Bar Room Floor")
|
||||
onItemView(0, R.id.tag0).check(
|
||||
ViewAssertions.matches(
|
||||
ViewMatchers.withText("Silent film")
|
||||
)
|
||||
)
|
||||
onItemView(0, R.id.tag1).check(
|
||||
ViewAssertions.matches(
|
||||
ViewMatchers.withText("Director")
|
||||
)
|
||||
)
|
||||
onItemView(0, R.id.tag2).check(
|
||||
ViewAssertions.matches(
|
||||
not(ViewMatchers.isDisplayed())
|
||||
)
|
||||
)
|
||||
onItemView(1, R.id.tvTitle).checkHasText("The Great Dictator")
|
||||
onItemView(1, R.id.tag0).check(
|
||||
ViewAssertions.matches(
|
||||
ViewMatchers.withText("Sound film")
|
||||
)
|
||||
)
|
||||
onItemView(1, R.id.tag1).check(
|
||||
ViewAssertions.matches(
|
||||
ViewMatchers.withText("Director")
|
||||
)
|
||||
)
|
||||
onItemView(1, R.id.tag2).check(
|
||||
ViewAssertions.matches(
|
||||
not(ViewMatchers.isDisplayed())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.ext.content
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import com.anytypeio.anytype.utils.checkHasText
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ObjectSetHeaderTest : TestObjectSetSetup() {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
override val title: Block = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = "Data View UI Testing",
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldRenderObjectSetTitleWithViewerTitle() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = "Default Grid View",
|
||||
filters = emptyList(),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = emptyList(),
|
||||
type = Block.Content.DataView.Viewer.Type.GRID
|
||||
)
|
||||
|
||||
val dataview = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = emptyList(),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
val root = Block(
|
||||
id = ctx,
|
||||
fields = Block.Fields(emptyMap()),
|
||||
content = Block.Content.Smart(
|
||||
type = Block.Content.Smart.Type.SET
|
||||
),
|
||||
children = listOf(header.id, dataview.id)
|
||||
)
|
||||
|
||||
val set = listOf(root, header, title, dataview)
|
||||
|
||||
stubInterceptEvents()
|
||||
stubOpenObjectSet(
|
||||
set = set,
|
||||
relations = emptyList(),
|
||||
details = defaultDetails
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
launchFragment(bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to ctx))
|
||||
|
||||
onView(withId(R.id.title)).checkHasText(title.content<Block.Content.Text>().text)
|
||||
onView(withId(R.id.tvCurrentViewerName)).checkHasText(viewer.name)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetViewModelFactory
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
|
||||
class TestObjectSetFragment : ObjectSetFragment() {
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: ObjectSetViewModelFactory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package com.anytypeio.anytype.features.sets.dv
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateText
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.*
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.page.CloseBlock
|
||||
import com.anytypeio.anytype.domain.sets.OpenObjectSet
|
||||
import com.anytypeio.anytype.emojifier.data.DefaultDocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetRecordCache
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetReducer
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.stub
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
abstract class TestObjectSetSetup {
|
||||
|
||||
private lateinit var openObjectSet: OpenObjectSet
|
||||
private lateinit var addDataViewRelation: AddDataViewRelation
|
||||
private lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
private lateinit var updateDataViewRecord: UpdateDataViewRecord
|
||||
private lateinit var updateText: UpdateText
|
||||
private lateinit var createDataViewRecord: CreateDataViewRecord
|
||||
private lateinit var closeBlock: CloseBlock
|
||||
private lateinit var setActiveViewer: SetActiveViewer
|
||||
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
@Mock
|
||||
lateinit var interceptEvents: InterceptEvents
|
||||
|
||||
private val session = ObjectSetSession()
|
||||
private val reducer = ObjectSetReducer()
|
||||
private val dispatcher: Dispatcher<Payload> = Dispatcher.Default()
|
||||
private val objectSetRecordCache = ObjectSetRecordCache()
|
||||
|
||||
val ctx : Id = MockDataFactory.randomUuid()
|
||||
|
||||
abstract val title : Block
|
||||
|
||||
val header get() = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Layout(
|
||||
type = Block.Content.Layout.Type.HEADER
|
||||
),
|
||||
fields = Block.Fields.empty(),
|
||||
children = listOf(title.id)
|
||||
)
|
||||
|
||||
val defaultDetails = Block.Details(
|
||||
mapOf(
|
||||
ctx to Block.Fields(
|
||||
mapOf(
|
||||
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
open fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
addDataViewRelation = AddDataViewRelation(repo)
|
||||
updateText = UpdateText(repo)
|
||||
openObjectSet = OpenObjectSet(repo)
|
||||
createDataViewRecord = CreateDataViewRecord(repo)
|
||||
updateDataViewRecord = UpdateDataViewRecord(repo)
|
||||
updateDataViewViewer = UpdateDataViewViewer(repo)
|
||||
setActiveViewer = SetActiveViewer(repo)
|
||||
closeBlock = CloseBlock(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
|
||||
TestObjectSetFragment.testVmFactory = ObjectSetViewModelFactory(
|
||||
openObjectSet = openObjectSet,
|
||||
closeBlock = closeBlock,
|
||||
addDataViewRelation = addDataViewRelation,
|
||||
interceptEvents = interceptEvents,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
setActiveViewer = setActiveViewer,
|
||||
createDataViewRecord = createDataViewRecord,
|
||||
updateDataViewRecord = updateDataViewRecord,
|
||||
updateText = updateText,
|
||||
urlBuilder = urlBuilder,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
reducer = reducer,
|
||||
objectSetRecordCache = objectSetRecordCache
|
||||
)
|
||||
}
|
||||
|
||||
fun stubInterceptEvents() {
|
||||
interceptEvents.stub {
|
||||
onBlocking { build(any()) } doReturn emptyFlow()
|
||||
}
|
||||
}
|
||||
|
||||
fun stubOpenObjectSet(
|
||||
set: List<Block>,
|
||||
details: Block.Details = Block.Details(),
|
||||
relations: List<Relation> = emptyList()
|
||||
) {
|
||||
repo.stub {
|
||||
onBlocking { openObjectSet(ctx) } doReturn Payload(
|
||||
context = ctx,
|
||||
events = listOf(
|
||||
Event.Command.ShowBlock(
|
||||
context = ctx,
|
||||
root = ctx,
|
||||
details = details,
|
||||
blocks = set,
|
||||
relations = relations
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun stubOpenObjectSetWithRecord(
|
||||
set: List<Block>,
|
||||
details: Block.Details = Block.Details(),
|
||||
relations: List<Relation> = emptyList(),
|
||||
dataview: Id,
|
||||
viewer: Id,
|
||||
total: Int,
|
||||
records: List<DVRecord>,
|
||||
objectTypes: List<ObjectType>
|
||||
) {
|
||||
repo.stub {
|
||||
onBlocking { openObjectSet(ctx) } doReturn Payload(
|
||||
context = ctx,
|
||||
events = listOf(
|
||||
Event.Command.ShowBlock(
|
||||
context = ctx,
|
||||
root = ctx,
|
||||
details = details,
|
||||
blocks = set,
|
||||
relations = relations,
|
||||
objectTypes = objectTypes
|
||||
),
|
||||
Event.Command.DataView.SetRecords(
|
||||
context = ctx,
|
||||
id = dataview,
|
||||
view = viewer,
|
||||
total = total,
|
||||
records = records
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun launchFragment(args: Bundle): FragmentScenario<TestObjectSetFragment> {
|
||||
return launchFragmentInContainer<TestObjectSetFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
package com.anytypeio.anytype.features.sets.filter
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.typeText
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromInputFieldValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verifyBlocking
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class ModifyInputValueFilterTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
lateinit var searchObjects: SearchObjects
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val session = ObjectSetSession()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val dispatcher = Dispatcher.Default<Payload>()
|
||||
|
||||
// @Before
|
||||
// fun setup() {
|
||||
// MockitoAnnotations.initMocks(this)
|
||||
// updateDataViewViewer = UpdateDataViewViewer(repo)
|
||||
// searchObjects = SearchObjects(repo)
|
||||
// urlBuilder = UrlBuilder(gateway)
|
||||
// TestModifyFilterFromInputFieldValueFragment.testVmFactory = FilterViewModel.Factory(
|
||||
// objectSetState = state,
|
||||
// session = session,
|
||||
// updateDataViewViewer = updateDataViewViewer,
|
||||
// dispatcher = dispatcher,
|
||||
// searchObjects = searchObjects,
|
||||
// urlBuilder = urlBuilder
|
||||
// )
|
||||
// }
|
||||
|
||||
//todo Тесты выключены пока DataView in read mode only 15/03/21
|
||||
// @Test
|
||||
// fun shouldTypeTextThenClickActionButtonToApplyChanges() {
|
||||
//
|
||||
// val relationKey = MockDataFactory.randomUuid()
|
||||
//
|
||||
// val target = MockDataFactory.randomUuid()
|
||||
//
|
||||
// val record: Map<String, Any?> = mapOf(
|
||||
// ObjectSetConfig.ID_KEY to target,
|
||||
// relationKey to emptyList<String>()
|
||||
// )
|
||||
//
|
||||
// // Defining viewer containing one filter
|
||||
//
|
||||
// val initialFilterText = "Foo"
|
||||
// val textToType = "Bar"
|
||||
//
|
||||
// val filter = DVFilter(
|
||||
// relationKey = relationKey,
|
||||
// value = initialFilterText,
|
||||
// condition = DVFilterCondition.EQUAL
|
||||
// )
|
||||
//
|
||||
// val viewer = Block.Content.DataView.Viewer(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// name = MockDataFactory.randomString(),
|
||||
// filters = listOf(filter),
|
||||
// sorts = emptyList(),
|
||||
// viewerRelations = listOf(
|
||||
// Block.Content.DataView.Viewer.ViewerRelation(
|
||||
// key = relationKey,
|
||||
// isVisible = true
|
||||
// )
|
||||
// ),
|
||||
// type = Block.Content.DataView.Viewer.Type.values().random()
|
||||
// )
|
||||
//
|
||||
// val relation = Relation(
|
||||
// key = relationKey,
|
||||
// defaultValue = null,
|
||||
// isHidden = false,
|
||||
// isReadOnly = false,
|
||||
// isMulti = true,
|
||||
// name = MockDataFactory.randomString(),
|
||||
// source = Relation.Source.values().random(),
|
||||
// format = Relation.Format.LONG_TEXT,
|
||||
// selections = emptyList()
|
||||
// )
|
||||
//
|
||||
// val dv = Block(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// children = emptyList(),
|
||||
// fields = Block.Fields.empty(),
|
||||
// content = Block.Content.DataView(
|
||||
// relations = listOf(relation),
|
||||
// viewers = listOf(viewer),
|
||||
// source = MockDataFactory.randomUuid()
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// state.value = ObjectSet(
|
||||
// blocks = listOf(dv),
|
||||
// viewerDb = mapOf(
|
||||
// viewer.id to ObjectSet.ViewerData(
|
||||
// records = listOf(record),
|
||||
// total = 1
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// // Launching fragment
|
||||
//
|
||||
// launchFragment(
|
||||
// bundleOf(
|
||||
// ModifyFilterFromInputFieldValueFragment.CTX_KEY to root,
|
||||
// ModifyFilterFromInputFieldValueFragment.IDX_KEY to 0,
|
||||
// ModifyFilterFromInputFieldValueFragment.RELATION_KEY to relationKey,
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// // Veryfying that the initial filter text is visibile to our user
|
||||
//
|
||||
// val inputFieldInteraction = onView(withId(R.id.enterTextValueInputField))
|
||||
//
|
||||
// inputFieldInteraction.check(matches(withText(initialFilterText)))
|
||||
//
|
||||
// // Checking input type
|
||||
//
|
||||
// inputFieldInteraction.check(matches(withInputType(InputType.TYPE_CLASS_TEXT)))
|
||||
//
|
||||
// // Typing additional text before pressing action button
|
||||
//
|
||||
// inputFieldInteraction.perform(
|
||||
// typeText(textToType)
|
||||
// )
|
||||
//
|
||||
// // Clicking to apply button, in order to save filter changes
|
||||
//
|
||||
// onView(withId(R.id.btnBottomAction)).apply {
|
||||
// perform(click())
|
||||
// }
|
||||
//
|
||||
// // Veryfying that the appropriate request was made
|
||||
//
|
||||
// verifyBlocking(repo, times(1)) {
|
||||
// updateDataViewViewer(
|
||||
// context = root,
|
||||
// target = dv.id,
|
||||
// viewer = viewer.copy(
|
||||
// filters = listOf(filter.copy(value = initialFilterText + textToType))
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun shouldTypeNumberFilterTextThenClickActionButtonToApplyChanges() {
|
||||
//
|
||||
// val relationKey = MockDataFactory.randomUuid()
|
||||
//
|
||||
// val target = MockDataFactory.randomUuid()
|
||||
//
|
||||
// val record: Map<String, Any?> = mapOf(
|
||||
// ObjectSetConfig.ID_KEY to target,
|
||||
// relationKey to emptyList<String>()
|
||||
// )
|
||||
//
|
||||
// // Defining viewer containing one filter
|
||||
//
|
||||
// val initialFilterText = "1"
|
||||
// val textToType = "2"
|
||||
//
|
||||
// val filter = DVFilter(
|
||||
// relationKey = relationKey,
|
||||
// value = initialFilterText,
|
||||
// condition = DVFilterCondition.EQUAL
|
||||
// )
|
||||
//
|
||||
// val viewer = Block.Content.DataView.Viewer(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// name = MockDataFactory.randomString(),
|
||||
// filters = listOf(filter),
|
||||
// sorts = emptyList(),
|
||||
// viewerRelations = listOf(
|
||||
// Block.Content.DataView.Viewer.ViewerRelation(
|
||||
// key = relationKey,
|
||||
// isVisible = true
|
||||
// )
|
||||
// ),
|
||||
// type = Block.Content.DataView.Viewer.Type.values().random()
|
||||
// )
|
||||
//
|
||||
// val relation = Relation(
|
||||
// key = relationKey,
|
||||
// defaultValue = null,
|
||||
// isHidden = false,
|
||||
// isReadOnly = false,
|
||||
// isMulti = true,
|
||||
// name = MockDataFactory.randomString(),
|
||||
// source = Relation.Source.values().random(),
|
||||
// format = Relation.Format.NUMBER,
|
||||
// selections = emptyList()
|
||||
// )
|
||||
//
|
||||
// val dv = Block(
|
||||
// id = MockDataFactory.randomUuid(),
|
||||
// children = emptyList(),
|
||||
// fields = Block.Fields.empty(),
|
||||
// content = Block.Content.DataView(
|
||||
// relations = listOf(relation),
|
||||
// viewers = listOf(viewer),
|
||||
// source = MockDataFactory.randomUuid()
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// state.value = ObjectSet(
|
||||
// blocks = listOf(dv),
|
||||
// viewerDb = mapOf(
|
||||
// viewer.id to ObjectSet.ViewerData(
|
||||
// records = listOf(record),
|
||||
// total = 1
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// // Launching fragment
|
||||
//
|
||||
// launchFragment(
|
||||
// bundleOf(
|
||||
// ModifyFilterFromInputFieldValueFragment.CTX_KEY to root,
|
||||
// ModifyFilterFromInputFieldValueFragment.IDX_KEY to 0,
|
||||
// ModifyFilterFromInputFieldValueFragment.RELATION_KEY to relationKey,
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// // Veryfying that the initial filter text is visibile to our user
|
||||
//
|
||||
// val inputFieldInteraction = onView(withId(R.id.enterTextValueInputField))
|
||||
//
|
||||
// inputFieldInteraction.check(matches(withText(initialFilterText)))
|
||||
//
|
||||
// // Checking input type
|
||||
//
|
||||
// inputFieldInteraction.check(matches(withInputType(InputType.TYPE_CLASS_NUMBER)))
|
||||
//
|
||||
// // Typing additional text before pressing action button
|
||||
//
|
||||
// inputFieldInteraction.perform(
|
||||
// typeText(textToType)
|
||||
// )
|
||||
//
|
||||
// // Clicking to apply button, in order to save filter changes
|
||||
//
|
||||
// onView(withId(R.id.btnBottomAction)).apply {
|
||||
// perform(click())
|
||||
// }
|
||||
//
|
||||
// // Veryfying that the appropriate request was made
|
||||
//
|
||||
// verifyBlocking(repo, times(1)) {
|
||||
// updateDataViewViewer(
|
||||
// context = root,
|
||||
// target = dv.id,
|
||||
// viewer = viewer.copy(
|
||||
// filters = listOf(filter.copy(value = initialFilterText + textToType))
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestModifyFilterFromInputFieldValueFragment> {
|
||||
return launchFragmentInContainer<TestModifyFilterFromInputFieldValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
package com.anytypeio.anytype.features.sets.filter
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromSelectedValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.utils.TestUtils
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verifyBlocking
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ModifyStatusFilterTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
lateinit var searchObjects: SearchObjects
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val session = ObjectSetSession()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val dispatcher = Dispatcher.Default<Payload>()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
updateDataViewViewer = UpdateDataViewViewer(repo)
|
||||
searchObjects = SearchObjects(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestModifyFilterFromSelectedValueFragment.testVmFactory = FilterViewModel.Factory(
|
||||
objectSetState = state,
|
||||
session = session,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
searchObjects = searchObjects,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldSelectSecondStatusAndApplyChangesOnClick() {
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
// Defining three different statuses:
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In progress",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "In Testing",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Done",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to emptyList<String>()
|
||||
)
|
||||
|
||||
// Defining viewer containing one filter
|
||||
|
||||
val filter = DVFilter(
|
||||
relationKey = relationKey,
|
||||
value = listOf(option1.id),
|
||||
condition = DVFilterCondition.EQUAL
|
||||
)
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = listOf(filter),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
Block.Content.DataView.Viewer.ViewerRelation(
|
||||
key = relationKey,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.values().random()
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.STATUS,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(dv),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Launching fragment
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ModifyFilterFromSelectedValueFragment.CTX_KEY to root,
|
||||
ModifyFilterFromSelectedValueFragment.IDX_KEY to 0,
|
||||
ModifyFilterFromSelectedValueFragment.RELATION_KEY to relationKey,
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
val rvMatcher = TestUtils.withRecyclerView(R.id.rvViewerFilterRecycler)
|
||||
|
||||
// Checking names
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvStatusName)).apply {
|
||||
check(matches(withText(option1.text)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.tvStatusName)).apply {
|
||||
check(matches(withText(option2.text)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(2, R.id.tvStatusName)).apply {
|
||||
check(matches(withText(option3.text)))
|
||||
}
|
||||
|
||||
// Veryfing that only the first status is selected
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.ivSelectStatusIcon)).apply {
|
||||
check(matches(isSelected()))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.ivSelectStatusIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(2, R.id.ivSelectStatusIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
// Verifying that the selection counter is equal to 1
|
||||
|
||||
onView(withId(R.id.tvOptionCount)).apply {
|
||||
check(matches(withText("1")))
|
||||
}
|
||||
|
||||
// Performing click, in order to sellect second status
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.ivSelectStatusIcon)).apply {
|
||||
perform(click())
|
||||
}
|
||||
|
||||
// Veryfing that only the second status is selected
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.ivSelectStatusIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.ivSelectStatusIcon)).apply {
|
||||
check(matches((isSelected())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(2, R.id.ivSelectStatusIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
// Verifying that the selection counter is still equal to 1
|
||||
|
||||
onView(withId(R.id.tvOptionCount)).apply {
|
||||
check(matches(withText("1")))
|
||||
}
|
||||
|
||||
// Performing a click to apply filter changes.
|
||||
|
||||
onView(withId(R.id.btnBottomAction)).apply {
|
||||
perform(click())
|
||||
}
|
||||
|
||||
// Verifying that viewer's filters are updated.
|
||||
|
||||
verifyBlocking(repo, times(1)) {
|
||||
updateDataViewViewer(
|
||||
context = root,
|
||||
target = dv.id,
|
||||
viewer = viewer.copy(
|
||||
filters = listOf(filter.copy(value = listOf(option2.id)))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestModifyFilterFromSelectedValueFragment> {
|
||||
return launchFragmentInContainer<TestModifyFilterFromSelectedValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
package com.anytypeio.anytype.features.sets.filter
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromSelectedValueFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.utils.TestUtils
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ModifyTagFilterTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
|
||||
lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
lateinit var searchObjects: SearchObjects
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val session = ObjectSetSession()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val dispatcher = Dispatcher.Default<Payload>()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
updateDataViewViewer = UpdateDataViewViewer(repo)
|
||||
searchObjects = SearchObjects(repo)
|
||||
urlBuilder = UrlBuilder(gateway)
|
||||
TestModifyFilterFromSelectedValueFragment.testVmFactory = FilterViewModel.Factory(
|
||||
objectSetState = state,
|
||||
session = session,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
searchObjects = searchObjects,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tagSelectionTest1() {
|
||||
|
||||
val relationKey = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
// Defining three different tags:
|
||||
|
||||
val option1 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Architect",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option2 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Manager",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val option3 = Relation.Option(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
text = "Developer",
|
||||
color = MockDataFactory.randomString()
|
||||
)
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationKey to emptyList<String>()
|
||||
)
|
||||
|
||||
// Defining viewer containing one filter
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = listOf(
|
||||
DVFilter(
|
||||
relationKey = relationKey,
|
||||
value = listOf(option1.id),
|
||||
condition = DVFilterCondition.ALL_IN
|
||||
)
|
||||
),
|
||||
sorts = emptyList(),
|
||||
viewerRelations = listOf(
|
||||
Block.Content.DataView.Viewer.ViewerRelation(
|
||||
key = relationKey,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.values().random()
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationKey,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = MockDataFactory.randomString(),
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.TAG,
|
||||
selections = listOf(option1, option2, option3)
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Launching fragment
|
||||
|
||||
launchFragment(
|
||||
bundleOf(
|
||||
ModifyFilterFromSelectedValueFragment.CTX_KEY to root,
|
||||
ModifyFilterFromSelectedValueFragment.IDX_KEY to 0,
|
||||
ModifyFilterFromSelectedValueFragment.RELATION_KEY to relationKey,
|
||||
)
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
val rvMatcher = TestUtils.withRecyclerView(R.id.rvViewerFilterRecycler)
|
||||
|
||||
// Checking names
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvTagName)).apply {
|
||||
check(matches(withText(option1.text)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.tvTagName)).apply {
|
||||
check(matches(withText(option2.text)))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(2, R.id.tvTagName)).apply {
|
||||
check(matches(withText(option3.text)))
|
||||
}
|
||||
|
||||
// Veryfing that only the first tag is selected
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.ivSelectTagIcon)).apply {
|
||||
check(matches(isSelected()))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.ivSelectTagIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(2, R.id.ivSelectTagIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
// Verifying that the selection counter is equal to 1
|
||||
|
||||
onView(withId(R.id.tvOptionCount)).apply {
|
||||
check(matches(withText("1")))
|
||||
}
|
||||
|
||||
// Performing click, in order to sellect second status
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.ivSelectTagIcon)).apply {
|
||||
perform(click())
|
||||
}
|
||||
|
||||
// Veryfing that only the first tag and the second tag are selected
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.ivSelectTagIcon)).apply {
|
||||
check(matches(isSelected()))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(1, R.id.ivSelectTagIcon)).apply {
|
||||
check(matches((isSelected())))
|
||||
}
|
||||
|
||||
onView(rvMatcher.atPositionOnView(2, R.id.ivSelectTagIcon)).apply {
|
||||
check(matches(not(isSelected())))
|
||||
}
|
||||
|
||||
// Verifying that the selection counter is now equal to 2
|
||||
|
||||
onView(withId(R.id.tvOptionCount)).apply {
|
||||
check(matches(withText("2")))
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestModifyFilterFromSelectedValueFragment> {
|
||||
return launchFragmentInContainer<TestModifyFilterFromSelectedValueFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.features.sets.filter
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromInputFieldValueFragment
|
||||
|
||||
class TestModifyFilterFromInputFieldValueFragment : ModifyFilterFromInputFieldValueFragment() {
|
||||
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: FilterViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.features.sets.filter
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromSelectedValueFragment
|
||||
|
||||
class TestModifyFilterFromSelectedValueFragment : ModifyFilterFromSelectedValueFragment() {
|
||||
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: FilterViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.features.sets.sort
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.sort.ViewerSortViewModel
|
||||
import com.anytypeio.anytype.ui.sets.modals.sort.ViewerSortFragment
|
||||
|
||||
class TestViewerSortFragment : ViewerSortFragment() {
|
||||
|
||||
init {
|
||||
factory = testVmFactory
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
lateinit var testVmFactory: ViewerSortViewModel.Factory
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.anytypeio.anytype.features.sets.sort
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.DVSort
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.Relation
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.mocking.MockDataFactory
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.sort.ViewerSortViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.sort.ViewerSortFragment
|
||||
import com.anytypeio.anytype.utils.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
import com.bartoszlipinski.disableanimationsrule.DisableAnimationsRule
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@LargeTest
|
||||
class ViewerObjectSortTest {
|
||||
|
||||
@get:Rule
|
||||
val animationsRule = DisableAnimationsRule()
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
private lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
|
||||
private val root = MockDataFactory.randomUuid()
|
||||
private val session = ObjectSetSession()
|
||||
private val state = MutableStateFlow(ObjectSet.init())
|
||||
private val dispatcher = Dispatcher.Default<Payload>()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
updateDataViewViewer = UpdateDataViewViewer(repo)
|
||||
TestViewerSortFragment.testVmFactory = ViewerSortViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
dispatcher = dispatcher
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDisplayObjectRelationSortWithRelationNameAndSortingType() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val name = "Some object"
|
||||
|
||||
val relationId = MockDataFactory.randomUuid()
|
||||
val target = MockDataFactory.randomUuid()
|
||||
|
||||
val record: Map<String, Any?> = mapOf(
|
||||
ObjectSetConfig.ID_KEY to target,
|
||||
relationId to emptyList<String>()
|
||||
)
|
||||
|
||||
// Defining viewer containing one filter
|
||||
|
||||
val viewer = Block.Content.DataView.Viewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
filters = emptyList(),
|
||||
sorts = listOf(
|
||||
DVSort(
|
||||
relationKey = relationId,
|
||||
type = Block.Content.DataView.Sort.Type.DESC
|
||||
)
|
||||
),
|
||||
viewerRelations = listOf(
|
||||
Block.Content.DataView.Viewer.ViewerRelation(
|
||||
key = relationId,
|
||||
isVisible = true
|
||||
)
|
||||
),
|
||||
type = Block.Content.DataView.Viewer.Type.values().random()
|
||||
)
|
||||
|
||||
val relation = Relation(
|
||||
key = relationId,
|
||||
defaultValue = null,
|
||||
isHidden = false,
|
||||
isReadOnly = false,
|
||||
isMulti = true,
|
||||
name = name,
|
||||
source = Relation.Source.values().random(),
|
||||
format = Relation.Format.OBJECT,
|
||||
selections = emptyList()
|
||||
)
|
||||
|
||||
state.value = ObjectSet(
|
||||
blocks = listOf(
|
||||
Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty(),
|
||||
content = Block.Content.DataView(
|
||||
relations = listOf(relation),
|
||||
viewers = listOf(viewer),
|
||||
source = MockDataFactory.randomUuid()
|
||||
)
|
||||
)
|
||||
),
|
||||
viewerDb = mapOf(
|
||||
viewer.id to ObjectSet.ViewerData(
|
||||
records = listOf(record),
|
||||
total = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Launching fragment
|
||||
|
||||
launchFragment(bundleOf(ViewerSortFragment.CTX_KEY to root))
|
||||
|
||||
// TESTING
|
||||
|
||||
val rvMatcher = withRecyclerView(R.id.viewerSortRecycler)
|
||||
|
||||
// Checking that the relation name is set
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvTitle)).apply {
|
||||
check(matches(withText(name)))
|
||||
}
|
||||
|
||||
// Checking that the sorting type is set
|
||||
|
||||
onView(rvMatcher.atPositionOnView(0, R.id.tvSubtitle)).apply {
|
||||
check(matches(withText(R.string.sort_from_z_to_a)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchFragment(args: Bundle): FragmentScenario<TestViewerSortFragment> {
|
||||
return launchFragmentInContainer<TestViewerSortFragment>(
|
||||
fragmentArgs = args,
|
||||
themeResId = R.style.AppTheme
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.anytypeio.anytype.mocking
|
||||
|
||||
import com.anytypeio.anytype.domain.block.model.Block
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
|
||||
object MockUiTests {
|
||||
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
package com.anytypeio.anytype.utils
|
||||
|
||||
import android.support.annotation.DimenRes
|
||||
import android.support.annotation.IntegerRes
|
||||
import android.support.annotation.StringRes
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.ViewInteraction
|
||||
import androidx.test.espresso.action.ViewActions
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.typeText
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import com.anytypeio.anytype.core_ui.features.page.BlockViewHolder
|
||||
import com.anytypeio.anytype.utils.TestUtils.withRecyclerView
|
||||
import org.hamcrest.Matchers.not
|
||||
|
||||
fun <T : BlockViewHolder> Int.scrollTo(position: Int) {
|
||||
onView(withId(this)).perform(RecyclerViewActions.scrollToPosition<T>(position))
|
||||
|
@ -13,4 +23,81 @@ fun <T : BlockViewHolder> Int.scrollTo(position: Int) {
|
|||
|
||||
fun Int.findItemAt(position: Int, layoutId: Int): ViewInteraction {
|
||||
return onView(withRecyclerView(this).atPositionOnView(position, layoutId))
|
||||
}
|
||||
|
||||
fun ViewInteraction.performClick(): ViewInteraction = perform(ViewActions.click())
|
||||
fun Int.matchView(): ViewInteraction = onView(withId(this))
|
||||
fun Int.performClick(): ViewInteraction = matchView().performClick()
|
||||
fun Int.type(text: String) = matchView().perform(click(), typeText(text))
|
||||
|
||||
fun ViewInteraction.checkHasText(text: String) {
|
||||
check(matches(ViewMatchers.withText(text)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasMarginStart(@DimenRes dimen: Int, coefficient: Int) {
|
||||
check(matches(WithMarginStart(dimen, coefficient)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasPaddingLeft(@DimenRes dimen: Int, coefficient: Int) {
|
||||
check(matches(WithPaddingLeft(dimen, coefficient)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkIsSelected() {
|
||||
check(matches(ViewMatchers.isSelected()))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkIsDisplayed() {
|
||||
check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkIsNotDisplayed() {
|
||||
check(matches(not(isDisplayed())))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkIsNotSelected() {
|
||||
check(matches(not(ViewMatchers.isSelected())))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasText(@StringRes resId: Int) {
|
||||
check(matches(ViewMatchers.withText(resId)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasTextColor(color: Int) {
|
||||
check(matches(WithTextColor(color)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasBackgroundColor(color: Int) {
|
||||
check(matches(WithBackgroundColor(color)))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasNoBackground() {
|
||||
check(matches(WithoutBackgroundColor()))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasChildViewCount(count: Int) : ViewInteraction {
|
||||
return check(matches(WithChildViewCount(count)))
|
||||
}
|
||||
|
||||
fun Int.rVMatcher(): RecyclerViewMatcher = RecyclerViewMatcher(this)
|
||||
|
||||
fun Int.checkRecyclerItemCount(expected: Int) = matchView().check(RecyclerViewItemCountAssertion(expected))
|
||||
|
||||
fun RecyclerViewMatcher.onItemView(pos: Int, @IntegerRes target: Int): ViewInteraction {
|
||||
return onView(atPositionOnView(pos, target))
|
||||
}
|
||||
|
||||
fun ViewInteraction.checkHasChildViewWithText(
|
||||
pos: Int,
|
||||
text: String,
|
||||
@IntegerRes target: Int
|
||||
) : ViewInteraction {
|
||||
return check(matches(HasChildViewWithText(pos, text, target)))
|
||||
}
|
||||
|
||||
fun RecyclerViewMatcher.onItem(pos: Int): ViewInteraction {
|
||||
return onView(atPosition(pos))
|
||||
}
|
||||
|
||||
fun RecyclerViewMatcher.checkIsRecyclerSize(expected: Int) {
|
||||
recyclerViewId.matchView().check(RecyclerViewItemCountAssertion(expected))
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.anytypeio.anytype.utils
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.NoMatchingViewException
|
||||
import androidx.test.espresso.ViewAssertion
|
||||
import androidx.test.espresso.matcher.ViewMatchers.assertThat
|
||||
import org.hamcrest.CoreMatchers.`is`
|
||||
|
||||
|
||||
class RecyclerViewItemCountAssertion(val expected: Int) : ViewAssertion {
|
||||
override fun check(view: View?, noViewFoundException: NoMatchingViewException?) {
|
||||
if (noViewFoundException != null) throw noViewFoundException
|
||||
val recycler = view as RecyclerView
|
||||
val adapter = recycler.adapter
|
||||
checkNotNull(adapter) { "Adapter wasn't set" }
|
||||
assertThat(adapter.itemCount, `is`(expected))
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import org.hamcrest.TypeSafeMatcher;
|
|||
|
||||
public class RecyclerViewMatcher {
|
||||
|
||||
private final int recyclerViewId;
|
||||
final int recyclerViewId;
|
||||
|
||||
public RecyclerViewMatcher(int recyclerViewId) {
|
||||
this.recyclerViewId = recyclerViewId;
|
||||
|
@ -28,18 +28,21 @@ public class RecyclerViewMatcher {
|
|||
View childView;
|
||||
|
||||
public void describeTo(Description description) {
|
||||
String idDescription = Integer.toString(recyclerViewId);
|
||||
String idRecyclerDescription = Integer.toString(recyclerViewId);
|
||||
String idTargetViewDescription = Integer.toString(targetViewId);
|
||||
if (this.resources != null) {
|
||||
try {
|
||||
idDescription = this.resources.getResourceName(recyclerViewId);
|
||||
} catch (Resources.NotFoundException var4) {
|
||||
idDescription = String.format("%s (resource name not found)",
|
||||
Integer.valueOf
|
||||
(recyclerViewId));
|
||||
idRecyclerDescription = this.resources.getResourceName(recyclerViewId);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
idRecyclerDescription = String.format("%s (resource name not found)", recyclerViewId);
|
||||
}
|
||||
try {
|
||||
idTargetViewDescription = this.resources.getResourceName(targetViewId);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
idTargetViewDescription = String.format("%s (resource name not found)", targetViewId);
|
||||
}
|
||||
}
|
||||
|
||||
description.appendText("with id: " + idDescription);
|
||||
description.appendText("\nwith id: [" + idTargetViewDescription + "] inside: [" + idRecyclerDescription + "]");
|
||||
}
|
||||
|
||||
public boolean matchesSafely(View view) {
|
||||
|
@ -50,7 +53,14 @@ public class RecyclerViewMatcher {
|
|||
RecyclerView recyclerView =
|
||||
view.getRootView().findViewById(recyclerViewId);
|
||||
if (recyclerView != null && recyclerView.getId() == recyclerViewId) {
|
||||
childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
|
||||
RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(position);
|
||||
if (holder == null) {
|
||||
throw new IllegalStateException(
|
||||
"No view holder found at position: " + position +
|
||||
". Actual child count: " + recyclerView.getChildCount()
|
||||
);
|
||||
}
|
||||
childView = holder.itemView;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ public class TestUtils {
|
|||
|
||||
|
||||
public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
|
||||
|
||||
return new RecyclerViewMatcher(recyclerViewId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package com.anytypeio.anytype.utils
|
||||
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.marginStart
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.matcher.BoundedMatcher
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.TypeSafeMatcher
|
||||
|
||||
|
||||
class WithTextColor(private val expectedColor: Int) : BoundedMatcher<View, TextView>(TextView::class.java) {
|
||||
override fun matchesSafely(item: TextView) = item.currentTextColor == expectedColor
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with text color:")
|
||||
description.appendValue(expectedColor)
|
||||
}
|
||||
}
|
||||
|
||||
class WithBackgroundColor(private val expected: Int) : BoundedMatcher<View, View>(View::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with background color:")
|
||||
description.appendValue(expected)
|
||||
}
|
||||
|
||||
override fun matchesSafely(item: View): Boolean {
|
||||
val actual = (item.background as ColorDrawable).color
|
||||
return actual == expected
|
||||
}
|
||||
}
|
||||
|
||||
class WithoutBackgroundColor : BoundedMatcher<View, View>(View::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with background color:")
|
||||
}
|
||||
|
||||
override fun matchesSafely(item: View): Boolean {
|
||||
return item.background == null
|
||||
}
|
||||
}
|
||||
|
||||
class WithChildViewCount(private val expectedCount: Int) : BoundedMatcher<View, ViewGroup>(ViewGroup::class.java) {
|
||||
override fun matchesSafely(item: ViewGroup): Boolean = item.childCount == expectedCount
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("ViewGroup with child-count = $expectedCount");
|
||||
}
|
||||
}
|
||||
|
||||
class HasChildViewWithText(private val pos: Int, val text: String, val target: Int) : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
|
||||
|
||||
private var actual: String? = null
|
||||
|
||||
override fun matchesSafely(item: RecyclerView): Boolean {
|
||||
val holder = item.findViewHolderForLayoutPosition(pos)
|
||||
checkNotNull(holder) { throw IllegalStateException("No holder at position: $pos") }
|
||||
val target = holder.itemView.findViewById<TextView>(target)
|
||||
actual = target.text.toString()
|
||||
return actual == text
|
||||
}
|
||||
override fun describeTo(description: Description) {
|
||||
if (actual != null) {
|
||||
description.appendText("Should have text [$text] at position: $pos but was: $actual");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WithMarginStart(private val dimen: Int, private val coefficient: Int) : TypeSafeMatcher<View>() {
|
||||
|
||||
var actual: Int = 0
|
||||
var expected: Int = 0
|
||||
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with actual margin start:")
|
||||
description.appendValue(actual)
|
||||
description.appendText("with expected margin start:")
|
||||
description.appendValue(expected)
|
||||
}
|
||||
override fun matchesSafely(item: View): Boolean {
|
||||
actual = item.marginStart
|
||||
expected = (item.context.dimen(dimen) * coefficient).toInt()
|
||||
return actual == expected
|
||||
}
|
||||
}
|
||||
|
||||
class WithPaddingLeft(private val dimen: Int, private val coefficient: Int) : TypeSafeMatcher<View>() {
|
||||
|
||||
var actual: Int = 0
|
||||
var expected: Int = 0
|
||||
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with actual padding start:")
|
||||
description.appendValue(actual)
|
||||
description.appendText("with expected padding start:")
|
||||
description.appendValue(expected)
|
||||
}
|
||||
override fun matchesSafely(item: View): Boolean {
|
||||
actual = item.paddingLeft
|
||||
expected = (item.context.dimen(dimen) * coefficient).toInt()
|
||||
return actual == expected
|
||||
}
|
||||
}
|
||||
|
||||
class WithTextColorRes(private val expectedColorRes: Int) : BoundedMatcher<View, TextView>(TextView::class.java) {
|
||||
override fun matchesSafely(item: TextView): Boolean {
|
||||
val color = ContextCompat.getColor(item.context, expectedColorRes)
|
||||
return item.currentTextColor == color
|
||||
}
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("with text color:")
|
||||
description.appendValue(expectedColorRes)
|
||||
}
|
||||
}
|
39
app/src/debug/google-services.json
Normal file
39
app/src/debug/google-services.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "687711214896",
|
||||
"project_id": "anytype-debug",
|
||||
"storage_bucket": "anytype-debug.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:687711214896:android:20001e745ee8af044f7cf5",
|
||||
"android_client_info": {
|
||||
"package_name": "com.anytypeio.anytype.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "687711214896-otmhog2ql4ngk1gcatbc3b1afkudra8s.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC83X8q2Ya3-jTMp7b7i85WoY-TeBnX1qQ"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "687711214896-otmhog2ql4ngk1gcatbc3b1afkudra8s.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
5
app/src/debug/res/values/technical_strings.xml
Normal file
5
app/src/debug/res/values/technical_strings.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">DEBUG-Anytype</string>
|
||||
<color name="ic_app_back_main">#000</color>
|
||||
</resources>
|
|
@ -0,0 +1,191 @@
|
|||
package com.anytypeio.anytype.ui.desktop
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.View.OVER_SCROLL_NEVER
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ext.visible
|
||||
import com.anytypeio.anytype.core_utils.ui.EqualSpacingItemDecoration
|
||||
import com.anytypeio.anytype.core_utils.ui.EqualSpacingItemDecoration.Companion.GRID
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.desktop.DashboardView
|
||||
import com.anytypeio.anytype.presentation.desktop.HomeDashboardStateMachine.State
|
||||
import com.anytypeio.anytype.presentation.desktop.HomeDashboardViewModel
|
||||
import com.anytypeio.anytype.presentation.desktop.HomeDashboardViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.extension.filterByNotArchivedPages
|
||||
import com.anytypeio.anytype.ui.base.ViewStateFragment
|
||||
import com.anytypeio.anytype.ui.page.PageFragment
|
||||
import kotlinx.android.synthetic.experimental.fragment_desktop.*
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeDashboardFragment : ViewStateFragment<State>(R.layout.fragment_desktop) {
|
||||
|
||||
private val vm by viewModels<HomeDashboardViewModel> { factory }
|
||||
|
||||
private val dndBehavior by lazy {
|
||||
DashboardDragAndDropBehavior(
|
||||
onItemMoved = { from, to ->
|
||||
dashboardAdapter
|
||||
.onItemMove(from, to)
|
||||
.also {
|
||||
vm.onItemMoved(
|
||||
views = dashboardAdapter.provideAdapterData(),
|
||||
from = from,
|
||||
to = to
|
||||
)
|
||||
}
|
||||
},
|
||||
onItemDropped = { index ->
|
||||
try {
|
||||
vm.onItemDropped(dashboardAdapter.provideAdapterData()[index])
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error while dropping item at index: $index")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Inject
|
||||
lateinit var factory: HomeDashboardViewModelFactory
|
||||
|
||||
@Inject
|
||||
lateinit var builder: UrlBuilder
|
||||
|
||||
private val dashboardAdapter by lazy {
|
||||
DashboardAdapter(
|
||||
data = mutableListOf(),
|
||||
onDocumentClicked = { target, isLoading -> vm.onDocumentClicked(target, isLoading) },
|
||||
onArchiveClicked = { vm.onArchivedClicked(it) },
|
||||
onObjectSetClicked = { vm.onObjectSetClicked(it) }
|
||||
)
|
||||
}
|
||||
|
||||
private val profileAdapter by lazy {
|
||||
DashboardProfileAdapter(
|
||||
data = mutableListOf(),
|
||||
onProfileClicked = { vm.onProfileClicked() }
|
||||
)
|
||||
}
|
||||
|
||||
private val concatAdapter by lazy {
|
||||
ConcatAdapter(ProfileContainerAdapter(profileAdapter), dashboardAdapter)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setup()
|
||||
|
||||
with(vm) {
|
||||
state.observe(viewLifecycleOwner, this@HomeDashboardFragment)
|
||||
navigation.observe(viewLifecycleOwner, navObserver)
|
||||
}
|
||||
|
||||
parseIntent()
|
||||
}
|
||||
|
||||
private fun parseIntent() {
|
||||
val deepLinkPage = arguments?.getString(PageFragment.ID_KEY, null)
|
||||
if (deepLinkPage != null) {
|
||||
arguments?.remove(PageFragment.ID_KEY)
|
||||
|
||||
vm.onNavigationDeepLink(deepLinkPage)
|
||||
} else {
|
||||
vm.onViewCreated()
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(state: State) {
|
||||
when {
|
||||
state.error != null -> {
|
||||
requireActivity().toast("Error: ${state.error}")
|
||||
}
|
||||
state.isInitialzed -> {
|
||||
bottomToolbar.visible()
|
||||
state.blocks.let { views ->
|
||||
val profile = views.filterIsInstance<DashboardView.Profile>()
|
||||
val links = views.filterByNotArchivedPages()
|
||||
if (profile.isNotEmpty()) {
|
||||
profileAdapter.update(profile)
|
||||
}
|
||||
dashboardAdapter.update(links)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setup() {
|
||||
|
||||
val spacing = requireContext().dimen(R.dimen.default_dashboard_item_spacing).toInt()
|
||||
val decoration = EqualSpacingItemDecoration(
|
||||
topSpacing = spacing,
|
||||
leftSpacing = spacing,
|
||||
rightSpacing = spacing,
|
||||
bottomSpacing = 0,
|
||||
displayMode = GRID
|
||||
)
|
||||
|
||||
desktopRecycler.apply {
|
||||
overScrollMode = OVER_SCROLL_NEVER
|
||||
layoutManager = GridLayoutManager(context, 2).apply {
|
||||
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return if (position == 0) {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adapter = concatAdapter
|
||||
ItemTouchHelper(dndBehavior).attachToRecyclerView(this)
|
||||
addItemDecoration(decoration)
|
||||
setHasFixedSize(true)
|
||||
}
|
||||
|
||||
bottomToolbar
|
||||
.navigationClicks()
|
||||
.onEach { vm.onPageNavigationClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
bottomToolbar
|
||||
.addPageClick()
|
||||
.onEach { vm.onAddNewDocumentClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
bottomToolbar
|
||||
.searchClicks()
|
||||
.onEach { vm.onPageSearchClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
createSetButton
|
||||
.clicks()
|
||||
.onEach { vm.onCreateNewObjectSetClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().desktopComponent.get().inject(this)
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {
|
||||
componentManager().desktopComponent.release()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val COLUMN_COUNT = 2
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
package com.anytypeio.anytype.ui.page.sheets
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Url
|
||||
import com.anytypeio.anytype.core_ui.extensions.*
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.core_utils.ext.*
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.domain.status.SyncStatus
|
||||
import kotlinx.android.synthetic.experimental.fragment_doc_menu_bottom_sheet.*
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
class DocMenuBottomSheet : BaseBottomSheetFragment() {
|
||||
|
||||
private val title get() = arg<String?>(TITLE_KEY)
|
||||
private val status get() = SyncStatus.valueOf(arg(STATUS_KEY))
|
||||
private val image get() = arg<String?>(IMAGE_KEY)
|
||||
private val emoji get() = arg<String?>(EMOJI_KEY)
|
||||
private val isProfile get() = arg<Boolean>(IS_PROFILE_KEY)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? = inflater.inflate(R.layout.fragment_doc_menu_bottom_sheet, container, false)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
bindTitle()
|
||||
bindSyncStatus(status)
|
||||
closeButton.clicks().onEach { dismiss() }.launchIn(lifecycleScope)
|
||||
|
||||
searchOnPageContainer
|
||||
.clicks()
|
||||
.onEach {
|
||||
withParent<DocumentMenuActionReceiver> { onSearchOnPageClicked() }.also { dismiss() }
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
archiveContainer
|
||||
.clicks()
|
||||
.onEach {
|
||||
withParent<DocumentMenuActionReceiver> { onArchiveClicked() }.also { dismiss() }
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
addCoverContainer
|
||||
.clicks()
|
||||
.onEach {
|
||||
withParent<DocumentMenuActionReceiver> { onAddCoverClicked() }.also { dismiss() }
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
relationContainer
|
||||
.clicks()
|
||||
.onEach {
|
||||
withParent<DocumentMenuActionReceiver> { onDocRelationsClicked() }.also { dismiss() }
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
if (image != null && !isProfile) icon.setImageOrNull(image)
|
||||
if (emoji != null && !isProfile) icon.setEmojiOrNull(emoji)
|
||||
|
||||
if (isProfile) {
|
||||
avatar.visible()
|
||||
image?.let { avatar.icon(it) } ?: avatar.bind(
|
||||
name = title.orEmpty(),
|
||||
color = title.orEmpty().firstDigitByHash().let {
|
||||
requireContext().avatarColor(it)
|
||||
}
|
||||
)
|
||||
archiveContainer.gone()
|
||||
addCoverContainer.setBackgroundResource(R.drawable.rectangle_doc_menu_bottom)
|
||||
searchOnPageContainer.setBackgroundResource(R.drawable.rectangle_doc_menu_top)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindTitle() {
|
||||
tvTitle.text = title ?: getString(R.string.untitled)
|
||||
}
|
||||
|
||||
private fun bindSyncStatus(status: SyncStatus) {
|
||||
when (status) {
|
||||
SyncStatus.UNKNOWN -> {
|
||||
badge.tint(
|
||||
color = requireContext().color(R.color.sync_status_red)
|
||||
)
|
||||
tvSubtitle.setText(R.string.sync_status_unknown)
|
||||
}
|
||||
SyncStatus.FAILED -> {
|
||||
badge.tint(
|
||||
color = requireContext().color(R.color.sync_status_red)
|
||||
)
|
||||
tvSubtitle.setText(R.string.sync_status_failed)
|
||||
}
|
||||
SyncStatus.OFFLINE -> {
|
||||
badge.tint(
|
||||
color = requireContext().color(R.color.sync_status_red)
|
||||
)
|
||||
tvSubtitle.setText(R.string.sync_status_offline)
|
||||
}
|
||||
SyncStatus.SYNCING -> {
|
||||
badge.tint(
|
||||
color = requireContext().color(R.color.sync_status_orange)
|
||||
)
|
||||
tvSubtitle.setText(R.string.sync_status_syncing)
|
||||
}
|
||||
SyncStatus.SYNCED -> {
|
||||
badge.tint(
|
||||
color = requireContext().color(R.color.sync_status_green)
|
||||
)
|
||||
tvSubtitle.setText(R.string.sync_status_synced)
|
||||
}
|
||||
else -> badge.tint(Color.WHITE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {}
|
||||
override fun releaseDependencies() {}
|
||||
|
||||
companion object {
|
||||
fun new(
|
||||
title: String?,
|
||||
status: SyncStatus,
|
||||
image: Url?,
|
||||
emoji: String?,
|
||||
isProfile: Boolean = false
|
||||
) = DocMenuBottomSheet().apply {
|
||||
arguments = bundleOf(
|
||||
TITLE_KEY to title,
|
||||
STATUS_KEY to status.name,
|
||||
IMAGE_KEY to image,
|
||||
EMOJI_KEY to emoji,
|
||||
IS_PROFILE_KEY to isProfile
|
||||
)
|
||||
}
|
||||
|
||||
private const val TITLE_KEY = "arg.doc-menu-bottom-sheet.title"
|
||||
private const val IMAGE_KEY = "arg.doc-menu-bottom-sheet.image"
|
||||
private const val EMOJI_KEY = "arg.doc-menu-bottom-sheet.emoji"
|
||||
private const val STATUS_KEY = "arg.doc-menu-bottom-sheet.status"
|
||||
private const val IS_PROFILE_KEY = "arg.doc-menu-bottom-sheet.is-profile"
|
||||
}
|
||||
|
||||
interface DocumentMenuActionReceiver {
|
||||
fun onArchiveClicked()
|
||||
fun onSearchOnPageClicked()
|
||||
fun onDocRelationsClicked()
|
||||
fun onAddCoverClicked()
|
||||
}
|
||||
}
|
31
app/src/experimental/res/layout/fragment_desktop.xml
Normal file
31
app/src/experimental/res/layout/fragment_desktop.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/home_dashboard_cover">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="32dp"
|
||||
android:id="@+id/createSetButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/desktopRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingBottom="64dp"
|
||||
tools:listitem="@layout/item_desktop_page" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.toolbar.DesktopBottomToolbar
|
||||
android:id="@+id/bottomToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" />
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,218 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="12dp"
|
||||
android:background="@drawable/rectangle_doc_menu_background">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/iconContainer"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center"
|
||||
tools:src="@drawable/circle_solid_default" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.AvatarWidget
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/circle_solid_default"
|
||||
android:visibility="invisible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/closeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="18dp"
|
||||
android:src="@drawable/ic_doc_menu_close"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/iconContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/iconContainer" />
|
||||
|
||||
<View
|
||||
android:id="@+id/badge"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="@drawable/circle_solid_default"
|
||||
android:backgroundTint="@color/white"
|
||||
app:layout_constraintStart_toEndOf="@+id/iconContainer"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
|
||||
tools:background="@drawable/circle_solid_default"
|
||||
tools:backgroundTint="@color/anytype_text_red" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:fontFamily="@font/inter_medium"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/closeButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/iconContainer"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Spaceship Earth" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSubtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:textSize="13sp"
|
||||
android:lineHeight="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/badge"
|
||||
app:layout_constraintStart_toEndOf="@+id/badge"
|
||||
app:layout_constraintTop_toTopOf="@+id/badge"
|
||||
tools:text="Offline" />
|
||||
|
||||
<View
|
||||
android:background="#DFDDD0"
|
||||
android:id="@+id/statusDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iconContainer" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/searchOnPageContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:background="@drawable/rectangle_doc_menu_top"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/statusDivider">
|
||||
|
||||
<TextView
|
||||
style="@style/DocMenuOptionTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/search_on_page" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@drawable/ic_doc_menu_search" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/optionDivider1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/searchOnPageContainer" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/addCoverContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/optionDivider1">
|
||||
|
||||
<TextView
|
||||
style="@style/DocMenuOptionTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="Add cover" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@drawable/ic_doc_menu_doc_style" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/optionDivider2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/addCoverContainer" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/archiveContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/rectangle_doc_menu_bottom"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/optionDivider2">
|
||||
|
||||
<TextView
|
||||
style="@style/DocMenuOptionTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/archive" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@drawable/ic_doc_menu_move_to_bin" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/relationContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/rectangle_doc_menu_default"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/archiveContainer">
|
||||
|
||||
<TextView
|
||||
style="@style/DocMenuOptionTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/relations" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -38,9 +38,6 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
android:value="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -14,7 +14,6 @@ import com.anytypeio.anytype.di.main.ContextModule
|
|||
import com.anytypeio.anytype.di.main.DaggerMainComponent
|
||||
import com.anytypeio.anytype.di.main.MainComponent
|
||||
import com.facebook.stetho.Stetho
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -38,7 +37,6 @@ class AndroidApplication : Application() {
|
|||
super.onCreate()
|
||||
main.inject(this)
|
||||
setupAnalytics()
|
||||
setupCrashlytics()
|
||||
setupEmojiCompat()
|
||||
setupTimber()
|
||||
setupStetho()
|
||||
|
@ -74,11 +72,4 @@ class AndroidApplication : Application() {
|
|||
Amplitude.getInstance().initialize(this, getString(R.string.amplitude_api_key))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCrashlytics() {
|
||||
if (BuildConfig.DEBUG)
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false)
|
||||
else
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.anytypeio.anytype.device
|
||||
|
||||
import com.anytypeio.anytype.domain.common.Id
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.cover.GradientCollectionProvider
|
||||
import com.anytypeio.anytype.presentation.page.cover.CoverGradient
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
package com.anytypeio.anytype.di.common
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.di.feature.*
|
||||
import com.anytypeio.anytype.di.feature.sets.CreateFilterModule
|
||||
import com.anytypeio.anytype.di.feature.sets.ModifyFilterModule
|
||||
import com.anytypeio.anytype.di.feature.sets.PickConditionModule
|
||||
import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationModule
|
||||
import com.anytypeio.anytype.di.main.MainComponent
|
||||
import com.anytypeio.anytype.domain.common.Id
|
||||
|
||||
class ComponentManager(private val main: MainComponent) {
|
||||
|
||||
|
@ -134,15 +138,17 @@ class ComponentManager(private val main: MainComponent) {
|
|||
.build()
|
||||
}
|
||||
|
||||
val documentIconActionMenuComponent = Component {
|
||||
main
|
||||
val documentIconActionMenuComponent = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
.documentActionMenuComponentBuilder()
|
||||
.documentIconActionMenuModule(DocumentIconActionMenuModule())
|
||||
.build()
|
||||
}
|
||||
|
||||
val documentEmojiIconPickerComponent = Component {
|
||||
main
|
||||
val documentEmojiIconPickerComponent = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
.documentEmojiIconPickerComponentBuilder()
|
||||
.documentIconActionMenuModule(DocumentEmojiIconPickerModule())
|
||||
.build()
|
||||
|
@ -180,6 +186,278 @@ class ComponentManager(private val main: MainComponent) {
|
|||
.build()
|
||||
}
|
||||
|
||||
val createSetComponent = Component {
|
||||
main.createSetComponentBuilder()
|
||||
.module(CreateSetModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val createObjectTypeComponent = Component {
|
||||
main.createObjectTypeComponentBuilder()
|
||||
.module(CreateObjectTypeModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectSetComponent = ComponentMap {
|
||||
main.objectSetComponentBuilder()
|
||||
.module(ObjectSetModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val documentRelationComponent = DependentComponentMap { id ->
|
||||
pageComponent
|
||||
.get(id)
|
||||
.documentRelationSubComponent()
|
||||
.module(DocumentRelationModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val viewerSortByComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.viewerSortBySubComponent()
|
||||
.module(ViewerSortByModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val createDataViewRelationComponent = Component {
|
||||
main.createDataViewRelationBuilder()
|
||||
.module(CreateDataViewRelationModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val editGridCellComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.editCellsComponent()
|
||||
.module(EditGridCellModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val editRelationCellComponent = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
.editRelationCellComponent()
|
||||
.module(EditGridCellModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectSetObjectRelationDataValueComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.editCellDateComponent()
|
||||
.module(EditGridCellDateModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectObjectRelationDateValueComponet = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
.editRelationDateComponent()
|
||||
.module(EditGridCellDateModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val documentAddNewBlockComponent = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
.documentAddNewBlockComponentBuilder()
|
||||
.documentAddNewBlockModule(DocumentAddNewBlockModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val viewerFilterComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.viewerFilterBySubComponent()
|
||||
.module(ViewerFilterModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val viewerCustomizeComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.viewerCustomizeSubComponent()
|
||||
.module(ViewerCustomizeModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectSetRecordComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.objectSetRecordComponent()
|
||||
.module(ObjectSetRecordModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val createDataViewViewerComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.createDataViewViewerSubComponent()
|
||||
.module(CreateDataViewViewerModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val editDataViewViewerComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.editDataViewViewerComponent()
|
||||
.module(EditDataViewViewerModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectSetObjectRelationValueComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.objectRelationValueComponent()
|
||||
.module(ObjectRelationValueModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val addObjectSetObjectRelationValueComponent = DependentComponentMap { ctx ->
|
||||
objectSetObjectRelationValueComponent
|
||||
.get(ctx)
|
||||
.addObjectRelationValueComponent()
|
||||
.module(AddObjectRelationValueModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectObjectRelationValueComponent = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
.editDocRelationComponent()
|
||||
.module(ObjectRelationValueModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val addObjectObjectRelationValueComponent = DependentComponentMap { ctx ->
|
||||
objectObjectRelationValueComponent
|
||||
.get(ctx)
|
||||
.addObjectRelationValueComponent()
|
||||
.module(AddObjectRelationValueModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val addObjectSetObjectRelationObjectValueComponent = DependentComponentMap { ctx ->
|
||||
objectSetObjectRelationValueComponent
|
||||
.get(ctx)
|
||||
.addObjectRelationObjectValueComponent()
|
||||
.module(AddObjectRelationObjectValueModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val addObjectRelationObjectValueComponent = DependentComponentMap { ctx ->
|
||||
objectObjectRelationValueComponent
|
||||
.get(ctx)
|
||||
.addObjectRelationObjectValueComponent()
|
||||
.module(AddObjectRelationObjectValueModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val relationFileValueComponent = DependentComponentMap { ctx ->
|
||||
objectObjectRelationValueComponent
|
||||
.get(ctx)
|
||||
.addRelationFileValueAddComponent()
|
||||
.module(RelationFileValueAddModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val relationFileValueDVComponent = DependentComponentMap { ctx ->
|
||||
objectSetObjectRelationValueComponent
|
||||
.get(ctx)
|
||||
.addRelationFileValueAddComponent()
|
||||
.module(RelationFileValueAddModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val manageViewerComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.manageViewerComponent()
|
||||
.module(ManageViewerModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val viewerRelationsComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.viewerRelationsComponent()
|
||||
.module(ViewerRelationsModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val dataviewViewerActionComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.dataviewViewerActionComponent()
|
||||
.module(DataViewViewerActionModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val selectSortRelationComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.selectSortRelationComponent()
|
||||
.module(SelectSortRelationModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val selectFilterRelationComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.selectFilterRelationComponent()
|
||||
.module(SelectFilterRelationModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val createFilterComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.createFilterComponent()
|
||||
.module(CreateFilterModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val pickFilterConditionComponentCreate = DependentComponentMap { ctx ->
|
||||
createFilterComponent
|
||||
.get(ctx)
|
||||
.createPickConditionComponent()
|
||||
.module(PickConditionModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val pickFilterConditionComponentModify = DependentComponentMap { ctx ->
|
||||
modifyFilterComponent
|
||||
.get(ctx)
|
||||
.createPickConditionComponent()
|
||||
.module(PickConditionModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val modifyFilterComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.modifyFilterComponent()
|
||||
.module(ModifyFilterModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val viewerSortComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.viewerSortComponent()
|
||||
.module(ViewerSortModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val modifyViewerSortComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.modifyViewerSortComponent()
|
||||
.module(ModifyViewerSortModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val docCoverGalleryComponent = DependentComponentMap { ctx ->
|
||||
pageComponent
|
||||
.get(ctx)
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
|
||||
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.relations.AddObjectRelationObjectValueViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
|
||||
import com.anytypeio.anytype.ui.relations.AddObjectRelationObjectValueFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [AddObjectRelationObjectValueModule::class])
|
||||
@PerDialog
|
||||
interface AddObjectRelationObjectValueSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: AddObjectRelationObjectValueModule): Builder
|
||||
fun build(): AddObjectRelationObjectValueSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: AddObjectRelationObjectValueFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object AddObjectRelationObjectValueModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideViewModelFactory(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider,
|
||||
searchObjects: SearchObjects,
|
||||
urlBuilder: UrlBuilder
|
||||
): AddObjectRelationObjectValueViewModel.Factory =
|
||||
AddObjectRelationObjectValueViewModel.Factory(
|
||||
relations, values, searchObjects, urlBuilder
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideSearchObjectsUseCase(
|
||||
repo: BlockRepository
|
||||
): SearchObjects = SearchObjects(repo = repo)
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddStatusToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.relations.AddObjectRelationOption
|
||||
import com.anytypeio.anytype.presentation.relations.AddObjectObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.AddObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.relations.AddObjectObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.ui.relations.AddObjectSetObjectRelationValueFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [AddObjectRelationValueModule::class])
|
||||
@PerDialog
|
||||
interface AddObjectRelationValueSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: AddObjectRelationValueModule): Builder
|
||||
fun build(): AddObjectRelationValueSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: AddObjectSetObjectRelationValueFragment)
|
||||
fun inject(fragment: AddObjectObjectRelationValueFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object AddObjectRelationValueModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideViewModelFactoryForSets(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider,
|
||||
details: ObjectDetailProvider,
|
||||
types: ObjectTypeProvider,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
addDataViewRelationOption: AddDataViewRelationOption,
|
||||
addTagToDataViewRecord: AddTagToDataViewRecord,
|
||||
addStatusToDataViewRecord: AddStatusToDataViewRecord,
|
||||
urlBuilder: UrlBuilder
|
||||
): AddObjectSetObjectRelationValueViewModel.Factory = AddObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = relations,
|
||||
values = values,
|
||||
details = details,
|
||||
types = types,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
addDataViewRelationOption = addDataViewRelationOption,
|
||||
addTagToDataViewRecord = addTagToDataViewRecord,
|
||||
addStatusToDataViewRecord = addStatusToDataViewRecord
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideViewModelFactoryForObjects(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider,
|
||||
details: ObjectDetailProvider,
|
||||
types: ObjectTypeProvider,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
addObjectRelationOption: AddObjectRelationOption,
|
||||
updateDetail: UpdateDetail,
|
||||
urlBuilder: UrlBuilder
|
||||
): AddObjectObjectRelationValueViewModel.Factory = AddObjectObjectRelationValueViewModel.Factory(
|
||||
relations = relations,
|
||||
values = values,
|
||||
details = details,
|
||||
types = types,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
addObjectRelationOption = addObjectRelationOption,
|
||||
updateDetail = updateDetail
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideAddObjectRelationOptionUseCase(
|
||||
repo: BlockRepository
|
||||
): AddObjectRelationOption = AddObjectRelationOption(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideAddStatusToDataViewRecordUseCase(
|
||||
repo: BlockRepository
|
||||
): AddStatusToDataViewRecord = AddStatusToDataViewRecord(repo)
|
||||
}
|
|
@ -4,7 +4,7 @@ import com.anytypeio.anytype.analytics.base.Analytics
|
|||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.anytypeio.anytype.domain.page.ArchiveDocument
|
||||
import com.anytypeio.anytype.domain.page.ClosePage
|
||||
import com.anytypeio.anytype.domain.page.CloseBlock
|
||||
import com.anytypeio.anytype.domain.page.OpenPage
|
||||
import com.anytypeio.anytype.presentation.page.DocumentExternalEventReducer
|
||||
import com.anytypeio.anytype.presentation.page.archive.ArchiveViewModelFactory
|
||||
|
@ -42,7 +42,7 @@ object ArchiveModule {
|
|||
@Provides
|
||||
fun provideArchiveViewModelFactory(
|
||||
openPage: OpenPage,
|
||||
closePage: ClosePage,
|
||||
closePage: CloseBlock,
|
||||
archiveDocument: ArchiveDocument,
|
||||
interceptEvents: InterceptEvents,
|
||||
renderer: DefaultBlockViewRenderer,
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.presentation.relations.CreateDataViewRelationViewModelFactory
|
||||
import com.anytypeio.anytype.ui.relations.CreateDataViewRelationFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [CreateDataViewRelationModule::class])
|
||||
@PerScreen
|
||||
interface CreateDataViewRelationSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: CreateDataViewRelationModule): Builder
|
||||
fun build(): CreateDataViewRelationSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: CreateDataViewRelationFragment)
|
||||
|
||||
}
|
||||
|
||||
@Module
|
||||
object CreateDataViewRelationModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateDVRelationViewModelFactory() = CreateDataViewRelationViewModelFactory()
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.sets.CreateDataViewViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.CreateDataViewViewerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [CreateDataViewViewerModule::class])
|
||||
@PerModal
|
||||
interface CreateDataViewViewerSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: CreateDataViewViewerModule): Builder
|
||||
fun build(): CreateDataViewViewerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: CreateDataViewViewerFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object CreateDataViewViewerModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideCreateDataViewViewerViewModelFactory(
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
addDataViewViewer: AddDataViewViewer
|
||||
): CreateDataViewViewerViewModel.Factory = CreateDataViewViewerViewModel.Factory(
|
||||
dispatcher = dispatcher,
|
||||
addDataViewViewer = addDataViewViewer
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideAddDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): AddDataViewViewer = AddDataViewViewer(repo = repo)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.CreateObjectSet
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.CreateObjectType
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.icon.DocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.presentation.sets.CreateObjectSetViewModel
|
||||
import com.anytypeio.anytype.ui.sets.CreateObjectSetFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [CreateSetModule::class])
|
||||
@PerScreen
|
||||
interface CreateSetSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: CreateSetModule): Builder
|
||||
fun build(): CreateSetSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: CreateObjectSetFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object CreateSetModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateSetViewModelFactory(
|
||||
getObjectTypes: GetObjectTypes,
|
||||
createObjectSet: CreateObjectSet,
|
||||
createObjectType: CreateObjectType
|
||||
): CreateObjectSetViewModel.Factory {
|
||||
return CreateObjectSetViewModel.Factory(
|
||||
getObjectTypes = getObjectTypes,
|
||||
createObjectSet = createObjectSet,
|
||||
createObjectType = createObjectType
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateObjectTypeUseCase(
|
||||
repo: BlockRepository,
|
||||
documentEmojiProvider: DocumentEmojiIconProvider
|
||||
): CreateObjectType = CreateObjectType(
|
||||
repo = repo,
|
||||
documentEmojiProvider = documentEmojiProvider
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideGetObjectTypesUseCase(
|
||||
repo: BlockRepository
|
||||
): GetObjectTypes = GetObjectTypes(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateObjectSetUseCase(
|
||||
repo: BlockRepository
|
||||
): CreateObjectSet = CreateObjectSet(repo = repo)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.CreateObjectTypeViewModel
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.ui.sets.CreateObjectTypeFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [CreateObjectTypeModule::class])
|
||||
@PerScreen
|
||||
interface CreateObjectTypeSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: CreateObjectTypeModule): Builder
|
||||
fun build(): CreateObjectTypeSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: CreateObjectTypeFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object CreateObjectTypeModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateObjectTypeViewModelFactory(
|
||||
): CreateObjectTypeViewModel.Factory {
|
||||
return CreateObjectTypeViewModel.Factory()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DuplicateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RenameDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.sets.DataViewViewerActionViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.DataViewViewerActionFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [DataViewViewerActionModule::class])
|
||||
@PerModal
|
||||
interface DataViewViewerActionSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: DataViewViewerActionModule): Builder
|
||||
fun build(): DataViewViewerActionSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: DataViewViewerActionFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object DataViewViewerActionModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideEditDataViewViewerViewModelFactory(
|
||||
duplicateDataViewViewer: DuplicateDataViewViewer,
|
||||
deleteDataViewViewer: DeleteDataViewViewer,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
objectSetState: StateFlow<ObjectSet>
|
||||
): DataViewViewerActionViewModel.Factory = DataViewViewerActionViewModel.Factory(
|
||||
duplicateDataViewViewer = duplicateDataViewViewer,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
objectSetState = objectSetState
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideRenameDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): RenameDataViewViewer = RenameDataViewViewer(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideDuplicateDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): DuplicateDataViewViewer = DuplicateDataViewViewer(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideDeleteDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): DeleteDataViewViewer = DeleteDataViewViewer(repo = repo)
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.GetDebugSettings
|
||||
import com.anytypeio.anytype.domain.config.InfrastructureRepository
|
||||
import com.anytypeio.anytype.domain.config.UseCustomContextMenu
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DebugSync
|
||||
import com.anytypeio.anytype.ui.settings.DebugSettingsFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
@ -37,4 +39,8 @@ class DebugSettingsModule {
|
|||
): GetDebugSettings = GetDebugSettings(
|
||||
repo = repo
|
||||
)
|
||||
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDebugSync(repo: BlockRepository) : DebugSync = DebugSync(repo = repo)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.presentation.page.picker.DocumentAddBlockViewModelFactory
|
||||
import com.anytypeio.anytype.ui.page.modals.AddBlockFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [DocumentAddNewBlockModule::class])
|
||||
@PerModal
|
||||
interface DocumentAddNewBlockSubComponent{
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun documentAddNewBlockModule(module: DocumentAddNewBlockModule): Builder
|
||||
fun build(): DocumentAddNewBlockSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: AddBlockFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object DocumentAddNewBlockModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideGetObjectTypesUseCase(
|
||||
repo: BlockRepository
|
||||
): GetObjectTypes = GetObjectTypes(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideFactory(getObjectTypes: GetObjectTypes): DocumentAddBlockViewModelFactory =
|
||||
DocumentAddBlockViewModelFactory(getObjectTypes)
|
||||
}
|
|
@ -1,20 +1,21 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.domain.icon.SetDocumentEmojiIcon
|
||||
import com.anytypeio.anytype.emojifier.data.Emoji
|
||||
import com.anytypeio.anytype.emojifier.suggest.EmojiSuggester
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.picker.DocumentEmojiIconPickerViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.util.Bridge
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.page.modals.DocumentEmojiIconPickerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [DocumentEmojiIconPickerModule::class])
|
||||
@PerScreen
|
||||
@PerModal
|
||||
interface DocumentEmojiIconPickerSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
@ -30,20 +31,22 @@ interface DocumentEmojiIconPickerSubComponent {
|
|||
class DocumentEmojiIconPickerModule {
|
||||
|
||||
@Provides
|
||||
@PerScreen
|
||||
@PerModal
|
||||
fun provideDocumentEmojiIconPickerViewModel(
|
||||
setEmojiIcon: SetDocumentEmojiIcon,
|
||||
emojiSuggester: EmojiSuggester,
|
||||
bridge: Bridge<Payload>
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
details: DetailModificationManager
|
||||
): DocumentEmojiIconPickerViewModelFactory = DocumentEmojiIconPickerViewModelFactory(
|
||||
setEmojiIcon = setEmojiIcon,
|
||||
emojiSuggester = emojiSuggester,
|
||||
emojiProvider = Emoji,
|
||||
bridge = bridge
|
||||
dispatcher = dispatcher,
|
||||
details = details
|
||||
)
|
||||
|
||||
@Provides
|
||||
@PerScreen
|
||||
@PerModal
|
||||
fun provideSetDocumentEmojiIconUseCase(
|
||||
repo: BlockRepository
|
||||
): SetDocumentEmojiIcon = SetDocumentEmojiIcon(
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.domain.icon.SetDocumentEmojiIcon
|
||||
import com.anytypeio.anytype.domain.icon.SetDocumentImageIcon
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.picker.DocumentIconActionMenuViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.util.Bridge
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.page.modals.actions.DocumentIconActionMenuFragment
|
||||
import com.anytypeio.anytype.ui.page.modals.actions.ProfileIconActionMenuFragment
|
||||
import dagger.Module
|
||||
|
@ -14,7 +15,7 @@ import dagger.Provides
|
|||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [DocumentIconActionMenuModule::class])
|
||||
@PerScreen
|
||||
@PerModal
|
||||
interface DocumentActionMenuSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
|
@ -31,19 +32,21 @@ interface DocumentActionMenuSubComponent {
|
|||
class DocumentIconActionMenuModule {
|
||||
|
||||
@Provides
|
||||
@PerScreen
|
||||
@PerModal
|
||||
fun provideDocumentIconActionMenuViewModelFactory(
|
||||
setEmojiIcon: SetDocumentEmojiIcon,
|
||||
setImageIcon: SetDocumentImageIcon,
|
||||
bridge: Bridge<Payload>
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
details: DetailModificationManager
|
||||
): DocumentIconActionMenuViewModelFactory = DocumentIconActionMenuViewModelFactory(
|
||||
setEmojiIcon = setEmojiIcon,
|
||||
setImageIcon = setImageIcon,
|
||||
bridge = bridge
|
||||
dispatcher = dispatcher,
|
||||
details = details
|
||||
)
|
||||
|
||||
@Provides
|
||||
@PerScreen
|
||||
@PerModal
|
||||
fun provideSetDocumentEmojiIconUseCase(
|
||||
repo: BlockRepository
|
||||
): SetDocumentEmojiIcon = SetDocumentEmojiIcon(
|
||||
|
@ -51,7 +54,7 @@ class DocumentIconActionMenuModule {
|
|||
)
|
||||
|
||||
@Provides
|
||||
@PerScreen
|
||||
@PerModal
|
||||
fun provideSetDocumentImageIconUseCase(
|
||||
repo: BlockRepository
|
||||
): SetDocumentImageIcon = SetDocumentImageIcon(
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RenameDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.sets.EditDataViewViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.EditDataViewViewerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [EditDataViewViewerModule::class])
|
||||
@PerModal
|
||||
interface EditDataViewViewerSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: EditDataViewViewerModule): Builder
|
||||
fun build(): EditDataViewViewerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: EditDataViewViewerFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object EditDataViewViewerModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideEditDataViewViewerViewModelFactory(
|
||||
renameDataViewViewer: RenameDataViewViewer,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
objectSetState: StateFlow<ObjectSet>
|
||||
): EditDataViewViewerViewModel.Factory = EditDataViewViewerViewModel.Factory(
|
||||
renameDataViewViewer = renameDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
objectSetState = objectSetState
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideRenameDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): RenameDataViewViewer = RenameDataViewViewer(repo = repo)
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectRelationDateValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectRelationTextValueViewModel
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationDateValueFragment
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationTextValueFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [EditGridCellModule::class])
|
||||
@PerModal
|
||||
interface EditGridCellSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: EditGridCellModule): Builder
|
||||
fun build(): EditGridCellSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ObjectRelationTextValueFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object EditGridCellModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideEditGridCellViewModelFactory(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider
|
||||
) = ObjectRelationTextValueViewModel.Factory(relations, values)
|
||||
}
|
||||
|
||||
@Subcomponent(modules = [EditGridCellDateModule::class])
|
||||
@PerModal
|
||||
interface EditGridCellDateSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: EditGridCellDateModule): Builder
|
||||
fun build(): EditGridCellDateSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ObjectRelationDateValueFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object EditGridCellDateModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideEditGridCellViewModelFactory(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider
|
||||
) = ObjectRelationDateValueViewModel.Factory(relations, values)
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetActiveViewer
|
||||
import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.ManageViewerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [ManageViewerModule::class])
|
||||
@PerModal
|
||||
interface ManageViewerSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ManageViewerModule): Builder
|
||||
fun build(): ManageViewerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ManageViewerFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ManageViewerModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideManageViewerViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
setActiveViewer: SetActiveViewer
|
||||
): ManageViewerViewModel.Factory = ManageViewerViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
setActiveViewer = setActiveViewer
|
||||
)
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.sort.ModifyViewerSortViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.sort.ModifyViewerSortFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [ModifyViewerSortModule::class])
|
||||
@PerModal
|
||||
interface ModifyViewerSortSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ModifyViewerSortModule): Builder
|
||||
fun build(): ModifyViewerSortSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ModifyViewerSortFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ModifyViewerSortModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDataViewViewer: UpdateDataViewViewer
|
||||
): ModifyViewerSortViewModel.Factory = ModifyViewerSortViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewViewer = updateDataViewViewer
|
||||
)
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.ObjectRelationList
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.page.Editor
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationListViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [DocumentRelationModule::class])
|
||||
@PerModal
|
||||
interface DocumentRelationSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: DocumentRelationModule): Builder
|
||||
fun build(): DocumentRelationSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ObjectRelationListFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object DocumentRelationModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideObjectRelationViewModelFactory(
|
||||
stores: Editor.Storage,
|
||||
urlBuilder: UrlBuilder,
|
||||
objectRelationList: ObjectRelationList,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDetail: UpdateDetail,
|
||||
detailModificationManager: DetailModificationManager
|
||||
): ObjectRelationListViewModelFactory {
|
||||
return ObjectRelationListViewModelFactory(
|
||||
stores = stores,
|
||||
urlBuilder = urlBuilder,
|
||||
objectRelationList = objectRelationList,
|
||||
dispatcher = dispatcher,
|
||||
updateDetail = updateDetail,
|
||||
detailModificationManager = detailModificationManager
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideObjectRelationListUseCase(
|
||||
repository: BlockRepository
|
||||
) : ObjectRelationList = ObjectRelationList(repository)
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewRelationOption
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddTagToDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RemoveTagFromDataViewRecord
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewRecord
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectTypeProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetObjectRelationValueViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectObjectRelationValueFragment
|
||||
import com.anytypeio.anytype.ui.database.modals.ObjectSetObjectRelationValueFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [ObjectRelationValueModule::class, ObjectSetObjectRelationValueModule::class])
|
||||
@PerModal
|
||||
interface ObjectSetObjectRelationValueSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ObjectRelationValueModule): Builder
|
||||
fun build(): ObjectSetObjectRelationValueSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ObjectSetObjectRelationValueFragment)
|
||||
|
||||
fun addObjectRelationValueComponent(): AddObjectRelationValueSubComponent.Builder
|
||||
fun addObjectRelationObjectValueComponent(): AddObjectRelationObjectValueSubComponent.Builder
|
||||
fun addRelationFileValueAddComponent() : RelationFileValueAddSubComponent.Builder
|
||||
}
|
||||
|
||||
@Subcomponent(modules = [ObjectRelationValueModule::class, ObjectObjectRelationValueModule::class])
|
||||
@PerModal
|
||||
interface ObjectObjectRelationValueSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ObjectRelationValueModule): Builder
|
||||
fun build(): ObjectObjectRelationValueSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ObjectObjectRelationValueFragment)
|
||||
|
||||
fun addObjectRelationValueComponent(): AddObjectRelationValueSubComponent.Builder
|
||||
fun addObjectRelationObjectValueComponent(): AddObjectRelationObjectValueSubComponent.Builder
|
||||
fun addRelationFileValueAddComponent() : RelationFileValueAddSubComponent.Builder
|
||||
}
|
||||
|
||||
@Module
|
||||
object ObjectRelationValueModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideAddRelationOptionUseCase(
|
||||
repo: BlockRepository
|
||||
): AddDataViewRelationOption = AddDataViewRelationOption(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideAddTagToDataViewRecordUseCase(
|
||||
repo: BlockRepository
|
||||
): AddTagToDataViewRecord = AddTagToDataViewRecord(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideRemoveTagFromDataViewRecordUseCase(
|
||||
repo: BlockRepository
|
||||
): RemoveTagFromDataViewRecord = RemoveTagFromDataViewRecord(repo = repo)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ObjectSetObjectRelationValueModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewModelFactoryForDataView(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider,
|
||||
details: ObjectDetailProvider,
|
||||
types: ObjectTypeProvider,
|
||||
removeTagFromDataViewRecord: RemoveTagFromDataViewRecord,
|
||||
urlBuilder: UrlBuilder,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDataViewRecord: UpdateDataViewRecord
|
||||
): ObjectSetObjectRelationValueViewModel.Factory = ObjectSetObjectRelationValueViewModel.Factory(
|
||||
relations = relations,
|
||||
values = values,
|
||||
details = details,
|
||||
types = types,
|
||||
removeTagFromRecord = removeTagFromDataViewRecord,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewRecord = updateDataViewRecord
|
||||
)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ObjectObjectRelationValueModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewModelFactoryForObject(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider,
|
||||
details: ObjectDetailProvider,
|
||||
types: ObjectTypeProvider,
|
||||
urlBuilder: UrlBuilder,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDetail: UpdateDetail,
|
||||
): ObjectObjectRelationValueViewModel.Factory = ObjectObjectRelationValueViewModel.Factory(
|
||||
relations = relations,
|
||||
values = values,
|
||||
details = details,
|
||||
types = types,
|
||||
urlBuilder = urlBuilder,
|
||||
dispatcher = dispatcher,
|
||||
updateDetail = updateDetail
|
||||
)
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.di.feature.sets.CreateFilterSubComponent
|
||||
import com.anytypeio.anytype.di.feature.sets.ModifyFilterSubComponent
|
||||
import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationSubComponent
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateText
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.*
|
||||
import com.anytypeio.anytype.domain.event.interactor.EventChannel
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.page.CloseBlock
|
||||
import com.anytypeio.anytype.domain.sets.OpenObjectSet
|
||||
import com.anytypeio.anytype.presentation.relations.providers.*
|
||||
import com.anytypeio.anytype.presentation.sets.*
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [ObjectSetModule::class])
|
||||
@PerScreen
|
||||
interface ObjectSetSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ObjectSetModule): Builder
|
||||
fun build(): ObjectSetSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ObjectSetFragment)
|
||||
|
||||
fun objectSetRecordComponent(): ObjectSetRecordSubComponent.Builder
|
||||
fun viewerCustomizeSubComponent(): ViewerCustomizeSubComponent.Builder
|
||||
fun viewerSortBySubComponent(): ViewerSortBySubComponent.Builder
|
||||
fun viewerFilterBySubComponent(): ViewerFilterSubComponent.Builder
|
||||
fun createDataViewViewerSubComponent(): CreateDataViewViewerSubComponent.Builder
|
||||
fun editDataViewViewerComponent(): EditDataViewViewerSubComponent.Builder
|
||||
fun objectRelationValueComponent(): ObjectSetObjectRelationValueSubComponent.Builder
|
||||
fun manageViewerComponent(): ManageViewerSubComponent.Builder
|
||||
fun viewerRelationsComponent(): ViewerRelationsSubComponent.Builder
|
||||
fun dataviewViewerActionComponent(): DataViewViewerActionSubComponent.Builder
|
||||
fun selectSortRelationComponent(): SelectSortRelationSubComponent.Builder
|
||||
fun selectFilterRelationComponent(): SelectFilterRelationSubComponent.Builder
|
||||
fun createFilterComponent(): CreateFilterSubComponent.Builder
|
||||
fun modifyFilterComponent(): ModifyFilterSubComponent.Builder
|
||||
fun viewerSortComponent(): ViewerSortSubComponent.Builder
|
||||
fun modifyViewerSortComponent(): ModifyViewerSortSubComponent.Builder
|
||||
fun editCellsComponent(): EditGridCellSubComponent.Builder
|
||||
fun editCellDateComponent(): EditGridCellDateSubComponent.Builder
|
||||
}
|
||||
|
||||
@Module
|
||||
object ObjectSetModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectSetViewModelFactory(
|
||||
openObjectSet: OpenObjectSet,
|
||||
closeBlock: CloseBlock,
|
||||
setActiveViewer: SetActiveViewer,
|
||||
addDataViewRelation: AddDataViewRelation,
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
updateDataViewRecord: UpdateDataViewRecord,
|
||||
updateText: UpdateText,
|
||||
interceptEvents: InterceptEvents,
|
||||
createDataViewRecord: CreateDataViewRecord,
|
||||
reducer: ObjectSetReducer,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
objectSetRecordCache: ObjectSetRecordCache,
|
||||
urlBuilder: UrlBuilder,
|
||||
session: ObjectSetSession
|
||||
): ObjectSetViewModelFactory = ObjectSetViewModelFactory(
|
||||
openObjectSet = openObjectSet,
|
||||
closeBlock = closeBlock,
|
||||
setActiveViewer = setActiveViewer,
|
||||
addDataViewRelation = addDataViewRelation,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
updateDataViewRecord = updateDataViewRecord,
|
||||
createDataViewRecord = createDataViewRecord,
|
||||
updateText = updateText,
|
||||
interceptEvents = interceptEvents,
|
||||
reducer = reducer,
|
||||
dispatcher = dispatcher,
|
||||
objectSetRecordCache = objectSetRecordCache,
|
||||
urlBuilder = urlBuilder,
|
||||
session = session
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideOpenObjectSetUseCase(repo: BlockRepository): OpenObjectSet = OpenObjectSet(repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideSetActiveViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): SetActiveViewer = SetActiveViewer(repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideAddDataViewRelationUseCase(
|
||||
repo: BlockRepository
|
||||
): AddDataViewRelation = AddDataViewRelation(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideUpdateDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): UpdateDataViewViewer = UpdateDataViewViewer(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateDataViewRecordUseCase(
|
||||
repo: BlockRepository
|
||||
): CreateDataViewRecord = CreateDataViewRecord(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideUpdateDataViewRecordUseCase(
|
||||
repo: BlockRepository
|
||||
): UpdateDataViewRecord = UpdateDataViewRecord(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideUpdateTextUseCase(
|
||||
repo: BlockRepository
|
||||
): UpdateText = UpdateText(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideInterceptEventsUseCase(
|
||||
channel: EventChannel
|
||||
): InterceptEvents = InterceptEvents(
|
||||
channel = channel,
|
||||
context = Dispatchers.IO
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCloseBlockUseCase(
|
||||
repo: BlockRepository
|
||||
): CloseBlock = CloseBlock(repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectSetReducer(): ObjectSetReducer = ObjectSetReducer()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideState(
|
||||
reducer: ObjectSetReducer
|
||||
): StateFlow<ObjectSet> = reducer.state
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectSetSession(): ObjectSetSession = ObjectSetSession()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDispatcher(): Dispatcher<Payload> = Dispatcher.Default()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectSetRecordCache(): ObjectSetRecordCache = ObjectSetRecordCache()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDataViewObjectRelationProvider(
|
||||
state: StateFlow<ObjectSet>
|
||||
) : ObjectRelationProvider = DataViewObjectRelationProvider(state)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDataViewObjectValueProvider(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession
|
||||
) : ObjectValueProvider = DataViewObjectValueProvider(state, session)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectTypeProvider(
|
||||
state: StateFlow<ObjectSet>,
|
||||
) : ObjectTypeProvider = object : ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectDetailProvider(
|
||||
state: StateFlow<ObjectSet>,
|
||||
) : ObjectDetailProvider = object : ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideUpdateDetailUseCase(
|
||||
repository: BlockRepository
|
||||
) : UpdateDetail = UpdateDetail(repository)
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewRecord
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetRecordCache
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetRecordViewModel
|
||||
import com.anytypeio.anytype.ui.sets.SetObjectSetRecordNameFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Scope
|
||||
|
||||
@Subcomponent(modules = [ObjectSetRecordModule::class])
|
||||
@ObjectSetRecordScope
|
||||
interface ObjectSetRecordSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ObjectSetRecordModule): Builder
|
||||
fun build(): ObjectSetRecordSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: SetObjectSetRecordNameFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ObjectSetRecordModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@ObjectSetRecordScope
|
||||
fun provideObjectSetRecordViewModelFactory(
|
||||
updateDataViewRecord: UpdateDataViewRecord,
|
||||
objectSetState: StateFlow<ObjectSet>,
|
||||
objectSetRecordCache: ObjectSetRecordCache
|
||||
): ObjectSetRecordViewModel.Factory = ObjectSetRecordViewModel.Factory(
|
||||
objectSetState = objectSetState,
|
||||
objectSetRecordCache = objectSetRecordCache,
|
||||
updateDataViewRecord = updateDataViewRecord
|
||||
)
|
||||
}
|
||||
|
||||
@Scope
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ObjectSetRecordScope
|
|
@ -1,8 +1,13 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.core_utils.tools.Counter
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.*
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
@ -11,11 +16,11 @@ import com.anytypeio.anytype.domain.clipboard.Copy
|
|||
import com.anytypeio.anytype.domain.clipboard.Paste
|
||||
import com.anytypeio.anytype.domain.cover.RemoveDocCover
|
||||
import com.anytypeio.anytype.domain.cover.SetDocCoverImage
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetRelationKey
|
||||
import com.anytypeio.anytype.domain.download.DownloadFile
|
||||
import com.anytypeio.anytype.domain.download.Downloader
|
||||
import com.anytypeio.anytype.domain.event.interactor.EventChannel
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.domain.icon.DocumentEmojiIconProvider
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.page.*
|
||||
|
@ -27,13 +32,16 @@ import com.anytypeio.anytype.presentation.page.DocumentExternalEventReducer
|
|||
import com.anytypeio.anytype.presentation.page.Editor
|
||||
import com.anytypeio.anytype.presentation.page.PageViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.page.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.editor.Interactor
|
||||
import com.anytypeio.anytype.presentation.page.editor.InternalDetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.page.editor.Orchestrator
|
||||
import com.anytypeio.anytype.presentation.page.editor.pattern.DefaultPatternMatcher
|
||||
import com.anytypeio.anytype.presentation.page.render.DefaultBlockViewRenderer
|
||||
import com.anytypeio.anytype.presentation.page.selection.SelectionStateHolder
|
||||
import com.anytypeio.anytype.presentation.page.toggle.ToggleStateHolder
|
||||
import com.anytypeio.anytype.presentation.util.Bridge
|
||||
import com.anytypeio.anytype.presentation.relations.providers.*
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.providers.DefaultCoverImageHashProvider
|
||||
import com.anytypeio.anytype.ui.page.PageFragment
|
||||
import dagger.Module
|
||||
|
@ -54,16 +62,26 @@ interface PageSubComponent {
|
|||
|
||||
fun inject(fragment: PageFragment)
|
||||
|
||||
fun documentEmojiIconPickerComponentBuilder(): DocumentEmojiIconPickerSubComponent.Builder
|
||||
fun documentActionMenuComponentBuilder(): DocumentActionMenuSubComponent.Builder
|
||||
|
||||
fun documentRelationSubComponent(): DocumentRelationSubComponent.Builder
|
||||
fun editRelationCellComponent(): EditGridCellSubComponent.Builder
|
||||
fun editDocRelationComponent() : ObjectObjectRelationValueSubComponent.Builder
|
||||
fun editRelationDateComponent(): EditGridCellDateSubComponent.Builder
|
||||
|
||||
fun docCoverGalleryComponentBuilder(): SelectDocCoverSubComponent.Builder
|
||||
fun uploadDocCoverImageComponentBuilder(): UploadDocCoverImageSubComponent.Builder
|
||||
|
||||
fun documentAddNewBlockComponentBuilder(): DocumentAddNewBlockSubComponent.Builder
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sesssion-related dependencies, session being defined as active work with a document visible to our user.
|
||||
* Session-related dependencies, session being defined as active work with a document visible to our user.
|
||||
* Hence, these dependencies are stateful and therefore should not be shared between different sessions of the same document.
|
||||
* Consider the following navigation scenario: Document A > Document B > Document A'.
|
||||
* In this case, statetul dependencies should not be shared between A and A'.
|
||||
* In this case, stateful dependencies should not be shared between A and A'.
|
||||
*/
|
||||
@Module
|
||||
object EditorSessionModule {
|
||||
|
@ -82,19 +100,21 @@ object EditorSessionModule {
|
|||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideStorage(): Editor.Storage = Editor.Storage()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
fun providePageViewModelFactory(
|
||||
openPage: OpenPage,
|
||||
closePage: ClosePage,
|
||||
closePage: CloseBlock,
|
||||
interceptEvents: InterceptEvents,
|
||||
interceptThreadStatus: InterceptThreadStatus,
|
||||
updateLinkMarks: UpdateLinkMarks,
|
||||
removeLinkMark: RemoveLinkMark,
|
||||
createPage: CreatePage,
|
||||
createDocument: CreateDocument,
|
||||
createObject: CreateObject,
|
||||
createNewDocument: CreateNewDocument,
|
||||
documentExternalEventReducer: DocumentExternalEventReducer,
|
||||
setDocCoverImage: SetDocCoverImage,
|
||||
|
@ -105,12 +125,15 @@ object EditorSessionModule {
|
|||
orchestrator: Orchestrator,
|
||||
getListPages: GetListPages,
|
||||
analytics: Analytics,
|
||||
bridge: Bridge<Payload>
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
detailModificationManager: DetailModificationManager,
|
||||
updateDetail: UpdateDetail
|
||||
): PageViewModelFactory = PageViewModelFactory(
|
||||
openPage = openPage,
|
||||
closePage = closePage,
|
||||
createPage = createPage,
|
||||
createDocument = createDocument,
|
||||
createObject = createObject,
|
||||
createNewDocument = createNewDocument,
|
||||
interceptEvents = interceptEvents,
|
||||
interceptThreadStatus = interceptThreadStatus,
|
||||
|
@ -125,7 +148,9 @@ object EditorSessionModule {
|
|||
orchestrator = orchestrator,
|
||||
getListPages = getListPages,
|
||||
analytics = analytics,
|
||||
bridge = bridge
|
||||
dispatcher = dispatcher,
|
||||
detailModificationManager = detailModificationManager,
|
||||
updateDetail = updateDetail
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
@ -198,6 +223,7 @@ object EditorSessionModule {
|
|||
paste: Paste,
|
||||
undo: Undo,
|
||||
redo: Redo,
|
||||
setRelationKey: SetRelationKey,
|
||||
analytics: Analytics
|
||||
): Orchestrator = Orchestrator(
|
||||
stores = storage,
|
||||
|
@ -231,6 +257,7 @@ object EditorSessionModule {
|
|||
move = move,
|
||||
paste = paste,
|
||||
copy = copy,
|
||||
setRelationKey = setRelationKey,
|
||||
analytics = analytics,
|
||||
updateFields = updateFields,
|
||||
turnIntoStyle = turnInto
|
||||
|
@ -265,7 +292,7 @@ object EditorUseCaseModule {
|
|||
@PerScreen
|
||||
fun provideClosePageUseCase(
|
||||
repo: BlockRepository
|
||||
): ClosePage = ClosePage(
|
||||
): CloseBlock = CloseBlock(
|
||||
repo = repo
|
||||
)
|
||||
|
||||
|
@ -361,6 +388,15 @@ object EditorUseCaseModule {
|
|||
repo = repo
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideSetRelationKeyUseCase(
|
||||
repo: BlockRepository
|
||||
): SetRelationKey = SetRelationKey(
|
||||
repo = repo
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
|
@ -457,6 +493,17 @@ object EditorUseCaseModule {
|
|||
documentEmojiProvider = documentEmojiIconProvider
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideCreateObjectUseCase(
|
||||
repo: BlockRepository,
|
||||
documentEmojiIconProvider: DocumentEmojiIconProvider
|
||||
): CreateObject = CreateObject(
|
||||
repo = repo,
|
||||
documentEmojiProvider = documentEmojiIconProvider
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
|
@ -562,6 +609,52 @@ object EditorUseCaseModule {
|
|||
repo: BlockRepository
|
||||
): UpdateFields = UpdateFields(repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDefaultObjectRelationProvider(
|
||||
storage: Editor.Storage
|
||||
) : ObjectRelationProvider = DefaultObjectRelationProvider(storage.relations)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDefaultObjectValueProvider(
|
||||
storage: Editor.Storage
|
||||
) : ObjectValueProvider = DefaultObjectValueProvider(storage.details)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectTypeProvider(
|
||||
storage: Editor.Storage
|
||||
) : ObjectTypeProvider = object : ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = storage.objectTypes.current()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectDetailProvider(
|
||||
storage: Editor.Storage
|
||||
) : ObjectDetailProvider = object : ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = storage.details.current().details
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun providePayloadDispatcher() : Dispatcher<Payload> = Dispatcher.Default()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDetailManager(
|
||||
storage: Editor.Storage
|
||||
) : DetailModificationManager = InternalDetailModificationManager(
|
||||
store = storage.details
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
|
@ -580,4 +673,11 @@ object EditorUseCaseModule {
|
|||
@Provides
|
||||
@PerScreen
|
||||
fun provideTurnIntoUseCase(repo: BlockRepository): TurnIntoStyle = TurnIntoStyle(repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideUpdateDetailUseCase(
|
||||
repository: BlockRepository
|
||||
) : UpdateDetail = UpdateDetail(repository)
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
|
||||
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.relations.RelationFileValueAddViewModel
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
|
||||
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
|
||||
import com.anytypeio.anytype.ui.relations.RelationFileValueAddFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [RelationFileValueAddModule::class])
|
||||
@PerDialog
|
||||
interface RelationFileValueAddSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: RelationFileValueAddModule): Builder
|
||||
fun build(): RelationFileValueAddSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: RelationFileValueAddFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object RelationFileValueAddModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideViewModelFactory(
|
||||
relations: ObjectRelationProvider,
|
||||
values: ObjectValueProvider,
|
||||
searchObjects: SearchObjects,
|
||||
urlBuilder: UrlBuilder
|
||||
): RelationFileValueAddViewModel.Factory =
|
||||
RelationFileValueAddViewModel.Factory(
|
||||
relations, values, searchObjects, urlBuilder
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideSearchObjectsUseCase(
|
||||
repo: BlockRepository
|
||||
): SearchObjects = SearchObjects(repo = repo)
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import android.content.Context
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.device.DefaultGradientCollectionProvider
|
||||
import com.anytypeio.anytype.device.DeviceCoverCollectionProvider
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.cover.*
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.page.cover.SelectDocCoverViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Bridge
|
||||
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.page.cover.DocCoverGalleryFragment
|
||||
import com.google.gson.Gson
|
||||
import dagger.Module
|
||||
|
@ -37,17 +38,19 @@ object SelectDocCoverModule {
|
|||
fun provideSelectDocCoverViewModelFactory(
|
||||
setDocCoverColor: SetDocCoverColor,
|
||||
setDocCoverGradient: SetDocCoverGradient,
|
||||
payloadDispatcher: Bridge<Payload>,
|
||||
payloadDispatcher: Dispatcher<Payload>,
|
||||
getCoverCollection: GetCoverImageCollection,
|
||||
getCoverGradientCollection: GetCoverGradientCollection,
|
||||
urlBuilder: UrlBuilder
|
||||
urlBuilder: UrlBuilder,
|
||||
detailModificationManager: DetailModificationManager
|
||||
): SelectDocCoverViewModel.Factory = SelectDocCoverViewModel.Factory(
|
||||
setDocCoverColor = setDocCoverColor,
|
||||
setDocCoverGradient = setDocCoverGradient,
|
||||
payloadDispatcher = payloadDispatcher,
|
||||
dispatcher = payloadDispatcher,
|
||||
getCoverCollection = getCoverCollection,
|
||||
getCoverGradientCollection = getCoverGradientCollection,
|
||||
urlBuilder = urlBuilder
|
||||
urlBuilder = urlBuilder,
|
||||
details = detailModificationManager
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewViewerSort
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.SelectSortRelationViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.sort.SelectSortRelationFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [SelectSortRelationModule::class])
|
||||
@PerModal
|
||||
interface SelectSortRelationSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: SelectSortRelationModule): Builder
|
||||
fun build(): SelectSortRelationSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: SelectSortRelationFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object SelectSortRelationModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideSelectSortRelationViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
addDataViewViewerSort: AddDataViewViewerSort
|
||||
): SelectSortRelationViewModel.Factory = SelectSortRelationViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
addDataViewViewerSort = addDataViewViewerSort
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideAddDataViewViewerSort(
|
||||
repo: BlockRepository
|
||||
): AddDataViewViewerSort = AddDataViewViewerSort(repo = repo)
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.cover.SetDocCoverImage
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.presentation.page.cover.UploadDocCoverImageViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Bridge
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.page.cover.UploadCoverImageFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
@ -31,7 +31,7 @@ object UploadDocCoverImageModule {
|
|||
@PerModal
|
||||
fun provideViewModelFactory(
|
||||
setDocCoverImage: SetDocCoverImage,
|
||||
payloadDispatcher: Bridge<Payload>,
|
||||
payloadDispatcher: Dispatcher<Payload>,
|
||||
): UploadDocCoverImageViewModel.Factory = UploadDocCoverImageViewModel.Factory(
|
||||
setDocCoverImage = setDocCoverImage,
|
||||
payloadDispatcher = payloadDispatcher
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerCustomizeViewModel
|
||||
import com.anytypeio.anytype.ui.sets.modals.ViewerCustomizeFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Scope
|
||||
|
||||
@Subcomponent(modules = [ViewerCustomizeModule::class])
|
||||
@ViewerCustomizeScope
|
||||
interface ViewerCustomizeSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ViewerCustomizeModule): Builder
|
||||
fun build(): ViewerCustomizeSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ViewerCustomizeFragment)
|
||||
|
||||
}
|
||||
|
||||
@Module
|
||||
object ViewerCustomizeModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@ViewerCustomizeScope
|
||||
fun provideViewerCustomizeViewModelFactory(
|
||||
state: StateFlow<ObjectSet>
|
||||
): ViewerCustomizeViewModel.Factory = ViewerCustomizeViewModel.Factory(
|
||||
state = state
|
||||
)
|
||||
}
|
||||
|
||||
@Scope
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ViewerCustomizeScope
|
|
@ -0,0 +1,52 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.filter.ViewerFilterViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.ViewerFilterFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Scope
|
||||
|
||||
@Subcomponent(modules = [ViewerFilterModule::class])
|
||||
@ViewerFilterByScope
|
||||
interface ViewerFilterSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ViewerFilterModule): Builder
|
||||
fun build(): ViewerFilterSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ViewerFilterFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ViewerFilterModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@ViewerFilterByScope
|
||||
fun provideViewerFilterViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
urlBuilder: UrlBuilder
|
||||
): ViewerFilterViewModel.Factory = ViewerFilterViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
}
|
||||
|
||||
@Scope
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ViewerFilterByScope
|
|
@ -0,0 +1,56 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.ModifyDataViewViewerRelationOrder
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.relations.ViewerRelationsViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.ViewerRelationsFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [ViewerRelationsModule::class])
|
||||
@PerModal
|
||||
interface ViewerRelationsSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ViewerRelationsModule): Builder
|
||||
fun build(): ViewerRelationsSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ViewerRelationsFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ViewerRelationsModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewerRelationsListViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
modifyViewerRelationOrder: ModifyDataViewViewerRelationOrder,
|
||||
updateDataViewViewer: UpdateDataViewViewer
|
||||
): ViewerRelationsViewModel.Factory = ViewerRelationsViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
modifyViewerRelationOrder = modifyViewerRelationOrder,
|
||||
updateDataViewViewer = updateDataViewViewer
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideModifyViewerRelationOrderUseCase(
|
||||
repo: BlockRepository
|
||||
): ModifyDataViewViewerRelationOrder = ModifyDataViewViewerRelationOrder(repo = repo)
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.sort.ViewerSortViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.sort.ViewerSortFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [ViewerSortModule::class])
|
||||
@PerModal
|
||||
interface ViewerSortSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ViewerSortModule): Builder
|
||||
fun build(): ViewerSortSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ViewerSortFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ViewerSortModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
dispatcher: Dispatcher<Payload>
|
||||
): ViewerSortViewModel.Factory = ViewerSortViewModel.Factory(
|
||||
state = state,
|
||||
session = session,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
dispatcher = dispatcher
|
||||
)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.anytypeio.anytype.di.feature
|
||||
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ViewerSortByViewModel
|
||||
import com.anytypeio.anytype.ui.sets.ViewerSortByFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Scope
|
||||
|
||||
@Subcomponent(modules = [ViewerSortByModule::class])
|
||||
@ViewerSortByScope
|
||||
interface ViewerSortBySubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ViewerSortByModule): Builder
|
||||
fun build(): ViewerSortBySubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ViewerSortByFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ViewerSortByModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@ViewerSortByScope
|
||||
fun provideViewerSortByViewModelFactory(
|
||||
state: StateFlow<ObjectSet>
|
||||
): ViewerSortByViewModel.Factory = ViewerSortByViewModel.Factory(state)
|
||||
}
|
||||
|
||||
@Scope
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ViewerSortByScope
|
|
@ -0,0 +1,62 @@
|
|||
package com.anytypeio.anytype.di.feature.sets;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.CreateFilterFromInputFieldValueFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.CreateFilterFromSelectedValueFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [CreateFilterModule::class])
|
||||
@PerModal
|
||||
interface CreateFilterSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: CreateFilterModule): Builder
|
||||
fun build(): CreateFilterSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: CreateFilterFromSelectedValueFragment)
|
||||
fun inject(fragment: CreateFilterFromInputFieldValueFragment)
|
||||
fun createPickConditionComponent(): PickFilterConditionSubComponent.Builder
|
||||
}
|
||||
|
||||
@Module
|
||||
object CreateFilterModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
searchObjects: SearchObjects,
|
||||
urlBuilder: UrlBuilder
|
||||
): FilterViewModel.Factory = FilterViewModel.Factory(
|
||||
objectSetState = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
searchObjects = searchObjects,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideSearchObjectsUseCase(
|
||||
repo: BlockRepository
|
||||
): SearchObjects = SearchObjects(repo = repo)
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.anytypeio.anytype.di.feature.sets;
|
||||
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SearchObjects
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.filter.FilterViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromInputFieldValueFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.ModifyFilterFromSelectedValueFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [ModifyFilterModule::class])
|
||||
@PerModal
|
||||
interface ModifyFilterSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ModifyFilterModule): Builder
|
||||
fun build(): ModifyFilterSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ModifyFilterFromInputFieldValueFragment)
|
||||
fun inject(fragment: ModifyFilterFromSelectedValueFragment)
|
||||
fun createPickConditionComponent(): PickFilterConditionSubComponent.Builder
|
||||
}
|
||||
|
||||
@Module
|
||||
object ModifyFilterModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
searchObjects: SearchObjects,
|
||||
urlBuilder: UrlBuilder
|
||||
): FilterViewModel.Factory = FilterViewModel.Factory(
|
||||
objectSetState = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
searchObjects = searchObjects,
|
||||
urlBuilder = urlBuilder
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideSearchObjectsUseCase(
|
||||
repo: BlockRepository
|
||||
): SearchObjects = SearchObjects(repo = repo)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.anytypeio.anytype.di.feature.sets
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
|
||||
import com.anytypeio.anytype.presentation.sets.filter.PickFilterConditionViewModel
|
||||
import com.anytypeio.anytype.ui.sets.modals.PickFilterConditionFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [PickConditionModule::class])
|
||||
@PerDialog
|
||||
interface PickFilterConditionSubComponent {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
fun module(module: PickConditionModule): Builder
|
||||
fun build(): PickFilterConditionSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: PickFilterConditionFragment)
|
||||
|
||||
}
|
||||
|
||||
@Module
|
||||
object PickConditionModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerDialog
|
||||
fun provideFactory(): PickFilterConditionViewModel.Factory =
|
||||
PickFilterConditionViewModel.Factory()
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.anytypeio.anytype.di.feature.sets
|
||||
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSet
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.SelectFilterRelationViewModel
|
||||
import com.anytypeio.anytype.ui.sets.modals.filter.SelectFilterRelationFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [SelectFilterRelationModule::class])
|
||||
@PerModal
|
||||
interface SelectFilterRelationSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: SelectFilterRelationModule): Builder
|
||||
fun build(): SelectFilterRelationSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: SelectFilterRelationFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object SelectFilterRelationModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideSelectSortRelationViewModelFactory(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession
|
||||
): SelectFilterRelationViewModel.Factory = SelectFilterRelationViewModel.Factory(
|
||||
state = state,
|
||||
session = session
|
||||
)
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package com.anytypeio.anytype.di.main
|
||||
|
||||
import com.anytypeio.anytype.domain.event.model.Payload
|
||||
import com.anytypeio.anytype.presentation.util.Bridge
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@Module
|
||||
object BridgeModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePayloadPridge(): Bridge<Payload> = Bridge()
|
||||
}
|
|
@ -3,7 +3,7 @@ package com.anytypeio.anytype.di.main
|
|||
import com.anytypeio.anytype.data.auth.repo.config.Configuration
|
||||
import com.anytypeio.anytype.data.auth.repo.config.Configurator
|
||||
import com.anytypeio.anytype.data.auth.repo.config.GatewayProvider
|
||||
import com.anytypeio.anytype.domain.config.Config
|
||||
import com.anytypeio.anytype.core_models.Config
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
import com.anytypeio.anytype.middleware.config.DefaultConfigurator
|
||||
import dagger.Module
|
||||
|
|
|
@ -21,7 +21,6 @@ import com.anytypeio.anytype.middleware.auth.AuthMiddleware
|
|||
import com.anytypeio.anytype.middleware.block.BlockMiddleware
|
||||
import com.anytypeio.anytype.middleware.interactor.Middleware
|
||||
import com.anytypeio.anytype.middleware.interactor.MiddlewareFactory
|
||||
import com.anytypeio.anytype.middleware.interactor.MiddlewareMapper
|
||||
import com.anytypeio.anytype.middleware.service.MiddlewareService
|
||||
import com.anytypeio.anytype.middleware.service.MiddlewareServiceImplementation
|
||||
import com.anytypeio.anytype.persistence.db.AnytypeDatabase
|
||||
|
@ -213,20 +212,14 @@ object DataModule {
|
|||
@Singleton
|
||||
fun provideMiddleware(
|
||||
service: MiddlewareService,
|
||||
factory: MiddlewareFactory,
|
||||
mapper: MiddlewareMapper
|
||||
): Middleware = Middleware(service, factory, mapper)
|
||||
factory: MiddlewareFactory
|
||||
): Middleware = Middleware(service, factory)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideMiddlewareFactory(): MiddlewareFactory = MiddlewareFactory()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideMiddlewareMapper(): MiddlewareMapper = MiddlewareMapper()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
|
@ -16,8 +16,7 @@ import javax.inject.Singleton
|
|||
UtilModule::class,
|
||||
EmojiModule::class,
|
||||
ClipboardModule::class,
|
||||
AnalyticsModule::class,
|
||||
BridgeModule::class
|
||||
AnalyticsModule::class
|
||||
]
|
||||
)
|
||||
interface MainComponent {
|
||||
|
@ -39,8 +38,6 @@ interface MainComponent {
|
|||
fun pageComponentBuilder(): PageSubComponent.Builder
|
||||
fun archiveComponentBuilder(): ArchiveSubComponent.Builder
|
||||
fun linkAddComponentBuilder(): LinkSubComponent.Builder
|
||||
fun documentActionMenuComponentBuilder(): DocumentActionMenuSubComponent.Builder
|
||||
fun documentEmojiIconPickerComponentBuilder(): DocumentEmojiIconPickerSubComponent.Builder
|
||||
fun createBookmarkBuilder(): CreateBookmarkSubComponent.Builder
|
||||
fun debugSettingsBuilder(): DebugSettingsSubComponent.Builder
|
||||
fun navigationComponentBuilder(): PageNavigationSubComponent.Builder
|
||||
|
@ -48,4 +45,8 @@ interface MainComponent {
|
|||
fun moveToBuilder(): MoveToSubComponent.Builder
|
||||
fun pageSearchComponentBuilder(): PageSearchSubComponent.Builder
|
||||
fun mainEntryComponentBuilder(): MainEntrySubComponent.Builder
|
||||
fun createSetComponentBuilder(): CreateSetSubComponent.Builder
|
||||
fun createObjectTypeComponentBuilder(): CreateObjectTypeSubComponent.Builder
|
||||
fun objectSetComponentBuilder(): ObjectSetSubComponent.Builder
|
||||
fun createDataViewRelationBuilder(): CreateDataViewRelationSubComponent.Builder
|
||||
}
|
|
@ -4,9 +4,9 @@ import android.text.Editable
|
|||
import android.text.Spanned
|
||||
import com.anytypeio.anytype.core_ui.common.Span
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.MentionSpan
|
||||
import com.anytypeio.anytype.domain.block.model.Block.Content.Text.Mark
|
||||
import com.anytypeio.anytype.domain.ext.overlap
|
||||
import com.anytypeio.anytype.domain.misc.Overlap
|
||||
import com.anytypeio.anytype.core_models.Block.Content.Text.Mark
|
||||
import com.anytypeio.anytype.core_models.ext.overlap
|
||||
import com.anytypeio.anytype.core_models.misc.Overlap
|
||||
import com.anytypeio.anytype.presentation.page.editor.ThemeColor
|
||||
|
||||
fun Editable.extractMarks(): List<Mark> = getSpans(0, length, Span::class.java).mapNotNull { span ->
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue