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

DROID-3415 Primitives | The button "Properties" is hidden in the case of permissions (#2249)

This commit is contained in:
Konstantin Ivanov 2025-04-07 15:51:27 +02:00 committed by GitHub
parent 95249d4f9d
commit bf5565195e
Signed by: github
GPG key ID: B5690EEEBB952194
7 changed files with 75 additions and 227 deletions

View file

@ -46,7 +46,7 @@ class ObjectTypeFieldsFragment : BaseBottomSheetComposeFragment() {
) = content {
MaterialTheme {
FieldsMainModalScreen(
uiFieldsListState = vm.uiFieldsListState.collectAsStateWithLifecycle().value,
uiFieldsListState = vm.uiTypePropertiesListState.collectAsStateWithLifecycle().value,
uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
uiEditPropertyState = vm.uiEditPropertyScreen.collectAsStateWithLifecycle().value,

View file

@ -143,9 +143,7 @@ class ObjectTypeFragment : BaseComposeFragment() {
uiSyncStatusBadgeState = vm.uiSyncStatusBadgeState.collectAsStateWithLifecycle().value,
uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
uiFieldsButtonState = vm.uiFieldsButtonState.collectAsStateWithLifecycle().value,
uiLayoutButtonState = vm.uiLayoutButtonState.collectAsStateWithLifecycle().value,
uiTemplatesButtonState = vm.uiTemplatesButtonState.collectAsStateWithLifecycle().value,
uiHorizontalButtonsState = vm.uiHorizontalButtonsState.collectAsStateWithLifecycle().value,
uiTemplatesModalListState = vm.uiTemplatesModalListState.collectAsStateWithLifecycle().value,
uiLayoutTypeState = vm.uiTypeLayoutsState.collectAsStateWithLifecycle().value,
uiSyncStatusState = vm.uiSyncStatusWidgetState.collectAsStateWithLifecycle().value,
@ -157,7 +155,7 @@ class ObjectTypeFragment : BaseComposeFragment() {
}
composable(route = OBJ_TYPE_PROPERTIES) {
FieldsMainScreen(
uiFieldsListState = vm.uiFieldsListState.collectAsStateWithLifecycle().value,
uiFieldsListState = vm.uiTypePropertiesListState.collectAsStateWithLifecycle().value,
uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
uiEditPropertyState = vm.uiEditPropertyScreen.collectAsStateWithLifecycle().value,

View file

@ -31,7 +31,8 @@ import com.anytypeio.anytype.feature_object_type.ui.TopBarContent
import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
import com.anytypeio.anytype.feature_object_type.ui.UiDeleteAlertState
import com.anytypeio.anytype.feature_object_type.ui.UiEditButton
import com.anytypeio.anytype.feature_object_type.ui.UiFieldsButtonState
import com.anytypeio.anytype.feature_object_type.ui.UiHorizontalButtonsState
import com.anytypeio.anytype.feature_object_type.ui.UiPropertiesButtonState
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
@ -57,11 +58,9 @@ fun WithSetScreen(
//header
uiIconState: UiIconState,
uiTitleState: UiTitleState,
//layout and fields buttons
uiFieldsButtonState: UiFieldsButtonState,
uiLayoutButtonState: UiLayoutButtonState,
//layout, properties and templates buttons
uiHorizontalButtonsState: UiHorizontalButtonsState,
uiLayoutTypeState: UiLayoutTypeState,
uiTemplatesButtonState: UiTemplatesButtonState,
//templates modal list
uiTemplatesModalListState: UiTemplatesModalListState,
//delete alert
@ -95,9 +94,7 @@ fun WithSetScreen(
paddingValues = paddingValues,
uiIconState = uiIconState,
uiTitleState = uiTitleState,
uiFieldsButtonState = uiFieldsButtonState,
uiLayoutButtonState = uiLayoutButtonState,
uiTemplatesButtonState = uiTemplatesButtonState,
uiHorizontalButtonsState = uiHorizontalButtonsState,
objectId = objectId,
space = space,
onTypeEvent = onTypeEvent
@ -139,9 +136,7 @@ private fun MainContentSet(
paddingValues: PaddingValues,
uiIconState: UiIconState,
uiTitleState: UiTitleState,
uiFieldsButtonState: UiFieldsButtonState,
uiLayoutButtonState: UiLayoutButtonState,
uiTemplatesButtonState: UiTemplatesButtonState,
uiHorizontalButtonsState: UiHorizontalButtonsState,
objectId: String,
space: String,
onTypeEvent: (TypeEvent) -> Unit
@ -168,18 +163,20 @@ private fun MainContentSet(
uiTitleState = uiTitleState,
onTypeEvent = onTypeEvent
)
Spacer(modifier = Modifier.height(20.dp))
HorizontalButtons(
modifier = Modifier
.fillMaxWidth()
.height(36.dp)
.padding(horizontal = 20.dp),
uiFieldsButtonState = uiFieldsButtonState,
uiLayoutButtonState = uiLayoutButtonState,
uiTemplatesButtonState = uiTemplatesButtonState,
onTypeEvent = onTypeEvent
)
Spacer(modifier = Modifier.height(24.dp))
if (uiHorizontalButtonsState.isVisible) {
Spacer(modifier = Modifier.height(20.dp))
HorizontalButtons(
modifier = Modifier
.fillMaxWidth()
.height(36.dp)
.padding(horizontal = 20.dp),
uiPropertiesButtonState = uiHorizontalButtonsState.uiPropertiesButtonState,
uiLayoutButtonState = uiHorizontalButtonsState.uiLayoutButtonState,
uiTemplatesButtonState = uiHorizontalButtonsState.uiTemplatesButtonState,
onTypeEvent = onTypeEvent
)
}
Spacer(modifier = Modifier.height(32.dp))
AndroidFragment<ObjectSetFragment>(
modifier = Modifier
.fillMaxSize(),

View file

@ -3,8 +3,6 @@ package com.anytypeio.anytype.feature_object_type.ui
import android.os.Build
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@ -14,158 +12,17 @@ import androidx.compose.foundation.layout.padding
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.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.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.multiplayer.P2PStatusUpdate
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
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_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.syncstatus.SpaceSyncStatusScreen
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
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.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ObjectTypeMainScreen(
//top bar
uiEditButtonState: UiEditButton,
uiSyncStatusBadgeState: UiSyncStatusBadgeState,
uiSyncStatusState: SyncStatusWidgetState,
//header
uiIconState: UiIconState,
uiTitleState: UiTitleState,
//layout and fields buttons
uiFieldsButtonState: UiFieldsButtonState,
uiLayoutButtonState: UiLayoutButtonState,
uiLayoutTypeState: UiLayoutTypeState,
//delete alert
uiDeleteAlertState: UiDeleteAlertState,
//events
onTypeEvent: (TypeEvent) -> Unit
) {
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
state = rememberTopAppBarState()
)
Scaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(topAppBarScrollBehavior.nestedScrollConnection),
containerColor = colorResource(id = R.color.background_primary),
contentColor = colorResource(id = R.color.background_primary),
topBar = {
TopBarContent(
uiSyncStatusBadgeState = uiSyncStatusBadgeState,
uiEditButtonState = uiEditButtonState,
uiTitleState = uiTitleState,
topBarScrollBehavior = topAppBarScrollBehavior,
onTypeEvent = onTypeEvent
)
},
content = { paddingValues ->
MainContent(
paddingValues = paddingValues,
uiIconState = uiIconState,
uiTitleState = uiTitleState,
uiFieldsButtonState = uiFieldsButtonState,
uiLayoutButtonState = uiLayoutButtonState,
onTypeEvent = onTypeEvent
)
}
)
BottomSyncStatus(
uiSyncStatusState = uiSyncStatusState,
onDismiss = { onTypeEvent(TypeEvent.OnSyncStatusDismiss) }
)
if (uiDeleteAlertState is UiDeleteAlertState.Show) {
DeleteAlertScreen(
onTypeEvent = onTypeEvent
)
}
if (uiLayoutTypeState is UiLayoutTypeState.Visible) {
TypeLayoutsScreen(
modifier = Modifier.fillMaxWidth(),
uiState = uiLayoutTypeState,
onTypeEvent = onTypeEvent
)
}
}
@Composable
private fun MainContent(
paddingValues: PaddingValues,
uiIconState: UiIconState,
uiTitleState: UiTitleState,
uiFieldsButtonState: UiFieldsButtonState,
uiLayoutButtonState: UiLayoutButtonState,
onTypeEvent: (TypeEvent) -> Unit
) {
// Adjust content modifier based on SDK version for proper insets handling
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) {
item {
IconAndTitleWidget(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(top = 32.dp)
.padding(horizontal = 20.dp),
uiIconState = uiIconState,
uiTitleState = uiTitleState,
onTypeEvent = onTypeEvent
)
Spacer(modifier = Modifier.height(20.dp))
}
item {
HorizontalButtons(
modifier = Modifier
.fillMaxWidth()
.height(36.dp)
.padding(horizontal = 20.dp),
uiFieldsButtonState = uiFieldsButtonState,
uiLayoutButtonState = uiLayoutButtonState,
onTypeEvent = onTypeEvent
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBarContent(
@ -220,32 +77,3 @@ fun BottomSyncStatus(
}
}
@DefaultPreviews
@Composable
fun ObjectTypeMainScreenPreview() {
val spaceSyncUpdate = SpaceSyncUpdate.Update(
id = "1",
status = SpaceSyncStatus.SYNCING,
network = SpaceSyncNetwork.ANYTYPE,
error = SpaceSyncError.NULL,
syncingObjectsCounter = 2
)
ObjectTypeMainScreen(
uiSyncStatusBadgeState = UiSyncStatusBadgeState.Visible(
status = SpaceSyncAndP2PStatusState.Success(
spaceSyncUpdate = spaceSyncUpdate,
p2PStatusUpdate = P2PStatusUpdate.Initial
)
),
uiSyncStatusState = SyncStatusWidgetState.Hidden,
uiIconState = UiIconState(icon = ObjectIcon.TypeIcon.Default.DEFAULT, isEditable = true),
uiTitleState = UiTitleState(title = "title", isEditable = true),
uiFieldsButtonState = UiFieldsButtonState.Visible(4),
uiLayoutButtonState = UiLayoutButtonState.Visible(layout = ObjectType.Layout.VIDEO),
uiDeleteAlertState = UiDeleteAlertState.Hidden,
uiEditButtonState = UiEditButton.Visible,
uiLayoutTypeState = UiLayoutTypeState.Hidden,
onTypeEvent = {}
)
}

View file

@ -65,9 +65,16 @@ sealed class UiLayoutTypeState {
}
//endregion
sealed class UiFieldsButtonState {
data object Hidden : UiFieldsButtonState()
data class Visible(val count: Int) : UiFieldsButtonState()
data class UiHorizontalButtonsState(
val uiPropertiesButtonState: UiPropertiesButtonState,
val uiLayoutButtonState: UiLayoutButtonState,
val uiTemplatesButtonState: UiTemplatesButtonState,
val isVisible: Boolean
)
sealed class UiPropertiesButtonState {
data object Hidden : UiPropertiesButtonState()
data class Visible(val count: Int) : UiPropertiesButtonState()
}

View file

@ -23,11 +23,10 @@ import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.common.OldDevicesPreview
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
import com.anytypeio.anytype.core_ui.views.PreviewTitle2Medium
import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
import com.anytypeio.anytype.feature_object_type.ui.UiFieldsButtonState
import com.anytypeio.anytype.feature_object_type.ui.UiPropertiesButtonState
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutButtonState
import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesButtonState
@ -35,7 +34,7 @@ import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesButtonState
fun HorizontalButtons(
modifier: Modifier,
uiLayoutButtonState: UiLayoutButtonState,
uiFieldsButtonState: UiFieldsButtonState,
uiPropertiesButtonState: UiPropertiesButtonState,
uiTemplatesButtonState: UiTemplatesButtonState = UiTemplatesButtonState.Hidden,
onTypeEvent: (TypeEvent) -> Unit
) {
@ -54,7 +53,7 @@ fun HorizontalButtons(
shape = RoundedCornerShape(size = 8.dp)
)
if (uiFieldsButtonState is UiFieldsButtonState.Visible) {
if (uiPropertiesButtonState is UiPropertiesButtonState.Visible) {
Row(
modifier = modifierButton.noRippleThrottledClickable {
onTypeEvent(TypeEvent.OnFieldsButtonClick)
@ -73,7 +72,7 @@ fun HorizontalButtons(
modifier = Modifier
.wrapContentSize()
.padding(start = 6.dp, end = 12.dp),
text = uiFieldsButtonState.count.toString(),
text = uiPropertiesButtonState.count.toString(),
style = PreviewTitle2Medium,
color = colorResource(R.color.glyph_active)
)
@ -145,7 +144,7 @@ fun HorizontalButtonsPreview() {
.fillMaxWidth()
.padding(start = 20.dp),
uiLayoutButtonState = UiLayoutButtonState.Visible(ObjectType.Layout.BASIC),
uiFieldsButtonState = UiFieldsButtonState.Visible(3),
uiPropertiesButtonState = UiPropertiesButtonState.Visible(3),
uiTemplatesButtonState = UiTemplatesButtonState.Visible(2),
onTypeEvent = {}
)

View file

@ -40,7 +40,8 @@ import com.anytypeio.anytype.feature_object_type.ui.UiEditButton
import com.anytypeio.anytype.feature_object_type.ui.UiErrorState
import com.anytypeio.anytype.feature_object_type.ui.UiErrorState.*
import com.anytypeio.anytype.feature_object_type.ui.UiErrorState.Reason.*
import com.anytypeio.anytype.feature_object_type.ui.UiFieldsButtonState
import com.anytypeio.anytype.feature_object_type.ui.UiHorizontalButtonsState
import com.anytypeio.anytype.feature_object_type.ui.UiPropertiesButtonState
import com.anytypeio.anytype.feature_object_type.ui.UiIconsPickerState
import com.anytypeio.anytype.feature_object_type.ui.UiIconState
import com.anytypeio.anytype.feature_object_type.ui.UiLayoutButtonState
@ -60,7 +61,6 @@ import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.extension.sendAnalyticsScreenObjectType
import com.anytypeio.anytype.presentation.mapper.objectIcon
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeys
import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
@ -118,11 +118,16 @@ class ObjectTypeViewModel(
val uiTitleState = MutableStateFlow<UiTitleState>(UiTitleState.Companion.EMPTY)
val uiIconState = MutableStateFlow<UiIconState>(UiIconState.Companion.EMPTY)
//layout, fields and templates buttons
val uiFieldsButtonState = MutableStateFlow<UiFieldsButtonState>(UiFieldsButtonState.Hidden)
val uiLayoutButtonState = MutableStateFlow<UiLayoutButtonState>(UiLayoutButtonState.Hidden)
val uiTemplatesButtonState =
MutableStateFlow<UiTemplatesButtonState>(UiTemplatesButtonState.Hidden)
//layout, properties and templates buttons
val uiHorizontalButtonsState =
MutableStateFlow<UiHorizontalButtonsState>(
UiHorizontalButtonsState(
uiLayoutButtonState = UiLayoutButtonState.Hidden,
uiPropertiesButtonState = UiPropertiesButtonState.Hidden,
uiTemplatesButtonState = UiTemplatesButtonState.Hidden,
isVisible = false
)
)
//type layouts
val uiTypeLayoutsState = MutableStateFlow<UiLayoutTypeState>(UiLayoutTypeState.Hidden)
@ -137,7 +142,7 @@ class ObjectTypeViewModel(
MutableStateFlow<UiLocalsFieldsInfoState>(UiLocalsFieldsInfoState.Hidden)
//properties list
val uiFieldsListState = MutableStateFlow<UiFieldsListState>(UiFieldsListState.EMPTY)
val uiTypePropertiesListState = MutableStateFlow<UiFieldsListState>(UiFieldsListState.EMPTY)
//edit property
val uiEditPropertyScreen = MutableStateFlow<UiEditPropertyState>(UiEditPropertyState.Hidden)
@ -337,7 +342,11 @@ class ObjectTypeViewModel(
}
objType.recommendedLayout?.let { layout ->
if (_objectTypePermissionsState.value?.canChangeRecommendedLayoutForThisType == true) {
uiLayoutButtonState.value = UiLayoutButtonState.Visible(layout = layout)
uiHorizontalButtonsState.value =
uiHorizontalButtonsState.value.copy(
uiLayoutButtonState = UiLayoutButtonState.Visible(layout = layout),
isVisible = true
)
}
}
updateDefaultTemplates(defaultTemplate = objType.defaultTemplateId)
@ -351,10 +360,16 @@ class ObjectTypeViewModel(
showHiddenProperty = vmParams.showHiddenFields,
objectPermissions = objectPermissions
)
uiFieldsListState.value = UiFieldsListState(items = items)
uiFieldsButtonState.value = UiFieldsButtonState.Visible(
count = items.count { it is UiFieldsListItem.Item }
)
uiTypePropertiesListState.value = UiFieldsListState(items = items)
if (objectPermissions.canEditRelationsList) {
uiHorizontalButtonsState.value =
uiHorizontalButtonsState.value.copy(
uiPropertiesButtonState = UiPropertiesButtonState.Visible(
count = items.count { it is UiFieldsListItem.Item }
),
isVisible = true
)
}
}
private fun mapTemplatesSubscriptionToUi(
@ -362,7 +377,11 @@ class ObjectTypeViewModel(
templates: List<TemplateView>,
permissions: ObjectPermissions
) {
uiTemplatesButtonState.value = UiTemplatesButtonState.Visible(count = templates.size)
uiHorizontalButtonsState.value = uiHorizontalButtonsState.value.copy(
uiTemplatesButtonState = UiTemplatesButtonState.Visible(count = templates.size),
isVisible = true
)
val updatedTemplates = templates.mapNotNull { template ->
if (template is TemplateView.Template) {
@ -735,7 +754,7 @@ class ObjectTypeViewModel(
}
FieldEvent.DragEvent.OnDragEnd -> {
val newItems = uiFieldsListState.value.items
val newItems = uiTypePropertiesListState.value.items
val headerItems = mutableListOf<Id>()
val sideBarItems = mutableListOf<Id>()
val hiddenItems = mutableListOf<Id>()
@ -765,13 +784,13 @@ class ObjectTypeViewModel(
}
is FieldEvent.DragEvent.OnMove -> {
val currentList = uiFieldsListState.value.items.toMutableList()
val currentList = uiTypePropertiesListState.value.items.toMutableList()
val fromIndex = currentList.indexOfFirst { it.id == event.fromKey }
val toIndex = currentList.indexOfFirst { it.id == event.toKey }
if ((fromIndex == -1) || (toIndex == -1)) return
val item = currentList.removeAt(fromIndex)
currentList.add(toIndex, item)
uiFieldsListState.value = UiFieldsListState(items = currentList)
uiTypePropertiesListState.value = UiFieldsListState(items = currentList)
}
is FieldEvent.EditProperty -> proceedWithEditPropertyEvent(event)
@ -792,7 +811,7 @@ class ObjectTypeViewModel(
val hiddenItems = mutableListOf<Id>()
val filesItems = mutableListOf<Id>()
var currentSection: UiFieldsListItem.Section? = null
uiFieldsListState.value.items.forEach { item ->
uiTypePropertiesListState.value.items.forEach { item ->
when (item) {
is UiFieldsListItem.Item -> {
when (currentSection) {