diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt index 6d0f95ee3d..987a63585a 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt @@ -129,6 +129,7 @@ import com.anytypeio.anytype.ui.relations.RelationTextValueFragment.TextValueEdi import com.anytypeio.anytype.ui.relations.value.ObjectValueFragment import com.anytypeio.anytype.ui.relations.value.TagOrStatusValueFragment import com.anytypeio.anytype.ui.sets.modals.ObjectSetSettingsFragment +import com.anytypeio.anytype.ui.sets.modals.SetObjectCreateBookmarkRecordFragment import com.anytypeio.anytype.ui.sets.modals.SetObjectCreateRecordFragmentBase import com.anytypeio.anytype.ui.sets.modals.sort.ViewerSortFragment import com.anytypeio.anytype.ui.templates.EditorTemplateFragment.Companion.ARG_TARGET_TYPE_ID @@ -1251,14 +1252,13 @@ open class ObjectSetFragment : ) } is ObjectSetCommand.Modal.CreateBookmark -> { - findNavController().safeNavigate( - R.id.objectSetScreen, - R.id.setUrlForNewBookmark, - SetObjectCreateRecordFragmentBase.args( + val fr = SetObjectCreateBookmarkRecordFragment().apply { + arguments = SetObjectCreateRecordFragmentBase.args( ctx = command.ctx, - space = command.space + space = command.space, ) - ) + } + fr.showChildFragment() } is ObjectSetCommand.Modal.OpenDataViewSelectQueryScreen -> { val fr = DataViewSelectSourceFragment.newInstance( diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/permissions/ObjectPermissions.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/permissions/ObjectPermissions.kt index 747b143de5..05066be6c6 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/permissions/ObjectPermissions.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/permissions/ObjectPermissions.kt @@ -10,7 +10,6 @@ import com.anytypeio.anytype.core_models.SupportedLayouts import com.anytypeio.anytype.core_models.getSingleValue import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction import kotlin.collections.contains -import kotlin.collections.get /** * Represents a set of user permissions for a given object. @@ -60,7 +59,12 @@ data class ObjectPermissions( val canChangeRecommendedLayoutForThisType: Boolean = false, val canCreateTemplatesForThisType: Boolean = false, val participantCanEdit: Boolean = false, -) + val canUnlinkPropertyFromType: Boolean = false +) { + companion object { + val NOT_EDITABLE = ObjectPermissions() + } +} /** * Converts this [ObjectView] instance into an [ObjectPermissions] by inspecting @@ -149,25 +153,34 @@ fun ObjectWrapper.Type.toObjectPermissionsForTypes( participantCanEdit: Boolean ): ObjectPermissions { - val isArchived = getSingleValue(Relations.IS_ARCHIVED) == true - val canEdit = !isArchived && participantCanEdit + if (!participantCanEdit) return ObjectPermissions.NOT_EDITABLE + val isArchived = getSingleValue(Relations.IS_ARCHIVED) == true + + if (isArchived) return ObjectPermissions.NOT_EDITABLE + + val isTemplate = uniqueKey == ObjectTypeIds.TEMPLATE + + // General details edit permission: allowed if the DETAILS restriction is not present val canEditDetails = !restrictions.contains(ObjectRestriction.DETAILS) - val canCreateTemplatesForObjectsThisType = layoutsWithTemplates.contains(recommendedLayout) - && uniqueKey != ObjectTypeIds.TEMPLATE + // Permission to create templates (only for non-template types and if a template layout exists) + val canCreateTemplatesForThisType = + !isTemplate && layoutsWithTemplates.contains(recommendedLayout) - val canChangeRecommendedLayoutForObjectsThisType = participantCanEdit - && possibleToChangeLayoutLayouts.contains(recommendedLayout) - && uniqueKey != ObjectTypeIds.TEMPLATE + // Permission to change the recommended layout requires several conditions to be met + val canChangeRecommendedLayoutForThisType = !isTemplate && + possibleToChangeLayoutLayouts.contains(recommendedLayout) return ObjectPermissions( - canDelete = participantCanEdit && !restrictions.contains(ObjectRestriction.DELETE), - canEditDetails = canEditDetails && canEdit, - canCreateTemplatesForThisType = canCreateTemplatesForObjectsThisType, - canCreateObjectThisType = !restrictions.contains(ObjectRestriction.CREATE_OBJECT_OF_THIS_TYPE) && participantCanEdit, - canChangeRecommendedLayoutForThisType = canChangeRecommendedLayoutForObjectsThisType, - participantCanEdit = canEdit + canDelete = !restrictions.contains(ObjectRestriction.DELETE), + canEditDetails = canEditDetails, + canCreateTemplatesForThisType = canCreateTemplatesForThisType, + canCreateObjectThisType = !restrictions.contains(ObjectRestriction.CREATE_OBJECT_OF_THIS_TYPE), + canChangeRecommendedLayoutForThisType = canChangeRecommendedLayoutForThisType, + participantCanEdit = true, + canEditRelationsList = canEditDetails && !restrictions.contains(ObjectRestriction.RELATIONS), + canUnlinkPropertyFromType = canEditDetails && !restrictions.contains(ObjectRestriction.RELATIONS) ) } diff --git a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/UiState.kt b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/UiState.kt index 410d62522c..c65cc7d91c 100644 --- a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/UiState.kt +++ b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/UiState.kt @@ -54,7 +54,8 @@ sealed class UiFieldsListItem { override val format: RelationFormat, override val limitObjectTypes: List, override val isPossibleToUnlinkFromType: Boolean, - override val isEditableField: Boolean + override val isEditableField: Boolean, + val isPossibleToDrag: Boolean ) : Item() data class Local( diff --git a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/ui/ListScreen.kt b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/ui/ListScreen.kt index 631a1207d5..9f9804e57d 100644 --- a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/ui/ListScreen.kt +++ b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/fields/ui/ListScreen.kt @@ -704,21 +704,23 @@ private fun LazyItemScope.FieldItemDraggable( ) } - Image( - modifier = Modifier - .padding(end = 14.dp) - .size(24.dp) - .draggableHandle( - onDragStarted = { - hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.START) - }, - onDragStopped = { - hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.END) - } - ), - painter = painterResource(R.drawable.ic_dnd), - contentDescription = "Icon drag" - ) + if (item.isPossibleToDrag) { + Image( + modifier = Modifier + .padding(end = 14.dp) + .size(24.dp) + .draggableHandle( + onDragStarted = { + hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.START) + }, + onDragStopped = { + hapticFeedback.performHapticFeedback(ReorderHapticFeedbackType.END) + } + ), + painter = painterResource(R.drawable.ic_dnd), + contentDescription = "Icon drag" + ) + } ItemDropDownMenu( item = item, @@ -815,7 +817,8 @@ fun PreviewTypeFieldsMainScreen() { format = RelationFormat.STATUS, isPossibleToUnlinkFromType = true, isEditableField = true, - limitObjectTypes = listOf() + limitObjectTypes = listOf(), + isPossibleToDrag = false ), UiFieldsListItem.Item.Draggable( id = "id2", @@ -824,7 +827,8 @@ fun PreviewTypeFieldsMainScreen() { format = RelationFormat.LONG_TEXT, isPossibleToUnlinkFromType = true, isEditableField = true, - limitObjectTypes = listOf() + limitObjectTypes = listOf(), + isPossibleToDrag = true ), UiFieldsListItem.Section.SideBar( canAdd = true @@ -836,7 +840,8 @@ fun PreviewTypeFieldsMainScreen() { format = RelationFormat.URL, isEditableField = true, isPossibleToUnlinkFromType = true, - limitObjectTypes = listOf() + limitObjectTypes = listOf(), + isPossibleToDrag = true ), UiFieldsListItem.Item.Draggable( id = "id4", @@ -845,7 +850,8 @@ fun PreviewTypeFieldsMainScreen() { format = RelationFormat.DATE, isEditableField = true, isPossibleToUnlinkFromType = true, - limitObjectTypes = listOf() + limitObjectTypes = listOf(), + isPossibleToDrag = false ), UiFieldsListItem.Section.Hidden(), UiFieldsListItem.Item.Draggable( @@ -855,7 +861,8 @@ fun PreviewTypeFieldsMainScreen() { format = RelationFormat.LONG_TEXT, isEditableField = true, isPossibleToUnlinkFromType = true, - limitObjectTypes = listOf() + limitObjectTypes = listOf(), + isPossibleToDrag = true ), UiFieldsListItem.Section.Local(), UiFieldsListItem.Item.Local( diff --git a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/ui/UiStateExt.kt b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/ui/UiStateExt.kt index 12bbbef899..ac4c152280 100644 --- a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/ui/UiStateExt.kt +++ b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/ui/UiStateExt.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.permissions.ObjectPermissions import com.anytypeio.anytype.core_models.primitives.TypeId import com.anytypeio.anytype.core_models.primitives.TypeKey import com.anytypeio.anytype.domain.misc.UrlBuilder @@ -67,7 +68,8 @@ suspend fun buildUiPropertiesList( storeOfObjectTypes: StoreOfObjectTypes, storeOfRelations: StoreOfRelations, objectTypeConflictingPropertiesIds: List, - showHiddenProperty: Boolean + showHiddenProperty: Boolean, + objectPermissions: ObjectPermissions ): List { val parsedProperties = fieldParser.getObjectTypeParsedProperties( @@ -82,7 +84,8 @@ suspend fun buildUiPropertiesList( property = it, stringResourceProvider = stringResourceProvider, fieldParser = fieldParser, - storeOfObjectTypes = storeOfObjectTypes + storeOfObjectTypes = storeOfObjectTypes, + objectPermissions = objectPermissions ) } val sidebarItems = parsedProperties.sidebar.mapNotNull { @@ -90,7 +93,8 @@ suspend fun buildUiPropertiesList( property = it, stringResourceProvider = stringResourceProvider, fieldParser = fieldParser, - storeOfObjectTypes = storeOfObjectTypes + storeOfObjectTypes = storeOfObjectTypes, + objectPermissions = objectPermissions ) } val hiddenItems = parsedProperties.hidden.mapNotNull { @@ -98,7 +102,8 @@ suspend fun buildUiPropertiesList( property = it, stringResourceProvider = stringResourceProvider, fieldParser = fieldParser, - storeOfObjectTypes = storeOfObjectTypes + storeOfObjectTypes = storeOfObjectTypes, + objectPermissions = objectPermissions ) } val conflictedItems = parsedProperties.localWithoutSystem.mapNotNull { @@ -116,7 +121,8 @@ suspend fun buildUiPropertiesList( property = it, stringResourceProvider = stringResourceProvider, fieldParser = fieldParser, - storeOfObjectTypes = storeOfObjectTypes + storeOfObjectTypes = storeOfObjectTypes, + objectPermissions = objectPermissions ) } @@ -125,7 +131,8 @@ suspend fun buildUiPropertiesList( property = it, stringResourceProvider = stringResourceProvider, fieldParser = fieldParser, - storeOfObjectTypes = storeOfObjectTypes + storeOfObjectTypes = storeOfObjectTypes, + objectPermissions = objectPermissions ) } @@ -133,7 +140,7 @@ suspend fun buildUiPropertiesList( add(Section.Header(canAdd = false)) addAll(headerItems) - add(Section.SideBar(canAdd = true)) + add(Section.SideBar(canAdd = objectPermissions.canEditRelationsList)) addAll(sidebarItems) //todo file fields are off for now @@ -185,7 +192,8 @@ private suspend fun mapToUiPropertiesDraggableListItem( property: ObjectWrapper.Relation, stringResourceProvider: StringResourceProvider, storeOfObjectTypes: StoreOfObjectTypes, - fieldParser: FieldParser + fieldParser: FieldParser, + objectPermissions: ObjectPermissions ): UiFieldsListItem? { if (property.key == Relations.DESCRIPTION) return null @@ -199,7 +207,10 @@ private suspend fun mapToUiPropertiesDraggableListItem( storeOfObjectTypes = storeOfObjectTypes ), isEditableField = fieldParser.isPropertyEditable(property), - isPossibleToUnlinkFromType = fieldParser.isPropertyCanBeDeletedFromType(property) + isPossibleToUnlinkFromType = + objectPermissions.canUnlinkPropertyFromType && + fieldParser.isPropertyCanBeDeletedFromType(property), + isPossibleToDrag = objectPermissions.canEditRelationsList ) } diff --git a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/viewmodel/ObjectTypeViewModel.kt b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/viewmodel/ObjectTypeViewModel.kt index af6d9d5649..52ab0a3261 100644 --- a/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/viewmodel/ObjectTypeViewModel.kt +++ b/feature-object-type/src/main/java/com/anytypeio/anytype/feature_object_type/viewmodel/ObjectTypeViewModel.kt @@ -336,7 +336,8 @@ class ObjectTypeViewModel( storeOfObjectTypes = storeOfObjectTypes, storeOfRelations = storeOfRelations, objectTypeConflictingPropertiesIds = conflictingFields, - showHiddenProperty = vmParams.showHiddenFields + showHiddenProperty = vmParams.showHiddenFields, + objectPermissions = objectPermissions ) uiFieldsListState.value = UiFieldsListState(items = items) uiFieldsButtonState.value = UiFieldsButtonState.Visible(