mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3571 Primitives | Space types and properties, sections ui (#2319)
This commit is contained in:
parent
d0c3412e8c
commit
f69d922791
12 changed files with 425 additions and 86 deletions
|
@ -9,10 +9,12 @@ import com.anytypeio.anytype.core_models.RelationFormat
|
|||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.primitives.RelationKey
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
|
||||
import com.anytypeio.anytype.core_ui.extensions.simpleIcon
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
|
||||
import com.anytypeio.anytype.domain.objects.SetObjectListIsArchived
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfRelations
|
||||
import com.anytypeio.anytype.domain.objects.mapLimitObjectTypes
|
||||
|
@ -53,7 +55,8 @@ class SpacePropertiesViewModel(
|
|||
private val storeOfRelations: StoreOfRelations,
|
||||
private val stringResourceProvider: StringResourceProvider,
|
||||
private val setObjectDetails: SetObjectDetails,
|
||||
private val createRelation: CreateRelation
|
||||
private val createRelation: CreateRelation,
|
||||
private val setObjectListIsArchived: SetObjectListIsArchived
|
||||
) : ViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate {
|
||||
|
||||
// Main UI states
|
||||
|
@ -76,24 +79,64 @@ class SpacePropertiesViewModel(
|
|||
storeOfRelations.trackChanges()
|
||||
.collectLatest { event ->
|
||||
val allProperties = storeOfRelations.getAll().mapNotNull { property ->
|
||||
if (property.isHidden == true) {
|
||||
if (property.isHidden == true || property.isDeleted == true || property.isArchived == true) {
|
||||
null
|
||||
} else {
|
||||
UiSpacePropertyItem(
|
||||
property
|
||||
}
|
||||
}
|
||||
val (myProperties, systemProperties) =
|
||||
allProperties.partition { !it.restrictions.contains(ObjectRestriction.DELETE) }
|
||||
val list = buildList {
|
||||
add(UiSpacePropertyItem.Section.MyProperties())
|
||||
addAll(myProperties.map { property ->
|
||||
UiSpacePropertyItem.Item(
|
||||
id = property.id,
|
||||
key = RelationKey(property.key),
|
||||
name = property.name.orEmpty(),
|
||||
format = property.format,
|
||||
isEditableField = fieldParser.isPropertyEditable(property),
|
||||
limitObjectTypes = storeOfObjectTypes.mapLimitObjectTypes(property = property)
|
||||
limitObjectTypes = storeOfObjectTypes.mapLimitObjectTypes(property = property),
|
||||
isPossibleMoveToBin = true
|
||||
)
|
||||
}
|
||||
}.sortedBy { it.name }
|
||||
uiItemsState.value = UiSpacePropertiesScreenState(allProperties)
|
||||
}.sortedBy { it.name })
|
||||
add(UiSpacePropertyItem.Section.SystemProperties())
|
||||
addAll(systemProperties.map { property ->
|
||||
UiSpacePropertyItem.Item(
|
||||
id = property.id,
|
||||
key = RelationKey(property.key),
|
||||
name = property.name.orEmpty(),
|
||||
format = property.format,
|
||||
isEditableField = fieldParser.isPropertyEditable(property),
|
||||
limitObjectTypes = storeOfObjectTypes.mapLimitObjectTypes(property = property),
|
||||
isPossibleMoveToBin = false
|
||||
)
|
||||
}.sortedBy { it.name })
|
||||
}
|
||||
|
||||
uiItemsState.value = UiSpacePropertiesScreenState(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onMoveToBinProperty(item: UiSpacePropertyItem.Item) {
|
||||
val propertyId = item.id
|
||||
viewModelScope.launch {
|
||||
val params = SetObjectListIsArchived.Params(
|
||||
targets = listOf(propertyId),
|
||||
isArchived = true
|
||||
)
|
||||
setObjectListIsArchived.async(params).fold(
|
||||
onSuccess = {
|
||||
Timber.d("Property $propertyId moved to bin")
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while moving property $propertyId to bin")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onBackClicked() {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.Back)
|
||||
|
@ -124,7 +167,7 @@ class SpacePropertiesViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onPropertyClicked(item: UiSpacePropertyItem) {
|
||||
fun onPropertyClicked(item: UiSpacePropertyItem.Item) {
|
||||
viewModelScope.launch {
|
||||
val computedLimitTypes = computeLimitTypes(item = item)
|
||||
val formatName = stringResourceProvider.getPropertiesFormatPrettyString(item.format)
|
||||
|
@ -158,7 +201,7 @@ class SpacePropertiesViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun computeLimitTypes(item: UiSpacePropertyItem): List<UiPropertyLimitTypeItem> {
|
||||
private suspend fun computeLimitTypes(item: UiSpacePropertyItem.Item): List<UiPropertyLimitTypeItem> {
|
||||
return item.limitObjectTypes.mapNotNull { id ->
|
||||
storeOfObjectTypes.get(id = id)?.let { objType ->
|
||||
UiPropertyLimitTypeItem(
|
||||
|
@ -329,7 +372,8 @@ class SpacePropertiesVmFactory @Inject constructor(
|
|||
private val storeOfRelations: StoreOfRelations,
|
||||
private val stringResourceProvider: StringResourceProvider,
|
||||
private val setObjectDetails: SetObjectDetails,
|
||||
private val createRelation: CreateRelation
|
||||
private val createRelation: CreateRelation,
|
||||
private val setObjectListIsArchived: SetObjectListIsArchived
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T =
|
||||
|
@ -343,7 +387,8 @@ class SpacePropertiesVmFactory @Inject constructor(
|
|||
storeOfRelations = storeOfRelations,
|
||||
stringResourceProvider = stringResourceProvider,
|
||||
setObjectDetails = setObjectDetails,
|
||||
createRelation = createRelation
|
||||
createRelation = createRelation,
|
||||
setObjectListIsArchived = setObjectListIsArchived
|
||||
) as T
|
||||
}
|
||||
|
||||
|
@ -355,11 +400,22 @@ data class UiSpacePropertiesScreenState(
|
|||
}
|
||||
}
|
||||
|
||||
data class UiSpacePropertyItem(
|
||||
val id: Id,
|
||||
val key: RelationKey,
|
||||
val name: String,
|
||||
val format: RelationFormat,
|
||||
val isEditableField: Boolean,
|
||||
val limitObjectTypes: List<Id>
|
||||
)
|
||||
sealed class UiSpacePropertyItem{
|
||||
|
||||
abstract val id: Id
|
||||
|
||||
sealed class Section : UiSpacePropertyItem() {
|
||||
data class MyProperties(override val id: Id = "section_my_properties") : Section()
|
||||
data class SystemProperties(override val id: Id = "section_system_properties") : Section()
|
||||
}
|
||||
|
||||
data class Item(
|
||||
override val id: Id,
|
||||
val key: RelationKey,
|
||||
val name: String,
|
||||
val format: RelationFormat,
|
||||
val isEditableField: Boolean,
|
||||
val limitObjectTypes: List<Id>,
|
||||
val isPossibleMoveToBin: Boolean = false
|
||||
) : UiSpacePropertyItem()
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package com.anytypeio.anytype.feature_properties.space.ui
|
||||
|
||||
import android.os.Build
|
||||
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.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
@ -24,10 +25,14 @@ import androidx.compose.foundation.layout.windowInsetsPadding
|
|||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
|
@ -38,14 +43,17 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.extensions.simpleIcon
|
||||
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.views.Caption1Medium
|
||||
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.core_ui.views.UxSmallTextRegular
|
||||
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
|
||||
import com.anytypeio.anytype.feature_properties.space.UiSpacePropertiesScreenState
|
||||
import com.anytypeio.anytype.feature_properties.space.UiSpacePropertyItem
|
||||
|
@ -53,9 +61,10 @@ import com.anytypeio.anytype.feature_properties.space.UiSpacePropertyItem
|
|||
@Composable
|
||||
fun SpacePropertiesListScreen(
|
||||
uiState: UiSpacePropertiesScreenState,
|
||||
onPropertyClicked: (UiSpacePropertyItem) -> Unit,
|
||||
onPropertyClicked: (UiSpacePropertyItem.Item) -> Unit,
|
||||
onBackPressed: () -> Unit,
|
||||
onAddIconClicked: () -> Unit
|
||||
onAddIconClicked: () -> Unit,
|
||||
onMoveToBin: (UiSpacePropertyItem.Item) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
@ -93,17 +102,23 @@ fun SpacePropertiesListScreen(
|
|||
key = { index -> items[index].id },
|
||||
itemContent = {
|
||||
val item = items[it]
|
||||
Relation(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp)
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.clickable {
|
||||
onPropertyClicked(item)
|
||||
},
|
||||
item = item
|
||||
)
|
||||
Divider()
|
||||
when (item ) {
|
||||
is UiSpacePropertyItem.Item -> {
|
||||
Property(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp)
|
||||
.padding(start = 20.dp, end = 20.dp),
|
||||
item = item,
|
||||
onPropertyClicked = onPropertyClicked,
|
||||
onMoveToBin = onMoveToBin
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
is UiSpacePropertyItem.Section -> {
|
||||
Section(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
item {
|
||||
|
@ -118,12 +133,47 @@ fun SpacePropertiesListScreen(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Relation(
|
||||
private fun Section(section: UiSpacePropertyItem.Section) {
|
||||
val text = when (section) {
|
||||
is UiSpacePropertyItem.Section.MyProperties ->
|
||||
stringResource(R.string.space_properties_screen_section_my_types)
|
||||
is UiSpacePropertyItem.Section.SystemProperties ->
|
||||
stringResource(R.string.space_properties_screen_section_system_types)
|
||||
}
|
||||
Column {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp, start = 20.dp)
|
||||
.align(Alignment.BottomStart),
|
||||
text = text,
|
||||
style = Caption1Medium,
|
||||
color = colorResource(R.color.text_secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun Property(
|
||||
modifier: Modifier,
|
||||
item: UiSpacePropertyItem
|
||||
item: UiSpacePropertyItem.Item,
|
||||
onPropertyClicked: (UiSpacePropertyItem.Item) -> Unit,
|
||||
onMoveToBin: (UiSpacePropertyItem.Item) -> Unit
|
||||
) {
|
||||
val isMenuExpanded = remember { mutableStateOf(false) }
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.combinedClickable(
|
||||
onClick = { onPropertyClicked(item) },
|
||||
onLongClick = { isMenuExpanded.value = true }
|
||||
),
|
||||
verticalAlignment = CenterVertically
|
||||
) {
|
||||
val icon = item.format.simpleIcon()
|
||||
|
@ -143,6 +193,50 @@ private fun Relation(
|
|||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
if (item.isPossibleMoveToBin) {
|
||||
ItemDropDownMenu(
|
||||
item = item,
|
||||
showMenu = isMenuExpanded.value,
|
||||
onDismissRequest = { isMenuExpanded.value = false },
|
||||
onMoveToBin = {
|
||||
isMenuExpanded.value = false
|
||||
onMoveToBin(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ItemDropDownMenu(
|
||||
item: UiSpacePropertyItem.Item,
|
||||
showMenu: Boolean,
|
||||
onDismissRequest: () -> Unit,
|
||||
onMoveToBin: (UiSpacePropertyItem.Item) -> Unit
|
||||
) {
|
||||
DropdownMenu(
|
||||
modifier = Modifier
|
||||
.width(244.dp),
|
||||
expanded = showMenu,
|
||||
offset = DpOffset(x = 0.dp, y = 0.dp),
|
||||
onDismissRequest = {
|
||||
onDismissRequest()
|
||||
},
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(
|
||||
text = stringResource(R.string.space_properties_screen_menu_move_to_bin),
|
||||
style = UxSmallTextRegular,
|
||||
color = colorResource(id = R.color.text_primary)
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
onMoveToBin(item)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue