1
0
Fork 0
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:
Konstantin Ivanov 2025-04-15 18:42:51 +02:00 committed by GitHub
parent d0c3412e8c
commit f69d922791
Signed by: github
GPG key ID: B5690EEEBB952194
12 changed files with 425 additions and 86 deletions

View file

@ -222,6 +222,14 @@ interface SpaceTypesComponent {
@Module
object SpaceTypesModule {
@JvmStatic
@PerScreen
@Provides
fun getSetObjectListIsArchived(
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): SetObjectListIsArchived = SetObjectListIsArchived(repo, dispatchers)
@Module
interface Declarations {
@PerScreen
@ -268,6 +276,14 @@ interface SpacePropertiesComponent {
@Module
object SpacePropertiesModule {
@JvmStatic
@PerScreen
@Provides
fun getSetObjectListIsArchived(
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): SetObjectListIsArchived = SetObjectListIsArchived(repo, dispatchers)
@JvmStatic
@Provides
@PerScreen

View file

@ -49,7 +49,8 @@ class SpacePropertiesFragment : BaseComposeFragment() {
uiState = vm.uiItemsState.collectAsStateWithLifecycle().value,
onBackPressed = vm::onBackClicked,
onPropertyClicked = vm::onPropertyClicked,
onAddIconClicked = vm::onCreateNewPropertyClicked
onAddIconClicked = vm::onCreateNewPropertyClicked,
onMoveToBin = vm::onMoveToBinProperty
)
SpacePropertyScreen(
uiState = vm.uiEditPropertyScreen.collectAsStateWithLifecycle().value

View file

@ -46,6 +46,7 @@ class SpaceTypesFragment : BaseComposeFragment() {
onBackPressed = vm::onBackClicked,
onTypeClicked = vm::onTypeClicked,
onAddIconClicked = vm::onCreateNewTypeClicked,
onMoveToBin = vm::onMoveToBin
)
}
LaunchedEffect(Unit) {

View file

@ -336,8 +336,8 @@ private fun SectionLocal(
) {
val text = stringResource(id = R.string.object_properties_section_local)
val iconRes = when (item) {
is Model.Section.Local.Shown -> R.drawable.ic_arrow_up_18
is Model.Section.Local.Unshown -> R.drawable.ic_list_arrow_18
is Model.Section.Local.Shown -> R.drawable.ic_list_arrow_18
is Model.Section.Local.Unshown -> R.drawable.ic_arrow_right_18
}
Box(
modifier = Modifier
@ -409,8 +409,8 @@ private fun SectionHidden(
) {
val text = stringResource(id = R.string.object_properties_section_hidden)
val iconRes = when (item) {
is Model.Section.Hidden.Shown -> R.drawable.ic_arrow_up_18
is Model.Section.Hidden.Unshown -> R.drawable.ic_list_arrow_18
is Model.Section.Hidden.Shown -> R.drawable.ic_list_arrow_18
is Model.Section.Hidden.Unshown -> R.drawable.ic_arrow_right_18
}
Box(
modifier = Modifier

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="18"
android:viewportHeight="18">
<path
android:pathData="M6.22,14.789C5.927,14.508 5.927,14.052 6.22,13.771L11.189,9L6.22,4.229C5.927,3.948 5.927,3.492 6.22,3.211C6.513,2.93 6.987,2.93 7.28,3.211L13.311,9L7.28,14.789C6.987,15.07 6.513,15.07 6.22,14.789Z"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
</vector>

View file

@ -20,6 +20,7 @@ import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
import com.anytypeio.anytype.core_ui.views.ButtonPrimary
import com.anytypeio.anytype.core_ui.views.ButtonSecondary
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
@ -91,12 +92,12 @@ fun LocalInfoScreen(
text = stringResource(description)
)
Spacer(modifier = Modifier.height(30.dp))
ButtonSecondary(
ButtonPrimary(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp),
text = stringResource(R.string.object_type_fields_local_info_button),
size = ButtonSize.LargeSecondary,
size = ButtonSize.Large,
onClick = {
onDismiss()
}

View file

@ -1,9 +1,10 @@
package com.anytypeio.anytype.feature_object_type.ui.space
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
@ -21,10 +22,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
@ -34,14 +39,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.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.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_ui.widgets.ListWidgetObjectIcon
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
import com.anytypeio.anytype.presentation.objects.ObjectIcon
@ -52,9 +60,10 @@ import com.anytypeio.anytype.presentation.types.UiSpaceTypesScreenState
@Composable
fun SpaceTypesListScreen(
uiState: UiSpaceTypesScreenState,
onTypeClicked: (UiSpaceTypeItem) -> Unit,
onTypeClicked: (UiSpaceTypeItem.Type) -> Unit,
onBackPressed: () -> Unit,
onAddIconClicked: () -> Unit
onAddIconClicked: () -> Unit,
onMoveToBin: (UiSpaceTypeItem.Type) -> Unit
) {
Column(
modifier = Modifier
@ -91,17 +100,24 @@ fun SpaceTypesListScreen(
key = { index -> items[index].id },
itemContent = {
val item = items[it]
Type(
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
.padding(start = 12.dp, end = 20.dp)
.clickable {
onTypeClicked(item)
},
item = item
)
Divider()
when (item) {
is UiSpaceTypeItem.Section -> {
Section(item)
}
is UiSpaceTypeItem.Type -> {
Type(
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
.padding(start = 12.dp, end = 20.dp),
item = item,
onTypeClicked = onTypeClicked,
onMoveToBin = onMoveToBin
)
Divider()
}
}
}
)
item {
@ -115,13 +131,48 @@ fun SpaceTypesListScreen(
}
}
@Composable
private fun Section(section: UiSpaceTypeItem.Section) {
val text = when (section) {
is UiSpaceTypeItem.Section.MyTypes ->
stringResource(R.string.space_types_screen_section_my_types)
is UiSpaceTypeItem.Section.System ->
stringResource(R.string.space_types_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 Type(
modifier: Modifier,
item: UiSpaceTypeItem
item: UiSpaceTypeItem.Type,
onTypeClicked: (UiSpaceTypeItem.Type) -> Unit,
onMoveToBin: (UiSpaceTypeItem.Type) -> Unit
) {
val isMenuExpanded = remember { mutableStateOf(false) }
Row(
modifier = modifier.fillMaxWidth(),
modifier = modifier.fillMaxWidth()
.combinedClickable(
onClick = { onTypeClicked(item) },
onLongClick = { isMenuExpanded.value = true }
),
verticalAlignment = CenterVertically
) {
ListWidgetObjectIcon(
@ -141,6 +192,51 @@ private fun Type(
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: UiSpaceTypeItem.Type,
showMenu: Boolean,
onDismissRequest: () -> Unit,
onMoveToBin: (UiSpaceTypeItem.Type) -> 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)
},
)
}
}
@ -208,7 +304,8 @@ fun SpaceTypesListScreenPreview() {
SpaceTypesListScreen(
uiState = UiSpaceTypesScreenState(
items = listOf(
UiSpaceTypeItem(
UiSpaceTypeItem.Section.MyTypes(),
UiSpaceTypeItem.Type(
id = "1",
name = "Type 1",
icon = ObjectIcon.TypeIcon.Default(
@ -216,7 +313,8 @@ fun SpaceTypesListScreenPreview() {
color = CustomIconColor.Teal
)
),
UiSpaceTypeItem(
UiSpaceTypeItem.Section.System(),
UiSpaceTypeItem.Type(
id = "2",
name = "Type 2",
icon = ObjectIcon.TypeIcon.Default(
@ -228,6 +326,7 @@ fun SpaceTypesListScreenPreview() {
),
onBackPressed = {},
onTypeClicked = {},
onAddIconClicked = {}
onAddIconClicked = {},
onMoveToBin = {}
)
}

View file

@ -351,9 +351,10 @@ class ObjectTypeViewModel(
(uiTitleAndIconUpdateState.value as? UiTypeSetupTitleAndIconState.Visible.EditType)?.let {
uiTitleAndIconUpdateState.value = it.copy(icon = newIcon)
}
if (objectPermissions.canDelete) {
uiEditButtonState.value = UiEditButton.Visible
}
//turn off button, we give Move to Bin logic in Library now
// if (objectPermissions.canDelete) {
// uiEditButtonState.value = UiEditButton.Visible
// }
objType.recommendedLayout?.let { layout ->
if (_objectTypePermissionsState.value?.canChangeRecommendedLayoutForThisType == true) {
uiHorizontalButtonsState.value =

View file

@ -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()
}

View file

@ -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)
},
)
}
}

View file

@ -2034,6 +2034,12 @@ Please provide specific details of your needs here.</string>
<string name="space_settings_auto_create_widgets">Auto Create Type Widgets</string>
<string name="space_types_screen_title">Object types</string>
<string name="space_types_screen_section_my_types">My Types</string>
<string name="space_types_screen_section_system_types">System Types</string>
<string name="space_properties_screen_title">Properties</string>
<string name="space_properties_screen_section_my_types">My Properties</string>
<string name="space_properties_screen_section_system_types">System Properties</string>
<string name="space_properties_screen_menu_move_to_bin">Move to bin</string>
</resources>

View file

@ -6,9 +6,11 @@ import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
import com.anytypeio.anytype.domain.base.fold
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.objects.SetObjectListIsArchived
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.primitives.FieldParser
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
@ -29,6 +31,7 @@ class SpaceTypesViewModel(
private val fieldParser: FieldParser,
private val storeOfObjectTypes: StoreOfObjectTypes,
private val userPermissionProvider: UserPermissionProvider,
private val setObjectListIsArchived: SetObjectListIsArchived
) : ViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate {
val uiItemsState =
@ -60,19 +63,64 @@ class SpaceTypesViewModel(
.collectLatest { event ->
val allTypes =
storeOfObjectTypes.getAll().mapNotNull { objectType ->
val resolvedLayout = objectType.recommendedLayout ?: return@mapNotNull null
val resolvedLayout =
objectType.recommendedLayout ?: return@mapNotNull null
if (notAllowedTypesLayouts.contains(resolvedLayout)) {
return@mapNotNull null
} else {
objectType.toUiItem()
objectType
}
}
.sortedBy { it.name }
uiItemsState.value = UiSpaceTypesScreenState(allTypes)
val (myTypes, systemTypes) = allTypes.partition {
!it.restrictions.contains(
ObjectRestriction.DELETE
)
}
val list = buildList {
add(UiSpaceTypeItem.Section.MyTypes())
addAll(myTypes.map { type ->
UiSpaceTypeItem.Type(
id = type.id,
name = fieldParser.getObjectName(type),
icon = type.objectIcon(),
isPossibleMoveToBin = true
)
}.sortedBy { it.name })
add(UiSpaceTypeItem.Section.System())
addAll(systemTypes.map { type ->
UiSpaceTypeItem.Type(
id = type.id,
name = fieldParser.getObjectName(type),
icon = type.objectIcon(),
isPossibleMoveToBin = false
)
}.sortedBy { it.name })
}
uiItemsState.value = UiSpaceTypesScreenState(list)
}
}
}
fun onMoveToBin(item: UiSpaceTypeItem.Type) {
val typeId = item.id
viewModelScope.launch {
val params = SetObjectListIsArchived.Params(
targets = listOf(typeId),
isArchived = true
)
setObjectListIsArchived.async(params).fold(
onSuccess = {
Timber.d("Object Type $typeId moved to bin")
},
onFailure = {
Timber.e(it, "Error while moving pbject type $typeId to bin")
}
)
}
}
fun onBackClicked() {
viewModelScope.launch {
commands.emit(Command.Back)
@ -80,7 +128,7 @@ class SpaceTypesViewModel(
}
fun onCreateNewTypeClicked() {
if (permission.value?.isOwnerOrEditor() == true) {
if (permission.value?.isOwnerOrEditor() == true) {
viewModelScope.launch {
commands.emit(Command.CreateNewType(vmParams.spaceId.id))
}
@ -91,7 +139,7 @@ class SpaceTypesViewModel(
}
}
fun onTypeClicked(type: UiSpaceTypeItem) {
fun onTypeClicked(type: UiSpaceTypeItem.Type) {
viewModelScope.launch {
commands.emit(
Command.OpenType(
@ -109,13 +157,6 @@ class SpaceTypesViewModel(
data class ShowToast(val message: String) : Command()
}
private fun ObjectWrapper.Type.toUiItem() = UiSpaceTypeItem(
id = id,
name = fieldParser.getObjectName(this),
icon = this.objectIcon()
)
data class VmParams(
val spaceId: SpaceId
)
@ -127,7 +168,8 @@ class SpaceTypesVmFactory @Inject constructor(
private val analytics: Analytics,
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
private val userPermissionProvider: UserPermissionProvider,
private val fieldParser: FieldParser
private val fieldParser: FieldParser,
private val setObjectListIsArchived: SetObjectListIsArchived
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T =
@ -137,14 +179,26 @@ class SpaceTypesVmFactory @Inject constructor(
analytics = analytics,
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
userPermissionProvider = userPermissionProvider,
fieldParser = fieldParser
fieldParser = fieldParser,
setObjectListIsArchived = setObjectListIsArchived
) as T
}
data class UiSpaceTypesScreenState(val items: List<UiSpaceTypeItem>)
data class UiSpaceTypeItem(
val id: Id,
val name: String,
val icon: ObjectIcon.TypeIcon
)
sealed class UiSpaceTypeItem {
abstract val id: Id
data class Type(
override val id: Id,
val name: String,
val icon: ObjectIcon.TypeIcon,
val isPossibleMoveToBin: Boolean = false
) : UiSpaceTypeItem()
sealed class Section : UiSpaceTypeItem() {
data class MyTypes(override val id: Id = "section_my_types") : Section()
data class System(override val id: Id = "section_system") : Section()
}
}