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

DROID-3414 Primitives | Adjust templates object type (#2309)

This commit is contained in:
Konstantin Ivanov 2025-04-14 15:42:49 +02:00 committed by GitHub
parent a47fadb0d0
commit b1bd1edf1a
Signed by: github
GPG key ID: B5690EEEBB952194
11 changed files with 152 additions and 123 deletions

View file

@ -23,6 +23,12 @@ class NavigationRouter(
templateTypeKey = command.templateTypeKey,
space = command.space
)
is AppNavigation.Command.OpenModalTemplateEdit -> navigation.openModalTemplateEdit(
template = command.template,
templateTypeId = command.templateTypeId,
templateTypeKey = command.templateTypeKey,
space = command.space
)
is AppNavigation.Command.OpenSetOrCollection -> navigation.openObjectSet(
target = command.target,
space = command.space,

View file

@ -71,6 +71,7 @@ class ObjectFieldsFragment : BaseBottomSheetComposeFragment(),
MaterialTheme {
FieldListScreen(
state = vm.views.collectAsStateWithLifecycle().value,
uiSettingsIconState = vm.uiSettingsIconState.collectAsStateWithLifecycle().value,
onRelationClicked = {
vm.onRelationClicked(
ctx = ctx,

View file

@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
@ -40,13 +39,16 @@ import com.anytypeio.anytype.core_ui.views.BodyCalloutMedium
import com.anytypeio.anytype.core_ui.views.Relations1
import com.anytypeio.anytype.core_ui.views.Title1
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
import com.anytypeio.anytype.presentation.relations.RelationListViewModel
import com.anytypeio.anytype.presentation.relations.RelationListViewModel.Model
import com.anytypeio.anytype.presentation.relations.UiPropertiesSettingsIconState
import timber.log.Timber
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun FieldListScreen(
state: List<Model>,
uiSettingsIconState: UiPropertiesSettingsIconState,
onRelationClicked: (Model.Item) -> Unit,
onTypeIconClicked: () -> Unit,
onLocalInfoIconClicked: () -> Unit,
@ -85,21 +87,23 @@ fun FieldListScreen(
color = colorResource(id = R.color.text_primary),
)
Box(
modifier = Modifier
.align(Alignment.CenterEnd)
.width(56.dp)
.height(48.dp)
.noRippleThrottledClickable {
onTypeIconClicked()
},
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier.wrapContentSize(),
painter = painterResource(R.drawable.ic_settings_24),
contentDescription = "Open object's type"
)
if (uiSettingsIconState is UiPropertiesSettingsIconState.Shown) {
Box(
modifier = Modifier
.align(Alignment.CenterEnd)
.width(56.dp)
.height(48.dp)
.noRippleThrottledClickable {
onTypeIconClicked()
},
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier.wrapContentSize(),
painter = painterResource(R.drawable.ic_settings_24),
contentDescription = "Open object's type"
)
}
}
}
}
@ -336,7 +340,8 @@ private fun SectionLocal(
is Model.Section.Local.Unshown -> R.drawable.ic_list_arrow_18
}
Box(
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.noRippleThrottledClickable {
onLocalSectionToggle(item)
},
@ -529,6 +534,7 @@ fun FieldListScreenPreview() {
onLocalInfoIconClicked = {},
onTypeIconClicked = {},
onAddToTypeClicked = {},
onRemoveFromObjectClicked = {}
onRemoveFromObjectClicked = {},
uiSettingsIconState = UiPropertiesSettingsIconState.Shown,
)
}

View file

@ -267,6 +267,7 @@ import com.anytypeio.anytype.presentation.navigation.leftButtonClickAnalytics
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.objects.getObjectTypeViewsForSBPage
import com.anytypeio.anytype.presentation.objects.getProperType
import com.anytypeio.anytype.presentation.objects.getTypeForObjectAndTargetTypeForTemplate
import com.anytypeio.anytype.presentation.objects.hasLayoutConflict
import com.anytypeio.anytype.presentation.objects.isTemplatesAllowed
import com.anytypeio.anytype.presentation.objects.toViews
@ -5348,26 +5349,25 @@ class EditorViewModel(
}
private fun getProperties(action: (List<SlashPropertyView.Item>) -> Unit) {
val objectViewDetails = orchestrator.stores.details.current()
val currentObj = objectViewDetails.getObject(vmParams.ctx)
if (currentObj == null) {
Timber.e("Object with id $context not found.")
return
}
val objType = objectViewDetails.getTypeForObject(vmParams.ctx)
if (objType == null) {
Timber.e("Object type of object $context not found.")
return
}
viewModelScope.launch {
val objectViewDetails = orchestrator.stores.details.current()
val currentObj = objectViewDetails.getObject(vmParams.ctx)
if (currentObj == null) {
Timber.e("Object with id $context not found.")
return@launch
}
val objType = currentObj.getTypeForObjectAndTargetTypeForTemplate(storeOfObjectTypes)
if (objType == null) {
Timber.w("Object type of object $context not found.")
return@launch
}
val parsedFields = fieldParser.getObjectParsedProperties(
objectType = objType,
storeOfRelations = storeOfRelations,
objPropertiesKeys = currentObj.map.keys.toList().orEmpty()
)
val properties = (parsedFields.header + parsedFields.sidebar).mapNotNull {
val properties = (parsedFields.header + parsedFields.sidebar).map {
it.view(
details = objectViewDetails,
values = currentObj.map,

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.Block.Content
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectViewDetails
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.ThemeColor
@ -16,24 +17,21 @@ import com.anytypeio.anytype.domain.editor.Editor.Focus
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import com.anytypeio.anytype.domain.objects.getTypeOfObject
import com.anytypeio.anytype.domain.primitives.FieldParser
import com.anytypeio.anytype.presentation.editor.Editor
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.core_models.ObjectViewDetails
import com.anytypeio.anytype.domain.objects.getTypeOfObject
import com.anytypeio.anytype.presentation.editor.editor.ext.getTextAndMarks
import com.anytypeio.anytype.presentation.extension.getBookmarkObject
import com.anytypeio.anytype.presentation.extension.getObject
import com.anytypeio.anytype.presentation.editor.editor.model.Alignment
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Appearance.InEditor
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Mode
import com.anytypeio.anytype.presentation.editor.toggle.ToggleStateHolder
import com.anytypeio.anytype.presentation.extension.getBookmarkObject
import com.anytypeio.anytype.presentation.extension.getObject
import com.anytypeio.anytype.presentation.mapper.getFileUrl
import com.anytypeio.anytype.presentation.mapper.marks
import com.anytypeio.anytype.presentation.extension.getTypeForObject
import com.anytypeio.anytype.presentation.mapper.objectIcon
import com.anytypeio.anytype.presentation.mapper.marks
import com.anytypeio.anytype.presentation.mapper.toFileView
import com.anytypeio.anytype.presentation.mapper.toPictureView
import com.anytypeio.anytype.presentation.mapper.toVideoView

View file

@ -1,10 +1,9 @@
package com.anytypeio.anytype.presentation.extension
import com.anytypeio.anytype.core_models.ObjectViewDetails
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectViewDetails
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Struct
import com.anytypeio.anytype.core_models.ext.isValidObject
import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType
import com.anytypeio.anytype.core_models.ext.mapToOptionObject
import com.anytypeio.anytype.core_models.ext.toBookmarkObject
@ -12,19 +11,9 @@ import com.anytypeio.anytype.core_models.ext.toDateObject
import com.anytypeio.anytype.core_models.ext.toFileObject
import com.anytypeio.anytype.core_models.ext.toInternalFlagsObject
import com.anytypeio.anytype.core_models.ext.toObject
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import com.anytypeio.anytype.domain.primitives.FieldParser
import com.anytypeio.anytype.presentation.objects.getProperType
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
import com.anytypeio.anytype.presentation.relations.getNotIncludedRecommendedRelations
import com.anytypeio.anytype.presentation.relations.view
fun ObjectViewDetails.getStruct(id: Id): Struct? = details[id]
fun ObjectViewDetails.containsObject(id: Id): Boolean {
return details.containsKey(id) && details[id]?.isValidObject() == true
}
fun ObjectViewDetails.getObject(id: Id): ObjectWrapper.Basic? {
return details[id]?.toObject()
@ -54,59 +43,6 @@ fun ObjectViewDetails.getInternalFlagsObject(id: Id): ObjectWrapper.ObjectIntern
return details[id]?.toInternalFlagsObject()
}
suspend fun ObjectViewDetails.getObjRelationsViews(
ctx: Id,
storeOfRelations: StoreOfRelations,
fieldParser: FieldParser,
urlBuilder: UrlBuilder,
storeOfObjectTypes: StoreOfObjectTypes
): List<ObjectRelationView> {
val currentObject = getObject(ctx)
if (currentObject == null || !currentObject.isValid) return emptyList()
val keys = currentObject.map.keys.toList()
return storeOfRelations.getByKeys(keys).map {
it.view(
details = this,
values = currentObject.map,
urlBuilder = urlBuilder,
fieldParser = fieldParser,
isFeatured = currentObject.featuredRelations.contains(it.key),
storeOfObjectTypes = storeOfObjectTypes
)
}
}
suspend fun ObjectViewDetails.getRecommendedRelations(
ctx: Id,
storeOfRelations: StoreOfRelations,
fieldParser: FieldParser,
urlBuilder: UrlBuilder,
storeOfObjectTypes: StoreOfObjectTypes
): List<ObjectRelationView> {
val currentObject = getObject(ctx)
if (currentObject == null || !currentObject.isValid) return emptyList()
val typeObjectId = currentObject.getProperType()
if (typeObjectId == null) return emptyList()
val typeObject = getTypeObject(typeObjectId)
if (typeObject == null) return emptyList()
val recommendedRelations = typeObject.recommendedRelations
val notIncludedRecommendedRelations = getNotIncludedRecommendedRelations(
relationKeys = currentObject.map.keys,
recommendedRelations = recommendedRelations,
storeOfRelations = storeOfRelations
)
return notIncludedRecommendedRelations.map {
it.view(
details = this,
values = currentObject.map,
urlBuilder = urlBuilder,
fieldParser = fieldParser,
isFeatured = currentObject.featuredRelations.contains(it.key),
storeOfObjectTypes = storeOfObjectTypes
)
}
}
fun ObjectViewDetails.getTypeForObject(currentObjectId: Id): ObjectWrapper.Type? {
val currentObject = getObject(currentObjectId)
val type = currentObject?.getProperType()

View file

@ -90,6 +90,13 @@ interface AppNavigation {
val space: Id
) : Command()
data class OpenModalTemplateEdit(
val template: Id,
val templateTypeId: Id,
val templateTypeKey: Key,
val space: Id
) : Command()
object OpenSettings : Command()
data class OpenShareScreen(

View file

@ -2,6 +2,7 @@ package com.anytypeio.anytype.presentation.objects
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.ext.DateParser
import com.anytypeio.anytype.core_utils.ext.readableFileSize
@ -9,6 +10,8 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.getTypeOfObject
import com.anytypeio.anytype.domain.primitives.FieldParser
import com.anytypeio.anytype.presentation.extension.getObject
import com.anytypeio.anytype.presentation.extension.getTypeObject
import com.anytypeio.anytype.presentation.linking.LinkToItemView
import com.anytypeio.anytype.presentation.mapper.objectIcon
import com.anytypeio.anytype.presentation.navigation.DefaultObjectView
@ -130,6 +133,27 @@ suspend fun List<ObjectWrapper.Basic>.toCreateFilterObjectView(
private fun ObjectWrapper.Basic.getProperLayout() = layout ?: ObjectType.Layout.BASIC
fun ObjectWrapper.Basic.getProperType() = type.firstOrNull()
suspend fun ObjectWrapper.Basic.isTemplateObject(storeOfObjectTypes: StoreOfObjectTypes): Boolean {
val currentObjectType = storeOfObjectTypes.getTypeOfObject(this)
return currentObjectType?.uniqueKey == ObjectTypeIds.TEMPLATE
}
suspend fun ObjectWrapper.Basic.getTypeForObjectAndTargetTypeForTemplate(
storeOfObjectTypes: StoreOfObjectTypes
): ObjectWrapper.Type? {
val type = getProperType()
if (type != null) {
val currType = storeOfObjectTypes.getTypeOfObject(this)
val effectiveType = if (currType?.uniqueKey == ObjectTypeIds.TEMPLATE) {
targetObjectType?.let { storeOfObjectTypes.get(it) }
} else {
currType
}
return effectiveType
}
return null
}
private fun getProperTypeName(id: Id?, types: List<ObjectWrapper.Type>) =
types.find { it.id == id }?.name.orEmpty()

View file

@ -9,6 +9,7 @@ import com.anytypeio.anytype.analytics.base.EventsDictionary.relationsScreenShow
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectViewDetails
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Payload
@ -75,6 +76,7 @@ class RelationListViewModel(
val commands = MutableSharedFlow<Command>(replay = 0)
val views = MutableStateFlow<List<Model>>(emptyList())
val showLocalInfo = MutableStateFlow(false)
val uiSettingsIconState = MutableStateFlow<UiPropertiesSettingsIconState>(UiPropertiesSettingsIconState.Hidden)
private val permission = MutableStateFlow(userPermissionProvider.get(vmParams.spaceId))
@ -112,6 +114,12 @@ class RelationListViewModel(
return emptyList()
}
uiSettingsIconState.value = if (objType.uniqueKey == ObjectTypeIds.TEMPLATE) {
UiPropertiesSettingsIconState.Hidden
} else {
UiPropertiesSettingsIconState.Shown
}
val parsedFields = fieldParser.getObjectParsedProperties(
objectType = objType,
storeOfRelations = storeOfRelations,
@ -814,4 +822,9 @@ class RelationListViewModel(
const val NOT_FOUND_IN_RELATION_STORE = "Couldn't find in relation store by id:"
const val NOT_SUPPORTED_UPDATE_VALUE = "Update value of this relation isn't supported"
}
}
sealed class UiPropertiesSettingsIconState {
data object Hidden : UiPropertiesSettingsIconState()
data object Shown : UiPropertiesSettingsIconState()
}

View file

@ -735,7 +735,8 @@ object ObjectSearchConstants {
Relations.PAGE_COVER,
Relations.FILE_EXT,
Relations.FILE_MIME_TYPE,
Relations.RESTRICTIONS
Relations.RESTRICTIONS,
Relations.TARGET_OBJECT_TYPE
)
val defaultRelationKeys = listOf(

View file

@ -21,6 +21,8 @@ import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.SupportedLayouts
import com.anytypeio.anytype.core_models.TimeInMillis
import com.anytypeio.anytype.core_models.isDataView
import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions
import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncAndP2PStatusState
@ -68,21 +70,21 @@ import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.model.TextUpdate
import com.anytypeio.anytype.presentation.extension.ObjectStateAnalyticsEvent
import com.anytypeio.anytype.presentation.extension.getObject
import com.anytypeio.anytype.presentation.extension.logEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectCreateEvent
import com.anytypeio.anytype.presentation.extension.sendAnalyticsRelationEvent
import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Companion.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION
import com.anytypeio.anytype.presentation.mapper.toTemplateObjectTypeViewItems
import com.anytypeio.anytype.presentation.navigation.AppNavigation
import com.anytypeio.anytype.presentation.navigation.SupportNavigation
import com.anytypeio.anytype.core_models.SupportedLayouts
import com.anytypeio.anytype.core_models.TimeInMillis
import com.anytypeio.anytype.presentation.extension.getObject
import com.anytypeio.anytype.presentation.navigation.NavPanelState
import com.anytypeio.anytype.presentation.navigation.SupportNavigation
import com.anytypeio.anytype.presentation.navigation.leftButtonClickAnalytics
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
import com.anytypeio.anytype.presentation.objects.getTypeForObjectAndTargetTypeForTemplate
import com.anytypeio.anytype.presentation.objects.hasLayoutConflict
import com.anytypeio.anytype.presentation.objects.isCreateObjectAllowed
import com.anytypeio.anytype.presentation.objects.isTemplateObject
import com.anytypeio.anytype.presentation.objects.isTemplatesAllowed
import com.anytypeio.anytype.presentation.objects.toFeaturedPropertiesViews
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
@ -90,7 +92,6 @@ import com.anytypeio.anytype.presentation.relations.ObjectSetConfig.DEFAULT_LIMI
import com.anytypeio.anytype.presentation.relations.RelationListViewModel
import com.anytypeio.anytype.presentation.relations.render
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import com.anytypeio.anytype.presentation.sets.ObjectSetCommand.Modal.*
import com.anytypeio.anytype.presentation.sets.model.CellView
import com.anytypeio.anytype.presentation.sets.model.Viewer
import com.anytypeio.anytype.presentation.sets.state.ObjectState
@ -110,7 +111,6 @@ import com.anytypeio.anytype.presentation.templates.TemplateView
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.widgets.TypeTemplatesWidgetUI
import com.anytypeio.anytype.presentation.widgets.TypeTemplatesWidgetUIAction
import com.anytypeio.anytype.presentation.widgets.collection.CollectionViewModel.Command
import com.anytypeio.anytype.presentation.widgets.enterEditing
import com.anytypeio.anytype.presentation.widgets.exitEditing
import com.anytypeio.anytype.presentation.widgets.hideMoreMenu
@ -1080,9 +1080,7 @@ class ObjectSetViewModel(
val obj = objectStore.get(target)
if (obj != null) {
proceedWithNavigation(
target = target,
layout = obj.layout,
space = vmParams.space.id,
obj = obj,
identityProfileLink = obj.getSingleValue(Relations.IDENTITY_PROFILE_LINK)
)
} else {
@ -1613,17 +1611,12 @@ class ObjectSetViewModel(
}
}
private suspend fun proceedWithNavigation(
private suspend fun navigateByLayout(
target: Id,
space: Id,
layout: ObjectType.Layout?,
identityProfileLink: Id? = null
) {
if (target == vmParams.ctx) {
toast("You are already here")
Timber.d("proceedWithOpeningObject, target == vmParams.ctx")
return
}
when (layout) {
ObjectType.Layout.BASIC,
ObjectType.Layout.TODO,
@ -1708,6 +1701,54 @@ class ObjectSetViewModel(
}
}
private suspend fun proceedWithNavigation(
target: Id,
space: Id,
layout: ObjectType.Layout?,
identityProfileLink: Id? = null
) {
if (target == vmParams.ctx) {
toast("You are already here")
Timber.d("proceedWithNavigation, target == vmParams.ctx")
return
}
navigateByLayout(target, space, layout, identityProfileLink)
}
private suspend fun proceedWithNavigation(
obj: ObjectWrapper.Basic,
identityProfileLink: Id? = null
) {
if (obj.id == vmParams.ctx) {
toast("You are already here")
Timber.d("proceedWithNavigation, target == vmParams.ctx")
return
}
val target = obj.id
val space = vmParams.space.id
if (obj.isTemplateObject(storeOfObjectTypes = storeOfObjectTypes)) {
obj.getTypeForObjectAndTargetTypeForTemplate(storeOfObjectTypes = storeOfObjectTypes)
?.let { objType ->
val event = AppNavigation.Command.OpenModalTemplateEdit(
template = target,
space = vmParams.space.id,
templateTypeId = objType.id,
templateTypeKey = objType.uniqueKey
)
navigate(EventWrapper(event))
return
}
}
navigateByLayout(
target = target,
space = space,
layout = obj.layout,
identityProfileLink = identityProfileLink
)
}
//endregion NAVIGATION
fun onUnsupportedViewErrorClicked() {
@ -3075,11 +3116,7 @@ class ObjectSetViewModel(
timeInSeconds = timeInMillis / 1000,
spaceId = vmParams.space,
actionSuccess = { obj ->
proceedWithNavigation(
target = obj.id,
space = vmParams.space.id,
layout = obj.layout
)
proceedWithNavigation(obj = obj)
},
actionFailure = {
toast("Error while parsing date object")