DROID-824 Library | Enhancement | Added reactive changes on library support (#2883)

DROID-824 Library | Enhancement | Added reactive changes on library support
This commit is contained in:
Allan Quatermain 2023-02-02 13:47:37 +03:00 committed by GitHub
parent b89099c915
commit 7b373339f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 792 additions and 231 deletions

View File

@ -3,10 +3,12 @@ package com.anytypeio.anytype.di.feature.library
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.library.LibraryInteractor
import com.anytypeio.anytype.presentation.library.LibraryListDelegate
import com.anytypeio.anytype.presentation.library.LibraryViewModel
import com.anytypeio.anytype.presentation.library.delegates.LibraryRelationsDelegate
@ -18,6 +20,7 @@ import dagger.Binds
import dagger.Component
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.Dispatchers
@Component(
dependencies = [LibraryDependencies::class],
@ -43,33 +46,49 @@ object LibraryModule {
@PerScreen
@Provides
fun provideMyTypesDelegate(
interactor: LibraryInteractor,
workspaceManager: WorkspaceManager
container: StorelessSubscriptionContainer,
workspaceManager: WorkspaceManager,
urlBuilder: UrlBuilder
): LibraryListDelegate {
return MyTypesDelegate(interactor, workspaceManager)
return MyTypesDelegate(container, workspaceManager, urlBuilder)
}
@PerScreen
@Provides
fun provideLibTypesDelegate(interactor: LibraryInteractor): LibraryListDelegate {
return LibraryTypesDelegate(interactor)
fun provideLibTypesDelegate(
container: StorelessSubscriptionContainer,
urlBuilder: UrlBuilder
): LibraryListDelegate {
return LibraryTypesDelegate(container, urlBuilder)
}
@PerScreen
@Provides
fun provideMyRelationsDelegate(
interactor: LibraryInteractor,
workspaceManager: WorkspaceManager
container: StorelessSubscriptionContainer,
workspaceManager: WorkspaceManager,
urlBuilder: UrlBuilder
): LibraryListDelegate {
return MyRelationsDelegate(interactor, workspaceManager)
return MyRelationsDelegate(container, workspaceManager, urlBuilder)
}
@PerScreen
@Provides
fun provideLibRelationsDelegate(interactor: LibraryInteractor): LibraryListDelegate {
return LibraryRelationsDelegate(interactor)
fun provideLibRelationsDelegate(
container: StorelessSubscriptionContainer,
urlBuilder: UrlBuilder
): LibraryListDelegate {
return LibraryRelationsDelegate(container, urlBuilder)
}
@PerScreen
@Provides
fun provideAppCoroutineDispatchers() : AppCoroutineDispatchers = AppCoroutineDispatchers(
io = Dispatchers.IO,
computation = Dispatchers.Default,
main = Dispatchers.Main
)
@Module
interface Declarations {
@ -79,7 +98,7 @@ object LibraryModule {
@PerScreen
@Binds
fun bindInteractor(interactor: LibraryInteractor.Impl): LibraryInteractor
fun bindContainer(container: StorelessSubscriptionContainer.Impl): StorelessSubscriptionContainer
}
@ -89,4 +108,5 @@ interface LibraryDependencies : ComponentDependencies {
fun blockRepository(): BlockRepository
fun workspaceManager(): WorkspaceManager
fun urlBuilder(): UrlBuilder
fun channel(): SubscriptionEventChannel
}

View File

@ -76,7 +76,7 @@ fun TabContentScreen(
verticalArrangement = Arrangement.Top,
) {
Text(
color = colorResource(id = R.color.black),
color = colorResource(id = R.color.text_primary),
text = stringResource(config.description),
style = MaterialTheme.typography.h1,
textAlign = TextAlign.Center,
@ -85,7 +85,9 @@ fun TabContentScreen(
Box(Modifier.height(18.dp))
Button(
onClick = { /*TODO*/ },
colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(id = R.color.black)),
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.glyph_selected)
),
shape = RoundedCornerShape(10.dp),
contentPadding = PaddingValues(
28.dp, 10.dp, 28.dp, 10.dp
@ -93,7 +95,7 @@ fun TabContentScreen(
content = {
Text(
text = stringResource(config.mainBtnTitle),
color = colorResource(id = R.color.library_action_btn_text_color),
color = colorResource(id = R.color.text_white),
fontSize = 17.sp,
fontWeight = FontWeight.SemiBold
)

View File

@ -52,13 +52,13 @@ fun LibraryListSearchWidget(
},
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = colorResource(id = R.color.text_primary),
backgroundColor = colorResource(id = R.color.light_grayish),
backgroundColor = colorResource(id = R.color.shape_transparent),
disabledBorderColor = Color.Transparent,
errorBorderColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
placeholderColor = colorResource(id = R.color.text_tertiary),
cursorColor = colorResource(id = R.color.black)
placeholderColor = colorResource(id = R.color.glyph_active),
cursorColor = colorResource(id = R.color.text_primary)
),
singleLine = true,
maxLines = 1,

View File

@ -1,7 +1,6 @@
package com.anytypeio.anytype.ui.library.views.list
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
@ -10,17 +9,15 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.core_models.ObjectTypeIds.OBJECT_TYPE as MY_TYPE
import com.anytypeio.anytype.core_models.ObjectTypeIds.RELATION as MY_RELATION
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds.OBJECT_TYPE as LIB_TYPE
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds.RELATION as LIB_RELATION
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.library.LibraryEvent
import com.anytypeio.anytype.presentation.library.LibraryScreenState
import com.anytypeio.anytype.presentation.navigation.LibraryView
import com.anytypeio.anytype.ui.library.LibraryListConfig
import com.anytypeio.anytype.ui.library.views.list.items.ItemDefaults
import com.anytypeio.anytype.ui.library.views.list.items.LibRelationItem
@ -64,29 +61,59 @@ fun LibraryListTabsContent(
.fillMaxHeight(),
contentPadding = PaddingValues(start = 16.dp, end = 16.dp)
) {
items(data.items.size) { index ->
val item = data.items[index]
when (item.type) {
LIB_TYPE -> {
LibTypeItem(modifier = itemModifier, item = item)
items(
count = data.items.size,
key = { index ->
data.items[index].id
},
itemContent = { ix ->
when (val item = data.items[ix]) {
is LibraryView.LibraryTypeView -> {
LibTypeItem(
name = item.name,
icon = item.icon,
installed = item.installed,
modifier = itemModifier
)
}
is LibraryView.MyTypeView -> {
MyTypeItem(
name = item.name,
icon = item.icon,
readOnly = item.readOnly,
modifier = itemModifier
)
}
is LibraryView.LibraryRelationView -> {
LibRelationItem(
modifier = itemModifier,
name = item.name,
format = item.format,
installed = item.installed
)
}
is LibraryView.MyRelationView -> {
MyRelationItem(
modifier = itemModifier,
name = item.name,
readOnly = item.readOnly,
format = item.format
)
}
is LibraryView.UnknownView -> {
// do nothing
}
}
MY_TYPE -> {
MyTypeItem(modifier = itemModifier, item = item)
}
LIB_RELATION -> {
LibRelationItem(modifier = itemModifier, item = item)
}
MY_RELATION -> {
MyRelationItem(modifier = itemModifier, item = item)
}
else -> {
Timber.d("Unknown item type: ${item.type}")
if (ix < data.items.lastIndex) {
Divider(
thickness = 1.dp,
modifier = Modifier.padding(start = 4.dp, end = 4.dp),
color = colorResource(id = R.color.shape_primary)
)
}
}
if (index < data.items.size.minus(1)) {
Divider(thickness = 1.dp, modifier = Modifier.padding(start = 4.dp, end = 4.dp))
}
}
)
}
}
}

View File

@ -1,92 +1,161 @@
package com.anytypeio.anytype.ui.library.views.list.items
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_ui.extensions.simpleIcon
import com.anytypeio.anytype.core_ui.widgets.ObjectIconWidget
import com.anytypeio.anytype.core_ui.widgets.RelationFormatIconWidget
import com.anytypeio.anytype.presentation.navigation.LibraryView
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.ui.library.views.list.items.ItemDefaults.TEXT_PADDING_START
@Composable
fun MyTypeItem(item: LibraryView, modifier: Modifier) {
fun MyTypeItem(
name: String,
icon: ObjectIcon?,
readOnly: Boolean = false,
modifier: Modifier
) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Icon(icon = item.icon)
Icon(icon = icon)
Text(
text = item.name,
text = name,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
}
}
@Composable
fun LibTypeItem(item: LibraryView, modifier: Modifier) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Icon(icon = item.icon)
Text(
text = item.name,
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
}
}
@Composable
fun MyRelationItem(item: LibraryView, modifier: Modifier) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = item.name,
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
}
}
@Composable
fun LibRelationItem(item: LibraryView, modifier: Modifier) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = item.name,
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
}
}
@Composable
fun Icon(icon: ObjectIcon) {
AndroidView(factory = { ctx ->
ObjectIconWidget(ctx).apply {
setIcon(icon)
Spacer(modifier = Modifier.weight(1f))
if (readOnly) {
Image(
painter = painterResource(id = R.drawable.ic_object_locked),
contentDescription = "",
)
}
})
}
}
@Composable
fun LibTypeItem(
name: String,
icon: ObjectIcon?,
installed: Boolean = false,
modifier: Modifier,
) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
Icon(icon = icon)
Text(
text = name,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
Spacer(modifier = Modifier.weight(1f))
val installedImageRes = if (installed) {
R.drawable.ic_type_installed
} else {
R.drawable.ic_type_not_installed
}
Image(
painter = painterResource(id = installedImageRes),
contentDescription = installedImageRes.toString(),
)
}
}
@Composable
fun MyRelationItem(
modifier: Modifier,
name: String,
format: RelationFormat,
readOnly: Boolean = false,
) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
format.simpleIcon()?.let {
Image(painter = painterResource(id = it), contentDescription = "")
}
Text(
text = name,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
Spacer(modifier = Modifier.weight(1f))
if (readOnly) {
Image(
painter = painterResource(id = R.drawable.ic_object_locked),
contentDescription = ""
)
}
}
}
@Composable
fun LibRelationItem(
modifier: Modifier,
name: String,
format: RelationFormat,
installed: Boolean
) {
Row(
modifier,
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
format.simpleIcon()?.let {
Image(painter = painterResource(id = it), contentDescription = "")
}
Text(
text = name,
color = colorResource(id = R.color.text_primary),
modifier = Modifier
.padding(start = TEXT_PADDING_START)
)
Spacer(modifier = Modifier.weight(1f))
val installedImageRes = if (installed) {
R.drawable.ic_type_installed
} else {
R.drawable.ic_type_not_installed
}
Image(
painter = painterResource(id = installedImageRes),
contentDescription = installedImageRes.toString(),
)
}
}
@Composable
fun Icon(icon: ObjectIcon?) {
icon?.let {
AndroidView(factory = { ctx ->
ObjectIconWidget(ctx).apply {
setIcon(it)
}
})
}
}

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:pathData="M14,0L14,0A14,14 0,0 1,28 14L28,14A14,14 0,0 1,14 28L14,28A14,14 0,0 1,0 14L0,14A14,14 0,0 1,14 0z"
android:fillColor="@color/shape_tertiary"/>
<path
android:pathData="M9,14L13.031,18.5L18.5,9"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="@color/text_primary"/>
</vector>

View File

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:strokeWidth="1"
android:pathData="M14,0.5L14,0.5A13.5,13.5 0,0 1,27.5 14L27.5,14A13.5,13.5 0,0 1,14 27.5L14,27.5A13.5,13.5 0,0 1,0.5 14L0.5,14A13.5,13.5 0,0 1,14 0.5z"
android:fillColor="#00000000"
android:strokeColor="@color/shape_primary"/>
<path
android:pathData="M8.75,14.75L19.25,14.75A0.75,0.75 0,0 0,20 14L20,14A0.75,0.75 0,0 0,19.25 13.25L8.75,13.25A0.75,0.75 0,0 0,8 14L8,14A0.75,0.75 0,0 0,8.75 14.75z"
android:fillColor="@color/text_primary"/>
<path
android:pathData="M13.25,8.75L13.25,19.25A0.75,0.75 0,0 0,14 20L14,20A0.75,0.75 0,0 0,14.75 19.25L14.75,8.75A0.75,0.75 0,0 0,14 8L14,8A0.75,0.75 0,0 0,13.25 8.75z"
android:fillColor="@color/text_primary"/>
</vector>

View File

@ -221,6 +221,22 @@ fun RelationFormat.icon(isMedium: Boolean = false): Int = when (this) {
}
}
fun RelationFormat.simpleIcon(): Int? = when (this) {
RelationFormat.SHORT_TEXT -> R.drawable.ic_relation_format_text_small
RelationFormat.LONG_TEXT -> R.drawable.ic_relation_format_text_small
RelationFormat.NUMBER -> R.drawable.ic_relation_format_number_small
RelationFormat.STATUS -> R.drawable.ic_relation_format_status_small
RelationFormat.TAG -> R.drawable.ic_relation_format_tag_small
RelationFormat.DATE -> R.drawable.ic_relation_format_date_small
RelationFormat.FILE -> R.drawable.ic_relation_format_attachment_small
RelationFormat.CHECKBOX -> R.drawable.ic_relation_format_checkbox_small
RelationFormat.URL -> R.drawable.ic_relation_format_url_small
RelationFormat.EMAIL -> R.drawable.ic_relation_format_email_small
RelationFormat.PHONE -> R.drawable.ic_relation_format_phone_number_small
RelationFormat.OBJECT -> R.drawable.ic_relation_format_object_small
else -> null
}
fun DVSortType.text(format: RelationFormat): Int = when (format) {
RelationFormat.TAG, RelationFormat.STATUS -> {
if (this == DVSortType.ASC)

View File

@ -5,6 +5,7 @@ import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.extensions.simpleIcon
import com.anytypeio.anytype.presentation.sets.model.ColumnView
import timber.log.Timber
@ -13,21 +14,10 @@ class RelationFormatIconWidget @JvmOverloads constructor(
attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
fun bind(format: RelationFormat) {
when (format) {
RelationFormat.SHORT_TEXT -> setImageResource(R.drawable.ic_relation_format_text_small)
RelationFormat.LONG_TEXT -> setImageResource(R.drawable.ic_relation_format_text_small)
RelationFormat.NUMBER -> setImageResource(R.drawable.ic_relation_format_number_small)
RelationFormat.STATUS -> setImageResource(R.drawable.ic_relation_format_status_small)
RelationFormat.TAG -> setImageResource(R.drawable.ic_relation_format_tag_small)
RelationFormat.DATE -> setImageResource(R.drawable.ic_relation_format_date_small)
RelationFormat.FILE -> setImageResource(R.drawable.ic_relation_format_attachment_small)
RelationFormat.CHECKBOX -> setImageResource(R.drawable.ic_relation_format_checkbox_small)
RelationFormat.URL -> setImageResource(R.drawable.ic_relation_format_url_small)
RelationFormat.EMAIL -> setImageResource(R.drawable.ic_relation_format_email_small)
RelationFormat.PHONE -> setImageResource(R.drawable.ic_relation_format_phone_number_small)
RelationFormat.OBJECT -> setImageResource(R.drawable.ic_relation_format_object_small)
else -> Timber.d("Unexpected format: $format")
}
format.simpleIcon()?.let {
setImageResource(it)
return
} ?: Timber.e("Unexpected format: $format")
}
fun bind(format: ColumnView.Format) {
when (format) {

View File

@ -10,6 +10,8 @@ dependencies {
implementation libs.kotlin
implementation libs.coroutines
compileOnly libs.javaxInject
testImplementation project(":test:utils")
testImplementation libs.kotlinTest
testImplementation libs.turbine

View File

@ -4,7 +4,7 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Id
class LibrarySearchParams(
class StoreSearchParams(
val subscription: Id,
val sorts: List<DVSort> = emptyList(),
val filters: List<DVFilter> = emptyList(),

View File

@ -0,0 +1,105 @@
package com.anytypeio.anytype.domain.library
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.library.processors.EventAddProcessor
import com.anytypeio.anytype.domain.library.processors.EventAmendProcessor
import com.anytypeio.anytype.domain.library.processors.EventPositionProcessor
import com.anytypeio.anytype.domain.library.processors.EventRemoveProcessor
import com.anytypeio.anytype.domain.library.processors.EventSetProcessor
import com.anytypeio.anytype.domain.library.processors.EventUnsetProcessor
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.scan
interface StorelessSubscriptionContainer {
fun subscribe(searchParams: StoreSearchParams): Flow<List<ObjectWrapper.Basic>>
class Impl @Inject constructor(
private val repo: BlockRepository,
private val channel: SubscriptionEventChannel,
private val dispatchers: AppCoroutineDispatchers
) : StorelessSubscriptionContainer {
private val addEventProcessor by lazy { EventAddProcessor() }
private val unsetEventProcessor by lazy { EventUnsetProcessor() }
private val removeEventProcessor by lazy { EventRemoveProcessor() }
private val setEventProcessor by lazy { EventSetProcessor() }
private val amendEventProcessor by lazy { EventAmendProcessor() }
private val positionEventProcessor by lazy { EventPositionProcessor() }
private fun subscribe(subscriptions: List<Id>) = channel.subscribe(subscriptions)
override fun subscribe(searchParams: StoreSearchParams): Flow<List<ObjectWrapper.Basic>> =
flow {
with(searchParams) {
val initial = repo.searchObjectsWithSubscription(
subscription = subscription,
sorts = sorts,
filters = filters,
offset = offset,
limit = limit,
keys = keys,
afterId = null,
beforeId = null,
source = source,
ignoreWorkspace = null,
noDepSubscription = null
).results.map { SubscriptionObject(it.id, it) }.toMutableList()
val objectsFlow =
subscribe(
listOf(searchParams.subscription)
).scan(initial) { dataItems, payload ->
var result = dataItems
payload.forEach { event ->
when (event) {
is SubscriptionEvent.Add -> {
result = addEventProcessor.process(event, result)
}
is SubscriptionEvent.Amend -> {
result = amendEventProcessor.process(event, result)
}
is SubscriptionEvent.Position -> {
result = positionEventProcessor.process(event, result)
}
is SubscriptionEvent.Remove -> {
result = removeEventProcessor.process(event, result)
}
is SubscriptionEvent.Set -> {
result = setEventProcessor.process(event, result)
}
is SubscriptionEvent.Unset -> {
result = unsetEventProcessor.process(event, result)
}
else -> {
// do nothing
}
}
}
result
}.map {
it.mapNotNull { item -> item.objectWrapper }
}
emitAll(objectsFlow)
}
}.flowOn(dispatchers.io)
}
}
data class SubscriptionObject(
val id: Id,
val objectWrapper: ObjectWrapper.Basic? = null
)

View File

@ -0,0 +1,26 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
class EventAddProcessor : SubscriptionEventProcessor<SubscriptionEvent.Add> {
override fun process(
event: SubscriptionEvent.Add,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject> = with(dataItems) {
val afterId = event.afterId
if (afterId != null) {
val afterIdx = indexOfFirst { afterId == it.id }
if (afterIdx != -1) {
add(afterIdx.inc(), SubscriptionObject(event.target))
} else {
add(0, SubscriptionObject(event.target))
}
} else {
add(0, SubscriptionObject(event.target))
}
return this
}
}

View File

@ -0,0 +1,35 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
import com.anytypeio.anytype.domain.`object`.amend
class EventAmendProcessor: SubscriptionEventProcessor<SubscriptionEvent.Amend> {
override fun process(
event: SubscriptionEvent.Amend,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject> = with(dataItems) {
val item = find { it.id == event.target }
if (item?.objectWrapper != null) {
set(
indexOf(item),
SubscriptionObject(
id = item.id,
objectWrapper = item.objectWrapper.amend(event.diff)
)
)
} else {
set(
indexOf(item),
SubscriptionObject(
id = item?.id ?: event.target,
objectWrapper = ObjectWrapper.Basic(event.diff)
)
)
}
return this
}
}

View File

@ -0,0 +1,25 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
class EventPositionProcessor: SubscriptionEventProcessor<SubscriptionEvent.Position> {
override fun process(
event: SubscriptionEvent.Position,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject> = with(dataItems) {
val itemToMove = find { it.id == event.target }
if (itemToMove != null) {
remove(itemToMove)
val afterIdx = indexOfFirst { event.afterId == it.id }
if (afterIdx != -1) {
add(afterIdx.inc(), itemToMove)
} else {
add(0, itemToMove)
}
}
return this
}
}

View File

@ -0,0 +1,18 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
class EventRemoveProcessor : SubscriptionEventProcessor<SubscriptionEvent.Remove> {
override fun process(
event: SubscriptionEvent.Remove,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject> = with(dataItems) {
retainAll {
it.id != event.target
}
return this
}
}

View File

@ -0,0 +1,33 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
class EventSetProcessor : SubscriptionEventProcessor<SubscriptionEvent.Set> {
override fun process(
event: SubscriptionEvent.Set,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject> = with(dataItems) {
val indexOfItem = indexOfFirst { it.id == event.target }
if (indexOfItem != -1) {
set(
indexOfItem,
SubscriptionObject(
event.target,
com.anytypeio.anytype.core_models.ObjectWrapper.Basic(event.data)
)
)
} else {
add(
0,
SubscriptionObject(
event.target,
com.anytypeio.anytype.core_models.ObjectWrapper.Basic(event.data)
)
)
}
return this
}
}

View File

@ -0,0 +1,24 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
import com.anytypeio.anytype.domain.`object`.unset
class EventUnsetProcessor : SubscriptionEventProcessor<SubscriptionEvent.Unset> {
override fun process(
event: SubscriptionEvent.Unset,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject> = with(dataItems) {
val item = find { it.id == event.target }?.let {
SubscriptionObject(it.id, it.objectWrapper.apply {
this?.unset(event.keys)
})
}
if (item != null) {
set(indexOf(item), item)
}
return this
}
}

View File

@ -0,0 +1,11 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
interface SubscriptionEventProcessor<T: SubscriptionEvent> {
fun process(
event: T,
dataItems: MutableList<SubscriptionObject>
): MutableList<SubscriptionObject>
}

View File

@ -1,42 +0,0 @@
package com.anytypeio.anytype.presentation.library
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.library.LibrarySearchParams
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.navigation.LibraryView
import com.anytypeio.anytype.presentation.objects.toLibraryViews
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
interface LibraryInteractor {
fun subscribe(searchParams: LibrarySearchParams): Flow<List<LibraryView>>
class Impl @Inject constructor(
private val repo: BlockRepository,
private val urlBuilder: UrlBuilder,
) : LibraryInteractor {
override fun subscribe(searchParams: LibrarySearchParams): Flow<List<LibraryView>> =
flow {
with(searchParams) {
val initial = repo.searchObjectsWithSubscription(
subscription = subscription,
sorts = sorts,
filters = filters,
offset = offset,
limit = limit,
keys = keys,
afterId = null,
beforeId = null,
source = source,
ignoreWorkspace = null,
noDepSubscription = null
).results.toLibraryViews(urlBuilder = urlBuilder)
emit(initial)
}
}
}
}

View File

@ -1,5 +1,6 @@
package com.anytypeio.anytype.presentation.library
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.presentation.navigation.LibraryView
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
@ -12,7 +13,7 @@ interface LibraryListDelegate {
val queryFlow: MutableStateFlow<String>
val itemsFlow: Flow<LibraryScreenState.Tabs.TabData>
fun itemsFlow(): Flow<List<LibraryView>>
fun itemsFlow(): Flow<List<ObjectWrapper.Basic>>
@FlowPreview
fun queryFlow() = queryFlow

View File

@ -7,6 +7,7 @@ import com.anytypeio.anytype.presentation.library.delegates.LibraryRelationsDele
import com.anytypeio.anytype.presentation.library.delegates.LibraryTypesDelegate
import com.anytypeio.anytype.presentation.library.delegates.MyRelationsDelegate
import com.anytypeio.anytype.presentation.library.delegates.MyTypesDelegate
import com.anytypeio.anytype.presentation.navigation.LibraryView
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@ -55,10 +56,21 @@ class LibraryViewModel(
myRelationsDelegate.itemsFlow,
libraryRelationsDelegate.itemsFlow
) { myTypes, libTypes, myRel, libRel ->
LibraryScreenState(
types = LibraryScreenState.Tabs.Types(myTypes, libTypes),
relations = LibraryScreenState.Tabs.Relations(myRel, libRel)
val libTypesItems = updateInstalledValueForTypes(
libTypes,
myTypes
)
val libRelItems = updateInstalledValueForRelations(
libRel,
myRel
)
LibraryScreenState(
types = LibraryScreenState.Tabs.Types(myTypes, libTypesItems),
relations = LibraryScreenState.Tabs.Relations(myRel, libRelItems)
)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(STOP_SUBSCRIPTION_TIMEOUT),
@ -74,6 +86,40 @@ class LibraryViewModel(
)
)
private fun updateInstalledValueForTypes(
libTypes: LibraryScreenState.Tabs.TabData,
myTypes: LibraryScreenState.Tabs.TabData
): LibraryScreenState.Tabs.TabData {
return libTypes.copy(
items = libTypes.items.map { libType ->
if (libType is LibraryView.LibraryTypeView) {
libType.copy(installed = myTypes.items.find { myType ->
(myType as LibraryView.MyTypeView).sourceObject == libType.id
} != null)
} else {
libType
}
}
)
}
private fun updateInstalledValueForRelations(
libRelations: LibraryScreenState.Tabs.TabData,
myRelations: LibraryScreenState.Tabs.TabData
): LibraryScreenState.Tabs.TabData {
return libRelations.copy(
items = libRelations.items.map { libRelation ->
if (libRelation is LibraryView.LibraryRelationView) {
libRelation.copy(installed = myRelations.items.find { myType ->
(myType as LibraryView.MyRelationView).sourceObject == libRelation.id
} != null)
} else {
libRelation
}
}
)
}
class Factory @Inject constructor(
private val myTypesDelegate: MyTypesDelegate,
private val libraryTypesDelegate: LibraryTypesDelegate,

View File

@ -4,13 +4,15 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Marketplace
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.library.LibrarySearchParams
import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.dashboard.DEFAULT_KEYS
import com.anytypeio.anytype.presentation.library.LibraryInteractor
import com.anytypeio.anytype.presentation.library.LibraryListDelegate
import com.anytypeio.anytype.presentation.library.LibraryScreenState
import com.anytypeio.anytype.presentation.library.QueryListenerLibRelations
import com.anytypeio.anytype.presentation.library.filterByQuery
import com.anytypeio.anytype.presentation.objects.toLibraryViews
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@ -18,7 +20,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
class LibraryRelationsDelegate @Inject constructor(
private val interactor: LibraryInteractor
private val container: StorelessSubscriptionContainer,
private val urlBuilder: UrlBuilder
) : LibraryListDelegate, QueryListenerLibRelations {
override val queryFlow: MutableStateFlow<String> = MutableStateFlow("")
@ -31,15 +34,19 @@ class LibraryRelationsDelegate @Inject constructor(
itemsFlow(),
queryFlow()
) { items, query ->
LibraryScreenState.Tabs.TabData(items.filterByQuery(query))
LibraryScreenState.Tabs.TabData(
items
.toLibraryViews(urlBuilder)
.filterByQuery(query)
)
}
override fun itemsFlow() = interactor.subscribe(buildSearchParams())
override fun itemsFlow() = container.subscribe(buildSearchParams())
private fun buildSearchParams(): LibrarySearchParams {
return LibrarySearchParams(
private fun buildSearchParams(): StoreSearchParams {
return StoreSearchParams(
subscription = SUB_LIBRARY_RELATIONS,
keys = DEFAULT_KEYS,
keys = DEFAULT_KEYS + listOf(Relations.RELATION_FORMAT),
filters = buildList {
addAll(ObjectSearchConstants.filterMarketplaceRelations())
add(

View File

@ -3,14 +3,17 @@ package com.anytypeio.anytype.presentation.library.delegates
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Marketplace.MARKETPLACE_ID
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.library.LibrarySearchParams
import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.dashboard.DEFAULT_KEYS
import com.anytypeio.anytype.presentation.library.LibraryInteractor
import com.anytypeio.anytype.presentation.library.LibraryListDelegate
import com.anytypeio.anytype.presentation.library.LibraryScreenState
import com.anytypeio.anytype.presentation.library.QueryListenerLibTypes
import com.anytypeio.anytype.presentation.library.filterByQuery
import com.anytypeio.anytype.presentation.objects.toLibraryViews
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@ -18,7 +21,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
class LibraryTypesDelegate @Inject constructor(
private val interactor: LibraryInteractor
private val container: StorelessSubscriptionContainer,
private val urlBuilder: UrlBuilder
) : LibraryListDelegate, QueryListenerLibTypes {
override val queryFlow: MutableStateFlow<String> = MutableStateFlow("")
@ -31,17 +35,21 @@ class LibraryTypesDelegate @Inject constructor(
itemsFlow(),
queryFlow()
) { items, query ->
LibraryScreenState.Tabs.TabData(items.filterByQuery(query))
LibraryScreenState.Tabs.TabData(
items
.toLibraryViews(urlBuilder)
.filterByQuery(query)
)
}
override fun itemsFlow() = interactor.subscribe(buildSearchParams())
override fun itemsFlow() = container.subscribe(buildSearchParams())
private fun buildSearchParams(): LibrarySearchParams {
return LibrarySearchParams(
private fun buildSearchParams(): StoreSearchParams {
return StoreSearchParams(
subscription = SUB_LIBRARY_TYPES,
keys = DEFAULT_KEYS,
filters = buildList {
ObjectSearchConstants.filterTypes()
addAll(ObjectSearchConstants.filterTypes())
add(
DVFilter(
relation = Relations.WORKSPACE_ID,
@ -49,6 +57,13 @@ class LibraryTypesDelegate @Inject constructor(
value = MARKETPLACE_ID
)
)
add(
DVFilter(
relation = Relations.TYPE,
condition = DVFilterCondition.EQUAL,
value = MarketplaceObjectTypeIds.OBJECT_TYPE
)
)
}
)
}

View File

@ -4,14 +4,16 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.library.LibrarySearchParams
import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.dashboard.DEFAULT_KEYS
import com.anytypeio.anytype.presentation.library.LibraryInteractor
import com.anytypeio.anytype.presentation.library.LibraryListDelegate
import com.anytypeio.anytype.presentation.library.LibraryScreenState
import com.anytypeio.anytype.presentation.library.QueryListenerMyRelations
import com.anytypeio.anytype.presentation.library.filterByQuery
import com.anytypeio.anytype.presentation.objects.toLibraryViews
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import javax.inject.Inject
import kotlinx.coroutines.FlowPreview
@ -22,8 +24,9 @@ import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
class MyRelationsDelegate @Inject constructor(
private val interactor: LibraryInteractor,
private val workspaceManager: WorkspaceManager
private val container: StorelessSubscriptionContainer,
private val workspaceManager: WorkspaceManager,
private val urlBuilder: UrlBuilder
) : LibraryListDelegate, QueryListenerMyRelations {
override val queryFlow: MutableStateFlow<String> = MutableStateFlow("")
@ -37,7 +40,11 @@ class MyRelationsDelegate @Inject constructor(
itemsFlow(),
queryFlow()
) { items, query ->
LibraryScreenState.Tabs.TabData(items.filterByQuery(query))
LibraryScreenState.Tabs.TabData(
items
.toLibraryViews(urlBuilder)
.filterByQuery(query)
)
}
@FlowPreview
@ -45,13 +52,17 @@ class MyRelationsDelegate @Inject constructor(
emit(workspaceManager.getCurrentWorkspace())
}.flatMapMerge {
val searchParams = buildSearchParams(it)
interactor.subscribe(searchParams)
container.subscribe(searchParams)
}
private fun buildSearchParams(workspaceId: Id): LibrarySearchParams {
return LibrarySearchParams(
private fun buildSearchParams(workspaceId: Id): StoreSearchParams {
return StoreSearchParams(
subscription = SUB_LIBRARY_MY_RELATIONS,
keys = DEFAULT_KEYS,
keys = DEFAULT_KEYS + listOf(
Relations.SOURCE_OBJECT,
Relations.RELATION_FORMAT,
Relations.RELATION_READ_ONLY_VALUE
),
filters = buildList {
addAll(ObjectSearchConstants.filterMyRelations())
add(

View File

@ -3,15 +3,18 @@ package com.anytypeio.anytype.presentation.library.delegates
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.library.LibrarySearchParams
import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.dashboard.DEFAULT_KEYS
import com.anytypeio.anytype.presentation.library.LibraryInteractor
import com.anytypeio.anytype.presentation.library.LibraryListDelegate
import com.anytypeio.anytype.presentation.library.LibraryScreenState
import com.anytypeio.anytype.presentation.library.QueryListenerMyTypes
import com.anytypeio.anytype.presentation.library.filterByQuery
import com.anytypeio.anytype.presentation.objects.toLibraryViews
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import javax.inject.Inject
import kotlinx.coroutines.FlowPreview
@ -22,8 +25,9 @@ import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
class MyTypesDelegate @Inject constructor(
private val interactor: LibraryInteractor,
private val workspaceManager: WorkspaceManager
private val container: StorelessSubscriptionContainer,
private val workspaceManager: WorkspaceManager,
private val urlBuilder: UrlBuilder
) : LibraryListDelegate, QueryListenerMyTypes {
override val queryFlow: MutableStateFlow<String> = MutableStateFlow("")
@ -36,7 +40,11 @@ class MyTypesDelegate @Inject constructor(
override val itemsFlow: Flow<LibraryScreenState.Tabs.TabData> = combine(
itemsFlow(), queryFlow()
) { items, query ->
LibraryScreenState.Tabs.TabData(items.filterByQuery(query))
LibraryScreenState.Tabs.TabData(
items
.toLibraryViews(urlBuilder)
.filterByQuery(query)
)
}
@FlowPreview
@ -44,13 +52,16 @@ class MyTypesDelegate @Inject constructor(
emit(workspaceManager.getCurrentWorkspace())
}.flatMapMerge {
val searchParams = buildSearchParams(it)
interactor.subscribe(searchParams)
container.subscribe(searchParams)
}
private fun buildSearchParams(workspaceId: Id): LibrarySearchParams {
return LibrarySearchParams(
private fun buildSearchParams(workspaceId: Id): StoreSearchParams {
return StoreSearchParams(
subscription = SUB_LIBRARY_MY_TYPES,
keys = DEFAULT_KEYS,
keys = DEFAULT_KEYS + listOf(
Relations.SOURCE_OBJECT,
Relations.RELATION_READ_ONLY_VALUE
),
filters = buildList {
addAll(ObjectSearchConstants.filterTypes())
add(
@ -60,6 +71,13 @@ class MyTypesDelegate @Inject constructor(
value = workspaceId
)
)
add(
DVFilter(
relation = Relations.TYPE,
condition = DVFilterCondition.EQUAL,
value = ObjectTypeIds.OBJECT_TYPE
)
)
}
)
}

View File

@ -2,7 +2,7 @@ package com.anytypeio.anytype.presentation.navigation
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Struct
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.presentation.objects.ObjectIcon
interface DefaultSearchItem
@ -14,7 +14,7 @@ data class DefaultObjectView(
val typeName: String? = null,
val layout: ObjectType.Layout? = null,
val icon: ObjectIcon = ObjectIcon.None
): DefaultSearchItem
) : DefaultSearchItem
data class ObjectView(
val id: String,
@ -31,11 +31,43 @@ fun List<ObjectView>.filterBy(text: String): List<ObjectView> =
if (text.isNotEmpty()) this.filter { it.isContainsText(text) } else this
data class LibraryView(
val id: Id,
val name: String,
val type: String? = null,
val typeName: String? = null,
val layout: ObjectType.Layout? = null,
val icon: ObjectIcon = ObjectIcon.None
)
sealed interface LibraryView {
val id: Id
val name: String
class MyTypeView(
override val id: Id,
override val name: String,
val icon: ObjectIcon? = null,
val sourceObject: Id? = null,
val readOnly: Boolean = false
) : LibraryView
data class LibraryTypeView(
override val id: Id,
override val name: String,
val icon: ObjectIcon? = null,
val installed: Boolean = false,
) : LibraryView
class MyRelationView(
override val id: Id,
override val name: String,
val format: RelationFormat,
val sourceObject: Id? = null,
val readOnly: Boolean = false
) : LibraryView
data class LibraryRelationView(
override val id: Id,
override val name: String,
val format: RelationFormat,
val installed: Boolean = false,
) : LibraryView
class UnknownView(
override val id: Id = "",
override val name: String = "",
) : LibraryView
}

View File

@ -1,14 +1,18 @@
package com.anytypeio.anytype.presentation.objects
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds
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.Relations.SOURCE_OBJECT
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.linking.LinkToItemView
import com.anytypeio.anytype.presentation.navigation.DefaultObjectView
import com.anytypeio.anytype.presentation.navigation.LibraryView
import com.anytypeio.anytype.presentation.relations.RelationValueView
import com.anytypeio.anytype.presentation.sets.filter.CreateFilterView
import timber.log.Timber
@Deprecated("To be deleted")
fun List<ObjectWrapper.Basic>.toView(
@ -22,7 +26,10 @@ fun List<ObjectWrapper.Basic>.toView(
id = obj.id,
name = obj.getProperName(),
type = typeUrl,
typeName = getProperTypeName(id = typeUrl, types = objectTypes),
typeName = getProperTypeName(
id = typeUrl,
types = objectTypes
),
layout = layout,
icon = ObjectIcon.from(
obj = obj,
@ -55,19 +62,55 @@ fun List<ObjectWrapper.Basic>.toViews(
fun List<ObjectWrapper.Basic>.toLibraryViews(
urlBuilder: UrlBuilder,
): List<LibraryView> = map { obj ->
val typeUrl = obj.getProperType()
val layout = obj.getProperLayout()
LibraryView(
id = obj.id,
name = obj.getProperName(),
type = typeUrl,
layout = layout,
icon = ObjectIcon.from(
obj = obj,
layout = layout,
builder = urlBuilder
),
)
when (obj.getProperType()) {
MarketplaceObjectTypeIds.OBJECT_TYPE -> {
LibraryView.LibraryTypeView(
id = obj.id,
name = obj.name ?: "",
icon = ObjectIcon.from(
obj = obj,
layout = obj.getProperLayout(),
builder = urlBuilder
),
installed = false,
)
}
ObjectTypeIds.OBJECT_TYPE -> {
LibraryView.MyTypeView(
id = obj.id,
name = obj.name ?: "",
icon = ObjectIcon.from(
obj = obj,
layout = obj.getProperLayout(),
builder = urlBuilder
),
sourceObject = obj.map[SOURCE_OBJECT]?.toString(),
readOnly = obj.relationReadonlyValue ?: false
)
}
ObjectTypeIds.RELATION -> {
val relation = ObjectWrapper.Relation(obj.map)
LibraryView.MyRelationView(
id = obj.id,
name = obj.name ?: "",
format = relation.format,
sourceObject = obj.map[SOURCE_OBJECT]?.toString(),
readOnly = relation.isReadonlyValue
)
}
MarketplaceObjectTypeIds.RELATION -> {
val relation = ObjectWrapper.Relation(obj.map)
LibraryView.LibraryRelationView(
id = obj.id,
name = obj.name ?: "",
format = relation.format
)
}
else -> {
Timber.e("Unknown type: ${obj.getProperType()}")
LibraryView.UnknownView()
}
}
}
fun List<ObjectWrapper.Basic>.toLinkToView(
@ -198,7 +241,8 @@ private fun ObjectWrapper.Basic.getProperType() = type.firstOrNull()
private fun ObjectWrapper.Basic.getProperFileExt() = fileExt.orEmpty()
private fun ObjectWrapper.Basic.getProperFileMime() = fileMimeType.orEmpty()
private fun getProperTypeName(id: Id?, types: List<ObjectWrapper.Type>) = types.find { it.id == id }?.name.orEmpty()
private fun getProperTypeName(id: Id?, types: List<ObjectWrapper.Type>) =
types.find { it.id == id }?.name.orEmpty()
private fun ObjectWrapper.Basic.getProperFileImage(urlBuilder: UrlBuilder): String? =
iconImage?.let { if (it.isBlank()) null else urlBuilder.thumbnail(it) }

View File

@ -594,11 +594,6 @@ object ObjectSearchConstants {
)
fun filterTypes() : List<DVFilter> = listOf(
DVFilter(
relation = Relations.TYPE,
condition = DVFilterCondition.EQUAL,
value = OBJECT_TYPE
),
DVFilter(
relation = Relations.IS_ARCHIVED,
condition = DVFilterCondition.NOT_EQUAL,