1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-3438 Widgets | Enhancement | Make "All objects" widget a system widget (#2232)

This commit is contained in:
Evgenii Kozlov 2025-04-02 21:14:57 +02:00 committed by GitHub
parent c8900f3971
commit 359e0d3597
Signed by: github
GPG key ID: B5690EEEBB952194
18 changed files with 342 additions and 162 deletions

View file

@ -29,6 +29,7 @@ object WidgetAnalytics {
const val WIDGET_SOURCE_RECENT_LOCAL = "RecentLocal"
const val WIDGET_SOURCE_SETS = "Sets"
const val WIDGET_SOURCE_BIN = "Bin"
const val WIDGET_SOURCE_ALL_OBJECTS = "AllObjects"
const val WIDGET_SOURCE_COLLECTIONS = "Sets"
const val CUSTOM_OBJECT_TYPE = "custom"

View file

@ -416,10 +416,38 @@ private fun WidgetList(
)
}
is WidgetView.AllContent -> {
AllContentWidgetCard(
mode = mode,
onWidgetClicked = { onBundledWidgetHeaderClicked(item.id) }
)
if (mode is InteractionMode.Edit) {
ReorderableItem(
lazyListState, key = item.id
) { isDragged ->
val alpha = animateFloatAsState(if (isDragged) 0.8f else 1.0f)
AllContentWidgetCard(
index = index,
mode = mode,
onWidgetClicked = {
onWidgetSourceClicked(Widget.Source.Bundled.AllObjects)
},
onDropDownMenuAction = { action ->
onWidgetMenuAction(item.id, action)
},
alpha = alpha.value,
lazyListState = lazyListState,
)
}
} else {
AllContentWidgetCard(
index = index,
mode = mode,
onWidgetClicked = {
onWidgetSourceClicked(Widget.Source.Bundled.AllObjects)
},
onDropDownMenuAction = { action ->
onWidgetMenuAction(item.id, action)
},
alpha = 1.0f,
lazyListState = lazyListState,
)
}
}
is WidgetView.SpaceChat -> {
SpaceChatWidgetCard(

View file

@ -110,7 +110,7 @@ fun VaultScreen(
color = colorResource(id = R.color.background_primary)
)
.then(
if (USE_EDGE_TO_EDGE && SDK_INT >= EDGE_TO_EDGE_MIN_SDK)
if (SDK_INT >= EDGE_TO_EDGE_MIN_SDK)
Modifier.windowInsetsPadding(WindowInsets.systemBars)
else
Modifier

View file

@ -1,92 +1,164 @@
package com.anytypeio.anytype.ui.widgets.types
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.views.HeadlineSubheading
import com.anytypeio.anytype.presentation.home.InteractionMode
import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction
import com.anytypeio.anytype.ui.widgets.menu.WidgetMenu
import org.burnoutcrew.reorderable.ReorderableLazyListState
import org.burnoutcrew.reorderable.detectReorderAfterLongPress
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AllContentWidgetCard(
index: Int,
mode: InteractionMode,
onWidgetClicked: () -> Unit = {}
onWidgetClicked: () -> Unit = {},
onDropDownMenuAction: (DropDownMenuAction) -> Unit = {},
lazyListState: ReorderableLazyListState,
alpha: Float,
) {
val haptic = LocalHapticFeedback.current
val isCardMenuExpanded = remember {
mutableStateOf(false)
}
Box(
modifier = Modifier
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp)
.fillMaxWidth()
.height(52.dp)
.background(
shape = RoundedCornerShape(16.dp),
color = colorResource(id = R.color.dashboard_card_background)
)
.clip(RoundedCornerShape(16.dp))
.padding(top = if (index == 0) 6.dp else 0.dp)
.then(
if (mode !is InteractionMode.Edit) {
Modifier.clickable {
onWidgetClicked()
}
} else {
if (mode is InteractionMode.Edit)
Modifier.detectReorderAfterLongPress(lazyListState)
else
Modifier
}
)
.alpha(alpha)
) {
Image(
painter = painterResource(id = R.drawable.ic_widget_all_content),
contentDescription = "All content icon",
Box(
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 16.dp)
)
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp)
.fillMaxWidth()
.height(52.dp)
.background(
shape = RoundedCornerShape(16.dp),
color = colorResource(id = R.color.dashboard_card_background)
)
.clip(RoundedCornerShape(16.dp))
.then(
if (mode !is InteractionMode.Edit) {
Modifier.combinedClickable(
onClick = {
onWidgetClicked()
},
onLongClick = {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
isCardMenuExpanded.value = true
}
)
} else {
Modifier.detectReorderAfterLongPress(lazyListState)
}
)
.alpha(alpha)
) {
Image(
painter = painterResource(id = R.drawable.ic_widget_all_content),
contentDescription = "All content icon",
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 16.dp)
)
Text(
text = stringResource(id = R.string.all_content),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
Text(
text = stringResource(id = R.string.all_content),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 44.dp, end = 16.dp),
style = HeadlineSubheading,
color = colorResource(id = R.color.text_primary),
)
WidgetMenu(
isExpanded = isCardMenuExpanded,
onDropDownMenuAction = onDropDownMenuAction,
canEditWidgets = mode !is InteractionMode.Edit
)
}
AnimatedVisibility(
visible = mode is InteractionMode.Edit,
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 44.dp, end = 16.dp),
style = HeadlineSubheading,
color = colorResource(id = R.color.text_primary),
)
.align(Alignment.TopStart)
.padding(start = 12.dp),
enter = fadeIn() + slideInHorizontally { it / 4 },
exit = fadeOut() + slideOutHorizontally { it / 4 }
) {
Image(
painter = painterResource(id = R.drawable.ic_remove_widget),
modifier = Modifier
.height(24.dp)
.width(24.dp)
.noRippleClickable {
onDropDownMenuAction(DropDownMenuAction.RemoveWidget)
},
contentDescription = "Remove widget icon"
)
}
}
}
@Preview(
name = "Dark Mode",
showBackground = true,
uiMode = UI_MODE_NIGHT_YES
)
@Preview(
name = "Light Mode",
showBackground = true,
uiMode = UI_MODE_NIGHT_NO
)
@DefaultPreviews
@Composable
fun AllContentWidgetPreview() {
val lazyListState = rememberReorderableLazyListState(
onMove = { from, to ->
//
},
onDragEnd = { from, to ->
//
}
)
AllContentWidgetCard(
index = 0,
onWidgetClicked = {},
mode = InteractionMode.Default
mode = InteractionMode.Default,
alpha = 1.0f,
lazyListState = lazyListState
)
}

View file

@ -601,4 +601,5 @@ fun Widget.Source.Bundled.res(): Int = when (this) {
Widget.Source.Bundled.Sets -> R.string.sets
Widget.Source.Bundled.Collections -> R.string.collections
Widget.Source.Bundled.Bin -> R.string.bin
Widget.Source.Bundled.AllObjects -> R.string.all_content
}

View file

@ -238,6 +238,13 @@ class BundledWidgetSourceHolder(
ivIcon.setBackgroundResource(R.drawable.ic_widget_system_bin)
}
}
BundledWidgetSourceView.AllObjects -> {
with(binding) {
tvTitle.setText(R.string.all_content)
tvSubtitle.gone()
ivIcon.setBackgroundResource(R.drawable.ic_widget_system_all_objects)
}
}
}
}
}
@ -247,8 +254,9 @@ class SuggestWidgetObjectTypeViewHolder(
) : DefaultObjectViewAdapter.ObjectViewHolder(binding.root) {
init {
binding.ivIcon.binding.emojiContainer.invisible()
binding.tvSubtitle.gone()
binding.ivIcon.binding.emojiContainer.background = null
}
fun bind(source: SuggestWidgetObjectType) {

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0"
android:fillColor="#6D85F2"/>
<path
android:pathData="M17.313,16.5L17.313,16.5A6.25,6.25 0,0 1,23.563 22.75L23.563,22.75A6.25,6.25 0,0 1,17.313 29L17.313,29A6.25,6.25 0,0 1,11.063 22.75L11.063,22.75A6.25,6.25 0,0 1,17.313 16.5z"
android:fillColor="#ffffff"/>
<path
android:pathData="M16.13,15.09C16.516,15.031 16.911,15 17.313,15C21.593,15 25.063,18.47 25.063,22.75C25.063,23.152 25.032,23.547 24.973,23.932C25.452,23.879 25.824,23.785 26.152,23.618C26.81,23.283 27.346,22.747 27.681,22.089C28.063,21.34 28.063,20.36 28.063,18.4V17.6C28.063,15.64 28.063,14.66 27.681,13.911C27.346,13.252 26.81,12.717 26.152,12.382C25.403,12 24.423,12 22.462,12H21.663C19.702,12 18.722,12 17.973,12.382C17.315,12.717 16.779,13.252 16.444,13.911C16.277,14.239 16.183,14.611 16.13,15.09Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View file

@ -96,6 +96,6 @@ class GetSuggestedWidgetTypes @Inject constructor(
)
companion object {
const val DEFAULT_LIMIT = 5
const val DEFAULT_LIMIT = 10
}
}

View file

@ -1559,6 +1559,9 @@ fun CoroutineScope.sendChangeWidgetSourceEvent(
BundledWidgetSourceView.Bin -> {
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_BIN)
}
BundledWidgetSourceView.AllObjects -> {
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_ALL_OBJECTS)
}
}
if (isForNewWidget)
put(WidgetAnalytics.ROUTE, WidgetAnalytics.ROUTE_ADD_WIDGET)
@ -1655,6 +1658,9 @@ fun CoroutineScope.sendDeleteWidgetEvent(
Widget.Source.Bundled.Bin -> {
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_BIN)
}
Widget.Source.Bundled.AllObjects -> {
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_ALL_OBJECTS)
}
}
if (isInEditMode)
put(WidgetAnalytics.CONTEXT, WidgetAnalytics.CONTEXT_EDITOR)
@ -1698,6 +1704,9 @@ fun CoroutineScope.sendSelectHomeTabEvent(
Widget.Source.Bundled.Bin -> {
put(WidgetAnalytics.TAB, WidgetAnalytics.WIDGET_SOURCE_BIN)
}
Widget.Source.Bundled.AllObjects -> {
put(WidgetAnalytics.TAB, WidgetAnalytics.WIDGET_SOURCE_ALL_OBJECTS)
}
}
}
)
@ -1775,6 +1784,9 @@ fun CoroutineScope.sendReorderWidgetEvent(
Widget.Source.Bundled.Bin -> {
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_BIN)
}
Widget.Source.Bundled.AllObjects -> {
put(WidgetAnalytics.TYPE, WidgetAnalytics.WIDGET_SOURCE_ALL_OBJECTS)
}
}
}
)

View file

@ -135,6 +135,7 @@ import com.anytypeio.anytype.presentation.widgets.collection.Subscription
import com.anytypeio.anytype.presentation.widgets.hasValidLayout
import com.anytypeio.anytype.presentation.widgets.parseActiveViews
import com.anytypeio.anytype.presentation.widgets.parseWidgets
import com.anytypeio.anytype.presentation.widgets.source.BundledWidgetSourceView
import javax.inject.Inject
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
@ -253,8 +254,6 @@ class HomeScreenViewModel(
private val containers = MutableStateFlow<Containers>(null)
private val treeWidgetBranchStateHolder = TreeWidgetBranchStateHolder()
private val allContentWidget = AllContentWidgetContainer()
private val spaceWidgetView = spaceWidgetContainer.view
private val widgetObjectPipelineJobs = mutableListOf<Job>()
@ -459,7 +458,6 @@ class HomeScreenViewModel(
combine(
flows = buildList<Flow<WidgetView>> {
add(spaceWidgetView)
add(allContentWidget.view)
addAll(list.map { m -> m.view })
}
) { array ->
@ -584,6 +582,11 @@ class HomeScreenViewModel(
storeOfObjectTypes = storeOfObjectTypes
)
}
is Widget.AllObjects -> {
AllContentWidgetContainer(
widget = widget
)
}
}
}
}.collect {
@ -709,15 +712,25 @@ class HomeScreenViewModel(
}
}
is WidgetDispatchEvent.SourcePicked.Bundled -> {
commands.emit(
Command.SelectWidgetType(
if (dispatch.source == BundledWidgetSourceView.AllObjects.id) {
// Applying link layout automatically to all-objects widget
proceedWithCreatingWidget(
ctx = config.widgets,
source = dispatch.source,
layout = ObjectType.Layout.SET.code,
target = dispatch.target,
isInEditMode = isInEditMode()
type = Command.ChangeWidgetType.TYPE_LINK,
target = dispatch.target
)
)
} else {
commands.emit(
Command.SelectWidgetType(
ctx = config.widgets,
source = dispatch.source,
layout = ObjectType.Layout.SET.code,
target = dispatch.target,
isInEditMode = isInEditMode()
)
)
}
}
is WidgetDispatchEvent.SourceChanged -> {
proceedWithUpdatingWidget(
@ -1065,6 +1078,18 @@ class HomeScreenViewModel(
)
}
}
is Widget.Source.Bundled.AllObjects -> {
viewModelScope.launch {
if (mode.value == InteractionMode.Edit) {
return@launch
}
navigation(
Navigation.OpenAllContent(
space = spaceManager.get()
)
)
}
}
}
}
@ -1132,16 +1157,6 @@ class HomeScreenViewModel(
WidgetView.SpaceChat.id -> {
proceedWithSpaceChatWidgetHeaderClick()
}
WidgetView.AllContent.ALL_CONTENT_WIDGET_ID -> {
if (mode.value == InteractionMode.Edit) {
return@launch
}
navigation(
Navigation.OpenAllContent(
space = space
)
)
}
else -> {
Timber.w("Skipping widget click: $widget")
}
@ -1260,6 +1275,8 @@ class HomeScreenViewModel(
else
Command.ChangeWidgetType.TYPE_LIST
}
// All-objects widget has link appearance.
is Widget.AllObjects -> Command.ChangeWidgetType.TYPE_LINK
}
// TODO move to a separate reducer inject into this VM's constructor

View file

@ -3,8 +3,10 @@ package com.anytypeio.anytype.presentation.widgets
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
class AllContentWidgetContainer : WidgetContainer {
class AllContentWidgetContainer(
widget: Widget.AllObjects
) : WidgetContainer {
override val view: Flow<WidgetView> = flowOf(
WidgetView.AllContent
WidgetView.AllContent(widget.id)
)
}

View file

@ -93,7 +93,7 @@ class DataViewListWidgetContainer(
)
)
}
is Widget.Link, is Widget.Tree -> {
is Widget.Link, is Widget.Tree, is Widget.AllObjects -> {
throw IllegalStateException("Incompatible widget type.")
}
}
@ -150,7 +150,7 @@ class DataViewListWidgetContainer(
)
)
}
is Widget.Tree, is Widget.Link -> {
is Widget.Tree, is Widget.Link, is Widget.AllObjects -> {
throw IllegalStateException("Incompatible widget type.")
}
}
@ -181,7 +181,7 @@ class DataViewListWidgetContainer(
limit = when (widget) {
is Widget.List -> widget.limit
is Widget.View -> widget.limit
is Widget.Tree, is Widget.Link -> {
is Widget.Tree, is Widget.Link, is Widget.AllObjects -> {
throw IllegalStateException("Incompatible widget type.")
}
}
@ -355,7 +355,7 @@ class DataViewListWidgetContainer(
prettyPrintName = fieldParser.getObjectPluralName(widget.source.obj)
)
)
is Widget.Link, is Widget.Tree -> {
is Widget.Link, is Widget.Tree, is Widget.AllObjects -> {
throw IllegalStateException("Incompatible widget type.")
}
}

View file

@ -35,6 +35,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import timber.log.Timber
@ -61,7 +62,7 @@ class SelectWidgetSourceViewModel(
storeOfObjectTypes = storeOfObjectTypes
) {
val suggested = MutableStateFlow<List<SuggestWidgetObjectType>>(emptyList())
val suggested = MutableStateFlow<List<SuggestWidgetObjectType>?>(null)
val isDismissed = MutableStateFlow(false)
var config : Config = Config.None
@ -69,7 +70,7 @@ class SelectWidgetSourceViewModel(
val viewState = combine(
stateData
.asFlow(),
suggested
suggested.filterNotNull()
) { state, suggested ->
if (suggested.isNotEmpty()) {
when(state) {
@ -83,6 +84,7 @@ class SelectWidgetSourceViewModel(
add(BundledWidgetSourceView.Recent)
add(BundledWidgetSourceView.RecentLocal)
add(BundledWidgetSourceView.Bin)
add(BundledWidgetSourceView.AllObjects)
// Suggested widgets (aka object type widgets)
if (suggested.isNotEmpty()) {
@ -216,6 +218,9 @@ class SelectWidgetSourceViewModel(
isInEditMode = curr.isInEditMode
)
}
if (view is BundledWidgetSourceView.AllObjects) {
isDismissed.value = true
}
}
}
is Config.ExistingWidget -> {

View file

@ -59,6 +59,12 @@ sealed class Widget {
val limit: Int
) : Widget()
data class AllObjects(
override val id: Id,
override val source: Source.Bundled.AllObjects,
override val config: Config,
) : Widget()
sealed class Source {
abstract val id: Id
@ -101,6 +107,11 @@ sealed class Widget {
override val id: Id = BundledWidgetSourceIds.BIN
override val type: Id? = null
}
data object AllObjects : Bundled() {
override val id: Id = BundledWidgetSourceIds.ALL_OBJECTS
override val type: Id? = null
}
}
}
}
@ -150,51 +161,19 @@ fun List<Block>.parseWidgets(
is Widget.Source.Default -> source.obj.isValid && source.obj.notDeletedNorArchived
}
if (hasValidSource && !WidgetConfig.excludedTypes.contains(source.type)) {
when (widgetContent.layout) {
Block.Content.Widget.Layout.TREE -> {
add(
Widget.Tree(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config
)
if (source is Widget.Source.Bundled.AllObjects) {
add(
Widget.AllObjects(
id = w.id,
source = source,
config = config
)
}
Block.Content.Widget.Layout.LINK -> {
add(
Widget.Link(
id = w.id,
source = source,
config = config
)
)
}
Block.Content.Widget.Layout.LIST -> {
add(
Widget.List(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config
)
)
}
Block.Content.Widget.Layout.COMPACT_LIST -> {
add(
Widget.List(
id = w.id,
source = source,
isCompact = true,
limit = widgetContent.limit,
config = config
)
)
}
Block.Content.Widget.Layout.VIEW -> {
if (source is Widget.Source.Default) {
)
} else {
when (widgetContent.layout) {
Block.Content.Widget.Layout.TREE -> {
add(
Widget.View(
Widget.Tree(
id = w.id,
source = source,
limit = widgetContent.limit,
@ -202,9 +181,56 @@ fun List<Block>.parseWidgets(
)
)
}
Block.Content.Widget.Layout.LINK -> {
add(
Widget.Link(
id = w.id,
source = source,
config = config
)
)
}
Block.Content.Widget.Layout.LIST -> {
add(
Widget.List(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config
)
)
}
Block.Content.Widget.Layout.COMPACT_LIST -> {
add(
Widget.List(
id = w.id,
source = source,
isCompact = true,
limit = widgetContent.limit,
config = config
)
)
}
Block.Content.Widget.Layout.VIEW -> {
if (source is Widget.Source.Default) {
add(
Widget.View(
id = w.id,
source = source,
limit = widgetContent.limit,
config = config
)
)
}
}
}
}
}
}
}
}
@ -218,6 +244,7 @@ fun Id.bundled() : Widget.Source.Bundled = when (this) {
BundledWidgetSourceIds.COLLECTIONS -> Widget.Source.Bundled.Collections
BundledWidgetSourceIds.FAVORITE -> Widget.Source.Bundled.Favorites
BundledWidgetSourceIds.BIN -> Widget.Source.Bundled.Bin
BundledWidgetSourceIds.ALL_OBJECTS -> Widget.Source.Bundled.AllObjects
else -> throw IllegalStateException("Widget bundled id can't be $this")
}

View file

@ -77,11 +77,12 @@ object BundledWidgetSourceIds {
const val RECENT = "recent"
const val RECENT_LOCAL = "recentOpen"
const val BIN = "bin"
const val ALL_OBJECTS = "allObjects"
@Deprecated("DROID-3438 To be deleted")
const val SETS = "set"
@Deprecated("DROID-3438 To be deleted")
const val COLLECTIONS = "collection"
val ids = listOf(FAVORITE, RECENT, RECENT_LOCAL, SETS, COLLECTIONS, BIN)
val ids = listOf(FAVORITE, RECENT, RECENT_LOCAL, SETS, COLLECTIONS, BIN, ALL_OBJECTS)
}

View file

@ -129,10 +129,10 @@ sealed class WidgetView {
val isEmpty: Boolean = false
) : WidgetView()
data object AllContent: WidgetView() {
const val ALL_CONTENT_WIDGET_ID = "bundled-widget.all-content"
data class AllContent(
override val id: Id
): WidgetView() {
override val isLoading: Boolean = false
override val id: Id = ALL_CONTENT_WIDGET_ID
}
data object SpaceChat : WidgetView() {

View file

@ -25,6 +25,10 @@ sealed class BundledWidgetSourceView : DefaultSearchItem {
data object Bin : BundledWidgetSourceView() {
override val id: Id get() = BundledWidgetSourceIds.BIN
}
data object AllObjects : BundledWidgetSourceView() {
override val id: Id get() = BundledWidgetSourceIds.ALL_OBJECTS
}
}
data class SuggestWidgetObjectType(

View file

@ -316,13 +316,8 @@ class HomeScreenViewModelTest {
membersCount = 0
)
private val allContentWidgetView = WidgetView.AllContent
private val secondSpaceWidgetView = WidgetView.SpaceWidget.View(
space = StubSpaceView(),
icon = SpaceIconView.Placeholder(),
type = UNKNOWN_SPACE_TYPE,
membersCount = 0
private val allContentWidgetView = WidgetView.AllContent(
id = MockDataFactory.randomUuid()
)
private lateinit var urlBuilder: UrlBuilder
@ -394,7 +389,6 @@ class HomeScreenViewModelTest {
actual = secondTimeState,
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
addAll(HomeScreenViewModel.actions)
}
)
@ -446,7 +440,6 @@ class HomeScreenViewModelTest {
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
addAll(HomeScreenViewModel.actions)
},
actual = secondTimeItem
@ -530,14 +523,13 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.Tree && thirdWidget.isLoading
}
val secondTimeState = awaitItem()
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
add(
WidgetView.Tree(
id = widgetBlock.id,
@ -644,14 +636,13 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.Tree && thirdWidget.isLoading
}
val secondTimeState = awaitItem()
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
add(
WidgetView.Tree(
id = widgetBlock.id,
@ -774,14 +765,13 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.SetOfObjects && thirdWidget.isLoading
}
val secondTimeState = awaitItem()
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
add(
WidgetView.SetOfObjects(
id = widgetBlock.id,
@ -883,14 +873,13 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.SetOfObjects && thirdWidget.isLoading
}
val secondTimeState = awaitItem()
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
add(
WidgetView.SetOfObjects(
id = widgetBlock.id,
@ -1090,15 +1079,15 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState1 = awaitItem()
assertTrue {
val firstWidget = firstTimeLoadingState1[2]
val firstWidget = firstTimeLoadingState1[1]
firstWidget is WidgetView.Tree && firstWidget.isLoading
}
assertTrue {
val secondWidget = firstTimeLoadingState1[3]
val secondWidget = firstTimeLoadingState1[2]
secondWidget is WidgetView.Tree && secondWidget.isLoading
}
assertTrue {
val thirdWidget = firstTimeLoadingState1[4]
val thirdWidget = firstTimeLoadingState1[3]
thirdWidget is WidgetView.Tree && thirdWidget.isLoading
}
@ -1106,15 +1095,15 @@ class HomeScreenViewModelTest {
val firstTimeLoadingState2 = awaitItem()
assertTrue {
val firstWidget = firstTimeLoadingState2[2]
val firstWidget = firstTimeLoadingState2[1]
firstWidget is WidgetView.Tree && firstWidget.isLoading
}
assertTrue {
val secondWidget = firstTimeLoadingState2[3]
val secondWidget = firstTimeLoadingState2[2]
secondWidget is WidgetView.Tree && !secondWidget.isLoading
}
assertTrue {
val thirdWidget = firstTimeLoadingState2[4]
val thirdWidget = firstTimeLoadingState2[3]
thirdWidget is WidgetView.Tree && !thirdWidget.isLoading
}
@ -1125,7 +1114,6 @@ class HomeScreenViewModelTest {
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
add(
WidgetView.Tree(
id = favoriteWidgetBlock.id,
@ -1308,7 +1296,6 @@ class HomeScreenViewModelTest {
assertEquals(
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
add(
WidgetView.Link(
id = widgetBlock.id,
@ -2084,7 +2071,6 @@ class HomeScreenViewModelTest {
actual = secondTimeState,
expected = buildList {
add(defaultSpaceWidgetView)
add(allContentWidgetView)
addAll(HomeScreenViewModel.actions)
}
)
@ -2318,20 +2304,20 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.Tree && thirdWidget.isLoading
}
delay(1)
val secondTimeItem = awaitItem()
assertTrue {
val secondWidget = secondTimeItem[2]
val secondWidget = secondTimeItem[1]
(secondWidget is WidgetView.Tree
&& secondWidget.source.id == currentSourceObject.id && !secondWidget.isLoading)
}
val thirdTimeItem = awaitItem()
advanceUntilIdle()
assertTrue {
val thirdWidget = thirdTimeItem[2]
val thirdWidget = thirdTimeItem[1]
thirdWidget is WidgetView.Tree
&& thirdWidget.source.id == newSourceObject.id
&& thirdWidget.isLoading
@ -2339,7 +2325,7 @@ class HomeScreenViewModelTest {
advanceUntilIdle()
val fourthTimeItem = awaitItem()
assertTrue {
val thirdWidget = fourthTimeItem[2]
val thirdWidget = fourthTimeItem[1]
thirdWidget is WidgetView.Tree
&& thirdWidget.source.id == newSourceObject.id
&& !thirdWidget.isLoading
@ -2425,19 +2411,19 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.Tree && thirdWidget.isLoading
}
delay(1)
val secondTimeItem = awaitItem()
assertTrue {
val thirdWidget = secondTimeItem[2]
val thirdWidget = secondTimeItem[1]
thirdWidget is WidgetView.Tree
}
val thirdTimeItem = awaitItem()
advanceUntilIdle()
assertTrue {
val thirdWidget = thirdTimeItem[2]
val thirdWidget = thirdTimeItem[1]
thirdWidget is WidgetView.Link
}
}
@ -2582,13 +2568,13 @@ class HomeScreenViewModelTest {
)
val firstTimeLoadingState = awaitItem()
assertTrue {
val thirdWidget = firstTimeLoadingState[2]
val thirdWidget = firstTimeLoadingState[1]
thirdWidget is WidgetView.SetOfObjects && thirdWidget.isLoading
}
delay(1)
val secondTimeItem = awaitItem()
assertTrue {
val thirdWidget = secondTimeItem[2]
val thirdWidget = secondTimeItem[1]
thirdWidget is WidgetView.SetOfObjects && thirdWidget.tabs.first().isSelected
}
verifyBlocking(getObject, times(1)) {
@ -2614,7 +2600,7 @@ class HomeScreenViewModelTest {
val thirdTimeItem = awaitItem()
advanceUntilIdle()
assertTrue {
val thirdWidget = thirdTimeItem[2]
val thirdWidget = thirdTimeItem[1]
thirdWidget is WidgetView.SetOfObjects && thirdWidget.tabs.last().isSelected
}
verify(storelessSubscriptionContainer, times(1)).subscribe(