From 7b373339f0a58278d72f9fb8c77421053acca0a6 Mon Sep 17 00:00:00 2001
From: Allan Quatermain <122483431+quaterma1n@users.noreply.github.com>
Date: Thu, 2 Feb 2023 13:47:37 +0300
Subject: [PATCH] DROID-824 Library | Enhancement | Added reactive changes on
library support (#2883)
DROID-824 Library | Enhancement | Added reactive changes on library support
---
.../anytype/di/feature/library/LibraryDI.kt | 44 ++--
.../ui/library/views/LibraryTabsContent.kt | 8 +-
.../views/list/LibraryListSearchWidget.kt | 6 +-
.../views/list/LibraryListTabsContent.kt | 79 +++++---
.../ui/library/views/list/items/Items.kt | 191 ++++++++++++------
.../main/res/drawable/ic_type_installed.xml | 14 ++
.../res/drawable/ic_type_not_installed.xml | 17 ++
.../core_ui/extensions/ResExtension.kt | 16 ++
.../widgets/RelationFormatIconWidget.kt | 20 +-
domain/build.gradle | 2 +
...rySearchParams.kt => StoreSearchParams.kt} | 2 +-
.../library/StorelessSubscriptionContainer.kt | 105 ++++++++++
.../library/processors/EventAddProcessor.kt | 26 +++
.../library/processors/EventAmendProcessor.kt | 35 ++++
.../processors/EventPositionProcessor.kt | 25 +++
.../processors/EventRemoveProcessor.kt | 18 ++
.../library/processors/EventSetProcessor.kt | 33 +++
.../library/processors/EventUnsetProcessor.kt | 24 +++
.../processors/SubscriptionEventProcessor.kt | 11 +
.../presentation/library/LibraryInteractor.kt | 42 ----
.../library/LibraryListDelegate.kt | 3 +-
.../presentation/library/LibraryViewModel.kt | 52 ++++-
.../delegates/LibraryRelationsDelegate.kt | 23 ++-
.../library/delegates/LibraryTypesDelegate.kt | 31 ++-
.../library/delegates/MyRelationsDelegate.kt | 29 ++-
.../library/delegates/MyTypesDelegate.kt | 36 +++-
.../presentation/navigation/ObjectView.kt | 52 ++++-
.../objects/ObjectWrapperMapper.kt | 74 +++++--
.../search/ObjectSearchConstants.kt | 5 -
29 files changed, 792 insertions(+), 231 deletions(-)
create mode 100644 app/src/main/res/drawable/ic_type_installed.xml
create mode 100644 app/src/main/res/drawable/ic_type_not_installed.xml
rename domain/src/main/java/com/anytypeio/anytype/domain/library/{LibrarySearchParams.kt => StoreSearchParams.kt} (94%)
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/StorelessSubscriptionContainer.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAddProcessor.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAmendProcessor.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventPositionProcessor.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventRemoveProcessor.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventSetProcessor.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventUnsetProcessor.kt
create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/library/processors/SubscriptionEventProcessor.kt
delete mode 100644 presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryInteractor.kt
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/library/LibraryDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/library/LibraryDI.kt
index 92311eb545..374972b838 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/library/LibraryDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/library/LibraryDI.kt
@@ -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
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt
index 6666fb9f0a..cff5b5cecc 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt
@@ -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
)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt
index a068bbbe5e..049d33de45 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt
@@ -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,
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt
index 50f3b7a61e..fbde9cfb5a 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt
@@ -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))
- }
- }
+ )
}
}
}
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt
index 82fda0d5d0..954dbb6798 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt
@@ -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)
+ }
+ })
+ }
}
diff --git a/app/src/main/res/drawable/ic_type_installed.xml b/app/src/main/res/drawable/ic_type_installed.xml
new file mode 100644
index 0000000000..d92865f651
--- /dev/null
+++ b/app/src/main/res/drawable/ic_type_installed.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_type_not_installed.xml b/app/src/main/res/drawable/ic_type_not_installed.xml
new file mode 100644
index 0000000000..7c29d96357
--- /dev/null
+++ b/app/src/main/res/drawable/ic_type_not_installed.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/extensions/ResExtension.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/extensions/ResExtension.kt
index 2c21a6233c..c35cb6ef74 100644
--- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/extensions/ResExtension.kt
+++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/extensions/ResExtension.kt
@@ -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)
diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/RelationFormatIconWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/RelationFormatIconWidget.kt
index b3a128c036..772e2e1d1f 100644
--- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/RelationFormatIconWidget.kt
+++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/RelationFormatIconWidget.kt
@@ -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) {
diff --git a/domain/build.gradle b/domain/build.gradle
index f4d43154c1..c3ebd0b4b3 100644
--- a/domain/build.gradle
+++ b/domain/build.gradle
@@ -10,6 +10,8 @@ dependencies {
implementation libs.kotlin
implementation libs.coroutines
+ compileOnly libs.javaxInject
+
testImplementation project(":test:utils")
testImplementation libs.kotlinTest
testImplementation libs.turbine
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/LibrarySearchParams.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt
similarity index 94%
rename from domain/src/main/java/com/anytypeio/anytype/domain/library/LibrarySearchParams.kt
rename to domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt
index 39b50d5f27..3a540c96bc 100644
--- a/domain/src/main/java/com/anytypeio/anytype/domain/library/LibrarySearchParams.kt
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt
@@ -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 = emptyList(),
val filters: List = emptyList(),
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/StorelessSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/StorelessSubscriptionContainer.kt
new file mode 100644
index 0000000000..f5572e8c19
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/StorelessSubscriptionContainer.kt
@@ -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>
+
+ 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) = channel.subscribe(subscriptions)
+
+ override fun subscribe(searchParams: StoreSearchParams): Flow> =
+ 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
+)
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAddProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAddProcessor.kt
new file mode 100644
index 0000000000..5b9ff84c31
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAddProcessor.kt
@@ -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 {
+
+ override fun process(
+ event: SubscriptionEvent.Add,
+ dataItems: MutableList
+ ): MutableList = 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
+ }
+
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAmendProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAmendProcessor.kt
new file mode 100644
index 0000000000..f46a602875
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventAmendProcessor.kt
@@ -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 {
+
+ override fun process(
+ event: SubscriptionEvent.Amend,
+ dataItems: MutableList
+ ): MutableList = 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
+ }
+
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventPositionProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventPositionProcessor.kt
new file mode 100644
index 0000000000..ecfaab2d48
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventPositionProcessor.kt
@@ -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 {
+
+ override fun process(
+ event: SubscriptionEvent.Position,
+ dataItems: MutableList
+ ): MutableList = 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
+ }
+
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventRemoveProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventRemoveProcessor.kt
new file mode 100644
index 0000000000..a674f65138
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventRemoveProcessor.kt
@@ -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 {
+
+ override fun process(
+ event: SubscriptionEvent.Remove,
+ dataItems: MutableList
+ ): MutableList = with(dataItems) {
+ retainAll {
+ it.id != event.target
+ }
+ return this
+ }
+
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventSetProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventSetProcessor.kt
new file mode 100644
index 0000000000..142728b8fe
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventSetProcessor.kt
@@ -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 {
+
+ override fun process(
+ event: SubscriptionEvent.Set,
+ dataItems: MutableList
+ ): MutableList = 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
+ }
+
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventUnsetProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventUnsetProcessor.kt
new file mode 100644
index 0000000000..362238bbdc
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/EventUnsetProcessor.kt
@@ -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 {
+
+ override fun process(
+ event: SubscriptionEvent.Unset,
+ dataItems: MutableList
+ ): MutableList = 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
+ }
+
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/SubscriptionEventProcessor.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/SubscriptionEventProcessor.kt
new file mode 100644
index 0000000000..7446908182
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/processors/SubscriptionEventProcessor.kt
@@ -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 {
+ fun process(
+ event: T,
+ dataItems: MutableList
+ ): MutableList
+}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryInteractor.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryInteractor.kt
deleted file mode 100644
index 9305956d84..0000000000
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryInteractor.kt
+++ /dev/null
@@ -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>
-
- class Impl @Inject constructor(
- private val repo: BlockRepository,
- private val urlBuilder: UrlBuilder,
- ) : LibraryInteractor {
- override fun subscribe(searchParams: LibrarySearchParams): Flow> =
- 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)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt
index 9273283134..1b71373010 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt
@@ -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
val itemsFlow: Flow
- fun itemsFlow(): Flow>
+ fun itemsFlow(): Flow>
@FlowPreview
fun queryFlow() = queryFlow
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryViewModel.kt
index 582c5539c9..104d4a487d 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryViewModel.kt
@@ -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,
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryRelationsDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryRelationsDelegate.kt
index 15927cab6c..d1a9cfdfb2 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryRelationsDelegate.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryRelationsDelegate.kt
@@ -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 = 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(
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryTypesDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryTypesDelegate.kt
index e0dbe31d1a..0c801bd478 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryTypesDelegate.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryTypesDelegate.kt
@@ -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 = 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
+ )
+ )
}
)
}
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyRelationsDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyRelationsDelegate.kt
index 277c2ed7e2..4cf1ae4d69 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyRelationsDelegate.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyRelationsDelegate.kt
@@ -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 = 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(
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyTypesDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyTypesDelegate.kt
index 0cccdfaa1a..47443eacf5 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyTypesDelegate.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyTypesDelegate.kt
@@ -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 = MutableStateFlow("")
@@ -36,7 +40,11 @@ class MyTypesDelegate @Inject constructor(
override val itemsFlow: Flow = 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
+ )
+ )
}
)
}
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/ObjectView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/ObjectView.kt
index 7afc29ddf0..383156aec2 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/ObjectView.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/ObjectView.kt
@@ -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.filterBy(text: String): List =
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
-)
\ No newline at end of file
+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
+
+}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt
index 2fe6ed7330..3912a903b3 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt
@@ -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.toView(
@@ -22,7 +26,10 @@ fun List.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.toViews(
fun List.toLibraryViews(
urlBuilder: UrlBuilder,
): List = 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.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) = types.find { it.id == id }?.name.orEmpty()
+private fun getProperTypeName(id: Id?, types: List) =
+ 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) }
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt
index dedeb322a0..de4d202e15 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt
@@ -594,11 +594,6 @@ object ObjectSearchConstants {
)
fun filterTypes() : List = listOf(
- DVFilter(
- relation = Relations.TYPE,
- condition = DVFilterCondition.EQUAL,
- value = OBJECT_TYPE
- ),
DVFilter(
relation = Relations.IS_ARCHIVED,
condition = DVFilterCondition.NOT_EQUAL,