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

DROID-3435 Primitives | Ui fixes (#2152)

This commit is contained in:
Konstantin Ivanov 2025-03-12 13:01:22 +01:00 committed by GitHub
parent a65f78c8d4
commit 58f64ffd61
Signed by: github
GPG key ID: B5690EEEBB952194
19 changed files with 434 additions and 118 deletions

View file

@ -26,4 +26,9 @@ sealed class FieldEvent {
data class OnMove(val fromKey: String, val toKey: String) : DragEvent()
data object OnDragEnd : DragEvent()
}
sealed class EditProperty : FieldEvent() {
data class OnPropertyNameUpdate(val name: String) : EditProperty()
data object OnSaveButtonClicked : EditProperty()
}
}

View file

@ -44,7 +44,7 @@ sealed class UiFieldsListItem {
abstract val fieldTitle: String
abstract val format: RelationFormat
abstract val limitObjectTypes: List<UiPropertyLimitTypeItem>
abstract val canDelete: Boolean
abstract val isPossibleToUnlinkFromType: Boolean
abstract val isEditableField: Boolean
data class Draggable(
@ -53,7 +53,7 @@ sealed class UiFieldsListItem {
override val fieldTitle: String,
override val format: RelationFormat,
override val limitObjectTypes: List<UiPropertyLimitTypeItem> = emptyList(),
override val canDelete: Boolean,
override val isPossibleToUnlinkFromType: Boolean,
override val isEditableField: Boolean
) : Item()
@ -63,7 +63,7 @@ sealed class UiFieldsListItem {
override val fieldTitle: String,
override val format: RelationFormat,
override val limitObjectTypes: List<UiPropertyLimitTypeItem> = emptyList(),
override val canDelete: Boolean = false,
override val isPossibleToUnlinkFromType: Boolean = false,
override val isEditableField: Boolean
) : Item()
}

View file

@ -4,6 +4,7 @@ import android.os.Build
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -47,15 +48,14 @@ import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.common.ReorderHapticFeedback
import com.anytypeio.anytype.core_ui.common.ReorderHapticFeedbackType
import com.anytypeio.anytype.core_ui.common.bottomBorder
import com.anytypeio.anytype.core_ui.common.rememberReorderHapticFeedback
import com.anytypeio.anytype.core_ui.extensions.simpleIcon
import com.anytypeio.anytype.core_ui.foundation.Dragger
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
import com.anytypeio.anytype.core_ui.views.BodyCalloutMedium
import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
import com.anytypeio.anytype.core_ui.views.BodyRegular
import com.anytypeio.anytype.core_ui.views.Caption1Medium
import com.anytypeio.anytype.core_ui.views.Relations1
import com.anytypeio.anytype.core_ui.views.Title1
import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
@ -85,6 +85,7 @@ fun FieldsMainScreen(
uiIconState: UiIconState,
uiFieldLocalInfoState: UiLocalsFieldsInfoState,
uiEditPropertyState: UiEditPropertyState,
withDragger: Boolean = true,
fieldEvent: (FieldEvent) -> Unit
) {
@ -125,7 +126,8 @@ fun FieldsMainScreen(
TopBar(
modifier = Modifier.fillMaxWidth(),
uiTitleState = uiTitleState,
uiIconState = uiIconState
uiIconState = uiIconState,
withDragger = withDragger
)
},
content = { paddingValues ->
@ -141,7 +143,8 @@ fun FieldsMainScreen(
}
LazyColumn(
modifier = contentModifier,
state = lazyListState
state = lazyListState,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(
count = uiFieldsListState.items.size,
@ -224,10 +227,10 @@ fun FieldsMainScreen(
onDismissRequest = { fieldEvent(OnEditPropertyScreenDismiss) },
onFormatClick = {},
onLimitTypesClick = {},
onSaveButtonClicked = {},
onSaveButtonClicked = { fieldEvent(EditProperty.OnSaveButtonClicked) },
onCreateNewButtonClicked = {},
onPropertyNameUpdate = { },
onDeleteButtonClicked = { id -> fieldEvent(OnDeleteFromTypeClick(id)) },
onPropertyNameUpdate = { fieldEvent(EditProperty.OnPropertyNameUpdate(it)) },
onMenuUnlinkClick = { fieldEvent(OnDeleteFromTypeClick(it)) }
)
}
@ -259,15 +262,20 @@ private fun getContentType(item: UiFieldsListItem): String {
/** A common modifier for list items. **/
@Composable
fun LazyItemScope.commonItemModifier() = Modifier
.height(52.dp)
.height(48.dp)
.fillMaxWidth()
.padding(horizontal = 20.dp)
.bottomBorder()
.padding(horizontal = 16.dp)
.border(
width = 1.dp,
color = colorResource(id = R.color.shape_primary),
shape = RoundedCornerShape(12.dp)
)
.animateItem()
@Composable
private fun TopBar(
modifier: Modifier,
withDragger: Boolean = true,
uiTitleState: UiTitleState,
uiIconState: UiIconState,
) {
@ -283,11 +291,13 @@ private fun TopBar(
shape = RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp)
)
) {
Dragger(
modifier = Modifier
.padding(vertical = 6.dp)
.align(Alignment.CenterHorizontally)
)
if (withDragger) {
Dragger(
modifier = Modifier
.padding(vertical = 6.dp)
.align(Alignment.CenterHorizontally)
)
}
Box(
modifier = Modifier
.fillMaxWidth()
@ -388,7 +398,7 @@ private fun LazyItemScope.SectionItem(
) {
Text(
modifier = Modifier
.padding(bottom = 7.dp, start = 20.dp)
.padding(bottom = 4.dp, start = 20.dp)
.align(Alignment.BottomStart),
text = title,
style = BodyCalloutMedium,
@ -406,7 +416,7 @@ private fun LazyItemScope.SectionItem(
) {
Image(
modifier = Modifier
.padding(bottom = 6.dp, end = 20.dp)
.padding(bottom = 2.dp, end = 20.dp)
.wrapContentSize()
.align(Alignment.BottomEnd),
painter = painterResource(R.drawable.ic_default_plus),
@ -459,7 +469,7 @@ private fun FieldItemLocal(
if (formatIcon != null) {
Image(
modifier = Modifier
.padding(end = 10.dp)
.padding(start = 14.dp, end = 8.dp)
.size(24.dp),
painter = painterResource(id = formatIcon),
contentDescription = "Relation format icon",
@ -472,7 +482,7 @@ private fun FieldItemLocal(
.weight(1.0f)
.padding(end = 16.dp),
text = item.fieldTitle,
style = BodyRegular,
style = Relations1,
color = colorResource(id = R.color.text_primary),
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -480,6 +490,7 @@ private fun FieldItemLocal(
Image(
modifier = Modifier
.padding(end = 14.dp)
.size(24.dp)
.noRippleThrottledClickable {
isMenuExpanded.value = true
@ -524,7 +535,7 @@ private fun LazyItemScope.FieldItemDraggable(
if (formatIcon != null) {
Image(
modifier = Modifier
.padding(end = 10.dp)
.padding(start = 14.dp, end = 8.dp)
.size(24.dp),
painter = painterResource(id = formatIcon),
contentDescription = "Relation format icon",
@ -541,7 +552,7 @@ private fun LazyItemScope.FieldItemDraggable(
},
onLongClick = {
// show your menu, only if NOT dragging
if (item.canDelete) {
if (item.isPossibleToUnlinkFromType) {
isMenuExpanded.value = true
}
}
@ -553,7 +564,7 @@ private fun LazyItemScope.FieldItemDraggable(
.fillMaxWidth()
.padding(end = 16.dp),
text = item.fieldTitle,
style = BodyRegular,
style = Relations1,
color = colorResource(id = R.color.text_primary),
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -562,6 +573,7 @@ private fun LazyItemScope.FieldItemDraggable(
Image(
modifier = Modifier
.padding(end = 14.dp)
.size(24.dp)
.draggableHandle(
onDragStarted = {
@ -668,7 +680,7 @@ fun PreviewTypeFieldsMainScreen() {
fieldKey = "key1",
fieldTitle = "Status",
format = RelationFormat.STATUS,
canDelete = true,
isPossibleToUnlinkFromType = true,
isEditableField = true
),
UiFieldsListItem.Item.Draggable(
@ -676,7 +688,7 @@ fun PreviewTypeFieldsMainScreen() {
fieldKey = "key2",
fieldTitle = "Very long field title, just to test how it looks",
format = RelationFormat.LONG_TEXT,
canDelete = true,
isPossibleToUnlinkFromType = true,
isEditableField = true
),
UiFieldsListItem.Section.SideBar(
@ -688,7 +700,7 @@ fun PreviewTypeFieldsMainScreen() {
fieldTitle = "Links",
format = RelationFormat.URL,
isEditableField = true,
canDelete = true
isPossibleToUnlinkFromType = true
),
UiFieldsListItem.Item.Draggable(
id = "id4",
@ -696,7 +708,7 @@ fun PreviewTypeFieldsMainScreen() {
fieldTitle = "Very long field title, just to test how it looks",
format = RelationFormat.DATE,
isEditableField = true,
canDelete = true
isPossibleToUnlinkFromType = true
),
UiFieldsListItem.Section.Hidden(),
UiFieldsListItem.Item.Draggable(
@ -705,7 +717,7 @@ fun PreviewTypeFieldsMainScreen() {
fieldTitle = "Hidden field",
format = RelationFormat.LONG_TEXT,
isEditableField = true,
canDelete = true
isPossibleToUnlinkFromType = true
),
UiFieldsListItem.Section.Local(),
UiFieldsListItem.Item.Local(

View file

@ -210,7 +210,7 @@ private suspend fun mapToUiFieldsDraggableListItem(
format = field.format,
limitObjectTypes = limitObjectTypes,
isEditableField = fieldParser.isFieldEditable(field),
canDelete = fieldParser.isFieldCanBeDeletedFromType(field)
isPossibleToUnlinkFromType = fieldParser.isFieldCanBeDeletedFromType(field)
)
}

View file

@ -50,6 +50,7 @@ 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.toTemplateView
import com.anytypeio.anytype.feature_properties.edit.UiEditPropertyState
import com.anytypeio.anytype.feature_properties.edit.UiEditPropertyState.Visible.View
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.extension.sendAnalyticsScreenObjectType
@ -113,7 +114,8 @@ class ObjectTypeViewModel(
//layout, fields and templates buttons
val uiFieldsButtonState = MutableStateFlow<UiFieldsButtonState>(UiFieldsButtonState.Hidden)
val uiLayoutButtonState = MutableStateFlow<UiLayoutButtonState>(UiLayoutButtonState.Hidden)
val uiTemplatesButtonState = MutableStateFlow<UiTemplatesButtonState>(UiTemplatesButtonState.Hidden)
val uiTemplatesButtonState =
MutableStateFlow<UiTemplatesButtonState>(UiTemplatesButtonState.Hidden)
//type layouts
val uiTypeLayoutsState = MutableStateFlow<UiLayoutTypeState>(Hidden)
@ -376,7 +378,8 @@ class ObjectTypeViewModel(
formatName = stringResourceProvider.getPropertiesFormatPrettyString(item.format),
formatIcon = item.format.simpleIcon(),
format = item.format,
limitObjectTypes = item.limitObjectTypes
limitObjectTypes = item.limitObjectTypes,
isPossibleToUnlinkFromType = item.isPossibleToUnlinkFromType
)
} else {
uiEditPropertyScreen.value = UiEditPropertyState.Visible.View(
@ -386,7 +389,8 @@ class ObjectTypeViewModel(
formatName = stringResourceProvider.getPropertiesFormatPrettyString(item.format),
formatIcon = item.format.simpleIcon(),
format = item.format,
limitObjectTypes = item.limitObjectTypes
limitObjectTypes = item.limitObjectTypes,
isPossibleToUnlinkFromType = item.isPossibleToUnlinkFromType
)
}
}
@ -696,6 +700,7 @@ class ObjectTypeViewModel(
currentList.add(toIndex, item)
uiFieldsListState.value = UiFieldsListState(items = currentList)
}
is FieldEvent.EditProperty -> proceedWithEditPropertyEvent(event)
}
}
@ -749,7 +754,44 @@ class ObjectTypeViewModel(
val newRecommendedFields = currentRecommendedFields + event.item.id
proceedWithSetRecommendedFields(newRecommendedFields)
}
}
}
private fun proceedWithEditPropertyEvent(event: FieldEvent.EditProperty) {
when (event) {
is FieldEvent.EditProperty.OnPropertyNameUpdate -> {
val state = uiEditPropertyScreen.value as? UiEditPropertyState.Visible ?: return
uiEditPropertyScreen.value = when (state) {
is UiEditPropertyState.Visible.Edit -> state.copy(name = event.name)
is UiEditPropertyState.Visible.New -> state.copy(name = event.name)
is View -> state
}
}
FieldEvent.EditProperty.OnSaveButtonClicked -> {
val state =
uiEditPropertyScreen.value as? UiEditPropertyState.Visible.Edit ?: return
viewModelScope.launch {
val params = SetObjectDetails.Params(
ctx = state.id,
details = mapOf(
Relations.NAME to state.name
)
)
setObjectDetails.async(params).fold(
onSuccess = {
Timber.d("Relation updated: $it")
uiEditPropertyScreen.value = UiEditPropertyState.Hidden
},
onFailure = { error ->
Timber.e(error, "Failed to update relation")
errorState.value = UiErrorState.Show(
reason = UiErrorState.Reason.Other(error.message ?: "")
)
}
)
}
}
}
}
//endregion