mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-10 10:00:44 +09:00
DROID-946 Widgets | Enhancement | GUI basics for link-styled widgets + Processing widget object payload updates (#2901)
This commit is contained in:
parent
25a184085f
commit
878f84a052
9 changed files with 202 additions and 22 deletions
|
@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Event
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectView
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_models.ext.process
|
||||
import com.anytypeio.anytype.core_utils.ext.replace
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.Resultat
|
||||
|
@ -18,10 +19,12 @@ import com.anytypeio.anytype.domain.search.ObjectSearchSubscriptionContainer
|
|||
import com.anytypeio.anytype.domain.widgets.CreateWidget
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.presentation.widgets.LinkWidgetContainer
|
||||
import com.anytypeio.anytype.presentation.widgets.TreePath
|
||||
import com.anytypeio.anytype.presentation.widgets.TreeWidgetBranchStateHolder
|
||||
import com.anytypeio.anytype.presentation.widgets.TreeWidgetContainer
|
||||
import com.anytypeio.anytype.presentation.widgets.Widget
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetContainer
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetDispatchEvent
|
||||
import com.anytypeio.anytype.presentation.widgets.WidgetView
|
||||
import com.anytypeio.anytype.presentation.widgets.parseWidgets
|
||||
|
@ -52,7 +55,7 @@ class HomeScreenViewModel(
|
|||
|
||||
private val objectViewState = MutableStateFlow<ObjectViewState>(ObjectViewState.Idle)
|
||||
private val widgets = MutableStateFlow<List<Widget>>(emptyList())
|
||||
private val containers = MutableStateFlow<List<TreeWidgetContainer>>(emptyList())
|
||||
private val containers = MutableStateFlow<List<WidgetContainer>>(emptyList())
|
||||
private val expanded = TreeWidgetBranchStateHolder()
|
||||
|
||||
init {
|
||||
|
@ -107,14 +110,14 @@ class HomeScreenViewModel(
|
|||
widgets.map {
|
||||
it.map { w ->
|
||||
when (w) {
|
||||
is Widget.Link -> TODO()
|
||||
is Widget.Tree -> {
|
||||
TreeWidgetContainer(
|
||||
widget = w,
|
||||
container = objectSearchSubscriptionContainer,
|
||||
expandedBranches = expanded.stream(w.id)
|
||||
)
|
||||
}
|
||||
is Widget.Link -> LinkWidgetContainer(
|
||||
widget = w
|
||||
)
|
||||
is Widget.Tree -> TreeWidgetContainer(
|
||||
widget = w,
|
||||
container = objectSearchSubscriptionContainer,
|
||||
expandedBranches = expanded.stream(w.id)
|
||||
)
|
||||
}
|
||||
}
|
||||
}.collect {
|
||||
|
@ -217,9 +220,7 @@ class HomeScreenViewModel(
|
|||
event.events.forEach { e ->
|
||||
when (e) {
|
||||
is Event.Command.AddBlock -> {
|
||||
curr = curr.copy(
|
||||
blocks = curr.blocks + e.blocks
|
||||
)
|
||||
curr = curr.copy(blocks = curr.blocks + e.blocks)
|
||||
}
|
||||
is Event.Command.UpdateStructure -> {
|
||||
curr = curr.copy(
|
||||
|
@ -231,6 +232,9 @@ class HomeScreenViewModel(
|
|||
)
|
||||
)
|
||||
}
|
||||
is Event.Command.Details -> {
|
||||
curr = curr.copy(details = curr.details.process(e))
|
||||
}
|
||||
else -> {
|
||||
Timber.d("Skipping event: $e")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.anytypeio.anytype.presentation.widgets
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
class LinkWidgetContainer(
|
||||
private val widget: Widget.Link
|
||||
) : WidgetContainer {
|
||||
override val view: Flow<WidgetView.Link> = flowOf(
|
||||
WidgetView.Link(
|
||||
id = widget.id,
|
||||
obj = widget.source
|
||||
)
|
||||
)
|
||||
}
|
|
@ -15,11 +15,11 @@ class TreeWidgetContainer(
|
|||
private val widget: Widget.Tree,
|
||||
private val container: ObjectSearchSubscriptionContainer,
|
||||
private val expandedBranches: Flow<List<TreePath>>
|
||||
) {
|
||||
) : WidgetContainer {
|
||||
|
||||
private val store = mutableMapOf<Id, ObjectWrapper.Basic>()
|
||||
|
||||
val view: Flow<WidgetView.Tree> = expandedBranches.mapLatest {
|
||||
override val view: Flow<WidgetView.Tree> = expandedBranches.mapLatest {
|
||||
container.get(
|
||||
subscription = widget.id,
|
||||
keys = keys,
|
||||
|
|
|
@ -56,9 +56,11 @@ fun List<Block>.parseWidgets(
|
|||
)
|
||||
}
|
||||
Block.Content.Widget.Layout.LINK -> {
|
||||
Widget.Link(
|
||||
id = w.id,
|
||||
source = data
|
||||
add(
|
||||
Widget.Link(
|
||||
id = w.id,
|
||||
source = data
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package com.anytypeio.anytype.presentation.widgets
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
sealed interface WidgetContainer {
|
||||
val view: Flow<WidgetView>
|
||||
}
|
|
@ -24,6 +24,11 @@ sealed class WidgetView {
|
|||
}
|
||||
}
|
||||
|
||||
data class Link(
|
||||
val id: Id,
|
||||
val obj: ObjectWrapper.Basic,
|
||||
) : WidgetView()
|
||||
|
||||
sealed class Action : WidgetView() {
|
||||
object EditWidgets : Action()
|
||||
object CreateWidget: Action()
|
||||
|
|
|
@ -199,6 +199,81 @@ class HomeViewModelTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should emit link-widget and actions`() = runTest {
|
||||
|
||||
// SETUP
|
||||
|
||||
val sourceObject = StubObject(
|
||||
id = "SOURCE OBJECT",
|
||||
links = emptyList()
|
||||
)
|
||||
|
||||
val sourceLink = StubLinkToObjectBlock(
|
||||
id = "SOURCE LINK",
|
||||
target = sourceObject.id
|
||||
)
|
||||
|
||||
val widgetBlock = StubWidgetBlock(
|
||||
id = "WIDGET BLOCK",
|
||||
layout = Block.Content.Widget.Layout.LINK,
|
||||
children = listOf(sourceLink.id)
|
||||
)
|
||||
|
||||
val smartBlock = StubSmartBlock(
|
||||
id = WIDGET_OBJECT_ID,
|
||||
children = listOf(widgetBlock.id),
|
||||
type = SmartBlockType.WIDGET
|
||||
)
|
||||
|
||||
val givenObjectView = StubObjectView(
|
||||
root = WIDGET_OBJECT_ID,
|
||||
type = SmartBlockType.WIDGET,
|
||||
blocks = listOf(
|
||||
smartBlock,
|
||||
widgetBlock,
|
||||
sourceLink
|
||||
),
|
||||
details = mapOf(
|
||||
sourceObject.id to sourceObject.map
|
||||
)
|
||||
)
|
||||
|
||||
stubConfig()
|
||||
stubInterceptEvents(events = emptyFlow())
|
||||
stubOpenObject(givenObjectView)
|
||||
stubObjectSearchContainer(
|
||||
subscription = widgetBlock.id,
|
||||
targets = emptyList()
|
||||
)
|
||||
|
||||
val vm = buildViewModel()
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.views.test {
|
||||
val firstTimeState = awaitItem()
|
||||
assertEquals(
|
||||
actual = firstTimeState,
|
||||
expected = HomeScreenViewModel.actions
|
||||
)
|
||||
val secondTimeItem = awaitItem()
|
||||
assertEquals(
|
||||
expected = buildList {
|
||||
add(
|
||||
WidgetView.Link(
|
||||
id = widgetBlock.id,
|
||||
obj = sourceObject
|
||||
)
|
||||
)
|
||||
addAll(HomeScreenViewModel.actions)
|
||||
},
|
||||
actual = secondTimeItem
|
||||
)
|
||||
verify(openObject, times(1)).invoke(WIDGET_OBJECT_ID)
|
||||
}
|
||||
}
|
||||
|
||||
private fun stubInterceptEvents(events: Flow<List<Event>>) {
|
||||
interceptEvents.stub {
|
||||
on { build(InterceptEvents.Params(WIDGET_OBJECT_ID)) } doReturn events
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue