701 lines
27 KiB
Kotlin
701 lines
27 KiB
Kotlin
package com.anytypeio.anytype.presentation.sets
|
|
|
|
import com.anytypeio.anytype.core_models.Block
|
|
import com.anytypeio.anytype.core_models.CoverType
|
|
import com.anytypeio.anytype.core_models.DVFilter
|
|
import com.anytypeio.anytype.core_models.DVFilterCondition
|
|
import com.anytypeio.anytype.core_models.DVFilterQuickOption
|
|
import com.anytypeio.anytype.core_models.DVRecord
|
|
import com.anytypeio.anytype.core_models.DVSort
|
|
import com.anytypeio.anytype.core_models.DVViewer
|
|
import com.anytypeio.anytype.core_models.DVViewerRelation
|
|
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVFilterUpdate
|
|
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVSortUpdate
|
|
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVViewerFields
|
|
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVViewerRelationUpdate
|
|
import com.anytypeio.anytype.core_models.Id
|
|
import com.anytypeio.anytype.core_models.ObjectType
|
|
import com.anytypeio.anytype.core_models.ObjectWrapper
|
|
import com.anytypeio.anytype.core_models.Relation
|
|
import com.anytypeio.anytype.core_models.RelationFormat
|
|
import com.anytypeio.anytype.core_models.RelationLink
|
|
import com.anytypeio.anytype.core_models.Relations
|
|
import com.anytypeio.anytype.core_models.Struct
|
|
import com.anytypeio.anytype.core_models.ext.DateParser
|
|
import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType
|
|
import com.anytypeio.anytype.core_models.ext.title
|
|
import com.anytypeio.anytype.core_models.primitives.TypeId
|
|
import com.anytypeio.anytype.core_models.primitives.TypeKey
|
|
import com.anytypeio.anytype.core_utils.ext.addAfterIndexInLine
|
|
import com.anytypeio.anytype.core_utils.ext.mapInPlace
|
|
import com.anytypeio.anytype.core_utils.ext.moveAfterIndexInLine
|
|
import com.anytypeio.anytype.core_utils.ext.moveOnTop
|
|
import com.anytypeio.anytype.domain.misc.DateProvider
|
|
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.presentation.editor.cover.CoverImageHashProvider
|
|
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
|
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
|
import com.anytypeio.anytype.presentation.objects.getProperName
|
|
import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper
|
|
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
|
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig.ID_KEY
|
|
import com.anytypeio.anytype.presentation.relations.getCover
|
|
import com.anytypeio.anytype.presentation.relations.isSystemKey
|
|
import com.anytypeio.anytype.presentation.relations.linksFeaturedRelation
|
|
import com.anytypeio.anytype.presentation.relations.title
|
|
import com.anytypeio.anytype.presentation.relations.view
|
|
import com.anytypeio.anytype.core_models.PermittedConditions
|
|
import com.anytypeio.anytype.core_models.ext.DAYS_IN_MONTH
|
|
import com.anytypeio.anytype.core_models.ext.DAYS_IN_WEEK
|
|
import com.anytypeio.anytype.core_models.ext.EMPTY_STRING_VALUE
|
|
import com.anytypeio.anytype.core_models.ext.SECONDS_IN_DAY
|
|
import com.anytypeio.anytype.presentation.sets.model.ObjectView
|
|
import com.anytypeio.anytype.presentation.sets.model.SimpleRelationView
|
|
import com.anytypeio.anytype.presentation.sets.model.Viewer
|
|
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
|
import com.anytypeio.anytype.presentation.sets.state.ObjectState.Companion.VIEW_DEFAULT_OBJECT_TYPE
|
|
import com.anytypeio.anytype.presentation.sets.state.ObjectState.Companion.VIEW_TYPE_UNSUPPORTED
|
|
import com.anytypeio.anytype.presentation.sets.viewer.ViewerView
|
|
import com.anytypeio.anytype.presentation.templates.TemplateView
|
|
import timber.log.Timber
|
|
|
|
fun ObjectState.DataView.featuredRelations(
|
|
ctx: Id,
|
|
urlBuilder: UrlBuilder,
|
|
relations: List<ObjectWrapper.Relation>
|
|
): BlockView.FeaturedRelation? {
|
|
val block = blocks.find { it.content is Block.Content.FeaturedRelations }
|
|
if (block != null) {
|
|
val views = mutableListOf<ObjectRelationView>()
|
|
val ids = details[ctx]?.featuredRelations ?: emptyList()
|
|
views.addAll(
|
|
mapFeaturedRelations(
|
|
ctx = ctx,
|
|
keys = ids,
|
|
details = Block.Details(details),
|
|
relations = relations,
|
|
urlBuilder = urlBuilder
|
|
)
|
|
)
|
|
return BlockView.FeaturedRelation(
|
|
id = block.id,
|
|
relations = views
|
|
)
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
|
|
fun ObjectState.DataView.header(
|
|
ctx: Id,
|
|
urlBuilder: UrlBuilder,
|
|
coverImageHashProvider: CoverImageHashProvider
|
|
): SetOrCollectionHeaderState {
|
|
val title = blocks.title()
|
|
return if (title != null) {
|
|
val wrapper = ObjectWrapper.Basic(
|
|
map = details[ctx]?.map ?: emptyMap()
|
|
)
|
|
val featured = wrapper.featuredRelations
|
|
SetOrCollectionHeaderState.Default(
|
|
title = title(
|
|
ctx = ctx,
|
|
title = title,
|
|
urlBuilder = urlBuilder,
|
|
details = details,
|
|
coverImageHashProvider = coverImageHashProvider
|
|
),
|
|
description = if (featured.contains(Relations.DESCRIPTION)) {
|
|
SetOrCollectionHeaderState.Description.Default(
|
|
description = wrapper.description.orEmpty()
|
|
)
|
|
} else {
|
|
SetOrCollectionHeaderState.Description.None
|
|
}
|
|
)
|
|
} else {
|
|
return SetOrCollectionHeaderState.None
|
|
}
|
|
}
|
|
|
|
private fun ObjectState.DataView.mapFeaturedRelations(
|
|
ctx: Id,
|
|
keys: List<String>,
|
|
details: Block.Details,
|
|
relations: List<ObjectWrapper.Relation>,
|
|
urlBuilder: UrlBuilder
|
|
): List<ObjectRelationView> = keys.mapNotNull { key ->
|
|
when (key) {
|
|
Relations.DESCRIPTION -> null
|
|
Relations.TYPE -> details.details[ctx]?.type?.firstOrNull()?.let { typeId ->
|
|
val objectType = details.details[typeId]?.map?.mapToObjectWrapperType()
|
|
if (objectType?.isDeleted == true) {
|
|
ObjectRelationView.ObjectType.Deleted(
|
|
id = typeId,
|
|
key = key,
|
|
featured = true,
|
|
readOnly = false,
|
|
system = key.isSystemKey()
|
|
)
|
|
} else {
|
|
when (this) {
|
|
is ObjectState.DataView.Collection -> ObjectRelationView.ObjectType.Collection(
|
|
id = typeId,
|
|
key = key,
|
|
name = objectType?.name.orEmpty(),
|
|
featured = true,
|
|
readOnly = false,
|
|
type = typeId,
|
|
system = key.isSystemKey()
|
|
)
|
|
is ObjectState.DataView.Set -> ObjectRelationView.ObjectType.Set(
|
|
id = typeId,
|
|
key = key,
|
|
name = objectType?.name.orEmpty(),
|
|
featured = true,
|
|
readOnly = false,
|
|
type = typeId,
|
|
system = key.isSystemKey()
|
|
)
|
|
}
|
|
}
|
|
}
|
|
Relations.SET_OF -> {
|
|
val objectSet = ObjectWrapper.Basic(details.details[ctx]?.map.orEmpty())
|
|
val sources = mutableListOf<ObjectView>()
|
|
val source = objectSet.setOf.firstOrNull()
|
|
if (source != null) {
|
|
val wrapper = ObjectWrapper.Basic(details.details[source]?.map.orEmpty())
|
|
if (!wrapper.isEmpty()) {
|
|
if (wrapper.isDeleted == true) {
|
|
ObjectRelationView.Source.Deleted(
|
|
id = details.details[ctx]?.id.orEmpty(),
|
|
key = key,
|
|
name = Relations.RELATION_NAME_EMPTY,
|
|
featured = true,
|
|
readOnly = false,
|
|
system = key.isSystemKey()
|
|
)
|
|
} else {
|
|
sources.add(wrapper.toObjectView(urlBuilder = urlBuilder))
|
|
ObjectRelationView.Source.Base(
|
|
id = details.details[ctx]?.id.orEmpty(),
|
|
key = key,
|
|
name = Relations.RELATION_NAME_EMPTY,
|
|
featured = true,
|
|
readOnly = wrapper.relationReadonlyValue ?: false,
|
|
sources = sources,
|
|
system = key.isSystemKey()
|
|
)
|
|
}
|
|
} else {
|
|
ObjectRelationView.Source.Base(
|
|
id = details.details[ctx]?.id.orEmpty(),
|
|
key = key,
|
|
name = Relations.RELATION_NAME_EMPTY,
|
|
featured = true,
|
|
readOnly = wrapper.relationReadonlyValue ?: false,
|
|
sources = sources,
|
|
system = key.isSystemKey()
|
|
)
|
|
}
|
|
} else {
|
|
ObjectRelationView.Source.Base(
|
|
id = details.details[ctx]?.id.orEmpty(),
|
|
key = key,
|
|
name = Relations.RELATION_NAME_EMPTY,
|
|
featured = true,
|
|
readOnly = false,
|
|
sources = sources,
|
|
system = key.isSystemKey()
|
|
)
|
|
}
|
|
}
|
|
Relations.BACKLINKS, Relations.LINKS -> {
|
|
details.linksFeaturedRelation(
|
|
relations = relations,
|
|
ctx = ctx,
|
|
relationKey = key,
|
|
isFeatured = true
|
|
)
|
|
}
|
|
else -> {
|
|
val relation = relations.firstOrNull { it.key == key }
|
|
relation?.view(
|
|
details = details,
|
|
values = details.details[ctx]?.map ?: emptyMap(),
|
|
urlBuilder = urlBuilder,
|
|
isFeatured = true
|
|
)
|
|
}
|
|
}
|
|
}
|
|
.sortedByDescending { it.key == Relations.SET_OF }
|
|
.sortedByDescending { it.key == Relations.TYPE }
|
|
|
|
fun List<DVRecord>.update(new: List<DVRecord>): List<DVRecord> {
|
|
val update = new.associateBy { rec -> rec[ID_KEY] as String }
|
|
val result = mutableListOf<DVRecord>()
|
|
forEach { rec ->
|
|
val id = rec[ID_KEY]
|
|
if (update.containsKey(id)) {
|
|
val updated = update[id]
|
|
if (updated != null)
|
|
result.add(updated)
|
|
else
|
|
result.add(rec)
|
|
} else {
|
|
result.add(rec)
|
|
}
|
|
}
|
|
// TODO remove this part when middleware is fixed
|
|
update.forEach { (id, record) ->
|
|
val isAlreadyPresent = result.any { r -> r[ID_KEY] == id }
|
|
if (!isAlreadyPresent) result.add(record)
|
|
}
|
|
return result
|
|
}
|
|
|
|
fun ObjectState.DataView.viewerByIdOrFirst(currentViewerId: String?): DVViewer? {
|
|
if (!isInitialized) return null
|
|
return dataViewContent.viewers.find { it.id == currentViewerId }
|
|
?: dataViewContent.viewers.firstOrNull()
|
|
}
|
|
|
|
fun ObjectState.DataView.viewerById(currentViewerId: String?): DVViewer? {
|
|
if (!isInitialized) return null
|
|
return dataViewContent.viewers.find { it.id == currentViewerId }
|
|
}
|
|
|
|
fun ObjectState.DataView.viewerAndIndexById(currentViewerId: String?): Pair<DVViewer, Int>? {
|
|
if (!isInitialized) return null
|
|
val index = dataViewContent.viewers.indexOfFirst { it.id == currentViewerId }
|
|
return if (index != -1) {
|
|
Pair(dataViewContent.viewers[index], index)
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
|
|
fun ObjectState.DataView.Collection.getObjectOrderIds(currentViewerId: String): List<Id> {
|
|
return dataViewContent.objectOrders.find { it.view == currentViewerId }?.ids ?: emptyList()
|
|
}
|
|
|
|
fun List<DVFilter>.updateFormatForSubscription(relationLinks: List<RelationLink>): List<DVFilter> {
|
|
return map { f: DVFilter ->
|
|
val r = relationLinks.firstOrNull { it.key == f.relation }
|
|
if (r != null && r.format == RelationFormat.DATE) {
|
|
f.copy(relationFormat = r.format)
|
|
} else if (r != null && r.format == RelationFormat.OBJECT) {
|
|
// Temporary workaround for normalizing filter condition for object filters
|
|
f.copy(
|
|
relationFormat = r.format,
|
|
condition = if (f.condition == DVFilterCondition.EQUAL) {
|
|
DVFilterCondition.IN
|
|
} else {
|
|
f.condition
|
|
}
|
|
)
|
|
} else {
|
|
f
|
|
}
|
|
}
|
|
}
|
|
|
|
fun List<SimpleRelationView>.filterHiddenRelations(): List<SimpleRelationView> =
|
|
filter { !it.isHidden }
|
|
|
|
fun ObjectWrapper.Basic.toObjectView(urlBuilder: UrlBuilder): ObjectView = when (isDeleted) {
|
|
true -> ObjectView.Deleted(id)
|
|
else -> ObjectView.Default(
|
|
id = id,
|
|
name = getProperName(),
|
|
icon = ObjectIcon.from(
|
|
obj = this,
|
|
layout = layout,
|
|
builder = urlBuilder,
|
|
objectTypeNoIcon = true
|
|
),
|
|
types = type,
|
|
isRelation = layout == ObjectType.Layout.RELATION
|
|
)
|
|
}
|
|
|
|
fun List<DVFilter>.updateFilters(updates: List<DVFilterUpdate>): List<DVFilter> {
|
|
val filters = this.toMutableList()
|
|
updates.forEach { update ->
|
|
when (update) {
|
|
is DVFilterUpdate.Add -> {
|
|
filters.addAfterIndexInLine(
|
|
predicateIndex = { it.id == update.afterId },
|
|
items = update.filters
|
|
)
|
|
}
|
|
is DVFilterUpdate.Move -> {
|
|
filters.moveAfterIndexInLine(
|
|
predicateIndex = { filter -> filter.id == update.afterId },
|
|
predicateMove = { filter -> update.ids.contains(filter.id) }
|
|
)
|
|
}
|
|
is DVFilterUpdate.Remove -> {
|
|
filters.retainAll {
|
|
!update.ids.contains(it.id)
|
|
}
|
|
}
|
|
is DVFilterUpdate.Update -> {
|
|
filters.mapInPlace { filter ->
|
|
if (filter.id == update.id) update.filter else filter
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return filters
|
|
}
|
|
|
|
fun List<DVSort>.updateSorts(updates: List<DVSortUpdate>): List<DVSort> {
|
|
val sorts = this.toMutableList()
|
|
updates.forEach { update ->
|
|
when (update) {
|
|
is DVSortUpdate.Add -> {
|
|
sorts.addAfterIndexInLine(
|
|
predicateIndex = { it.id == update.afterId },
|
|
items = update.sorts
|
|
)
|
|
}
|
|
is DVSortUpdate.Move -> {
|
|
sorts.moveAfterIndexInLine(
|
|
predicateIndex = { sort -> sort.id == update.afterId },
|
|
predicateMove = { sort -> update.ids.contains(sort.id) }
|
|
)
|
|
}
|
|
is DVSortUpdate.Remove -> {
|
|
sorts.retainAll {
|
|
!update.ids.contains(it.id)
|
|
}
|
|
}
|
|
is DVSortUpdate.Update -> {
|
|
sorts.mapInPlace { sort ->
|
|
if (sort.id == update.id) update.sort else sort
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return sorts
|
|
}
|
|
|
|
fun List<DVViewerRelation>.updateViewerRelations(updates: List<DVViewerRelationUpdate>): List<DVViewerRelation> {
|
|
val relations = this.toMutableList()
|
|
updates.forEach { update ->
|
|
when (update) {
|
|
is DVViewerRelationUpdate.Add -> {
|
|
relations.addAfterIndexInLine(
|
|
predicateIndex = { it.key == update.afterId },
|
|
items = update.relations
|
|
)
|
|
}
|
|
is DVViewerRelationUpdate.Move -> {
|
|
if (update.afterId.isNotEmpty()) {
|
|
relations.moveAfterIndexInLine(
|
|
predicateIndex = { relation -> relation.key == update.afterId },
|
|
predicateMove = { relation -> update.ids.contains(relation.key) }
|
|
)
|
|
} else {
|
|
relations.moveOnTop { update.ids.contains(it.key) }
|
|
}
|
|
}
|
|
is DVViewerRelationUpdate.Remove -> {
|
|
relations.retainAll {
|
|
!update.ids.contains(it.key)
|
|
}
|
|
}
|
|
is DVViewerRelationUpdate.Update -> {
|
|
relations.mapInPlace { relation ->
|
|
if (relation.key == update.id) update.relation else relation
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return relations
|
|
}
|
|
|
|
fun ObjectState.DataView.Set.getSetOfValue(ctx: Id): List<Id> {
|
|
return ObjectWrapper.Basic(details[ctx]?.map.orEmpty()).setOf
|
|
}
|
|
|
|
fun ObjectState.DataView.filterOutDeletedAndMissingObjects(query: List<Id>): List<Id> {
|
|
return query.filter(::isValidObject)
|
|
}
|
|
|
|
fun ObjectState.DataView.Set.isSetByRelation(setOfValue: List<Id>): Boolean {
|
|
if (setOfValue.isEmpty()) return false
|
|
val objectDetails = details[setOfValue.first()]?.map.orEmpty()
|
|
val wrapper = ObjectWrapper.Basic(objectDetails)
|
|
return wrapper.layout == ObjectType.Layout.RELATION
|
|
}
|
|
|
|
private fun ObjectState.DataView.isValidObject(objectId: Id): Boolean {
|
|
val objectDetails = details[objectId] ?: return false
|
|
val objectWrapper = ObjectWrapper.Basic(objectDetails.map)
|
|
return objectWrapper.isDeleted != true
|
|
}
|
|
|
|
fun DVViewer.updateFields(fields: DVViewerFields?): DVViewer {
|
|
if (fields == null) return this
|
|
return copy(
|
|
name = fields.name,
|
|
type = fields.type,
|
|
coverRelationKey = fields.coverRelationKey,
|
|
hideIcon = fields.hideIcon,
|
|
cardSize = fields.cardSize,
|
|
coverFit = fields.coverFit,
|
|
defaultTemplate = fields.defaultTemplateId,
|
|
defaultObjectType = fields.defaultObjectTypeId
|
|
)
|
|
}
|
|
|
|
fun Viewer.isEmpty(): Boolean =
|
|
when (this) {
|
|
is Viewer.GalleryView -> this.items.isEmpty()
|
|
is Viewer.GridView -> this.rows.isEmpty()
|
|
is Viewer.ListView -> this.items.isEmpty()
|
|
is Viewer.Unsupported -> false
|
|
}
|
|
|
|
fun ObjectWrapper.Basic.toTemplateView(
|
|
urlBuilder: UrlBuilder,
|
|
coverImageHashProvider: CoverImageHashProvider,
|
|
viewerDefTemplateId: Id?,
|
|
viewerDefTypeKey: TypeKey
|
|
): TemplateView.Template {
|
|
val coverContainer = if (coverType != CoverType.NONE) {
|
|
BasicObjectCoverWrapper(this)
|
|
.getCover(urlBuilder, coverImageHashProvider)
|
|
} else {
|
|
null
|
|
}
|
|
return TemplateView.Template(
|
|
id = id,
|
|
name = name.orEmpty(),
|
|
targetTypeId = TypeId(targetObjectType.orEmpty()),
|
|
emoji = if (!iconEmoji.isNullOrBlank()) iconEmoji else null,
|
|
image = if (!iconImage.isNullOrBlank()) urlBuilder.thumbnail(iconImage!!) else null,
|
|
layout = layout ?: ObjectType.Layout.BASIC,
|
|
coverColor = coverContainer?.coverColor,
|
|
coverImage = coverContainer?.coverImage,
|
|
coverGradient = coverContainer?.coverGradient,
|
|
isDefault = viewerDefTemplateId == id,
|
|
targetTypeKey = viewerDefTypeKey
|
|
)
|
|
}
|
|
|
|
suspend fun ObjectState.DataView.toViewersView(ctx: Id, session: ObjectSetSession, storeOfRelations: StoreOfRelations): List<ViewerView> {
|
|
val viewers = dataViewContent.viewers
|
|
return when (this) {
|
|
is ObjectState.DataView.Collection -> mapViewers(
|
|
defaultObjectType = { it.defaultObjectType },
|
|
viewers = viewers,
|
|
session = session,
|
|
storeOfRelations = storeOfRelations
|
|
)
|
|
is ObjectState.DataView.Set -> {
|
|
val setOfValue = getSetOfValue(ctx)
|
|
if (isSetByRelation(setOfValue = setOfValue)) {
|
|
mapViewers(
|
|
defaultObjectType = { it.defaultObjectType },
|
|
viewers = viewers,
|
|
session = session,
|
|
storeOfRelations = storeOfRelations
|
|
)
|
|
} else {
|
|
mapViewers(
|
|
defaultObjectType = { setOfValue.firstOrNull() },
|
|
viewers = viewers,
|
|
session = session,
|
|
storeOfRelations = storeOfRelations
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private suspend fun mapViewers(
|
|
defaultObjectType: (DVViewer) -> Id?,
|
|
viewers: List<DVViewer>,
|
|
session: ObjectSetSession,
|
|
storeOfRelations: StoreOfRelations
|
|
): List<ViewerView> {
|
|
return viewers.mapIndexed { index, viewer ->
|
|
ViewerView(
|
|
id = viewer.id,
|
|
name = viewer.name,
|
|
type = viewer.type,
|
|
isUnsupported = viewer.type == VIEW_TYPE_UNSUPPORTED,
|
|
isActive = viewer.isActiveViewer(index, session),
|
|
defaultObjectType = defaultObjectType.invoke(viewer),
|
|
relations = viewer.viewerRelations.toView(storeOfRelations) { it.key },
|
|
sorts = viewer.sorts.toView(storeOfRelations) { it.relationKey },
|
|
filters = viewer.filters.toView(storeOfRelations) { it.relation },
|
|
isDefaultObjectTypeEnabled = true
|
|
)
|
|
}
|
|
}
|
|
|
|
fun DVViewer.isActiveViewer(index: Int, session: ObjectSetSession): Boolean {
|
|
return if (session.currentViewerId.value != null) {
|
|
id == session.currentViewerId.value
|
|
} else {
|
|
index == 0
|
|
}
|
|
}
|
|
|
|
suspend fun ObjectState.DataView.getActiveViewTypeAndTemplate(
|
|
ctx: Id,
|
|
activeView: DVViewer?,
|
|
storeOfObjectTypes: StoreOfObjectTypes
|
|
): Pair<ObjectWrapper.Type?, Id?> {
|
|
if (activeView == null) return Pair(null, null)
|
|
when (this) {
|
|
is ObjectState.DataView.Collection -> {
|
|
return resolveTypeAndActiveViewTemplate(activeView, storeOfObjectTypes)
|
|
}
|
|
is ObjectState.DataView.Set -> {
|
|
val setOfValue = getSetOfValue(ctx)
|
|
return if (isSetByRelation(setOfValue = setOfValue)) {
|
|
resolveTypeAndActiveViewTemplate(activeView, storeOfObjectTypes)
|
|
} else {
|
|
val setOf = setOfValue.firstOrNull()
|
|
if (setOf.isNullOrBlank()) {
|
|
Timber.d("Set by type setOf param is null or empty, not possible to get Type and Template")
|
|
Pair(null, null)
|
|
} else {
|
|
val defaultSetObjectType = details[setOf]?.map?.mapToObjectWrapperType()
|
|
if (activeView.defaultTemplate.isNullOrEmpty()) {
|
|
val defaultTemplateId = defaultSetObjectType?.defaultTemplateId
|
|
Pair(defaultSetObjectType, defaultTemplateId)
|
|
} else {
|
|
Pair(defaultSetObjectType, activeView.defaultTemplate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private suspend fun resolveTypeAndActiveViewTemplate(
|
|
activeView: DVViewer,
|
|
storeOfObjectTypes: StoreOfObjectTypes
|
|
): Pair<ObjectWrapper.Type?, Id?> {
|
|
val activeViewDefaultObjectType = activeView.defaultObjectType
|
|
val defaultSetObjectTypId = if (!activeViewDefaultObjectType.isNullOrBlank()) {
|
|
activeViewDefaultObjectType
|
|
} else {
|
|
VIEW_DEFAULT_OBJECT_TYPE
|
|
}
|
|
val defaultSetObjectType = storeOfObjectTypes.get(defaultSetObjectTypId) ?: storeOfObjectTypes.getByKey(defaultSetObjectTypId)
|
|
return if (activeView.defaultTemplate.isNullOrEmpty()) {
|
|
val defaultTemplateId = defaultSetObjectType?.defaultTemplateId
|
|
Pair(defaultSetObjectType, defaultTemplateId)
|
|
} else {
|
|
Pair(defaultSetObjectType, activeView.defaultTemplate)
|
|
}
|
|
}
|
|
|
|
fun ObjectState.DataView.isChangingDefaultTypeAvailable(): Boolean {
|
|
return when (this) {
|
|
is ObjectState.DataView.Collection -> true
|
|
is ObjectState.DataView.Set -> {
|
|
val setOfValue = getSetOfValue(root)
|
|
isSetByRelation(setOfValue = setOfValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
suspend fun DVViewer.prefillNewObjectDetails(
|
|
storeOfRelations: StoreOfRelations,
|
|
dateProvider: DateProvider,
|
|
dataViewRelationLinks: List<RelationLink>
|
|
): Struct =
|
|
buildMap {
|
|
filters.forEach { filter ->
|
|
val relationObject = storeOfRelations.getByKey(filter.relation) ?: return@forEach
|
|
if (!relationObject.isReadonlyValue && PermittedConditions.contains(
|
|
filter.condition
|
|
)
|
|
) {
|
|
//Relation format should be taken from DataView relation links
|
|
val filterRelationFormat =
|
|
dataViewRelationLinks.firstOrNull { it.key == filter.relation }?.format
|
|
when (filterRelationFormat) {
|
|
Relation.Format.DATE -> {
|
|
val value = DateParser.parse(filter.value)
|
|
val updatedValue = filter.quickOption.getTimestampForQuickOption(
|
|
value = value,
|
|
dateProvider = dateProvider
|
|
)
|
|
if (updatedValue != null) {
|
|
put(filter.relation, updatedValue.toDouble())
|
|
}
|
|
}
|
|
else -> {
|
|
filter.value?.let { put(filter.relation, it) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
suspend fun DVViewer.resolveSetByRelationPrefilledObjectData(
|
|
storeOfRelations: StoreOfRelations,
|
|
dateProvider: DateProvider,
|
|
objSetByRelation: ObjectWrapper.Relation,
|
|
dataViewRelationLinks: List<RelationLink>
|
|
): Struct {
|
|
val prefillWithSetOf = buildMap {
|
|
val relationFormat = objSetByRelation.relationFormat
|
|
val defaultValue = resolveDefaultValueByFormat(relationFormat)
|
|
put(objSetByRelation.key, defaultValue)
|
|
}
|
|
val prefillNewObjectDetails = prefillNewObjectDetails(storeOfRelations, dateProvider, dataViewRelationLinks)
|
|
return prefillWithSetOf + prefillNewObjectDetails
|
|
}
|
|
|
|
private fun resolveDefaultValueByFormat(format: RelationFormat): Any? = when (format) {
|
|
Relation.Format.LONG_TEXT,
|
|
Relation.Format.SHORT_TEXT,
|
|
Relation.Format.URL,
|
|
Relation.Format.EMAIL,
|
|
Relation.Format.PHONE,
|
|
Relation.Format.EMOJI -> EMPTY_STRING_VALUE
|
|
Relation.Format.CHECKBOX -> false
|
|
Relation.Format.NUMBER -> null
|
|
else -> null
|
|
}
|
|
|
|
fun DVFilterQuickOption.getTimestampForQuickOption(value: Long?, dateProvider: DateProvider): Long? {
|
|
val option = this
|
|
val time = dateProvider.getCurrentTimestampInSeconds()
|
|
return when (option) {
|
|
DVFilterQuickOption.DAYS_AGO -> {
|
|
if (value == null) return null
|
|
time - SECONDS_IN_DAY * value
|
|
}
|
|
DVFilterQuickOption.LAST_MONTH -> time - SECONDS_IN_DAY * DAYS_IN_MONTH
|
|
DVFilterQuickOption.LAST_WEEK -> time - SECONDS_IN_DAY * DAYS_IN_WEEK
|
|
DVFilterQuickOption.YESTERDAY -> time - SECONDS_IN_DAY
|
|
DVFilterQuickOption.CURRENT_WEEK,
|
|
DVFilterQuickOption.CURRENT_MONTH,
|
|
DVFilterQuickOption.TODAY -> time
|
|
DVFilterQuickOption.TOMORROW -> time + SECONDS_IN_DAY
|
|
DVFilterQuickOption.NEXT_WEEK -> time + SECONDS_IN_DAY * DAYS_IN_WEEK
|
|
DVFilterQuickOption.NEXT_MONTH -> time + SECONDS_IN_DAY * DAYS_IN_MONTH
|
|
DVFilterQuickOption.DAYS_AHEAD -> {
|
|
if (value == null) return null
|
|
time + SECONDS_IN_DAY * value
|
|
}
|
|
DVFilterQuickOption.EXACT_DATE -> value
|
|
}
|
|
}
|
|
|