mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3013 Primitives | Type screen, Sets migration, part 1 (#2133)
This commit is contained in:
parent
37da962c6a
commit
e0acb86116
8 changed files with 8 additions and 584 deletions
|
@ -71,7 +71,6 @@ class ObjectTypeFieldsFragment : BaseBottomSheetComposeFragment() {
|
|||
val params = ObjectTypeVmParams(
|
||||
spaceId = SpaceId(space),
|
||||
objectId = typeId,
|
||||
withSubscriptions = false,
|
||||
showHiddenFields = true
|
||||
)
|
||||
componentManager().objectTypeComponent.get(params).inject(this)
|
||||
|
|
|
@ -160,15 +160,6 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
|
||||
uiFieldsButtonState = vm.uiFieldsButtonState.collectAsStateWithLifecycle().value,
|
||||
uiLayoutButtonState = vm.uiLayoutButtonState.collectAsStateWithLifecycle().value,
|
||||
uiTemplatesHeaderState = vm.uiTemplatesHeaderState.collectAsStateWithLifecycle().value,
|
||||
uiTemplatesAddIconState = vm.uiTemplatesAddIconState.collectAsStateWithLifecycle().value,
|
||||
uiTemplatesListState = vm.uiTemplatesListState.collectAsStateWithLifecycle().value,
|
||||
uiObjectsHeaderState = vm.uiObjectsHeaderState.collectAsStateWithLifecycle().value,
|
||||
uiObjectsAddIconState = vm.uiObjectsAddIconState.collectAsStateWithLifecycle().value,
|
||||
uiObjectsSettingsIconState = vm.uiObjectsSettingsIconState.collectAsStateWithLifecycle().value,
|
||||
uiObjectsMenuState = vm.uiMenuState.collectAsStateWithLifecycle().value,
|
||||
uiObjectsListState = vm.uiObjectsListState.collectAsStateWithLifecycle().value,
|
||||
uiContentState = vm.uiContentState.collectAsStateWithLifecycle().value,
|
||||
uiDeleteAlertState = vm.uiAlertState.collectAsStateWithLifecycle().value,
|
||||
uiEditButtonState = vm.uiEditButtonState.collectAsStateWithLifecycle().value,
|
||||
uiLayoutTypeState = vm.uiTypeLayoutsState.collectAsStateWithLifecycle().value,
|
||||
|
@ -303,7 +294,6 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
val params = ObjectTypeVmParams(
|
||||
spaceId = SpaceId(space),
|
||||
objectId = objectId,
|
||||
withSubscriptions = true,
|
||||
showHiddenFields = true
|
||||
)
|
||||
componentManager().objectTypeComponent.get(params).inject(this)
|
||||
|
|
|
@ -15,21 +15,16 @@ import androidx.compose.foundation.layout.statusBars
|
|||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.multiplayer.P2PStatusUpdate
|
||||
|
@ -38,21 +33,8 @@ import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncError
|
|||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncNetwork
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncStatus
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncUpdate
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeId
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeKey
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.core_ui.extensions.swapList
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.lists.objects.ListItemLoading
|
||||
import com.anytypeio.anytype.core_ui.lists.objects.ObjectsListItem
|
||||
import com.anytypeio.anytype.core_ui.lists.objects.UiContentState
|
||||
import com.anytypeio.anytype.core_ui.lists.objects.UiObjectsListState
|
||||
import com.anytypeio.anytype.core_ui.syncstatus.SpaceSyncStatusScreen
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSecondary
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.Relations3
|
||||
import com.anytypeio.anytype.core_ui.views.Title2
|
||||
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
|
||||
import com.anytypeio.anytype.feature_object_type.R
|
||||
import com.anytypeio.anytype.feature_object_type.ui.alerts.DeleteAlertScreen
|
||||
|
@ -60,13 +42,8 @@ import com.anytypeio.anytype.feature_object_type.ui.header.HorizontalButtons
|
|||
import com.anytypeio.anytype.feature_object_type.ui.header.IconAndTitleWidget
|
||||
import com.anytypeio.anytype.feature_object_type.ui.header.TopToolbar
|
||||
import com.anytypeio.anytype.feature_object_type.ui.layouts.TypeLayoutsScreen
|
||||
import com.anytypeio.anytype.feature_object_type.ui.objects.ObjectsHeader
|
||||
import com.anytypeio.anytype.feature_object_type.ui.templates.TemplatesScreen
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.UiObjectsListItem
|
||||
import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
@ -82,28 +59,12 @@ fun ObjectTypeMainScreen(
|
|||
uiFieldsButtonState: UiFieldsButtonState,
|
||||
uiLayoutButtonState: UiLayoutButtonState,
|
||||
uiLayoutTypeState: UiLayoutTypeState,
|
||||
//templates header
|
||||
uiTemplatesHeaderState: UiTemplatesHeaderState,
|
||||
uiTemplatesAddIconState: UiTemplatesAddIconState,
|
||||
//templates list
|
||||
uiTemplatesListState: UiTemplatesListState,
|
||||
//objects header
|
||||
uiObjectsHeaderState: UiObjectsHeaderState,
|
||||
uiObjectsAddIconState: UiObjectsAddIconState,
|
||||
uiObjectsSettingsIconState: UiObjectsSettingsIconState,
|
||||
uiObjectsMenuState: UiMenuState,
|
||||
//objects list
|
||||
uiObjectsListState: UiObjectsListState,
|
||||
uiContentState: UiContentState,
|
||||
//delete alert
|
||||
uiDeleteAlertState: UiDeleteAlertState,
|
||||
//events
|
||||
onTypeEvent: (TypeEvent) -> Unit
|
||||
) {
|
||||
|
||||
val objects = remember { mutableStateListOf<UiObjectsListItem>() }
|
||||
objects.swapList(uiObjectsListState.items)
|
||||
|
||||
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
|
||||
state = rememberTopAppBarState()
|
||||
)
|
||||
|
@ -130,14 +91,6 @@ fun ObjectTypeMainScreen(
|
|||
uiTitleState = uiTitleState,
|
||||
uiFieldsButtonState = uiFieldsButtonState,
|
||||
uiLayoutButtonState = uiLayoutButtonState,
|
||||
uiTemplatesHeaderState = uiTemplatesHeaderState,
|
||||
uiTemplatesAddIconState = uiTemplatesAddIconState,
|
||||
uiTemplatesListState = uiTemplatesListState,
|
||||
uiObjectsHeaderState = uiObjectsHeaderState,
|
||||
uiObjectsAddIconState = uiObjectsAddIconState,
|
||||
uiObjectsSettingsIconState = uiObjectsSettingsIconState,
|
||||
uiObjectsMenuState = uiObjectsMenuState,
|
||||
objects = objects,
|
||||
onTypeEvent = onTypeEvent
|
||||
)
|
||||
}
|
||||
|
@ -170,14 +123,6 @@ private fun MainContent(
|
|||
uiTitleState: UiTitleState,
|
||||
uiFieldsButtonState: UiFieldsButtonState,
|
||||
uiLayoutButtonState: UiLayoutButtonState,
|
||||
uiTemplatesHeaderState: UiTemplatesHeaderState,
|
||||
uiTemplatesAddIconState: UiTemplatesAddIconState,
|
||||
uiTemplatesListState: UiTemplatesListState,
|
||||
uiObjectsHeaderState: UiObjectsHeaderState,
|
||||
uiObjectsAddIconState: UiObjectsAddIconState,
|
||||
uiObjectsSettingsIconState: UiObjectsSettingsIconState,
|
||||
uiObjectsMenuState: UiMenuState,
|
||||
objects: List<UiObjectsListItem>,
|
||||
onTypeEvent: (TypeEvent) -> Unit
|
||||
) {
|
||||
// Adjust content modifier based on SDK version for proper insets handling
|
||||
|
@ -218,98 +163,6 @@ private fun MainContent(
|
|||
onTypeEvent = onTypeEvent
|
||||
)
|
||||
}
|
||||
|
||||
if (uiTemplatesHeaderState is UiTemplatesHeaderState.Visible) {
|
||||
item {
|
||||
TemplatesScreen(
|
||||
uiTemplatesHeaderState = uiTemplatesHeaderState,
|
||||
uiTemplatesAddIconState = uiTemplatesAddIconState,
|
||||
uiTemplatesListState = uiTemplatesListState,
|
||||
onTypeEvent = onTypeEvent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
ObjectsHeader(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)
|
||||
.padding(horizontal = 20.dp),
|
||||
uiObjectsHeaderState = uiObjectsHeaderState,
|
||||
uiObjectsAddIconState = uiObjectsAddIconState,
|
||||
uiObjectsSettingsIconState = uiObjectsSettingsIconState,
|
||||
uiObjectsMenuState = uiObjectsMenuState,
|
||||
onTypeEvent = onTypeEvent
|
||||
)
|
||||
}
|
||||
|
||||
if (objects.isEmpty()) {
|
||||
item {
|
||||
EmptyScreen(
|
||||
modifier = Modifier.padding(top = 18.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
items(
|
||||
count = objects.size,
|
||||
key = { index -> objects[index].id },
|
||||
contentType = { index ->
|
||||
when (objects[index]) {
|
||||
is UiObjectsListItem.Loading -> "loading"
|
||||
is UiObjectsListItem.Item -> "item"
|
||||
}
|
||||
}
|
||||
) { index ->
|
||||
when (val item = objects[index]) {
|
||||
is UiObjectsListItem.Item -> {
|
||||
ObjectsListItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateItem()
|
||||
.padding(horizontal = 4.dp)
|
||||
.noRippleThrottledClickable {
|
||||
onTypeEvent(TypeEvent.OnObjectItemClick(item))
|
||||
},
|
||||
item = item
|
||||
)
|
||||
Divider(paddingStart = 20.dp, paddingEnd = 20.dp)
|
||||
}
|
||||
is UiObjectsListItem.Loading -> {
|
||||
ListItemLoading(modifier = Modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Objects menu actions
|
||||
when (val itemSet = uiObjectsMenuState.objSetItem) {
|
||||
UiMenuSetItem.CreateSet -> {
|
||||
item {
|
||||
ButtonSecondary(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, start = 20.dp, end = 20.dp),
|
||||
text = stringResource(R.string.object_type_objects_menu_create_set),
|
||||
size = ButtonSize.Large,
|
||||
onClick = { onTypeEvent(TypeEvent.OnCreateSetClick) }
|
||||
)
|
||||
}
|
||||
}
|
||||
is UiMenuSetItem.OpenSet -> {
|
||||
item {
|
||||
ButtonSecondary(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, start = 20.dp, end = 20.dp),
|
||||
text = stringResource(R.string.object_type_objects_menu_open_set),
|
||||
size = ButtonSize.Large,
|
||||
onClick = { onTypeEvent(TypeEvent.OnOpenSetClick(setId = itemSet.setId)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
UiMenuSetItem.Hidden -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,30 +220,6 @@ private fun BottomSyncStatus(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmptyScreen(modifier: Modifier) {
|
||||
Column(modifier = modifier) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 32.dp),
|
||||
text = stringResource(R.string.object_type_empty_items_title),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Title2,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 32.dp),
|
||||
text = stringResource(R.string.object_type_empty_items_subtitle),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Relations3,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DefaultPreviews
|
||||
@Composable
|
||||
fun ObjectTypeMainScreenPreview() {
|
||||
|
@ -413,46 +242,6 @@ fun ObjectTypeMainScreenPreview() {
|
|||
uiTitleState = UiTitleState(title = "title", isEditable = true),
|
||||
uiFieldsButtonState = UiFieldsButtonState.Visible(4),
|
||||
uiLayoutButtonState = UiLayoutButtonState.Visible(layout = ObjectType.Layout.VIDEO),
|
||||
uiTemplatesHeaderState = UiTemplatesHeaderState.Visible(count = "3"),
|
||||
uiTemplatesAddIconState = UiTemplatesAddIconState.Visible,
|
||||
uiTemplatesListState = UiTemplatesListState(
|
||||
items = listOf(
|
||||
TemplateView.Template(
|
||||
id = "1",
|
||||
name = "Template 1",
|
||||
targetTypeId = TypeId("page"),
|
||||
targetTypeKey = TypeKey("ot-page"),
|
||||
layout = ObjectType.Layout.BASIC,
|
||||
image = null,
|
||||
emoji = ":)",
|
||||
coverColor = CoverColor.RED,
|
||||
coverGradient = null,
|
||||
coverImage = null,
|
||||
),
|
||||
TemplateView.Template(
|
||||
id = "2",
|
||||
name = "Template 2",
|
||||
targetTypeId = TypeId("note"),
|
||||
targetTypeKey = TypeKey("ot-note"),
|
||||
layout = ObjectType.Layout.NOTE,
|
||||
image = null,
|
||||
emoji = null,
|
||||
coverColor = null,
|
||||
coverGradient = null,
|
||||
coverImage = null,
|
||||
),
|
||||
TemplateView.New(
|
||||
targetTypeId = TypeId("32423"),
|
||||
targetTypeKey = TypeKey("43232")
|
||||
)
|
||||
)
|
||||
),
|
||||
uiObjectsAddIconState = UiObjectsAddIconState.Visible,
|
||||
uiObjectsHeaderState = UiObjectsHeaderState(count = "3"),
|
||||
uiObjectsSettingsIconState = UiObjectsSettingsIconState.Visible,
|
||||
uiObjectsListState = UiObjectsListState(emptyList()),
|
||||
uiContentState = UiContentState.Idle(),
|
||||
uiObjectsMenuState = UiMenuState.EMPTY,
|
||||
uiDeleteAlertState = UiDeleteAlertState.Hidden,
|
||||
uiEditButtonState = UiEditButton.Visible,
|
||||
uiLayoutTypeState = UiLayoutTypeState.Hidden,
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package com.anytypeio.anytype.feature_object_type.ui
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType.Layout
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectsListSort
|
||||
import com.anytypeio.anytype.presentation.objects.UiObjectsListItem
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
|
||||
sealed class TypeEvent {
|
||||
|
@ -23,20 +20,6 @@ sealed class TypeEvent {
|
|||
data class OnObjectTypeTitleUpdate(val title: String) : TypeEvent()
|
||||
//endregion
|
||||
|
||||
//region Sets
|
||||
data object OnCreateSetClick : TypeEvent()
|
||||
data class OnOpenSetClick(val setId: Id) : TypeEvent()
|
||||
//endregion
|
||||
|
||||
//region Objects Header
|
||||
data class OnSortClick(val sort: ObjectsListSort) : TypeEvent()
|
||||
data object OnCreateObjectIconClick : TypeEvent()
|
||||
//endregion
|
||||
|
||||
//region Objects list
|
||||
data class OnObjectItemClick(val item: UiObjectsListItem) : TypeEvent()
|
||||
//endregion
|
||||
|
||||
//region Templates
|
||||
data object OnTemplatesAddIconClick : TypeEvent()
|
||||
data class OnTemplateItemClick(val item: TemplateView) : TypeEvent()
|
||||
|
@ -56,7 +39,4 @@ sealed class TypeEvent {
|
|||
|
||||
data object OnLayoutButtonClick : TypeEvent()
|
||||
data object OnFieldsButtonClick : TypeEvent()
|
||||
|
||||
data object OnObjectsSettingsIconClick : TypeEvent()
|
||||
|
||||
}
|
|
@ -15,7 +15,6 @@ import com.anytypeio.anytype.presentation.templates.TemplateView
|
|||
data class ObjectTypeVmParams(
|
||||
val objectId: Id,
|
||||
val spaceId: SpaceId,
|
||||
val withSubscriptions: Boolean,
|
||||
val showHiddenFields: Boolean
|
||||
)
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ fun ObjectsHeader(
|
|||
title = stringResource(R.string.object_type_objects_menu_create_set),
|
||||
isSelected = false,
|
||||
modifier = Modifier
|
||||
.clickable { onTypeEvent(TypeEvent.OnCreateSetClick) }
|
||||
)
|
||||
Divider(
|
||||
height = 8.dp,
|
||||
|
@ -126,7 +125,6 @@ fun ObjectsHeader(
|
|||
title = stringResource(R.string.object_type_objects_menu_open_set),
|
||||
isSelected = false,
|
||||
modifier = Modifier
|
||||
.clickable { onTypeEvent(TypeEvent.OnOpenSetClick(setId = item.setId)) }
|
||||
)
|
||||
Divider(
|
||||
height = 8.dp,
|
||||
|
@ -144,7 +142,6 @@ fun ObjectsHeader(
|
|||
types = uiObjectsMenuState.types,
|
||||
sortingExpanded = isSortingExpanded,
|
||||
onSortClick = {
|
||||
onTypeEvent(TypeEvent.OnSortClick(it))
|
||||
},
|
||||
onChangeSortExpandedState = { isSortingExpanded = it }
|
||||
)
|
||||
|
@ -157,7 +154,6 @@ fun ObjectsHeader(
|
|||
.height(48.dp)
|
||||
.width(32.dp)
|
||||
.noRippleThrottledClickable {
|
||||
onTypeEvent(TypeEvent.OnCreateObjectIconClick)
|
||||
},
|
||||
contentAlignment = Alignment.CenterEnd
|
||||
) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.ObjectOrigin
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
|
@ -13,9 +12,6 @@ import com.anytypeio.anytype.core_models.permissions.ObjectPermissions
|
|||
import com.anytypeio.anytype.core_models.permissions.toObjectPermissionsForTypes
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeId
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeKey
|
||||
import com.anytypeio.anytype.core_ui.lists.objects.UiContentState
|
||||
import com.anytypeio.anytype.core_ui.lists.objects.UiObjectsListState
|
||||
import com.anytypeio.anytype.core_utils.ext.orNull
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.CreateObjectSet
|
||||
import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvider
|
||||
|
@ -55,15 +51,9 @@ import com.anytypeio.anytype.feature_object_type.ui.UiIconState
|
|||
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutButtonState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutTypeState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutTypeState.*
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiMenuSetItem
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiMenuState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiObjectsAddIconState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiObjectsHeaderState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiObjectsSettingsIconState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiSyncStatusBadgeState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesAddIconState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesHeaderState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesListState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiTitleState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.buildUiFieldsList
|
||||
import com.anytypeio.anytype.feature_object_type.ui.mapToUiAddFieldListItem
|
||||
|
@ -75,13 +65,6 @@ import com.anytypeio.anytype.presentation.extension.sendAnalyticsScreenObjectTyp
|
|||
import com.anytypeio.anytype.presentation.home.OpenObjectNavigation
|
||||
import com.anytypeio.anytype.presentation.home.navigation
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectsListSort
|
||||
import com.anytypeio.anytype.presentation.objects.UiObjectsListItem
|
||||
import com.anytypeio.anytype.presentation.objects.toDVSort
|
||||
import com.anytypeio.anytype.presentation.objects.toMenuSortContainer
|
||||
import com.anytypeio.anytype.presentation.objects.toSortOptions
|
||||
import com.anytypeio.anytype.presentation.objects.toSortTypeOptions
|
||||
import com.anytypeio.anytype.presentation.objects.toUiObjectsListItem
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeys
|
||||
import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
|
||||
import com.anytypeio.anytype.presentation.sync.toSyncStatusWidgetState
|
||||
|
@ -102,10 +85,8 @@ import kotlinx.coroutines.flow.drop
|
|||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
@ -164,26 +145,6 @@ class ObjectTypeViewModel(
|
|||
val uiTemplatesAddIconState =
|
||||
MutableStateFlow<UiTemplatesAddIconState>(UiTemplatesAddIconState.Hidden)
|
||||
|
||||
//templates list
|
||||
val uiTemplatesListState =
|
||||
MutableStateFlow<UiTemplatesListState>(UiTemplatesListState.Companion.EMPTY)
|
||||
|
||||
//objects header
|
||||
val uiObjectsHeaderState =
|
||||
MutableStateFlow<UiObjectsHeaderState>(UiObjectsHeaderState.Companion.EMPTY)
|
||||
val uiObjectsAddIconState =
|
||||
MutableStateFlow<UiObjectsAddIconState>(UiObjectsAddIconState.Hidden)
|
||||
val uiObjectsSettingsIconState =
|
||||
MutableStateFlow<UiObjectsSettingsIconState>(UiObjectsSettingsIconState.Hidden)
|
||||
val uiMenuState = MutableStateFlow<UiMenuState>(UiMenuState.Companion.EMPTY)
|
||||
|
||||
//objects list
|
||||
val uiObjectsListState = MutableStateFlow<UiObjectsListState>(UiObjectsListState.Empty)
|
||||
val uiContentState = MutableStateFlow<UiContentState>(UiContentState.Idle())
|
||||
private val restartSubscription = MutableStateFlow(0L)
|
||||
private var shouldScrollToTopItems = false
|
||||
private val _sortState = MutableStateFlow<ObjectsListSort>(ObjectsListSort.ByName())
|
||||
|
||||
//alerts
|
||||
val uiAlertState = MutableStateFlow<UiDeleteAlertState>(UiDeleteAlertState.Hidden)
|
||||
val uiFieldLocalInfoState =
|
||||
|
@ -213,14 +174,11 @@ class ObjectTypeViewModel(
|
|||
proceedWithObservingSyncStatus()
|
||||
proceedWithObservingObjectType()
|
||||
proceedWithGetObjectTypeConflictingFields()
|
||||
setupObjectsMenuFlow()
|
||||
}
|
||||
|
||||
fun onStart() {
|
||||
Timber.d("onStart, vmParams: $vmParams")
|
||||
if (vmParams.withSubscriptions) {
|
||||
startSubscriptions()
|
||||
}
|
||||
startSubscriptions()
|
||||
viewModelScope.launch {
|
||||
sendAnalyticsScreenObjectType(
|
||||
analytics = analytics
|
||||
|
@ -230,28 +188,11 @@ class ObjectTypeViewModel(
|
|||
|
||||
fun onStop() {
|
||||
Timber.d("onStop")
|
||||
if (vmParams.withSubscriptions) {
|
||||
stopSubscriptions()
|
||||
}
|
||||
uiObjectsListState.value = UiObjectsListState.Empty
|
||||
stopSubscriptions()
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region DATA
|
||||
private fun setupObjectsMenuFlow() {
|
||||
viewModelScope.launch {
|
||||
_sortState.map { sort ->
|
||||
uiMenuState.value.copy(
|
||||
container = sort.toMenuSortContainer(),
|
||||
sorts = sort.toSortOptions(),
|
||||
types = sort.toSortTypeOptions()
|
||||
)
|
||||
}
|
||||
.collect { newMenuState ->
|
||||
uiMenuState.value = newMenuState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithObservingObjectType() {
|
||||
viewModelScope.launch {
|
||||
|
@ -309,8 +250,6 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
|
||||
private fun startSubscriptions() {
|
||||
startObjectsSubscription()
|
||||
startSetSubscription()
|
||||
startTemplatesSubscription()
|
||||
}
|
||||
|
||||
|
@ -318,59 +257,12 @@ class ObjectTypeViewModel(
|
|||
viewModelScope.launch {
|
||||
storelessSubscriptionContainer.unsubscribe(
|
||||
listOf(
|
||||
objectsSubId(vmParams.objectId),
|
||||
setsSubId(vmParams.objectId),
|
||||
templatesSubId(vmParams.objectId),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun startObjectsSubscription() {
|
||||
viewModelScope.launch {
|
||||
combine(
|
||||
restartSubscription,
|
||||
_objTypeState,
|
||||
_objectTypePermissionsState
|
||||
) { restart, objType, permission ->
|
||||
objType to permission
|
||||
}.flatMapLatest { (objType, permission) ->
|
||||
if (objType == null || permission == null) {
|
||||
emptyFlow()
|
||||
} else {
|
||||
loadObjects(
|
||||
typeName = fieldParser.getObjectName(objectWrapper = objType),
|
||||
permissions = permission
|
||||
).map { items -> items to permission }
|
||||
}
|
||||
}.catch {
|
||||
Timber.e(it, "Error while observing objects")
|
||||
errorState.value =
|
||||
UiErrorState.Show(UiErrorState.Reason.ErrorGettingObjects(it.message ?: ""))
|
||||
}.collect { (items, permission) ->
|
||||
mapObjectsSubscriptionToUi(items, permission)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun startSetSubscription() {
|
||||
viewModelScope.launch {
|
||||
_objectTypePermissionsState
|
||||
.flatMapLatest { permissions ->
|
||||
if (permissions != null) {
|
||||
loadSet().map { items -> items to permissions }
|
||||
} else {
|
||||
emptyFlow()
|
||||
}
|
||||
}.collect { (items, permissions) ->
|
||||
Timber.d("items: $items, permissions: $permissions")
|
||||
mapSetSubscriptionToUi(items, permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun startTemplatesSubscription() {
|
||||
viewModelScope.launch {
|
||||
|
@ -393,60 +285,6 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun loadObjects(
|
||||
typeName: String,
|
||||
permissions: ObjectPermissions
|
||||
): Flow<List<UiObjectsListItem>> {
|
||||
|
||||
val activeSort = _sortState.value
|
||||
|
||||
val searchParams = StoreSearchParams(
|
||||
filters = filtersForSearch(objectTypeId = vmParams.objectId),
|
||||
sorts = listOf(activeSort.toDVSort()),
|
||||
space = vmParams.spaceId,
|
||||
limit = OBJECTS_MAX_COUNT,
|
||||
keys = defaultKeys,
|
||||
subscription = objectsSubId(vmParams.objectId)
|
||||
)
|
||||
|
||||
return storelessSubscriptionContainer.subscribe(searchParams)
|
||||
.onStart {
|
||||
uiContentState.value = UiContentState.Paging
|
||||
}
|
||||
.map { objWrappers ->
|
||||
val items = objWrappers.map {
|
||||
it.toUiObjectsListItem(
|
||||
space = vmParams.spaceId,
|
||||
urlBuilder = urlBuilder,
|
||||
typeName = typeName,
|
||||
fieldParser = fieldParser,
|
||||
isOwnerOrEditor = permissions.participantCanEdit
|
||||
)
|
||||
}
|
||||
items
|
||||
}.catch { e ->
|
||||
handleError(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadSet(): Flow<List<ObjectWrapper.Basic>> {
|
||||
|
||||
val searchParams = StoreSearchParams(
|
||||
filters = filtersForSetsSearch(objectTypeId = vmParams.objectId),
|
||||
sorts = listOf(sortForSetSearch()),
|
||||
space = vmParams.spaceId,
|
||||
limit = 1,
|
||||
keys = defaultKeys,
|
||||
subscription = setsSubId(vmParams.objectId)
|
||||
)
|
||||
|
||||
return storelessSubscriptionContainer.subscribe(searchParams)
|
||||
.catch {
|
||||
handleError(it)
|
||||
emit(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadTemplates(objType: ObjectWrapper.Type): Flow<List<TemplateView>> {
|
||||
|
||||
val searchParams = StoreSearchParams(
|
||||
|
@ -478,18 +316,6 @@ class ObjectTypeViewModel(
|
|||
|
||||
//region UI STATE
|
||||
private fun updateDefaultTemplates(defaultTemplate: Id?) {
|
||||
val templates = uiTemplatesListState.value.items
|
||||
uiTemplatesListState.value = uiTemplatesListState.value.copy(
|
||||
templates.map { template ->
|
||||
when (template) {
|
||||
is TemplateView.Blank -> template
|
||||
is TemplateView.New -> template
|
||||
is TemplateView.Template -> {
|
||||
template.copy(isDefault = template.id == defaultTemplate)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun mapObjectTypeToUi(
|
||||
|
@ -502,7 +328,6 @@ class ObjectTypeViewModel(
|
|||
|
||||
if (!objectPermissions.canCreateTemplatesForThisType) {
|
||||
uiTemplatesHeaderState.value = UiTemplatesHeaderState.Hidden
|
||||
uiTemplatesListState.value = UiTemplatesListState.EMPTY
|
||||
uiTemplatesAddIconState.value = UiTemplatesAddIconState.Hidden
|
||||
}
|
||||
uiTitleState.value = UiTitleState(
|
||||
|
@ -513,10 +338,6 @@ class ObjectTypeViewModel(
|
|||
icon = objType.objectIcon(urlBuilder),
|
||||
isEditable = objectPermissions.canEditDetails
|
||||
)
|
||||
if (objectPermissions.canCreateObjectThisType) {
|
||||
uiObjectsAddIconState.value = UiObjectsAddIconState.Visible
|
||||
}
|
||||
uiObjectsSettingsIconState.value = UiObjectsSettingsIconState.Visible
|
||||
if (objectPermissions.canDelete) {
|
||||
uiEditButtonState.value = UiEditButton.Visible
|
||||
}
|
||||
|
@ -542,47 +363,6 @@ class ObjectTypeViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
private fun mapObjectsSubscriptionToUi(
|
||||
items: List<UiObjectsListItem>,
|
||||
permission: ObjectPermissions
|
||||
) {
|
||||
if (items.isEmpty()) {
|
||||
uiObjectsListState.value = UiObjectsListState.Empty
|
||||
uiContentState.value = UiContentState.Idle()
|
||||
uiObjectsHeaderState.value = UiObjectsHeaderState(count = "0")
|
||||
uiObjectsSettingsIconState.value = UiObjectsSettingsIconState.Visible
|
||||
} else {
|
||||
uiContentState.value = UiContentState.Idle(
|
||||
scrollToTop = shouldScrollToTopItems.also { shouldScrollToTopItems = false }
|
||||
)
|
||||
uiObjectsListState.value = UiObjectsListState(items = items)
|
||||
uiObjectsHeaderState.value = UiObjectsHeaderState(count = "${items.size}")
|
||||
uiObjectsSettingsIconState.value = UiObjectsSettingsIconState.Visible
|
||||
}
|
||||
if (permission.canCreateObjectThisType) {
|
||||
uiObjectsAddIconState.value = UiObjectsAddIconState.Visible
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapSetSubscriptionToUi(
|
||||
items: List<ObjectWrapper.Basic>,
|
||||
permissions: ObjectPermissions
|
||||
) {
|
||||
uiMenuState.value = if (!permissions.participantCanEdit) {
|
||||
if (items.isEmpty()) {
|
||||
uiMenuState.value.copy(objSetItem = UiMenuSetItem.Hidden)
|
||||
} else {
|
||||
uiMenuState.value.copy(objSetItem = UiMenuSetItem.OpenSet(setId = items[0].id))
|
||||
}
|
||||
} else {
|
||||
if (items.isEmpty()) {
|
||||
uiMenuState.value.copy(objSetItem = UiMenuSetItem.CreateSet)
|
||||
} else {
|
||||
uiMenuState.value.copy(objSetItem = UiMenuSetItem.OpenSet(setId = items[0].id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapTemplatesSubscriptionToUi(
|
||||
objType: ObjectWrapper.Type,
|
||||
templates: List<TemplateView>,
|
||||
|
@ -614,7 +394,6 @@ class ObjectTypeViewModel(
|
|||
uiTemplatesAddIconState.value = UiTemplatesAddIconState.Visible
|
||||
}
|
||||
}
|
||||
uiTemplatesListState.value = UiTemplatesListState(items = finalTemplates)
|
||||
}
|
||||
|
||||
fun hideError() {
|
||||
|
@ -661,26 +440,6 @@ class ObjectTypeViewModel(
|
|||
updateTitle(event.title)
|
||||
}
|
||||
|
||||
is TypeEvent.OnSortClick -> onSortClicked(event.sort)
|
||||
TypeEvent.OnObjectsSettingsIconClick -> {
|
||||
}
|
||||
|
||||
TypeEvent.OnCreateSetClick -> {
|
||||
proceedWithCreateSet()
|
||||
}
|
||||
|
||||
is TypeEvent.OnOpenSetClick -> {
|
||||
proceedWithNavigation(
|
||||
objectId = event.setId,
|
||||
objectLayout = ObjectType.Layout.SET
|
||||
)
|
||||
}
|
||||
|
||||
TypeEvent.OnCreateObjectIconClick -> {
|
||||
shouldScrollToTopItems = true
|
||||
proceedWithCreateObjectOfThisType()
|
||||
}
|
||||
|
||||
TypeEvent.OnMenuItemDeleteClick -> {
|
||||
uiAlertState.value = UiDeleteAlertState.Show
|
||||
}
|
||||
|
@ -694,21 +453,6 @@ class ObjectTypeViewModel(
|
|||
uiAlertState.value = UiDeleteAlertState.Hidden
|
||||
}
|
||||
|
||||
is TypeEvent.OnObjectItemClick -> {
|
||||
when (event.item) {
|
||||
is UiObjectsListItem.Item -> {
|
||||
proceedWithNavigation(
|
||||
objectId = event.item.id,
|
||||
objectLayout = event.item.layout
|
||||
)
|
||||
}
|
||||
|
||||
is UiObjectsListItem.Loading -> {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypeEvent.OnObjectTypeIconClick -> {
|
||||
viewModelScope.launch {
|
||||
commands.emit(OpenEmojiPicker)
|
||||
|
@ -812,30 +556,6 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onSortClicked(sort: ObjectsListSort) {
|
||||
Timber.d("onSortClicked: $sort")
|
||||
val newSort = when (sort) {
|
||||
is ObjectsListSort.ByDateCreated -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
|
||||
is ObjectsListSort.ByDateUpdated -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
|
||||
is ObjectsListSort.ByName -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
|
||||
is ObjectsListSort.ByDateUsed -> {
|
||||
sort.copy(isSelected = true)
|
||||
}
|
||||
}
|
||||
shouldScrollToTopItems = true
|
||||
_sortState.value = newSort
|
||||
restartSubscription.value++
|
||||
}
|
||||
|
||||
private fun updateTitle(input: String) {
|
||||
viewModelScope.launch {
|
||||
val params = SetObjectDetails.Params(
|
||||
|
@ -1128,33 +848,6 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCreateObjectOfThisType() {
|
||||
val uniqueKeys = _objTypeState.value?.uniqueKey ?: return
|
||||
val defaultTemplate =
|
||||
uiTemplatesListState.value.items.firstOrNull { it.isDefault } as? TemplateView.Template
|
||||
val params = CreateObject.Param(
|
||||
space = vmParams.spaceId,
|
||||
type = TypeKey(uniqueKeys),
|
||||
template = defaultTemplate?.id,
|
||||
prefilled = mapOf(
|
||||
Relations.ORIGIN to ObjectOrigin.BUILT_IN.code.toDouble()
|
||||
)
|
||||
)
|
||||
viewModelScope.launch {
|
||||
createObject.async(params).fold(
|
||||
onSuccess = { result ->
|
||||
proceedWithNavigation(
|
||||
objectId = result.objectId,
|
||||
objectLayout = result.obj.layout
|
||||
)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while creating object")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithObjectTypeDelete() {
|
||||
val params = DeleteObjects.Params(
|
||||
targets = listOf(vmParams.objectId)
|
||||
|
@ -1188,31 +881,6 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCreateSet() {
|
||||
val typeName = _objTypeState.value?.name.orEmpty()
|
||||
val emoji = _objTypeState.value?.iconEmoji.orNull()
|
||||
val params = CreateObjectSet.Params(
|
||||
space = vmParams.spaceId.id,
|
||||
type = vmParams.objectId,
|
||||
details = mapOf(
|
||||
Relations.NAME to "${stringResourceProvider.getSetOfObjectsTitle()} $typeName",
|
||||
Relations.ICON_EMOJI to emoji
|
||||
)
|
||||
)
|
||||
viewModelScope.launch {
|
||||
createObjectSet.run(params).process(
|
||||
failure = {},
|
||||
success = { response ->
|
||||
val obj = ObjectWrapper.Basic(response.details)
|
||||
proceedWithNavigation(
|
||||
objectId = obj.id,
|
||||
objectLayout = obj.layout
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCreateTemplate() {
|
||||
val params = CreateTemplate.Params(
|
||||
targetObjectTypeId = vmParams.objectId,
|
||||
|
@ -1409,11 +1077,8 @@ class ObjectTypeViewModel(
|
|||
//endregion
|
||||
|
||||
companion object {
|
||||
const val OBJECTS_MAX_COUNT = 20
|
||||
const val TEMPLATE_MAX_COUNT = 100
|
||||
|
||||
fun objectsSubId(objectId: Id) = "TYPE-OBJECTS-SUB-ID-$objectId"
|
||||
fun setsSubId(objectId: Id) = "TYPE-SET-ID--$objectId"
|
||||
fun templatesSubId(objectId: Id) = "TYPE-TEMPLATES-SUB-ID--$objectId"
|
||||
}
|
||||
}
|
|
@ -526,6 +526,12 @@ class TreeWidgetContainerTest {
|
|||
links = links.map { it.id },
|
||||
isDeleted = true
|
||||
)
|
||||
|
||||
stringResourceProvider.stub {
|
||||
onBlocking {
|
||||
getDeletedObjectTitle()
|
||||
} doReturn "Deleted object"
|
||||
}
|
||||
|
||||
val widget = Widget.Tree(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue