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

DROID-3505 Primitives | Properties screens, ui updates (#2207)

This commit is contained in:
Konstantin Ivanov 2025-03-28 17:03:20 +01:00 committed by GitHub
parent 5a505bf935
commit cdc2ded35d
Signed by: github
GPG key ID: B5690EEEBB952194
10 changed files with 442 additions and 189 deletions

View file

@ -115,24 +115,6 @@ sealed class UiFieldsListItem {
const val ID = "section_file_recommended"
}
}
data class SpaceFields(
override val id: Id = ID,
override val canAdd: Boolean = false
) : Section() {
companion object {
const val ID = "section_space_fields"
}
}
data class LibraryFields(
override val id: Id = ID,
override val canAdd: Boolean = false
) : Section() {
companion object {
const val ID = "section_library_fields"
}
}
}
}
//endregion

View file

@ -1,5 +1,6 @@
package com.anytypeio.anytype.feature_object_type.fields.ui
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -54,6 +55,8 @@ fun SectionLocalFieldsInfo(
fun LocalInfoScreen(
modifier: Modifier,
bottomSheetState: SheetState,
@StringRes title : Int = R.string.object_type_fields_local_info_title,
@StringRes description : Int = R.string.object_type_fields_local_info_description,
onDismiss: () -> Unit
) {
ModalBottomSheet(
@ -75,7 +78,7 @@ fun LocalInfoScreen(
textAlign = TextAlign.Center,
style = HeadlineHeading,
color = colorResource(id = R.color.text_primary),
text = stringResource(R.string.object_type_fields_local_info_title)
text = stringResource(title)
)
Spacer(modifier = Modifier.height(7.dp))
Text(
@ -85,7 +88,7 @@ fun LocalInfoScreen(
textAlign = TextAlign.Center,
style = BodyCalloutRegular,
color = colorResource(id = R.color.text_primary),
text = stringResource(R.string.object_type_fields_local_info_description)
text = stringResource(description)
)
Spacer(modifier = Modifier.height(30.dp))
ButtonSecondary(

View file

@ -9,6 +9,7 @@ import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
@ -24,6 +25,7 @@ import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DropdownMenu
@ -71,10 +73,8 @@ import com.anytypeio.anytype.feature_object_type.fields.UiFieldsListItem
import com.anytypeio.anytype.feature_object_type.fields.UiFieldsListItem.Section
import com.anytypeio.anytype.feature_object_type.fields.UiFieldsListState
import com.anytypeio.anytype.feature_object_type.fields.UiLocalsFieldsInfoState
import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
import com.anytypeio.anytype.feature_object_type.ui.UiIconState
import com.anytypeio.anytype.feature_object_type.ui.UiTitleState
import com.anytypeio.anytype.feature_properties.add.UiEditTypePropertiesEvent
import com.anytypeio.anytype.feature_properties.edit.UiEditPropertyState
import com.anytypeio.anytype.feature_properties.edit.ui.PropertyScreen
import com.anytypeio.anytype.presentation.objects.ObjectIcon
@ -91,7 +91,6 @@ fun FieldsMainScreen(
uiIconState: UiIconState,
uiFieldLocalInfoState: UiLocalsFieldsInfoState,
uiEditPropertyState: UiEditPropertyState,
withDragger: Boolean = true,
fieldEvent: (FieldEvent) -> Unit
) {
@ -132,99 +131,20 @@ fun FieldsMainScreen(
modifier = Modifier.fillMaxWidth(),
uiTitleState = uiTitleState,
uiIconState = uiIconState,
withDragger = withDragger,
onBackClick = {
fieldEvent(OnBackClick)
}
)
},
content = { paddingValues ->
val contentModifier = if (Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK) {
Modifier
.windowInsetsPadding(WindowInsets.navigationBars)
.fillMaxSize()
.padding(top = paddingValues.calculateTopPadding())
} else {
Modifier
.fillMaxSize()
.padding(paddingValues)
}
LazyColumn(
modifier = contentModifier,
state = lazyListState,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(
count = uiFieldsListState.items.size,
key = { index -> uiFieldsListState.items[index].id },
contentType = { index -> getContentType(uiFieldsListState.items[index]) },
itemContent = { index ->
val item = uiFieldsListState.items[index]
when (item) {
is UiFieldsListItem.Item.Draggable -> {
FieldItemDraggable(
modifier = commonItemModifier(),
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
hapticFeedback = hapticFeedback
)
}
is UiFieldsListItem.Item.Local -> {
FieldItemLocal(
modifier = commonItemModifier(),
item = item,
fieldEvent = fieldEvent
)
}
is Section.SideBar -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = true,
onAddIconClick = {
fieldEvent(FieldEvent.Section.OnAddToSidebarIconClick)
}
)
}
is Section.Hidden -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = true
)
}
is Section.Header -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = false
)
}
is Section.Local,
is Section.File -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = false
)
}
is Section.LibraryFields -> TODO()
is Section.SpaceFields -> TODO()
}
}
)
item {
Spacer(modifier = Modifier.height(60.dp))
}
}
Items(
uiFieldsListState = uiFieldsListState,
lazyListState = lazyListState,
reorderableLazyColumnState = reorderableLazyColumnState,
hapticFeedback = hapticFeedback,
paddingValues = paddingValues,
fieldEvent = fieldEvent
)
}
)
@ -252,6 +172,203 @@ fun FieldsMainScreen(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun FieldsMainModalScreen(
uiFieldsListState: UiFieldsListState,
uiTitleState: UiTitleState,
uiIconState: UiIconState,
uiFieldLocalInfoState: UiLocalsFieldsInfoState,
uiEditPropertyState: UiEditPropertyState,
fieldEvent: (FieldEvent) -> Unit
) {
val hapticFeedback = rememberReorderHapticFeedback()
val lazyListState = rememberLazyListState()
val reorderableLazyColumnState = rememberReorderableLazyListState(lazyListState) { from, to ->
fieldEvent(DragEvent.OnMove(from.key as String, to.key as String))
hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.MOVE)
}
var isDragging by remember { mutableStateOf(false) }
LaunchedEffect(reorderableLazyColumnState.isAnyItemDragging) {
if (reorderableLazyColumnState.isAnyItemDragging) {
isDragging = true
// Optional: Add a small delay to avoid triggering on very short drags
delay(50)
} else if (isDragging) {
isDragging = false
fieldEvent(DragEvent.OnDragEnd)
hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.MOVE)
}
}
Column(
modifier = Modifier.fillMaxSize()
.nestedScroll(rememberNestedScrollInteropConnection())
.background(
color = colorResource(id = R.color.background_primary),
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
)
) {
Dragger(
modifier = Modifier
.padding(vertical = 6.dp)
.align(Alignment.CenterHorizontally)
)
Box(
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
) {
Text(
modifier = Modifier
.wrapContentSize()
.align(Alignment.Center),
text = stringResource(R.string.object_type_fields_title),
style = Title1,
color = colorResource(R.color.text_primary)
)
}
InfoBar(
modifier = Modifier
.fillMaxWidth()
.height(36.dp)
.background(color = colorResource(R.color.shape_transparent_secondary)),
uiTitleState = uiTitleState,
uiIconState = uiIconState
)
Items(
uiFieldsListState = uiFieldsListState,
lazyListState = lazyListState,
reorderableLazyColumnState = reorderableLazyColumnState,
hapticFeedback = hapticFeedback,
paddingValues = PaddingValues(0.dp),
fieldEvent = fieldEvent
)
}
if (uiEditPropertyState is UiEditPropertyState.Visible) {
PropertyScreen(
modifier = Modifier.fillMaxWidth(),
uiState = uiEditPropertyState,
onDismissRequest = { fieldEvent(OnEditPropertyScreenDismiss) },
onFormatClick = {},
onSaveButtonClicked = { fieldEvent(EditProperty.OnSaveButtonClicked) },
onCreateNewButtonClicked = {},
onPropertyNameUpdate = { fieldEvent(EditProperty.OnPropertyNameUpdate(it)) },
onMenuUnlinkClick = { fieldEvent(OnDeleteFromTypeClick(it)) },
onLimitTypesClick = { fieldEvent(OnLimitTypesClick) },
onDismissLimitTypes = { fieldEvent(OnLimitTypesDismiss) },
)
}
if (uiFieldLocalInfoState is UiLocalsFieldsInfoState.Visible) {
SectionLocalFieldsInfo(
modifier = Modifier.fillMaxWidth(),
state = uiFieldLocalInfoState,
fieldEvent = fieldEvent
)
}
}
@Composable
private fun Items(
lazyListState: LazyListState,
reorderableLazyColumnState: ReorderableLazyListState,
uiFieldsListState: UiFieldsListState,
paddingValues: PaddingValues,
hapticFeedback: ReorderHapticFeedback,
fieldEvent: (FieldEvent) -> Unit,
) {
val contentModifier = if (Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK) {
Modifier
.windowInsetsPadding(WindowInsets.navigationBars)
.fillMaxSize()
.padding(top = paddingValues.calculateTopPadding())
} else {
Modifier
.fillMaxSize()
.padding(paddingValues)
}
LazyColumn(
modifier = contentModifier,
state = lazyListState,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(
count = uiFieldsListState.items.size,
key = { index -> uiFieldsListState.items[index].id },
contentType = { index -> getContentType(uiFieldsListState.items[index]) },
itemContent = { index ->
val item = uiFieldsListState.items[index]
when (item) {
is UiFieldsListItem.Item.Draggable -> {
FieldItemDraggable(
modifier = commonItemModifier(),
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
hapticFeedback = hapticFeedback
)
}
is UiFieldsListItem.Item.Local -> {
FieldItemLocal(
modifier = commonItemModifier(),
item = item,
fieldEvent = fieldEvent
)
}
is Section.SideBar -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = true,
onAddIconClick = {
fieldEvent(FieldEvent.Section.OnAddToSidebarIconClick)
}
)
}
is Section.Hidden -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = true
)
}
is Section.Header -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = false
)
}
is Section.Local,
is Section.File -> {
SectionItem(
item = item,
reorderingState = reorderableLazyColumnState,
fieldEvent = fieldEvent,
isReorderable = false
)
}
}
}
)
item {
Spacer(modifier = Modifier.height(60.dp))
}
}
}
/** Returns a content type string based on the item type. **/
private fun getContentType(item: UiFieldsListItem): String {
return when (item) {
@ -262,8 +379,6 @@ private fun getContentType(item: UiFieldsListItem): String {
is Section.Hidden -> FieldsItemsContentType.SECTION_HIDDEN
is Section.Local -> FieldsItemsContentType.SECTION_LOCAL
is Section.File -> FieldsItemsContentType.SECTION_FILE
is Section.LibraryFields -> "content_type_section_library_fields"
is Section.SpaceFields -> "content_type_section_space_fields"
}
}
@ -283,7 +398,6 @@ fun LazyItemScope.commonItemModifier() = Modifier
@Composable
private fun TopBar(
modifier: Modifier,
withDragger: Boolean = true,
uiTitleState: UiTitleState,
uiIconState: UiIconState,
onBackClick: () -> Unit = {}
@ -299,35 +413,26 @@ private fun TopBar(
color = colorResource(id = R.color.background_primary),
)
) {
if (withDragger) {
Dragger(
modifier = Modifier
.padding(vertical = 6.dp)
.align(Alignment.CenterHorizontally)
)
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
) {
if (!withDragger) {
Box(
modifier = Modifier
.width(56.dp)
.height(48.dp)
.align(Alignment.CenterStart)
.noRippleThrottledClickable {
onBackClick()
},
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier.wrapContentSize(),
painter = painterResource(R.drawable.ic_default_top_back),
contentDescription = stringResource(R.string.content_desc_back_button)
)
}
Box(
modifier = Modifier
.width(56.dp)
.height(48.dp)
.align(Alignment.CenterStart)
.noRippleThrottledClickable {
onBackClick()
},
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier.wrapContentSize(),
painter = painterResource(R.drawable.ic_default_top_back),
contentDescription = stringResource(R.string.content_desc_back_button)
)
}
Text(
@ -362,16 +467,16 @@ private fun InfoBar(modifier: Modifier, uiTitleState: UiTitleState, uiIconState:
style = Caption1Medium,
color = colorResource(id = R.color.text_primary),
)
Spacer(modifier = Modifier.width(4.dp))
ListWidgetObjectIcon(
modifier = Modifier
.padding(start = 4.dp)
.size(18.dp),
modifier = Modifier,
icon = uiIconState.icon,
backgroundColor = R.color.transparent_black
backgroundColor = R.color.transparent_black,
iconSize = 16.dp
)
Spacer(modifier = Modifier.width(2.dp))
Text(
modifier = Modifier.padding(start = 4.dp),
modifier = Modifier,
text = uiTitleState.title,
style = Caption1Medium,
maxLines = 1,
@ -404,11 +509,9 @@ private fun LazyItemScope.SectionItem(
)
is Section.Local -> stringResource(R.string.object_type_fields_section_local_fields) to colorResource(
id = R.color.text_primary
id = R.color.text_secondary
)
is Section.LibraryFields -> TODO()
is Section.SpaceFields -> TODO()
is Section.File -> stringResource(R.string.object_type_fields_section_file) to colorResource(
id = R.color.text_secondary
)