From b78e3e4d0d2ba262b259a2b4afde98878be9352c Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Tue, 22 Oct 2024 12:17:11 +0200 Subject: [PATCH] DROID-2916 App | Tech | Prepare staging release (#1666) Co-authored-by: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com> --- .../analytics/base/EventsDictionary.kt | 2 +- app/gradle.properties | 4 +- .../features/editor/base/EditorTestSetup.kt | 9 +- .../features/sets/dv/TestObjectSetSetup.kt | 5 +- .../anytype/di/feature/AllContentDI.kt | 7 +- .../anytype/di/feature/CreateObjectDI.kt | 15 +- .../anytypeio/anytype/di/feature/EditorDI.kt | 14 +- .../anytype/di/feature/ObjectSetDI.kt | 14 +- .../anytype/di/feature/ObjectTypeDI.kt | 8 +- .../anytype/di/feature/OtherSettingsDI.kt | 6 +- .../anytypeio/anytype/di/feature/SplashDi.kt | 10 +- .../feature/gallery/GalleryInstallationDi.kt | 2 + .../anytype/di/feature/home/HomescreenDI.kt | 11 +- .../anytype/di/feature/library/LibraryDI.kt | 12 +- .../feature/multiplayer/ShareSpaceInject.kt | 4 + .../anytype/di/feature/settings/ProfileDI.kt | 9 +- .../di/feature/spaces/SpaceSettingsDI.kt | 2 + .../anytype/di/feature/vault/VaultDI.kt | 9 + .../anytypeio/anytype/di/main/ConfigModule.kt | 8 + .../anytype/di/main/SubscriptionsModule.kt | 50 ++- .../ui/allcontent/AllContentFragment.kt | 13 +- .../anytypeio/anytype/ui/home/HomeScreen.kt | 97 +---- .../anytype/ui/home/HomeScreenFragment.kt | 6 +- .../anytype/ui/library/LibraryScreen.kt | 9 +- .../anytype/ui/search/GlobalSearchScreen.kt | 3 +- .../ui/settings/ProfileSettingsFragment.kt | 14 +- .../settings/space/SpaceSettingsFragment.kt | 8 + .../anytypeio/anytype/ui/sharing/Sharing.kt | 33 +- .../anytype/ui/spaces/CreateSpaceScreen.kt | 3 - .../anytype/ui/spaces/SelectSpaceFragment.kt | 2 - .../anytype/ui/spaces/SelectSpaceScreen.kt | 4 +- .../anytype/ui/splash/SplashFragment.kt | 39 +- .../anytype/ui/vault/IntroduceVaultScreen.kt | 5 +- .../anytype/ui/vault/VaultFragment.kt | 90 ++++- .../anytypeio/anytype/ui/vault/VaultScreen.kt | 13 +- .../ui/widgets/collection/CollectionDI.kt | 8 +- .../ui/widgets/collection/CollectionScreen.kt | 9 +- .../ui/widgets/types/SpaceWidgetCard.kt | 4 +- app/src/main/res/layout/fragment_editor.xml | 10 +- .../main/res/layout/fragment_object_set.xml | 6 +- app/src/main/res/navigation/graph.xml | 3 + core-ui/build.gradle | 2 + .../extensions/ComposableExtensions.kt | 6 + .../anytype/core_ui/features/Spaces.kt | 60 +-- .../features/dataview/ViewerGridAdapter.kt | 24 +- .../features/editor/holders/media/Bookmark.kt | 8 +- .../features/editor/holders/media/Picture.kt | 8 +- .../features/editor/holders/other/Title.kt | 20 +- .../features/multiplayer/SpaceListScreen.kt | 4 +- .../components/BottomNavigationMenu.kt | 70 +++- .../core_ui/widgets/GridCellObjectItem.kt | 20 +- .../core_ui/widgets/ObjectIconCompose.kt | 17 +- .../core_ui/widgets/ObjectIconWidget.kt | 10 +- .../res/drawable/ic_arrow_forward_legacy.xml | 10 - .../src/main/res/drawable/ic_icon_loading.xml | 26 ++ .../main/res/drawable/ic_sam_hint_arrows.xml | 20 - .../drawable/ic_settings_arrow_forward.xml | 14 - .../widget_main_bottom_toolbar_background.xml | 6 + .../res/layout/widget_main_bottom_toolbar.xml | 19 +- core-ui/src/main/res/values/dimens.xml | 3 + .../features/dataview/GridDiffUtilTest.kt | 11 +- .../data/auth/repo/UserSettingsCache.kt | 2 +- .../auth/repo/UserSettingsDataRepository.kt | 2 +- .../auth/repo/block/BlockDataRepository.kt | 6 + .../data/auth/repo/block/BlockRemote.kt | 3 + .../all_content/RestoreAllContentState.kt | 17 +- .../auth/interactor/GetLastOpenedObject.kt | 1 + .../domain/auth/interactor/GetProfile.kt | 3 + .../domain/auth/interactor/LaunchAccount.kt | 8 +- .../domain/auth/interactor/ResumeAccount.kt | 2 - .../anytypeio/anytype/domain/bin/EmptyBin.kt | 9 +- .../block/interactor/sets/GetObjectTypes.kt | 3 + .../domain/block/repo/BlockRepository.kt | 3 + .../anytype/domain/config/ConfigStorage.kt | 13 +- .../domain/config/UserSettingsRepository.kt | 2 +- .../domain/launch/GetDefaultObjectType.kt | 47 +-- .../domain/library/StoreSearchParams.kt | 3 + .../library/StorelessSubscriptionContainer.kt | 18 +- .../ActiveSpaceMemberSubscriptionContainer.kt | 8 +- .../multiplayer/CheckIsUserSpaceMember.kt | 8 +- .../DefaultUserPermissionProvider.kt | 89 +++-- .../multiplayer/GetSpaceMemberByIdentity.kt | 8 +- .../SpaceViewSubscriptionContainer.kt | 145 ++++--- .../anytype/domain/object/FetchObject.kt | 5 +- .../domain/objects/options/GetOptions.kt | 2 + .../anytype/domain/page/CreateObject.kt | 15 +- .../page/CreateObjectByTypeAndTemplate.kt | 11 +- .../anytype/domain/relations/GetRelations.kt | 3 + .../search/DataViewSubscriptionContainer.kt | 3 + .../ObjectSearchSubscriptionContainer.kt | 7 + .../ObjectTypesSubscriptionContainer.kt | 14 +- .../search/ObjectTypesSubscriptionManager.kt | 2 + .../search/ProfileSubscriptionManager.kt | 89 +++++ .../search/RelationsSubscriptionContainer.kt | 14 +- .../search/RelationsSubscriptionManager.kt | 16 +- .../anytype/domain/search/SearchObjects.kt | 3 + .../SearchObjectsByIdWithSubscription.kt | 3 + .../domain/sets/FindObjectSetForType.kt | 8 +- .../anytype/domain/spaces/GetSpaceView.kt | 5 + .../anytype/domain/spaces/GetSpaceViews.kt | 6 +- .../spaces/SpaceDeletedStatusWatcher.kt | 15 +- .../GlobalSubscriptionManager.kt | 6 +- .../anytype/domain/templates/GetTemplates.kt | 13 +- .../domain/workspace/WorkspaceManager.kt | 9 - .../domain/dashboard/GetProfileTest.kt | 5 + .../misc/DataViewSubscriptionContainerTest.kt | 8 + .../anytype/domain/misc/GetObjectTypeTest.kt | 9 + .../ObjectSearchSubscriptionContainerTest.kt | 8 + .../page/CreateObjectAsMentionOrLinkTest.kt | 2 +- .../anytype/domain/page/CreateObjectTest.kt | 27 +- .../ObjectTypesSubscriptionContainerTest.kt | 10 +- .../RelationsSubscriptionContainerTest.kt | 22 +- .../StorelessSubscriptionContainerTest.kt | 7 + .../models/AllContentModels.kt | 50 ++- .../models/AllContentSearchParams.kt | 2 + .../presentation/AllContentViewModel.kt | 181 ++++++--- .../feature_allcontent/ui/AllContentMenu.kt | 5 +- .../feature_allcontent/ui/AllContentScreen.kt | 283 +++++++++++--- .../ui/AllContentTopToolbar.kt | 10 +- .../GalleryInstallationSpacesScreen.kt | 50 +-- .../viewmodel/GalleryInstallationViewModel.kt | 52 +-- .../GalleryInstallationViewModelFactory.kt | 7 +- gradle/libs.versions.toml | 2 +- libs/build.gradle | 2 +- localization/src/main/res/values/strings.xml | 11 +- .../middleware/block/BlockMiddleware.kt | 6 + .../middleware/interactor/Middleware.kt | 10 +- .../interactor/MiddlewareProtobufLogger.kt | 15 +- .../repo/DefaultUserSettingsCache.kt | 17 +- .../presentation/editor/EditorViewModel.kt | 32 +- .../editor/editor/model/BlockView.kt | 1 - .../editor/render/DefaultBlockViewRenderer.kt | 1 - .../history/VersionHistoryViewModel.kt | 5 +- .../presentation/home/HomeScreenViewModel.kt | 23 +- .../presentation/library/LibraryViewModel.kt | 6 +- .../delegates/LibraryRelationsDelegate.kt | 3 + .../library/delegates/LibraryTypesDelegate.kt | 6 +- .../library/delegates/MyRelationsDelegate.kt | 9 +- .../library/delegates/MyTypesDelegate.kt | 3 +- .../linking/BackLinkOrAddToObjectViewModel.kt | 8 +- .../linking/LinkToObjectOrWebViewModel.kt | 6 +- .../linking/LinkToObjectViewModel.kt | 7 +- .../presentation/mapper/MapperExtension.kt | 6 +- .../presentation/moving/MoveToViewModel.kt | 5 +- .../multiplayer/ShareSpaceViewModel.kt | 33 +- .../multiplayer/SpaceJoinRequestViewModel.kt | 6 +- .../navigation/DeepLinkToObjectDelegate.kt | 9 +- .../objects/CreateObjectViewModel.kt | 23 +- .../objects/ObjectTypeChangeViewModel.kt | 10 +- .../objects/ObjectTypeExtensions.kt | 7 +- .../objects/ObjectWrapperExtensions.kt | 42 ++ .../objects/SelectObjectTypeViewModel.kt | 25 +- .../relations/LimitObjectTypeViewModel.kt | 13 +- .../relations/ObjectSetRenderMapper.kt | 7 - .../relations/RelationAddViewModelBase.kt | 12 +- .../value/object/ObjectValueViewModel.kt | 1 + .../tagstatus/TagOrStatusValueViewModel.kt | 5 +- .../search/GlobalSearchViewModel.kt | 8 +- .../search/ObjectSearchConstants.kt | 260 +++++++------ .../search/ObjectSearchViewModel.kt | 8 +- .../presentation/sets/GalleryViewMapper.kt | 9 +- .../presentation/sets/ListViewMapper.kt | 7 +- .../presentation/sets/ObjectSetViewModel.kt | 18 +- .../presentation/sets/SetsExtension.kt | 367 ++++++++++-------- .../sets/filter/FilterViewModel.kt | 11 +- .../anytype/presentation/sets/model/Viewer.kt | 1 + .../sets/subscription/DataViewSubscription.kt | 7 +- .../settings/FilesStorageViewModel.kt | 6 +- .../PersonalizationSettingsViewModel.kt | 13 +- .../settings/SpacesStorageViewModel.kt | 32 +- .../settings/SpacesStorageViewModelFactory.kt | 5 +- .../sharing/AddToAnytypeViewModel.kt | 16 +- .../spaces/CreateSpaceViewModel.kt | 17 +- .../spaces/SelectSpaceViewModel.kt | 58 +-- .../presentation/spaces/SpaceIconView.kt | 2 - .../spaces/SpaceSettingsViewModel.kt | 40 +- .../presentation/splash/SplashViewModel.kt | 12 +- .../templates/ObjectTypeTemplatesContainer.kt | 6 +- .../presentation/vault/VaultViewModel.kt | 126 +++++- .../widgets/DataViewListWidgetContainer.kt | 6 +- .../widgets/ListWidgetContainer.kt | 31 +- .../widgets/SelectWidgetTypeViewModel.kt | 12 +- .../widgets/SpaceWidgetContainer.kt | 1 + .../widgets/TreeWidgetContainer.kt | 4 + .../widgets/collection/CollectionViewModel.kt | 16 +- .../widgets/collection/Subscription.kt | 12 +- .../collections/ObjectStateSetViewTest.kt | 6 +- .../editor/EditorPresentationTestSetup.kt | 4 +- .../history/VersionHistoryViewModelTest.kt | 3 +- .../home/HomeScreenViewModelTest.kt | 11 +- .../home/TreeWidgetContainerTest.kt | 6 + .../relations/RelationAddViewModelBaseTest.kt | 19 +- .../presentation/sets/TagAndStatusTests.kt | 7 +- .../main/ObjectSetConvertToCollectionTest.kt | 89 +++-- .../sets/main/ObjectSetViewModelTestSetup.kt | 14 +- .../types/ObjectTypeChangeViewModelTest.kt | 36 +- protocol/src/main/proto/changes.proto | 49 +++ protocol/src/main/proto/commands.proto | 119 +++++- protocol/src/main/proto/models.proto | 6 +- .../ui_settings/account/ProfileScreen.kt | 46 +-- .../account/ProfileSettingsViewModel.kt | 96 ++--- .../fstorage/FilesStorageScreen.kt | 5 +- .../ui_settings/main/MainSettingScreen.kt | 3 +- 203 files changed, 2606 insertions(+), 1726 deletions(-) delete mode 100644 core-ui/src/main/res/drawable/ic_arrow_forward_legacy.xml create mode 100644 core-ui/src/main/res/drawable/ic_icon_loading.xml delete mode 100644 core-ui/src/main/res/drawable/ic_sam_hint_arrows.xml delete mode 100644 core-ui/src/main/res/drawable/ic_settings_arrow_forward.xml create mode 100644 core-ui/src/main/res/drawable/widget_main_bottom_toolbar_background.xml create mode 100644 domain/src/main/java/com/anytypeio/anytype/domain/search/ProfileSubscriptionManager.kt diff --git a/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt b/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt index cac9e4cace..fa5b4825cb 100644 --- a/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt +++ b/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt @@ -171,7 +171,7 @@ object EventsDictionary { // Vault events - const val screenVault = "ScreenOnboarding" + const val screenVault = "ScreenVault" // About-app screen diff --git a/app/gradle.properties b/app/gradle.properties index 338ea5537b..b5cdb45ec7 100644 --- a/app/gradle.properties +++ b/app/gradle.properties @@ -1,4 +1,4 @@ version.versionMajor=0 -version.versionMinor=34 -version.versionPatch=0 +version.versionMinor=33 +version.versionPatch=9 version.useDatedVersionName=false \ No newline at end of file diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt index f03e2ca89c..95f518c06f 100644 --- a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt +++ b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/base/EditorTestSetup.kt @@ -376,9 +376,7 @@ open class EditorTestSetup { getDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = repo, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) createObjectSet = CreateObjectSet(repo) findObjectSetForType = FindObjectSetForType(repo) @@ -579,9 +577,8 @@ open class EditorTestSetup { repo.stub { onBlocking { searchObjects( - filters = ObjectSearchConstants.filterTypes( - spaces = listOf(defaultSpace) - ), + space = SpaceId(defaultSpace), + filters = ObjectSearchConstants.filterTypes(), keys = ObjectSearchConstants.defaultKeysObjectType, sorts = emptyList(), limit = 0, diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt index f4e397f5b1..4d4e9a6676 100644 --- a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt +++ b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt @@ -241,9 +241,7 @@ abstract class TestObjectSetSetup { getDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = repo, - spaceManager = spaceManager, - dispatchers = dispatchers, - configStorage = configStorage + dispatchers = dispatchers ) createDataViewObject = CreateDataViewObject( repo = repo, @@ -378,6 +376,7 @@ abstract class TestObjectSetSetup { repo.stub { onBlocking { searchObjectsWithSubscription( + space = any(), subscription = any(), filters = any(), sorts = any(), diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/AllContentDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/AllContentDI.kt index 6b2464cc2d..98affa524e 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/AllContentDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/AllContentDI.kt @@ -112,8 +112,7 @@ object AllContentModule { ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @JvmStatic @@ -128,9 +127,7 @@ object AllContentModule { ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/CreateObjectDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/CreateObjectDI.kt index 7bc64b72c2..eea48e8257 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/CreateObjectDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/CreateObjectDI.kt @@ -42,8 +42,7 @@ object CreateObjectModule { ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @JvmStatic @@ -58,9 +57,7 @@ object CreateObjectModule { ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic @@ -81,6 +78,10 @@ object CreateObjectModule { @Provides @PerScreen fun provideViewModelFactory( - createObject: CreateObject - ): CreateObjectViewModel.Factory = CreateObjectViewModel.Factory(createObject = createObject) + createObject: CreateObject, + spaceManager: SpaceManager + ): CreateObjectViewModel.Factory = CreateObjectViewModel.Factory( + createObject = createObject, + spaceManager = spaceManager + ) } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt index 08e894c702..1bdb5212ed 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt @@ -986,15 +986,11 @@ object EditorUseCaseModule { fun provideGetDefaultPageType( repo: UserSettingsRepository, blockRepository: BlockRepository, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage + dispatchers: AppCoroutineDispatchers ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = repo, blockRepository = blockRepository, - spaceManager = spaceManager, - dispatchers = dispatchers, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic @@ -1192,13 +1188,11 @@ object EditorUseCaseModule { fun getCreateObject( repo: BlockRepository, getDefaultObjectType: GetDefaultObjectType, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager + dispatchers: AppCoroutineDispatchers ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @Module diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt index 725b99d10c..075f9cd274 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt @@ -307,13 +307,11 @@ object ObjectSetModule { fun getCreateObject( repo: BlockRepository, getDefaultObjectType: GetDefaultObjectType, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager + dispatchers: AppCoroutineDispatchers ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @JvmStatic @@ -330,15 +328,11 @@ object ObjectSetModule { fun provideGetDefaultPageType( userSettingsRepository: UserSettingsRepository, blockRepository: BlockRepository, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage + dispatchers: AppCoroutineDispatchers ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectTypeDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectTypeDI.kt index ad995fa78f..4321fa8dbb 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectTypeDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectTypeDI.kt @@ -81,15 +81,11 @@ object ObjectTypeChangeModule { fun provideGetDefaultPageType( userSettingsRepository: UserSettingsRepository, blockRepository: BlockRepository, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage + dispatchers: AppCoroutineDispatchers ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/OtherSettingsDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/OtherSettingsDI.kt index 9c20dbf84f..d02d34e560 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/OtherSettingsDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/OtherSettingsDI.kt @@ -41,14 +41,10 @@ object PersonalizationSettingsModule { userSettingsRepository: UserSettingsRepository, blockRepository: BlockRepository, dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt index c0924d3cd7..44a6a5dc3e 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt @@ -120,14 +120,10 @@ object SplashModule { userSettingsRepository: UserSettingsRepository, blockRepository: BlockRepository, dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - spaceManager = spaceManager, - dispatchers = dispatchers, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic @@ -148,12 +144,10 @@ object SplashModule { repo: BlockRepository, getDefaultObjectType: GetDefaultObjectType, dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt index fb8c09049d..810a707539 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.data.auth.event.EventProcessImportRemoteChannel 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.config.ConfigStorage import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.workspace.EventProcessImportChannel @@ -85,4 +86,5 @@ interface GalleryInstallationComponentDependencies : ComponentDependencies { fun urlBuilder(): UrlBuilder fun userPermissionProvider(): UserPermissionProvider fun eventProxy(): EventProxy + fun configStorage(): ConfigStorage } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt index 071f8e2a3c..be3e503e34 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt @@ -165,8 +165,7 @@ object HomeScreenModule { ): CreateObject = CreateObject( repo = repo, dispatchers = dispatchers, - getDefaultObjectType = getDefaultEditorType, - spaceManager = spaceManager + getDefaultObjectType = getDefaultEditorType ) @JvmStatic @@ -175,15 +174,11 @@ object HomeScreenModule { fun getDefaultPageType( userSettingsRepository: UserSettingsRepository, blockRepository: BlockRepository, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage + dispatchers: AppCoroutineDispatchers ) : GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic 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 c2559b0a98..852bd439cf 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 @@ -147,12 +147,10 @@ object LibraryModule { repo: BlockRepository, getDefaultObjectType: GetDefaultObjectType, dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @JvmStatic @@ -161,15 +159,11 @@ object LibraryModule { fun provideGetDefaultPageType( userSettingsRepository: UserSettingsRepository, blockRepository: BlockRepository, - dispatchers: AppCoroutineDispatchers, - spaceManager: SpaceManager, - configStorage: ConfigStorage + dispatchers: AppCoroutineDispatchers ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/multiplayer/ShareSpaceInject.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/multiplayer/ShareSpaceInject.kt index d7629fe342..24407ccd1e 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/multiplayer/ShareSpaceInject.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/multiplayer/ShareSpaceInject.kt @@ -9,8 +9,10 @@ import com.anytypeio.anytype.domain.auth.repo.AuthRepository import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.ConfigStorage +import com.anytypeio.anytype.domain.config.TechSpaceProvider import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.misc.UrlBuilder +import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate @@ -60,8 +62,10 @@ interface ShareSpaceDependencies : ComponentDependencies { fun dispatchers(): AppCoroutineDispatchers fun container(): StorelessSubscriptionContainer fun config(): ConfigStorage + fun techSpaceProvider(): TechSpaceProvider fun permissions(): UserPermissionProvider fun analytics(): Analytics fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate fun provideMembershipProvider(): MembershipProvider + fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/settings/ProfileDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/settings/ProfileDI.kt index e487a30570..8d831a3f89 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/settings/ProfileDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/settings/ProfileDI.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.networkmode.GetNetworkMode import com.anytypeio.anytype.domain.`object`.SetObjectDetails +import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider @@ -45,7 +46,6 @@ object ProfileModule { @Provides @PerScreen fun provideViewModelFactory( - deleteAccount: DeleteAccount, analytics: Analytics, storelessSubscriptionContainer: StorelessSubscriptionContainer, setObjectDetails: SetObjectDetails, @@ -53,9 +53,9 @@ object ProfileModule { urlBuilder: UrlBuilder, setDocumentImageIcon: SetDocumentImageIcon, membershipProvider: MembershipProvider, - getNetworkMode: GetNetworkMode + getNetworkMode: GetNetworkMode, + profileSubscriptionManager: ProfileSubscriptionManager ): ProfileSettingsViewModel.Factory = ProfileSettingsViewModel.Factory( - deleteAccount = deleteAccount, analytics = analytics, container = storelessSubscriptionContainer, setObjectDetails = setObjectDetails, @@ -63,7 +63,8 @@ object ProfileModule { urlBuilder = urlBuilder, setDocumentImageIcon = setDocumentImageIcon, membershipProvider = membershipProvider, - getNetworkMode = getNetworkMode + getNetworkMode = getNetworkMode, + profileSubscriptionManager = profileSubscriptionManager ) @Provides diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt index 51f30ead26..22c2428aa7 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/spaces/SpaceSettingsDI.kt @@ -19,6 +19,7 @@ import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionCon import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.payments.GetMembershipStatus +import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager import com.anytypeio.anytype.domain.workspace.SpaceManager import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider @@ -119,4 +120,5 @@ interface SpaceSettingsDependencies : ComponentDependencies { fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer fun activeSpaceMemberSubscriptionContainer(): ActiveSpaceMemberSubscriptionContainer fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate + fun profileContainer(): ProfileSubscriptionManager } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/vault/VaultDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/vault/VaultDI.kt index c73a5befc8..a2263382a1 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/vault/VaultDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/vault/VaultDI.kt @@ -10,7 +10,9 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.UserSettingsRepository import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer +import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.workspace.SpaceManager +import com.anytypeio.anytype.presentation.navigation.DeepLinkToObjectDelegate import com.anytypeio.anytype.presentation.vault.VaultViewModel import com.anytypeio.anytype.ui.vault.VaultFragment import dagger.Binds @@ -44,6 +46,12 @@ object VaultModule { fun bindViewModelFactory( factory: VaultViewModel.Factory ): ViewModelProvider.Factory + + @PerScreen + @Binds + fun deepLinkToObjectDelegate( + default: DeepLinkToObjectDelegate.Default + ) : DeepLinkToObjectDelegate } } @@ -55,5 +63,6 @@ interface VaultComponentDependencies : ComponentDependencies { fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer fun userSettingsRepository(): UserSettingsRepository fun spaceManager(): SpaceManager + fun userPermissionProvider(): UserPermissionProvider fun auth(): AuthRepository } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/ConfigModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/ConfigModule.kt index 1c7b40c6b3..84bc8e5915 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/ConfigModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/ConfigModule.kt @@ -5,6 +5,7 @@ import com.anytypeio.anytype.domain.account.AwaitAccountStartManager import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.config.Gateway +import com.anytypeio.anytype.domain.config.TechSpaceProvider import com.anytypeio.anytype.domain.debugging.Logger import dagger.Module import dagger.Provides @@ -33,6 +34,13 @@ object ConfigModule { @Singleton fun provideConfigProvider(): ConfigStorage = ConfigStorage.CacheStorage() + @JvmStatic + @Provides + @Singleton + fun provideTechSpaceProvider( + configStorage: ConfigStorage + ): TechSpaceProvider = configStorage + @JvmStatic @Provides @Singleton diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt index 701fe98a80..a8119fcd8e 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt @@ -19,6 +19,7 @@ import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import com.anytypeio.anytype.domain.objects.StoreOfRelations import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionContainer import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager +import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager import com.anytypeio.anytype.domain.search.RelationsSubscriptionContainer import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager import com.anytypeio.anytype.domain.search.SubscriptionEventChannel @@ -43,12 +44,14 @@ object SubscriptionsModule { repo: BlockRepository, channel: SubscriptionEventChannel, dispatchers: AppCoroutineDispatchers, - store: StoreOfRelations + store: StoreOfRelations, + logger: Logger ): RelationsSubscriptionContainer = RelationsSubscriptionContainer( repo = repo, channel = channel, store = store, - dispatchers = dispatchers + dispatchers = dispatchers, + logger = logger ) @JvmStatic @@ -58,12 +61,14 @@ object SubscriptionsModule { repo: BlockRepository, channel: SubscriptionEventChannel, dispatchers: AppCoroutineDispatchers, - store: StoreOfObjectTypes + store: StoreOfObjectTypes, + logger: Logger ): ObjectTypesSubscriptionContainer = ObjectTypesSubscriptionContainer( repo = repo, channel = channel, store = store, - dispatchers = dispatchers + dispatchers = dispatchers, + logger = logger ) @JvmStatic @@ -81,7 +86,7 @@ object SubscriptionsModule { @Singleton fun relationsSubscriptionManager( subscription: RelationsSubscriptionContainer, - spaceManager: SpaceManager + spaceManager: SpaceManager, ): RelationsSubscriptionManager = RelationsSubscriptionManager( container = subscription, spaceManager = spaceManager @@ -125,13 +130,15 @@ object SubscriptionsModule { @Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope, container: StorelessSubscriptionContainer, repo: AuthRepository, - logger: Logger + logger: Logger, + spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer ) : UserPermissionProvider = DefaultUserPermissionProvider( dispatchers = dispatchers, scope = scope, container = container, repo = repo, - logger = logger + logger = logger, + spaceViewSubscriptionContainer = spaceViewSubscriptionContainer ) @JvmStatic @@ -142,12 +149,33 @@ object SubscriptionsModule { @Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope, container: StorelessSubscriptionContainer, awaitAccountStartManager: AwaitAccountStartManager, - logger: Logger + logger: Logger, + configStorage: ConfigStorage ) : SpaceViewSubscriptionContainer = SpaceViewSubscriptionContainer.Default( dispatchers = dispatchers, scope = scope, container = container, awaitAccountStart = awaitAccountStartManager, + logger = logger, + config = configStorage + ) + + @JvmStatic + @Provides + @Singleton + fun profileSubscriptionManager( + dispatchers: AppCoroutineDispatchers, + @Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope, + container: StorelessSubscriptionContainer, + awaitAccountStartManager: AwaitAccountStartManager, + configStorage: ConfigStorage, + logger: Logger + ) : ProfileSubscriptionManager = ProfileSubscriptionManager.Default( + dispatchers = dispatchers, + scope = scope, + container = container, + awaitAccountStartManager = awaitAccountStartManager, + configStorage = configStorage, logger = logger ) @@ -188,11 +216,13 @@ object SubscriptionsModule { types: ObjectTypesSubscriptionManager, relations: RelationsSubscriptionManager, permissions: UserPermissionProvider, - isSpaceDeleted: SpaceDeletedStatusWatcher + isSpaceDeleted: SpaceDeletedStatusWatcher, + profileSubscriptionManager: ProfileSubscriptionManager ) : GlobalSubscriptionManager = GlobalSubscriptionManager.Default( types = types, relations = relations, permissions = permissions, - isSpaceDeleted = isSpaceDeleted + isSpaceDeleted = isSpaceDeleted, + profile = profileSubscriptionManager ) } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt index bf6549832c..c0f41acf19 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt @@ -213,7 +213,7 @@ class AllContentFragment : BaseComposeFragment() { is AllContentViewModel.Command.OpenTypeCreation -> { runCatching { navigation().openTypeCreationScreen( - name = command.name + name = "" ) }.onFailure { toast("Failed to open type creation screen") @@ -224,8 +224,8 @@ class AllContentFragment : BaseComposeFragment() { is AllContentViewModel.Command.OpenRelationCreation -> { runCatching { navigation().openRelationCreationScreen( - id = command.id, - name = command.name, + id = "", + name = "", space = command.space ) }.onFailure { @@ -265,6 +265,7 @@ class AllContentFragment : BaseComposeFragment() { uiTabsState = vm.uiTabsState.collectAsStateWithLifecycle().value, uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value, uiMenuState = vm.uiMenuState.collectAsStateWithLifecycle().value, + uiSnackbarState = vm.uiSnackbarState.collectAsStateWithLifecycle().value, onSortClick = vm::onSortClicked, onModeClick = vm::onAllContentModeClicked, onItemClicked = vm::onItemClicked, @@ -273,7 +274,6 @@ class AllContentFragment : BaseComposeFragment() { onUpdateLimitSearch = vm::updateLimit, uiContentState = vm.uiContentState.collectAsStateWithLifecycle().value, onTypeClicked = vm::onTypeClicked, - onHomeClicked = vm::onHomeClicked, onGlobalSearchClicked = vm::onGlobalSearchClicked, onAddDocClicked = vm::onAddDockClicked, onCreateObjectLongClicked = { @@ -296,7 +296,10 @@ class AllContentFragment : BaseComposeFragment() { Timber.e(it, "Error while opening space switcher from all-content screen") } }, - onRelationClicked = vm::onRelationClicked + onRelationClicked = vm::onRelationClicked, + undoMoveToBin = vm::proceedWithUndoMoveToBin, + onDismissSnackbar = vm::proceedWithDismissSnackbar, + uiBottomMenu = vm.uiBottomMenu.collectAsStateWithLifecycle().value ) } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt index 2274e2d927..a10a5def93 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt @@ -15,7 +15,6 @@ import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -34,8 +33,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha -import androidx.compose.ui.hapticfeedback.HapticFeedbackType -import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -45,9 +42,8 @@ import com.anytypeio.anytype.R import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_ui.extensions.throttledClick -import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults +import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu import com.anytypeio.anytype.core_ui.foundation.noRippleClickable -import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable import com.anytypeio.anytype.core_ui.views.UXBody import com.anytypeio.anytype.presentation.home.InteractionMode import com.anytypeio.anytype.presentation.profile.ProfileIconView @@ -101,7 +97,8 @@ fun HomeScreen( onSpaceShareIconClicked: (ObjectWrapper.SpaceView) -> Unit, onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit, onCreateObjectInsideWidget: (Id) -> Unit, - onCreateDataViewObject: (WidgetId, ViewId?) -> Unit + onCreateDataViewObject: (WidgetId, ViewId?) -> Unit, + onBackLongClicked: () -> Unit ) { Box(modifier = Modifier.fillMaxSize()) { @@ -160,13 +157,14 @@ fun HomeScreen( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) { - HomeScreenBottomToolbar( - onSearchClicked = throttledClick(onSearchClicked), - onCreateNewObjectClicked = throttledClick(onCreateNewObjectClicked), - onBackClicked = throttledClick(onBackClicked), - onCreateNewObjectLongClicked = onCreateNewObjectLongClicked, + BottomNavigationMenu( modifier = Modifier, - isReadOnlyAccess = mode is InteractionMode.ReadOnly + backClick = onBackClicked, + backLongClick = onBackLongClicked, + searchClick = onSearchClicked, + addDocClick = onCreateNewObjectClicked, + addDocLongClick = onCreateNewObjectLongClicked, + isOwnerOrEditor = mode !is InteractionMode.ReadOnly ) } } @@ -811,79 +809,4 @@ fun WidgetEditModeButton( color = colorResource(id = R.color.text_white) ) } -} - -@Composable -fun HomeScreenBottomToolbar( - modifier: Modifier, - onSearchClicked: () -> Unit, - onCreateNewObjectClicked: () -> Unit, - onCreateNewObjectLongClicked: () -> Unit, - onBackClicked: () -> Unit, - isReadOnlyAccess: Boolean -) { - val haptic = LocalHapticFeedback.current - Row( - modifier = modifier - .height(BottomNavigationDefaults.Height) - .width(BottomNavigationDefaults.Width) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.home_screen_toolbar_button) - ) - ) { - Box( - modifier = Modifier - .weight(1f) - .fillMaxSize() - .noRippleClickable { onBackClicked() } - ) { - Image( - painter = painterResource(id = R.drawable.ic_nav_panel_back), - contentDescription = "Search icon", - modifier = Modifier.align(Alignment.Center) - ) - } - Box( - modifier = Modifier - .weight(1f) - .alpha(if (isReadOnlyAccess) 0.2f else 1f) - .fillMaxSize() - .then( - if (isReadOnlyAccess) - Modifier.clickable { - // Do nothing. - } - else - Modifier.noRippleCombinedClickable( - onLongClicked = { - onCreateNewObjectLongClicked().also { - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - } - }, - onClick = { - onCreateNewObjectClicked() - } - ) - ) - ) { - Image( - painter = painterResource(id = R.drawable.ic_nav_panel_plus), - contentDescription = "Plus icon", - modifier = Modifier.align(Alignment.Center) - ) - } - Box( - modifier = Modifier - .weight(1f) - .fillMaxSize() - .noRippleClickable { onSearchClicked() } - ) { - Image( - painter = painterResource(id = R.drawable.ic_nav_panel_search), - contentDescription = "Search icon", - modifier = Modifier.align(Alignment.Center) - ) - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt index cfae698c35..c825e6dd46 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt @@ -114,7 +114,8 @@ class HomeScreenFragment : BaseComposeFragment() { onSpaceShareIconClicked = vm::onSpaceShareIconClicked, onSeeAllObjectsClicked = vm::onSeeAllObjectsClicked, onCreateObjectInsideWidget = vm::onCreateObjectInsideWidget, - onCreateDataViewObject = vm::onCreateDataViewObject + onCreateDataViewObject = vm::onCreateDataViewObject, + onBackLongClicked = vm::onBackLongClicked ) if (featureToggles.enableDiscussionDemo) { @@ -367,6 +368,9 @@ class HomeScreenFragment : BaseComposeFragment() { Timber.e(e, "Error while opening all content from widgets") } } + is Navigation.OpenSpaceSwitcher -> { + findNavController().navigate(R.id.actionOpenSpaceSwitcher) + } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreen.kt index 70051858ad..aa07170ddb 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreen.kt @@ -31,7 +31,6 @@ import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -162,14 +161,10 @@ fun Menu( backLongClick = { onBackLongClicked() }, - homeClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Back) }, searchClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Search) }, addDocClick = { viewModel.eventStream(LibraryEvent.BottomMenu.CreateObject) }, - onCreateObjectLongClicked = onCreateObjectLongClicked, - onProfileClicked = { - viewModel.eventStream(LibraryEvent.BottomMenu.OpenProfile) - }, - profileIcon = viewModel.icon.collectAsState().value + addDocLongClick = onCreateObjectLongClicked, + isOwnerOrEditor = false ) } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchScreen.kt index 67bf88085e..3c5236a3ed 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchScreen.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.input.nestedscroll.nestedScroll @@ -225,7 +226,7 @@ fun GlobalSearchScreen( ) }, colors = TextFieldDefaults.textFieldColors( - backgroundColor = colorResource(id = R.color.shape_transparent), + backgroundColor = Color.Transparent, cursorColor = colorResource(id = R.color.cursor_color), ), border = {}, diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt index 6caa2a735c..b9d3996834 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt @@ -39,8 +39,6 @@ import timber.log.Timber class ProfileSettingsFragment : BaseBottomSheetComposeFragment() { - private val space: Id get() = arg(SPACE_ID_KEY) - @Inject lateinit var factory: ProfileSettingsViewModel.Factory @@ -141,16 +139,6 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() { } } - private fun proceedWithAccountDeletion() { - vm.proceedWithAccountDeletion() - val dialog = DeleteAccountWarning() - dialog.onDeletionAccepted = { - dialog.dismiss() - vm.onDeleteAccountClicked() - } - dialog.show(childFragmentManager, null) - } - private fun proceedWithIconClick() { permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, null) } @@ -163,7 +151,7 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() { if (uri != null) { try { val path = uri.parseImagePath(requireContext()) - vm.onPickedImageFromDevice(path = path, space = space) + vm.onPickedImageFromDevice(path = path) } catch (e: Exception) { toast("Error while parsing path for cover image") Timber.d(e, "Error while parsing path for cover image") diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt index 7c3e408d3f..fbd18dca3b 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/space/SpaceSettingsFragment.kt @@ -197,6 +197,14 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment() { Command.NavigateToMembershipUpdate -> { findNavController().navigate(R.id.membershipUpdateScreen) } + is Command.ExitToVault -> { + runCatching { + findNavController() + .popBackStack(R.id.vaultScreen, false) + }.onFailure { + Timber.e(it, "Error while exiting to vault screen from space settings") + } + } } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sharing/Sharing.kt b/app/src/main/java/com/anytypeio/anytype/ui/sharing/Sharing.kt index b66abec5e1..4f0b8024d7 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sharing/Sharing.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sharing/Sharing.kt @@ -52,6 +52,7 @@ import coil.compose.rememberAsyncImagePainter import com.anytypeio.anytype.R import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_ui.features.SpaceIconView import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.views.BodyRegular import com.anytypeio.anytype.core_ui.views.ButtonPrimary @@ -78,7 +79,7 @@ fun AddToAnytypeScreenUrlPreview() { SpaceView( obj = ObjectWrapper.SpaceView(map = mapOf("name" to "Space 1")), isSelected = true, - icon = SpaceIconView.Gradient(from = "#FF0000", to = "#00FF00") + icon = SpaceIconView.Placeholder() ) ), onSelectSpaceClicked = {}, @@ -101,7 +102,7 @@ fun AddToAnytypeScreenNotePreview() { SpaceView( obj = ObjectWrapper.SpaceView(map = mapOf()), isSelected = false, - icon = SpaceIconView.Gradient(from = "#FF0000", to = "#00FF00") + icon = SpaceIconView.Placeholder() ) ), onSelectSpaceClicked = {}, @@ -250,7 +251,7 @@ fun AddToAnytypeScreen( ) } else { CurrentSpaceSection( - name = stringResource(id = R.string.unknown), + name = stringResource(id = R.string.three_dots_text_placeholder), spaces = spaces, onSelectSpaceClicked = onSelectSpaceClicked ) @@ -527,11 +528,15 @@ private fun CurrentSpaceSection( .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 14.dp), verticalAlignment = Alignment.CenterVertically ) { - val hasIcon = icon is SpaceIconView.Gradient || icon is SpaceIconView.Image + val hasIcon = icon is SpaceIconView.Placeholder || icon is SpaceIconView.Image if (icon != null && hasIcon) { - SmallSpaceIcon( + SpaceIconView( icon = icon, - modifier = Modifier.padding(end = 8.dp) + modifier = Modifier.padding(end = 8.dp), + mainSize = 20.dp, + onSpaceIconClick = { + // Do nothing. + } ) } Text( @@ -614,22 +619,6 @@ private fun SmallSpaceIcon( .clip(RoundedCornerShape(4.dp)) ) } - - is SpaceIconView.Gradient -> { - val gradient = Brush.radialGradient( - colors = listOf( - Color(icon.from.toColorInt()), - Color(icon.to.toColorInt()) - ) - ) - Box( - modifier = modifier - .size(size) - .clip(CircleShape) - .background(gradient) - ) - } - else -> { // Draw nothing. } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceScreen.kt index 6da5933a71..b266ea48f2 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceScreen.kt @@ -94,9 +94,6 @@ fun CreateSpaceScreen( Section(title = stringResource(id = R.string.type)) TypeOfSpace(spaceType = PRIVATE_SPACE_TYPE) Divider() - Section(title = stringResource(id = R.string.create_space_start_with)) - UseCase() - Divider() Spacer(modifier = Modifier.height(78.dp)) } CreateSpaceButton( diff --git a/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceFragment.kt index d7753e6201..46d2f880bd 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceFragment.kt @@ -25,8 +25,6 @@ import javax.inject.Inject class SelectSpaceFragment : BaseBottomSheetComposeFragment() { - private val exitHomeWhenSpaceIsSelected get() = argOrNull(EXIT_HOME_WHEN_SPACE_IS_SELECTED_KEY) - @Inject lateinit var factory: SelectSpaceViewModel.Factory diff --git a/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceScreen.kt index 3bb33d56bc..52a2c7009e 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/spaces/SelectSpaceScreen.kt @@ -162,9 +162,7 @@ private fun SelectSpaceSpaceItem( icon = item.view.icon, onSpaceIconClick = throttledClick( onClick = { onSpaceClicked(item.view) } - ), - gradientBackground = colorResource(id = R.color.default_gradient_background), - gradientCornerRadius = 4.dp + ) ) if (item.view.isShared) { Image( diff --git a/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt index 65f349be1a..f554307c36 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt @@ -14,6 +14,7 @@ import com.anytypeio.anytype.BuildConfig import com.anytypeio.anytype.R import com.anytypeio.anytype.app.DefaultAppActionManager.Companion.ACTION_CREATE_NEW_TYPE_KEY import com.anytypeio.anytype.core_utils.ext.gone +import com.anytypeio.anytype.core_utils.ext.orNull import com.anytypeio.anytype.core_utils.ext.toast import com.anytypeio.anytype.core_utils.ext.visible import com.anytypeio.anytype.core_utils.ui.BaseFragment @@ -27,7 +28,7 @@ import com.anytypeio.anytype.ui.editor.EditorFragment import com.anytypeio.anytype.ui.home.HomeScreenFragment import com.anytypeio.anytype.ui.onboarding.OnboardingFragment import com.anytypeio.anytype.ui.sets.ObjectSetFragment -import com.anytypeio.anytype.ui.widgets.collection.DefaultTheme +import com.anytypeio.anytype.ui.vault.VaultFragment import javax.inject.Inject import kotlinx.coroutines.launch import timber.log.Timber @@ -71,26 +72,6 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl } } } - - launch { - vm.loadingState.collect { isLoading -> - when (isLoading) { - true -> { - binding.loadingContainer.setContent { - DefaultTheme { - PulsatingCircleScreen() - } - } - binding.logo.visibility = View.GONE - binding.loadingContainer.visibility = View.VISIBLE - } - false -> { - binding.logo.visibility = View.GONE - binding.loadingContainer.visibility = View.GONE - } - } - } - } } } if (BuildConfig.DEBUG) { @@ -106,11 +87,11 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl runCatching { findNavController().navigate( resId = R.id.actionOpenVaultFromSplash, - args = HomeScreenFragment.args(command.deeplink) + args = VaultFragment.args(deeplink = null) ) findNavController().navigate( R.id.actionOpenSpaceFromVault, - args = HomeScreenFragment.args(command.deeplink) + args = HomeScreenFragment.args(deeplink = command.deeplink) ) }.onFailure { Timber.e(it, "Error while navigating to widgets from splash") @@ -120,7 +101,7 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl try { findNavController().navigate( resId = R.id.actionOpenVaultFromSplash, - args = HomeScreenFragment.args(command.deeplink) + args = HomeScreenFragment.args(deeplink = command.deeplink) ) } catch (e: Exception) { Timber.e(e, "Error while opening dashboard from splash screen") @@ -160,12 +141,12 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl is SplashViewModel.Command.NavigateToAuthStart -> { val intent = activity?.intent val deepLink: String? - if (intent != null && intent.action == Intent.ACTION_VIEW) { + if (intent != null && (intent.action == Intent.ACTION_VIEW || intent.action == Intent.ACTION_SEND)) { val data = intent.dataString deepLink = if (data != null && DefaultDeepLinkResolver.isDeepLink(data)) { data } else { - null + intent.extras?.getString(Intent.EXTRA_TEXT) } } else { deepLink = null @@ -178,7 +159,6 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl putExtras(Bundle()) } } - Timber.d("Deep link is empty: ${deepLink.isNullOrEmpty()}") findNavController().navigate( R.id.action_splashFragment_to_authStart, args = OnboardingFragment.args(deepLink) @@ -191,9 +171,8 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl } is SplashViewModel.Command.CheckAppStartIntent -> { val intent = activity?.intent - Timber.d("Timber intent: $intent") - if (intent != null && intent.action == Intent.ACTION_VIEW) { - val data = intent.dataString + if (intent != null && (intent.action == Intent.ACTION_VIEW || intent.action == Intent.ACTION_SEND)) { + val data = intent.dataString.orNull() ?: intent.extras?.getString(Intent.EXTRA_TEXT) if (data != null && DefaultDeepLinkResolver.isDeepLink(data)) { // Clearing intent to only handle it once: with(intent) { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt index b4f00a8537..90b3876c5b 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt @@ -130,7 +130,7 @@ fun IntroduceVaultScreen( }, horizontalArrangement = Arrangement.Center ) { - repeat(3) { iteration -> + repeat(2) { iteration -> val color = if (pagerState.currentPage == iteration) colorResource(id = R.color.glyph_active) else @@ -161,7 +161,8 @@ fun IntroduceVaultScreen( .constrainAs(first) { bottom.linkTo(btn.top) }, - textAlign = TextAlign.Center + textAlign = TextAlign.Center, + minLines = 3 ) ButtonSecondary( diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt index 7b83890a3c..57a7c5e3f7 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt @@ -12,14 +12,23 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.core.os.bundleOf import androidx.fragment.app.viewModels import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavOptions import androidx.navigation.fragment.findNavController import com.anytypeio.anytype.BuildConfig.USE_EDGE_TO_EDGE import com.anytypeio.anytype.R +import com.anytypeio.anytype.core_utils.ext.argOrNull +import com.anytypeio.anytype.core_utils.ext.toast import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment import com.anytypeio.anytype.di.common.componentManager +import com.anytypeio.anytype.other.DefaultDeepLinkResolver import com.anytypeio.anytype.presentation.vault.VaultViewModel +import com.anytypeio.anytype.presentation.vault.VaultViewModel.Navigation import com.anytypeio.anytype.presentation.vault.VaultViewModel.Command +import com.anytypeio.anytype.ui.base.navigation +import com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment +import com.anytypeio.anytype.ui.multiplayer.RequestJoinSpaceFragment +import com.anytypeio.anytype.ui.payments.MembershipFragment import com.anytypeio.anytype.ui.settings.ProfileSettingsFragment import com.anytypeio.anytype.ui.settings.typography import javax.inject.Inject @@ -27,7 +36,7 @@ import timber.log.Timber class VaultFragment : BaseComposeFragment() { - // TODO handle deeplink + private val deepLink: String? get() = argOrNull(DEEP_LINK_KEY) @Inject lateinit var factory: VaultViewModel.Factory @@ -51,14 +60,15 @@ class VaultFragment : BaseComposeFragment() { ) } LaunchedEffect(Unit) { - vm.commands.collect { command -> - proceedWithCommand(command) - } + vm.commands.collect { command -> proceed(command) } + } + LaunchedEffect(Unit) { + vm.navigation.collect { command -> proceed(command) } } } } - private fun proceedWithCommand(command: Command) { + private fun proceed(command: Command) { when (command) { is Command.EnterSpaceHomeScreen -> { runCatching { @@ -80,7 +90,7 @@ class VaultFragment : BaseComposeFragment() { runCatching { findNavController().navigate( R.id.profileScreen, - bundleOf(ProfileSettingsFragment.SPACE_ID_KEY to command.space.id) + null ) }.onFailure { Timber.e(it, "Error while opening profile settings from vault") @@ -93,6 +103,57 @@ class VaultFragment : BaseComposeFragment() { Timber.e(it, "Error while opening introduce-vault-screen from vault") } } + is Command.Deeplink.Invite -> { + findNavController().navigate( + R.id.requestJoinSpaceScreen, + RequestJoinSpaceFragment.args(link = command.link) + ) + } + is Command.Deeplink.GalleryInstallation -> { + findNavController().navigate( + R.id.galleryInstallationScreen, + GalleryInstallationFragment.args( + deepLinkType = command.deepLinkType, + deepLinkSource = command.deepLinkSource + ) + ) + } + is Command.Deeplink.MembershipScreen -> { + findNavController().navigate( + R.id.paymentsScreen, + MembershipFragment.args(command.tierId), + NavOptions.Builder().setLaunchSingleTop(true).build() + ) + } + is Command.Deeplink.DeepLinkToObjectNotWorking -> { + toast( + getString(R.string.multiplayer_deeplink_to_your_object_error) + ) + } + } + } + + private fun proceed(destination: Navigation) { + when (destination) { + is Navigation.OpenObject -> runCatching { + findNavController().navigate(R.id.actionOpenSpaceFromVault) + navigation().openDocument( + target = destination.ctx, + space = destination.space + ) + }.onFailure { + Timber.e(it, "Error while opening object from vault") + } + is Navigation.OpenSet -> runCatching { + findNavController().navigate(R.id.actionOpenSpaceFromVault) + navigation().openObjectSet( + target = destination.ctx, + space = destination.space, + view = destination.view + ) + }.onFailure { + Timber.e(it, "Error while opening set or collection from vault") + } } } @@ -106,7 +167,18 @@ class VaultFragment : BaseComposeFragment() { override fun onResume() { super.onResume() - vm.onResume() + proceedWithDeepLinks() + } + + private fun proceedWithDeepLinks() { + val deepLinkFromFragmentArgs = deepLink + if (deepLinkFromFragmentArgs != null) { + Timber.d("Deeplink from fragment args") + vm.onResume(DefaultDeepLinkResolver.resolve(deepLinkFromFragmentArgs)) + arguments?.putString(DEEP_LINK_KEY, null) + } else { + vm.onResume(null) + } } override fun injectDependencies() { @@ -118,8 +190,8 @@ class VaultFragment : BaseComposeFragment() { } companion object { - const val SHOW_MNEMONIC_KEY = "arg.vault-screen.show-mnemonic" - const val DEEP_LINK_KEY = "arg.vault-screen.deep-link" + private const val SHOW_MNEMONIC_KEY = "arg.vault-screen.show-mnemonic" + private const val DEEP_LINK_KEY = "arg.vault-screen.deep-link" fun args(deeplink: String?) : Bundle = bundleOf( DEEP_LINK_KEY to deeplink ) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultScreen.kt index 8d08117464..7a59517ad6 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultScreen.kt @@ -148,6 +148,14 @@ fun VaultScreen( Spacer(modifier = Modifier.height(40.dp)) } } + if (spaceList.isEmpty()) { + item { + VaultSpaceAddCard( + onCreateSpaceClicked = onCreateSpaceClicked + ) + Spacer(modifier = Modifier.height(40.dp)) + } + } } } } @@ -259,13 +267,10 @@ fun VaultSpaceCard( onSpaceIconClick = { onCardClicked() }, - gradientBackground = colorResource(id = R.color.default_gradient_background), - gradientCornerRadius = 4.dp, mainSize = 64.dp, modifier = Modifier .padding(start = 16.dp) - .align(Alignment.CenterStart), - gradientSize = 48.dp + .align(Alignment.CenterStart) ) Column( modifier = Modifier diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionDI.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionDI.kt index a485db975d..8517cd9896 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionDI.kt @@ -166,8 +166,7 @@ object CollectionModule { ): CreateObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers, - spaceManager = spaceManager + dispatchers = dispatchers ) @JvmStatic @@ -178,13 +177,10 @@ object CollectionModule { blockRepository: BlockRepository, dispatchers: AppCoroutineDispatchers, spaceManager: SpaceManager, - configStorage: ConfigStorage ): GetDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionScreen.kt index ed20190be9..7a150a959e 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionScreen.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionScreen.kt @@ -50,7 +50,6 @@ import androidx.compose.material.Text import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -148,13 +147,11 @@ fun ScreenContent( .padding(bottom = 20.dp)) { BottomNavigationMenu( backClick = { vm.onPrevClicked() }, - homeClick = { vm.onHomeClicked() }, searchClick = onSearchClicked, addDocClick = { vm.onAddClicked(null) }, - onCreateObjectLongClicked = onCreateObjectLongClicked, - onProfileClicked = vm::onProfileClicked, - profileIcon = vm.icon.collectAsState().value, - backLongClick = vm::onBackLongClicked + addDocLongClick = onCreateObjectLongClicked, + backLongClick = vm::onBackLongClicked, + isOwnerOrEditor = uiState.isActionButtonVisible ) } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceWidgetCard.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceWidgetCard.kt index 7b1abf2fc9..30075e4f4d 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceWidgetCard.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/SpaceWidgetCard.kt @@ -87,9 +87,7 @@ fun SpaceWidgetCard( SpaceIconView( icon = icon, onSpaceIconClick = { onClick() }, - mainSize = 40.dp, - gradientSize = 24.dp, - gradientCornerRadius = 2.dp + mainSize = 40.dp ) } Text( diff --git a/app/src/main/res/layout/fragment_editor.xml b/app/src/main/res/layout/fragment_editor.xml index 3dda9cb619..0e591ff635 100644 --- a/app/src/main/res/layout/fragment_editor.xml +++ b/app/src/main/res/layout/fragment_editor.xml @@ -144,10 +144,11 @@ diff --git a/app/src/main/res/navigation/graph.xml b/app/src/main/res/navigation/graph.xml index d7093f187e..a3ddff8d4d 100644 --- a/app/src/main/res/navigation/graph.xml +++ b/app/src/main/res/navigation/graph.xml @@ -169,6 +169,9 @@ + SnapshotStateList.swapList(newList: List){ + clear() + addAll(newList) +} diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/Spaces.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/Spaces.kt index ef56cd9653..e8d3f3f370 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/Spaces.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/Spaces.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale @@ -32,13 +33,11 @@ import com.anytypeio.anytype.presentation.spaces.SpaceIconView fun SpaceIconView( modifier: Modifier = Modifier, mainSize: Dp = 96.dp, - gradientSize: Dp = 64.dp, - gradientBackground: Color = colorResource(id = R.color.default_gradient_background), - gradientCornerRadius: Dp = 8.dp, icon: SpaceIconView, onSpaceIconClick: () -> Unit, ) { val radius = when(mainSize) { + 20.dp -> 4.dp 40.dp -> 5.dp 48.dp -> 6.dp 64.dp -> 8.dp @@ -47,6 +46,7 @@ fun SpaceIconView( } val fontSize = when(mainSize) { + 20.dp -> 16.sp 40.dp -> 24.sp 48.dp -> 28.sp 64.dp -> 40.sp @@ -68,46 +68,28 @@ fun SpaceIconView( } ) } - is SpaceIconView.Gradient -> { - val gradient = Brush.radialGradient( - colors = listOf( - Color(icon.from.toColorInt()), - Color(icon.to.toColorInt()) - ) - ) - Box( - modifier = modifier - .size(mainSize) - .clip(RoundedCornerShape(gradientCornerRadius)) - .background(color = gradientBackground) - .noRippleClickable { onSpaceIconClick.invoke() } - ) { - Box( - modifier = Modifier - .align(Alignment.Center) - .size(gradientSize) - .clip(CircleShape) - .background(gradient) - ) - } - - } is SpaceIconView.Placeholder -> { + val color = when (icon.color) { + SystemColor.YELLOW -> colorResource(id = R.color.palette_system_yellow) + SystemColor.AMBER -> colorResource(id = R.color.palette_system_amber_100) + SystemColor.RED -> colorResource(id = R.color.palette_system_red) + SystemColor.PINK -> colorResource(id = R.color.palette_system_pink) + SystemColor.PURPLE -> colorResource(id = R.color.palette_system_purple) + SystemColor.BLUE -> colorResource(id = R.color.palette_system_blue) + SystemColor.SKY -> colorResource(id = R.color.palette_system_sky) + SystemColor.TEAL -> colorResource(id = R.color.palette_system_teal) + SystemColor.GREEN -> colorResource(id = R.color.palette_system_green) + } Box( modifier = modifier .size(mainSize) .background( - color = when (icon.color) { - SystemColor.YELLOW -> colorResource(id = R.color.palette_system_yellow) - SystemColor.AMBER -> colorResource(id = R.color.palette_system_amber_100) - SystemColor.RED -> colorResource(id = R.color.palette_system_red) - SystemColor.PINK -> colorResource(id = R.color.palette_system_pink) - SystemColor.PURPLE -> colorResource(id = R.color.palette_system_purple) - SystemColor.BLUE -> colorResource(id = R.color.palette_system_blue) - SystemColor.SKY -> colorResource(id = R.color.palette_system_sky) - SystemColor.TEAL -> colorResource(id = R.color.palette_system_teal) - SystemColor.GREEN -> colorResource(id = R.color.palette_system_green) - }, + Brush.linearGradient( + colors = listOf( + color.copy(alpha = 0.5f), + color + ) + ), shape = RoundedCornerShape(radius) ) .clip(RoundedCornerShape(radius)) @@ -125,7 +107,7 @@ fun SpaceIconView( style = TextStyle( fontSize = fontSize, fontWeight = FontWeight(600), - color = colorResource(id = R.color.text_label_inversion), + color = colorResource(id = R.color.text_white), ) ) } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/ViewerGridAdapter.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/ViewerGridAdapter.kt index 78549217e2..a3fed9d39d 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/ViewerGridAdapter.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/dataview/ViewerGridAdapter.kt @@ -9,7 +9,6 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.anytypeio.anytype.core_models.Id -import com.anytypeio.anytype.core_models.ObjectType.Layout import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.ItemViewerGridRowBinding import com.anytypeio.anytype.core_ui.extensions.drawable @@ -128,28 +127,7 @@ class ViewerGridAdapter( private fun showIcon(row: Viewer.GridView.Row) { binding.objectIcon.visible() - when (row.layout) { - Layout.TODO -> binding.objectIcon.setTask(row.isChecked) - Layout.BASIC, Layout.BOOKMARK, Layout.SET, Layout.COLLECTION -> { - if (!row.image.isNullOrEmpty() || !row.emoji.isNullOrEmpty()) { - if (!row.image.isNullOrEmpty()) { - binding.objectIcon.setRectangularImage(row.image) - } else { - binding.objectIcon.setEmoji(row.emoji) - } - } else { - binding.objectIcon.gone() - } - } - Layout.PROFILE -> { - if (!row.image.isNullOrEmpty()) { - binding.objectIcon.setCircularImage(row.image) - } else { - binding.objectIcon.setProfileInitials(row.name.orEmpty()) - } - } - else -> binding.objectIcon.gone() - } + binding.objectIcon.setIcon(row.objectIcon) } fun bindObjectCells(row: Viewer.GridView.Row) { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt index 72e1b8403c..a5951d92f2 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Bookmark.kt @@ -55,7 +55,7 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec override fun onLoadFailed( e: GlideException?, model: Any?, - target: Target?, + target: Target, isFirstResource: Boolean ): Boolean { error.visible() @@ -63,10 +63,10 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec } override fun onResourceReady( - resource: Drawable?, - model: Any?, + resource: Drawable, + model: Any, target: Target?, - dataSource: DataSource?, + dataSource: DataSource, isFirstResource: Boolean ): Boolean { error.gone() diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt index 2bd03d6400..632f8d1222 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/media/Picture.kt @@ -39,7 +39,7 @@ class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root), Decor override fun onLoadFailed( e: GlideException?, model: Any?, - target: Target?, + target: Target, isFirstResource: Boolean ): Boolean { error.visible() @@ -48,10 +48,10 @@ class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root), Decor } override fun onResourceReady( - resource: Drawable?, - model: Any?, + resource: Drawable, + model: Any, target: Target?, - dataSource: DataSource?, + dataSource: DataSource, isFirstResource: Boolean ): Boolean { error.invisible() diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt index 327c96e555..103bbd9f6b 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/editor/holders/other/Title.kt @@ -438,23 +438,9 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder { .into(image) } ?: apply { hasImage = false - if (item is BlockView.Title.Profile && item.spaceGradient != null) { - val gradient = item.spaceGradient - requireNotNull(gradient) - gradientView.visible() - gradientView.setContent { - RadialGradientComposeView( - modifier = Modifier, - from = gradient.from, - to = gradient.to, - size = 0.dp - ) - } - } else { - gradientView.gone() - setIconText(item.text) - image.setImageDrawable(null) - } + gradientView.gone() + setIconText(item.text) + image.setImageDrawable(null) } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/SpaceListScreen.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/SpaceListScreen.kt index e571626fa0..4b598dc393 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/SpaceListScreen.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/SpaceListScreen.kt @@ -140,9 +140,7 @@ fun SpaceListCardItem( top.linkTo(parent.top, margin = 16.dp) start.linkTo(parent.start, margin = 16.dp) }, - mainSize = 48.dp, - gradientSize = 32.dp, - gradientCornerRadius = 4.dp + mainSize = 48.dp ) if (actions.isNotEmpty()) { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/foundation/components/BottomNavigationMenu.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/foundation/components/BottomNavigationMenu.kt index 907943085b..31788e4412 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/foundation/components/BottomNavigationMenu.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/foundation/components/BottomNavigationMenu.kt @@ -3,12 +3,12 @@ package com.anytypeio.anytype.core_ui.foundation.components import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.MaterialTheme @@ -28,29 +28,52 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter import com.anytypeio.anytype.core_ui.R +import com.anytypeio.anytype.core_ui.common.DefaultPreviews import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults.Height -import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults.Width import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable import com.anytypeio.anytype.presentation.profile.ProfileIconView +@DefaultPreviews +@Composable +private fun MyBottomNavigationMenu() { + BottomNavigationMenu( + backClick = {}, + backLongClick = {}, + searchClick = {}, + addDocClick = {}, + addDocLongClick = {}, + isOwnerOrEditor = true + ) +} + +@DefaultPreviews +@Composable +private fun MyBottomViewerNavigationMenu() { + BottomNavigationMenu( + backClick = {}, + backLongClick = {}, + searchClick = {}, + addDocClick = {}, + addDocLongClick = {}, + isOwnerOrEditor = false + ) +} @Composable fun BottomNavigationMenu( modifier: Modifier = Modifier, backClick: () -> Unit = {}, backLongClick: () -> Unit = {}, - homeClick: () -> Unit = {}, searchClick: () -> Unit = {}, addDocClick: () -> Unit = {}, - onCreateObjectLongClicked: () -> Unit = {}, - onProfileClicked: () -> Unit = {}, - profileIcon: ProfileIconView = ProfileIconView.Loading + addDocLongClick: () -> Unit = {}, + isOwnerOrEditor: Boolean ) { Row( modifier = modifier .height(Height) - .width(Width) + .wrapContentWidth() .background( shape = RoundedCornerShape(16.dp), color = colorResource(id = R.color.home_screen_toolbar_button) @@ -59,20 +82,27 @@ fun BottomNavigationMenu( * Workaround for clicks through the bottom navigation menu. */ .noRippleClickable { }, - horizontalArrangement = Arrangement.SpaceAround, verticalAlignment = Alignment.CenterVertically ) { MenuItem( + modifier = Modifier.width(72.dp).height(52.dp), + contentDescription = stringResource(id = R.string.main_navigation_content_desc_back_button), res = BottomNavigationItem.BACK.res, onClick = backClick, onLongClick = backLongClick ) + if (isOwnerOrEditor) { + MenuItem( + modifier = Modifier.width(72.dp).height(52.dp), + contentDescription = stringResource(id = R.string.main_navigation_content_desc_create_button), + res = BottomNavigationItem.ADD_DOC.res, + onClick = addDocClick, + onLongClick = addDocLongClick + ) + } MenuItem( - res = BottomNavigationItem.ADD_DOC.res, - onClick = addDocClick, - onLongClick = onCreateObjectLongClicked - ) - MenuItem( + modifier = Modifier.width(72.dp).height(52.dp), + contentDescription = stringResource(id = R.string.main_navigation_content_desc_search_button), res = BottomNavigationItem.SEARCH.res, onClick = searchClick ) @@ -81,15 +111,19 @@ fun BottomNavigationMenu( @Composable private fun MenuItem( + modifier: Modifier, + contentDescription: String, @DrawableRes res: Int, onClick: () -> Unit = {}, - onLongClick: () -> Unit = {}, + onLongClick: () -> Unit = {} ) { val haptic = LocalHapticFeedback.current Image( painter = painterResource(id = res), - contentDescription = "", - modifier = Modifier.noRippleCombinedClickable( + contentDescription = contentDescription, + contentScale = ContentScale.Inside, + modifier = modifier + .noRippleCombinedClickable( onClick = onClick, onLongClicked = { haptic.performHapticFeedback( @@ -106,7 +140,7 @@ private fun ProfileMenuItem( icon: ProfileIconView, onClick: () -> Unit = {} ) { - when(icon) { + when (icon) { is ProfileIconView.Image -> { Image( painter = rememberAsyncImagePainter( @@ -121,6 +155,7 @@ private fun ProfileMenuItem( .noRippleClickable { onClick() } ) } + is ProfileIconView.Placeholder -> { val name = icon.name val nameFirstChar = if (name.isNullOrEmpty()) { @@ -145,6 +180,7 @@ private fun ProfileMenuItem( ) } } + else -> { Box( modifier = Modifier diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/GridCellObjectItem.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/GridCellObjectItem.kt index 675c759e07..d97b94a98a 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/GridCellObjectItem.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/GridCellObjectItem.kt @@ -5,10 +5,10 @@ import android.graphics.Color import android.util.AttributeSet import android.view.LayoutInflater import android.widget.FrameLayout -import androidx.core.view.marginStart import androidx.core.view.updateLayoutParams import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.WidgetDvGridObjectBinding +import com.anytypeio.anytype.core_utils.ext.gone import com.anytypeio.anytype.core_utils.ext.visible import com.anytypeio.anytype.presentation.objects.ObjectIcon @@ -24,11 +24,19 @@ class GridCellObjectItem @JvmOverloads constructor( tvName.visible() tvName.text = name tvName.setTextColor(context.getColor(R.color.black)) - objectIcon.setIcon(icon) - objectIcon.visible() - if (tvName.marginStart == 0) { - tvName.updateLayoutParams { - marginStart = resources.getDimension(R.dimen.dp_20).toInt() + when (icon) { + ObjectIcon.None -> { + objectIcon.gone() + tvName.updateLayoutParams { + marginStart = 0 + } + } + else -> { + objectIcon.visible() + objectIcon.setIcon(icon) + tvName.updateLayoutParams { + marginStart = resources.getDimension(R.dimen.dp_20).toInt() + } } } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt index a2fbc41af3..8217ccc7db 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconCompose.kt @@ -23,6 +23,9 @@ import com.anytypeio.anytype.core_ui.widgets.objectIcon.DeletedIconView import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmojiIconView import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmptyIconView import com.anytypeio.anytype.presentation.objects.ObjectIcon +import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi +import com.bumptech.glide.integration.compose.GlideImage +import com.bumptech.glide.integration.compose.placeholder @Composable fun ListWidgetObjectIcon( @@ -46,7 +49,7 @@ fun ListWidgetObjectIcon( EmojiIconView(icon = icon, backgroundSize = iconSize, modifier = modifier) } is ObjectIcon.Basic.Image -> { - DefaultObjectImageIcon(icon.hash, modifier, iconSize) + DefaultObjectImageIcon(icon.hash, modifier, iconSize, fallback = icon.emptyState) } is ObjectIcon.Bookmark -> { DefaultObjectBookmarkIcon(icon.image, modifier, iconSize) @@ -106,19 +109,23 @@ fun DefaultTaskObjectIcon( } } +@OptIn(ExperimentalGlideComposeApi::class) @Composable fun DefaultObjectImageIcon( url: Url, modifier: Modifier, - iconSize: Dp + iconSize: Dp, + fallback: ObjectIcon.Empty ) { - Image( - painter = rememberAsyncImagePainter(model = url), + GlideImage( + model = url, contentDescription = "Icon from URI", contentScale = ContentScale.Crop, modifier = modifier .size(iconSize) - .clip(RoundedCornerShape(2.dp)) + .clip(RoundedCornerShape(2.dp)), + failure = placeholder(resourceId = imageAsset(fallback)), + loading = placeholder(resourceId = R.drawable.ic_icon_loading) ) } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt index 3d380981b3..206ad64144 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconWidget.kt @@ -171,7 +171,7 @@ class ObjectIconWidget @JvmOverloads constructor( binding.ivImage.setImageResource(R.drawable.ic_non_existent_object) } - fun setProfileInitials( + private fun setProfileInitials( name: String ) { with(binding) { @@ -188,7 +188,7 @@ class ObjectIconWidget @JvmOverloads constructor( } } - fun setEmoji(emoji: String?) { + private fun setEmoji(emoji: String?) { if (!emoji.isNullOrBlank()) { with(binding) { ivCheckbox.invisible() @@ -233,7 +233,7 @@ class ObjectIconWidget @JvmOverloads constructor( } } - fun setCircularImage(image: Url?) { + private fun setCircularImage(image: Url?) { if (!image.isNullOrBlank()) { with(binding) { ivCheckbox.invisible() @@ -259,7 +259,7 @@ class ObjectIconWidget @JvmOverloads constructor( } } - fun setRectangularImage(image: Url?) { + private fun setRectangularImage(image: Url?) { if (!image.isNullOrBlank()) { with(binding) { ivCheckbox.invisible() @@ -297,7 +297,7 @@ class ObjectIconWidget @JvmOverloads constructor( } } - fun setTask(isChecked: Boolean?) { + private fun setTask(isChecked: Boolean?) { with(binding) { ivCheckbox.visible() ivCheckbox.background = context.drawable(R.drawable.ic_data_view_grid_checkbox_selector) diff --git a/core-ui/src/main/res/drawable/ic_arrow_forward_legacy.xml b/core-ui/src/main/res/drawable/ic_arrow_forward_legacy.xml deleted file mode 100644 index 15bd57a475..0000000000 --- a/core-ui/src/main/res/drawable/ic_arrow_forward_legacy.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/core-ui/src/main/res/drawable/ic_icon_loading.xml b/core-ui/src/main/res/drawable/ic_icon_loading.xml new file mode 100644 index 0000000000..ee8a4d9418 --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_icon_loading.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/core-ui/src/main/res/drawable/ic_sam_hint_arrows.xml b/core-ui/src/main/res/drawable/ic_sam_hint_arrows.xml deleted file mode 100644 index 97c69324d5..0000000000 --- a/core-ui/src/main/res/drawable/ic_sam_hint_arrows.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/core-ui/src/main/res/drawable/ic_settings_arrow_forward.xml b/core-ui/src/main/res/drawable/ic_settings_arrow_forward.xml deleted file mode 100644 index f0e3df9a3a..0000000000 --- a/core-ui/src/main/res/drawable/ic_settings_arrow_forward.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/core-ui/src/main/res/drawable/widget_main_bottom_toolbar_background.xml b/core-ui/src/main/res/drawable/widget_main_bottom_toolbar_background.xml new file mode 100644 index 0000000000..9a772e07bb --- /dev/null +++ b/core-ui/src/main/res/drawable/widget_main_bottom_toolbar_background.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/core-ui/src/main/res/layout/widget_main_bottom_toolbar.xml b/core-ui/src/main/res/layout/widget_main_bottom_toolbar.xml index b66e2253da..d680c71b62 100644 --- a/core-ui/src/main/res/layout/widget_main_bottom_toolbar.xml +++ b/core-ui/src/main/res/layout/widget_main_bottom_toolbar.xml @@ -1,6 +1,8 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:context="com.anytypeio.anytype.core_ui.widgets.toolbar.MainBottomToolbar"> @@ -28,9 +31,10 @@ @@ -46,10 +50,11 @@ diff --git a/core-ui/src/main/res/values/dimens.xml b/core-ui/src/main/res/values/dimens.xml index cca3041e17..0101d4137d 100644 --- a/core-ui/src/main/res/values/dimens.xml +++ b/core-ui/src/main/res/values/dimens.xml @@ -23,6 +23,9 @@ 16dp 16dp + 72dp + 52dp + 64dp 64dp 10dp diff --git a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dataview/GridDiffUtilTest.kt b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dataview/GridDiffUtilTest.kt index 378433d660..a4e1ddceec 100644 --- a/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dataview/GridDiffUtilTest.kt +++ b/core-ui/src/test/java/com/anytypeio/anytype/core_ui/features/dataview/GridDiffUtilTest.kt @@ -1,5 +1,6 @@ package com.anytypeio.anytype.core_ui.features.dataview +import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.sets.model.Viewer import com.anytypeio.anytype.test_utils.MockDataFactory import org.junit.Test @@ -13,7 +14,10 @@ class GridDiffUtilTest { fun `showIcon changed - header payload exists`() { val old = Viewer.GridView.Row( id = MockDataFactory.randomUuid(), - showIcon = false + showIcon = false, + objectIcon = ObjectIcon.Basic.Image( + hash = MockDataFactory.randomUuid() + ) ) val new = old.copy( showIcon = true @@ -30,7 +34,10 @@ class GridDiffUtilTest { fun `nothing changed - payloads is empty`() { val old = Viewer.GridView.Row( id = MockDataFactory.randomUuid(), - showIcon = false + showIcon = false, + objectIcon = ObjectIcon.Basic.Image( + hash = MockDataFactory.randomUuid() + ) ) val new = old.copy() val payload = ViewerGridAdapter.GridDiffUtil.getChangePayload( diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt index 58af2adde5..e86801f5b1 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt @@ -44,6 +44,6 @@ interface UserSettingsCache { suspend fun saveWidgetSession(session: WidgetSession) suspend fun clear() - suspend fun getAllContentSort(space: SpaceId): Pair + suspend fun getAllContentSort(space: SpaceId): Pair? suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean) } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt index 6ec8087473..036412c489 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt @@ -110,7 +110,7 @@ class UserSettingsDataRepository(private val cache: UserSettingsCache) : UserSet ) } - override suspend fun getAllContentSort(space: SpaceId): Pair { + override suspend fun getAllContentSort(space: SpaceId): Pair? { return cache.getAllContentSort(space) } diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt index 99c482fc68..41a890d572 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt @@ -378,6 +378,7 @@ class BlockDataRepository( ) override suspend fun searchObjects( + space: SpaceId, sorts: List, filters: List, fulltext: String, @@ -385,6 +386,7 @@ class BlockDataRepository( limit: Int, keys: List ): List> = remote.searchObjects( + space = space, sorts = sorts, filters = filters, fulltext = fulltext, @@ -398,6 +400,7 @@ class BlockDataRepository( ): List = remote.searchObjectWithMeta(command) override suspend fun searchObjectsWithSubscription( + space: SpaceId, subscription: Id, sorts: List, filters: List, @@ -411,6 +414,7 @@ class BlockDataRepository( noDepSubscription: Boolean?, collection: Id? ): SearchResult = remote.searchObjectsWithSubscription( + space = space, subscription = subscription, sorts = sorts, filters = filters, @@ -426,10 +430,12 @@ class BlockDataRepository( ) override suspend fun searchObjectsByIdWithSubscription( + space: SpaceId, subscription: Id, ids: List, keys: List ): SearchResult = remote.searchObjectsByIdWithSubscription( + space = space, subscription = subscription, ids = ids, keys = keys diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt index 08f4c0dbde..edf782fbbb 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt @@ -148,6 +148,7 @@ interface BlockRemote { ): Payload suspend fun searchObjects( + space: SpaceId, sorts: List, filters: List, fulltext: String, @@ -161,6 +162,7 @@ interface BlockRemote { ): List suspend fun searchObjectsWithSubscription( + space: SpaceId, subscription: Id, sorts: List, filters: List, @@ -176,6 +178,7 @@ interface BlockRemote { ): SearchResult suspend fun searchObjectsByIdWithSubscription( + space: SpaceId, subscription: Id, ids: List, keys: List diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/all_content/RestoreAllContentState.kt b/domain/src/main/java/com/anytypeio/anytype/domain/all_content/RestoreAllContentState.kt index 8e05e50c55..ff46fbdf10 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/all_content/RestoreAllContentState.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/all_content/RestoreAllContentState.kt @@ -15,15 +15,22 @@ class RestoreAllContentState @Inject constructor( override suspend fun doWork(params: Params): Response { val res = settings.getAllContentSort(params.spaceId) - return Response(activeSort = res.first, isAsc = res.second) + return if (res == null) { + Response.Empty + } else { + Response.Success(activeSort = res.first, isAsc = res.second) + } } data class Params( val spaceId: SpaceId ) - data class Response( - val activeSort: String?, - val isAsc: Boolean - ) + sealed class Response { + data class Success( + val activeSort: String, + val isAsc: Boolean + ) : Response() + data object Empty : Response() + } } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt index ec38b32bd9..1955e4226f 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt @@ -26,6 +26,7 @@ class GetLastOpenedObject( Response.Empty } else { val searchResults = blockRepo.searchObjects( + space = params.space, limit = 1, filters = listOf( DVFilter( diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt index adc326e8a3..228c9d24e6 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetProfile.kt @@ -3,6 +3,7 @@ package com.anytypeio.anytype.domain.auth.interactor 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.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.`object`.amend import com.anytypeio.anytype.domain.`object`.unset import com.anytypeio.anytype.domain.base.BaseUseCase @@ -66,6 +67,7 @@ class GetProfile( ): ObjectWrapper.Basic { val config = provider.get() val result = repo.searchObjectsByIdWithSubscription( + space = SpaceId(config.techSpace), subscription = subscription, ids = listOf(config.profile), keys = keys @@ -80,6 +82,7 @@ class GetProfile( override suspend fun run(params: Params) = safe { val config = provider.get() val result = repo.searchObjectsByIdWithSubscription( + space = SpaceId(config.techSpace), subscription = params.subscription, ids = listOf(config.profile), keys = params.keys diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/LaunchAccount.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/LaunchAccount.kt index 7d4464c0b1..00ad1f261a 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/LaunchAccount.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/LaunchAccount.kt @@ -20,13 +20,13 @@ import kotlinx.coroutines.Dispatchers class LaunchAccount @Inject constructor( private val repository: AuthRepository, private val pathProvider: PathProvider, - private val context: CoroutineContext = Dispatchers.IO, private val configStorage: ConfigStorage, private val spaceManager: SpaceManager, private val metricsProvider: MetricsProvider, private val settings: UserSettingsRepository, - private val awaitAccountStartManager: AwaitAccountStartManager -) : BaseUseCase(context) { + private val awaitAccountStartManager: AwaitAccountStartManager, + context: CoroutineContext = Dispatchers.IO + ) : BaseUseCase(context) { override suspend fun run(params: None) = safe { repository.setMetrics( @@ -53,8 +53,6 @@ class LaunchAccount @Inject constructor( // Falling back to the default space spaceManager.set(setup.config.space) } - } else { - spaceManager.set(setup.config.space) } awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started) setup.config.analytics diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ResumeAccount.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ResumeAccount.kt index 339f58bd79..4ece8d2754 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ResumeAccount.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ResumeAccount.kt @@ -56,8 +56,6 @@ class ResumeAccount @Inject constructor( // Falling back to the default space spaceManager.set(setup.config.space) } - } else { - spaceManager.set(setup.config.space) } setup.account.id } diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/bin/EmptyBin.kt b/domain/src/main/java/com/anytypeio/anytype/domain/bin/EmptyBin.kt index 08c7d7837c..e67457dd62 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/bin/EmptyBin.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/bin/EmptyBin.kt @@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVFilterCondition import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -17,6 +18,8 @@ class EmptyBin( ) : ResultInteractor>(dispatchers.io) { override suspend fun doWork(params: Unit) : List { val archived = repo.searchObjects( + // TODO DROID-2916 Move space id to use case params + space = SpaceId(spaceManager.get()), filters = listOf( DVFilter( relation = Relations.IS_ARCHIVED, @@ -34,9 +37,9 @@ class EmptyBin( value = true ), DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = spaceManager.get() + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) ), sorts = emptyList(), diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/block/interactor/sets/GetObjectTypes.kt b/domain/src/main/java/com/anytypeio/anytype/domain/block/interactor/sets/GetObjectTypes.kt index 4347c8dc4e..dcbfa414f2 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/block/interactor/sets/GetObjectTypes.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/block/interactor/sets/GetObjectTypes.kt @@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVSort import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -17,6 +18,7 @@ class GetObjectTypes @Inject constructor( override suspend fun doWork(params: Params): List { val result = repo.searchObjects( + space = params.space, keys = params.keys, filters = params.filters, sorts = params.sorts, @@ -28,6 +30,7 @@ class GetObjectTypes @Inject constructor( } data class Params( + val space: SpaceId, val sorts: List = emptyList(), val filters: List = emptyList(), val keys: List = emptyList(), diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt index 41099d721f..4e71ee320d 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt @@ -188,6 +188,7 @@ interface BlockRepository { ): Payload suspend fun searchObjects( + space: SpaceId, sorts: List = emptyList(), filters: List = emptyList(), fulltext: String = "", @@ -201,6 +202,7 @@ interface BlockRepository { ): List suspend fun searchObjectsWithSubscription( + space: SpaceId, subscription: Id, sorts: List, filters: List, @@ -216,6 +218,7 @@ interface BlockRepository { ): SearchResult suspend fun searchObjectsByIdWithSubscription( + space: SpaceId, subscription: Id, ids: List, keys: List diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/config/ConfigStorage.kt b/domain/src/main/java/com/anytypeio/anytype/domain/config/ConfigStorage.kt index 26dc02c223..097313c74a 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/config/ConfigStorage.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/config/ConfigStorage.kt @@ -1,9 +1,10 @@ package com.anytypeio.anytype.domain.config import com.anytypeio.anytype.core_models.Config +import com.anytypeio.anytype.core_models.primitives.SpaceId @Deprecated("Refactoring needed") -interface ConfigStorage { +interface ConfigStorage : TechSpaceProvider { @Deprecated("Unsafe method. Use getOrNull() instead") @Throws(IllegalStateException::class) fun get(): Config @@ -26,5 +27,15 @@ interface ConfigStorage { override fun clear() { instance = null } + + override fun provide(): SpaceId? { + return instance?.let { + SpaceId(it.techSpace) + } + } } +} + +interface TechSpaceProvider { + fun provide(): SpaceId? } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt index db2bae3590..d7a5d4f3ce 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt @@ -46,7 +46,7 @@ interface UserSettingsRepository { suspend fun getWidgetSession() : WidgetSession suspend fun saveWidgetSession(session: WidgetSession) - suspend fun getAllContentSort(space: SpaceId): Pair + suspend fun getAllContentSort(space: SpaceId): Pair? suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean) suspend fun clear() diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/launch/GetDefaultObjectType.kt b/domain/src/main/java/com/anytypeio/anytype/domain/launch/GetDefaultObjectType.kt index ffa16a2dc7..e963e99b87 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/launch/GetDefaultObjectType.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/launch/GetDefaultObjectType.kt @@ -16,7 +16,6 @@ import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository -import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.config.UserSettingsRepository import com.anytypeio.anytype.domain.workspace.SpaceManager import javax.inject.Inject @@ -24,18 +23,15 @@ import javax.inject.Inject class GetDefaultObjectType @Inject constructor( private val userSettingsRepository: UserSettingsRepository, private val blockRepository: BlockRepository, - private val spaceManager: SpaceManager, - private val configStorage: ConfigStorage, dispatchers: AppCoroutineDispatchers -) : ResultInteractor(dispatchers.io) { +) : ResultInteractor(dispatchers.io) { - override suspend fun doWork(params: Unit): Response { - val space = SpaceId(spaceManager.get()) - val defaultType = userSettingsRepository.getDefaultObjectType(space) + override suspend fun doWork(params: SpaceId): Response { + val defaultType = userSettingsRepository.getDefaultObjectType(params) if (defaultType != null) { val item = searchObjectByIdAndSpaceId( type = defaultType, - space = space + space = params ) return if (item != null) { val key = TypeKey(item.uniqueKey) @@ -47,18 +43,20 @@ class GetDefaultObjectType @Inject constructor( defaultTemplate = item.defaultTemplateId ) } else { - fetchDefaultType() + fetchDefaultType(params) } } else { - return fetchDefaultType() + return fetchDefaultType(params) } } - private suspend fun fetchDefaultType(): Response { + private suspend fun fetchDefaultType(space: SpaceId): Response { val structs = blockRepository.searchObjects( + space = space, limit = 1, fulltext = NO_VALUE, filters = buildList { + // TODO DROID-2916 might need to delete this filter add( DVFilter( relation = Relations.UNIQUE_KEY, @@ -66,19 +64,6 @@ class GetDefaultObjectType @Inject constructor( value = ObjectTypeUniqueKeys.NOTE ) ) - val space = spaceManager.get().ifEmpty { - // Fallback to default space. - configStorage.getOrNull()?.space - } - if (!space.isNullOrEmpty()) { - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ) - ) - } }, offset = 0, sorts = emptyList(), @@ -110,10 +95,11 @@ class GetDefaultObjectType @Inject constructor( space: SpaceId ): ObjectWrapper.Type? { val structs = blockRepository.searchObjects( + space = space, limit = 1, fulltext = NO_VALUE, filters = buildList { - addAll(filterObjectTypeLibrary(space)) + addAll(filterObjectTypeLibrary()) add( DVFilter( relation = Relations.ID, @@ -135,7 +121,7 @@ class GetDefaultObjectType @Inject constructor( return structs.firstOrNull()?.mapToObjectWrapperType() } - private fun filterObjectTypeLibrary(space: SpaceId) = listOf( + private fun filterObjectTypeLibrary() = listOf( DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.EQUAL, @@ -157,9 +143,9 @@ class GetDefaultObjectType @Inject constructor( value = true ), DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space.id + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true ), DVFilter( relation = Relations.RESTRICTIONS, @@ -168,9 +154,6 @@ class GetDefaultObjectType @Inject constructor( ) ) - /** - * TODO provide space to params - */ data class Response( val id: TypeId, val type: TypeKey, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt b/domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt index c6bf767c5a..4084b74c7f 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/StoreSearchParams.kt @@ -4,8 +4,10 @@ import com.anytypeio.anytype.core_models.DVFilter import com.anytypeio.anytype.core_models.DVSort import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Key +import com.anytypeio.anytype.core_models.primitives.SpaceId data class StoreSearchParams( + val space: SpaceId, val subscription: Id, val sorts: List = emptyList(), val filters: List = emptyList(), @@ -17,6 +19,7 @@ data class StoreSearchParams( ) data class StoreSearchByIdsParams( + val space: SpaceId, val subscription: Id, val keys: List, val targets: List, 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 index 4dbc23fd50..c44c20da55 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/library/StorelessSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/library/StorelessSubscriptionContainer.kt @@ -16,6 +16,7 @@ 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.catch import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -62,6 +63,7 @@ interface StorelessSubscriptionContainer { flow { with(searchParams) { val initial = repo.searchObjectsWithSubscription( + space = space, subscription = subscription, sorts = sorts, filters = filters, @@ -82,11 +84,14 @@ interface StorelessSubscriptionContainer { ) ) } + }.catch { + logger.logException(it, "Error in storeless subscription container") }.flowOn(dispatchers.io) override fun subscribe(searchParams: StoreSearchByIdsParams) = flow { with(searchParams) { val initial = repo.searchObjectsByIdWithSubscription( + space = space, subscription = subscription, ids = targets, keys = keys @@ -100,7 +105,11 @@ interface StorelessSubscriptionContainer { ) ) } - }.flowOn(dispatchers.io) + }.catch { + logger.logException(it, "Error in storeless subscription container") + }.flowOn( + context = dispatchers.io + ) private fun buildObjectsFlow( subscription: Id, @@ -160,6 +169,7 @@ interface StorelessSubscriptionContainer { return flow { with(searchParams) { val initial = repo.searchObjectsWithSubscription( + space = searchParams.space, subscription = subscription, sorts = sorts, filters = filters, @@ -182,7 +192,11 @@ interface StorelessSubscriptionContainer { ) ) } - }.flowOn(dispatchers.io) + }.catch { + logger.logException(it, "Error in storeless subscription container") + }.flowOn( + context = dispatchers.io + ) } private fun buildObjectsFlow( diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/ActiveSpaceMemberSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/ActiveSpaceMemberSubscriptionContainer.kt index 7c98a212b7..0cb3000976 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/ActiveSpaceMemberSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/ActiveSpaceMemberSubscriptionContainer.kt @@ -94,6 +94,7 @@ interface ActiveSpaceMemberSubscriptionContainer { .flatMapLatest { config -> container.subscribe( StoreSearchParams( + space = SpaceId(config.space), subscription = GLOBAL_SUBSCRIPTION, filters = buildList { add( @@ -103,13 +104,6 @@ interface ActiveSpaceMemberSubscriptionContainer { condition = DVFilterCondition.EQUAL ) ) - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = config.space - ) - ) }, limit = 0, keys = listOf( diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/CheckIsUserSpaceMember.kt b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/CheckIsUserSpaceMember.kt index ed419ed90b..d275d53e3d 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/CheckIsUserSpaceMember.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/CheckIsUserSpaceMember.kt @@ -24,6 +24,7 @@ class CheckIsUserSpaceMember @Inject constructor( override suspend fun doWork(params: SpaceId): Boolean { val account = auth.getCurrentAccountId() val results = repo.searchObjects( + space = params, limit = 0, filters = buildList { add( @@ -40,13 +41,6 @@ class CheckIsUserSpaceMember @Inject constructor( condition = DVFilterCondition.EQUAL ) ) - add( - DVFilter( - relation = Relations.SPACE_ID, - value = params.id, - condition = DVFilterCondition.EQUAL - ) - ) }, keys = listOf( Relations.ID, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/DefaultUserPermissionProvider.kt b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/DefaultUserPermissionProvider.kt index bf771125ad..cc93b141fa 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/DefaultUserPermissionProvider.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/DefaultUserPermissionProvider.kt @@ -19,6 +19,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -54,6 +57,7 @@ interface UserPermissionProvider { } class DefaultUserPermissionProvider @Inject constructor( + private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer, private val container: StorelessSubscriptionContainer, private val repo: AuthRepository, private val dispatchers: AppCoroutineDispatchers, @@ -81,45 +85,57 @@ class DefaultUserPermissionProvider @Inject constructor( clear() jobs += scope.launch(dispatchers.io) { val account = repo.getCurrentAccountId() - container.subscribe( - StoreSearchParams( - subscription = GLOBAL_SUBSCRIPTION, - filters = buildList { - add( - DVFilter( - relation = Relations.LAYOUT, - value = ObjectType.Layout.PARTICIPANT.code.toDouble(), - condition = DVFilterCondition.EQUAL + spaceViewSubscriptionContainer + .observe() + .map { spaceViews -> + spaceViews.mapNotNull { spaceView -> spaceView.targetSpaceId } + } + .distinctUntilChanged() + .flatMapLatest { spaces -> + val subscriptions = spaces.map { space -> + container.subscribe( + StoreSearchParams( + space = SpaceId(space), + subscription = "$GLOBAL_SUBSCRIPTION-$space", + filters = buildList { + add( + DVFilter( + relation = Relations.LAYOUT, + value = ObjectType.Layout.PARTICIPANT.code.toDouble(), + condition = DVFilterCondition.EQUAL + ) + ) + add( + DVFilter( + relation = Relations.IDENTITY, + value = account, + condition = DVFilterCondition.EQUAL + ) + ) + }, + limit = 1, + keys = listOf( + Relations.ID, + Relations.SPACE_ID, + Relations.IDENTITY, + Relations.PARTICIPANT_PERMISSIONS + ) ) - ) - add( - DVFilter( - relation = Relations.IDENTITY, - value = account, - condition = DVFilterCondition.EQUAL - ) - ) - }, - limit = NO_LIMIT, - keys = listOf( - Relations.ID, - Relations.SPACE_ID, - Relations.IDENTITY, - Relations.PARTICIPANT_PERMISSIONS - ) - ) - ) - .catch { error -> + ).map { results -> + results.map { ObjectWrapper.SpaceMember(it.map) } + } + } + combine(flows = subscriptions) { flow -> + flow.toList().flatten() + } + }.catch { error -> logger.logException( e = error, msg = "Failed to subscribe to user-as-space-member-permissions" ) + }.collect { + members.value = it } - .collect { results -> - members.value = results.map { - ObjectWrapper.SpaceMember(it.map) - } - } } } @@ -138,7 +154,11 @@ class DefaultUserPermissionProvider @Inject constructor( override fun stop() { clear() scope.launch(dispatchers.io) { - container.unsubscribe(listOf(GLOBAL_SUBSCRIPTION)) + val subscriptions = spaceViewSubscriptionContainer + .get() + .mapNotNull { it.targetSpaceId } + .map { space -> "$GLOBAL_SUBSCRIPTION-$space" } + container.unsubscribe(subscriptions) } } @@ -148,7 +168,6 @@ class DefaultUserPermissionProvider @Inject constructor( companion object { const val GLOBAL_SUBSCRIPTION = "subscription.global.user-as-space-member-permissions" - const val NO_LIMIT = 0 } } diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/GetSpaceMemberByIdentity.kt b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/GetSpaceMemberByIdentity.kt index 0cf37f23a9..94629d0b35 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/GetSpaceMemberByIdentity.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/GetSpaceMemberByIdentity.kt @@ -19,6 +19,7 @@ class GetSpaceMemberByIdentity @Inject constructor( override suspend fun doWork(params: Params): ObjectWrapper.SpaceMember? { val results = repo.searchObjects( + space = params.space, limit = 0, filters = buildList { add( @@ -35,13 +36,6 @@ class GetSpaceMemberByIdentity @Inject constructor( condition = DVFilterCondition.EQUAL ) ) - add( - DVFilter( - relation = Relations.SPACE_ID, - value = params.space.id, - condition = DVFilterCondition.EQUAL - ) - ) }, keys = listOf( Relations.ID, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt index c5fd667a12..57e72bbaa7 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/multiplayer/SpaceViewSubscriptionContainer.kt @@ -17,6 +17,7 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.restrictions.SpaceStatus import com.anytypeio.anytype.domain.account.AwaitAccountStartManager import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -46,7 +47,8 @@ interface SpaceViewSubscriptionContainer { private val scope: CoroutineScope, private val dispatchers: AppCoroutineDispatchers, private val awaitAccountStart: AwaitAccountStartManager, - private val logger: Logger + private val logger: Logger, + private val config: ConfigStorage ) : SpaceViewSubscriptionContainer { private val data = MutableStateFlow>(emptyList()) @@ -90,68 +92,77 @@ interface SpaceViewSubscriptionContainer { override fun start() { jobs += scope.launch(dispatchers.io) { - container.subscribe( - StoreSearchParams( - subscription = GLOBAL_SUBSCRIPTION, - keys = listOf( - Relations.ID, - Relations.TARGET_SPACE_ID, - Relations.SPACE_ACCOUNT_STATUS, - Relations.SPACE_LOCAL_STATUS, - Relations.SPACE_ACCESS_TYPE, - Relations.SHARED_SPACES_LIMIT, - Relations.READERS_LIMIT, - Relations.WRITERS_LIMIT, - Relations.NAME, - Relations.CREATED_DATE, - Relations.CREATOR, - Relations.ICON_IMAGE, - Relations.ICON_OPTION, + val techSpace = config.getOrNull()?.techSpace + if (techSpace != null) { + proceedWithSubscription(techSpace) + } else { + logger.logException(IllegalStateException("Tech space was missing")) + } + } + } + + private suspend fun proceedWithSubscription(techSpace: Id) { + container.subscribe( + StoreSearchParams( + space = SpaceId(techSpace), + subscription = GLOBAL_SUBSCRIPTION, + keys = listOf( + Relations.ID, + Relations.TARGET_SPACE_ID, + Relations.SPACE_ACCOUNT_STATUS, + Relations.SPACE_LOCAL_STATUS, + Relations.SPACE_ACCESS_TYPE, + Relations.SHARED_SPACES_LIMIT, + Relations.READERS_LIMIT, + Relations.WRITERS_LIMIT, + Relations.NAME, + Relations.CREATED_DATE, + Relations.CREATOR, + Relations.ICON_IMAGE, + Relations.ICON_OPTION, + ), + filters = listOf( + DVFilter( + relation = Relations.LAYOUT, + value = ObjectType.Layout.SPACE_VIEW.code.toDouble(), + condition = DVFilterCondition.EQUAL ), - filters = listOf( - DVFilter( - relation = Relations.LAYOUT, - value = ObjectType.Layout.SPACE_VIEW.code.toDouble(), - condition = DVFilterCondition.EQUAL - ), - DVFilter( - relation = Relations.SPACE_ACCOUNT_STATUS, - value = buildList { - add(SpaceStatus.SPACE_DELETED.code.toDouble()) - }, - condition = DVFilterCondition.NOT_IN - ), - DVFilter( - relation = Relations.SPACE_LOCAL_STATUS, - value = buildList { - add(SpaceStatus.OK.code.toDouble()) - add(SpaceStatus.UNKNOWN.code.toDouble()) - }, - condition = DVFilterCondition.IN - ) + DVFilter( + relation = Relations.SPACE_ACCOUNT_STATUS, + value = buildList { + add(SpaceStatus.SPACE_DELETED.code.toDouble()) + }, + condition = DVFilterCondition.NOT_IN ), - sorts = listOf( - DVSort( - relationKey = Relations.LAST_OPENED_DATE, - type = DVSortType.DESC, - includeTime = true, - relationFormat = RelationFormat.DATE - ) + DVFilter( + relation = Relations.SPACE_LOCAL_STATUS, + value = buildList { + add(SpaceStatus.OK.code.toDouble()) + add(SpaceStatus.UNKNOWN.code.toDouble()) + }, + condition = DVFilterCondition.IN + ) + ), + sorts = listOf( + DVSort( + relationKey = Relations.LAST_OPENED_DATE, + type = DVSortType.DESC, + includeTime = true, + relationFormat = RelationFormat.DATE ) ) - ).map { objects -> - objects.map { obj -> - ObjectWrapper.SpaceView(obj.map) - } - }.catch { error -> - logger.logException( - e = error, - msg = "Failed to subscribe to space-views" - ) + ) + ).map { objects -> + objects.map { obj -> + ObjectWrapper.SpaceView(obj.map) } - .collect { - data.value = it - } + }.catch { error -> + logger.logException( + e = error, + msg = "Failed to subscribe to space-views" + ) + }.collect { + data.value = it } } @@ -168,6 +179,7 @@ interface SpaceViewSubscriptionContainer { } } +@Deprecated("To de deleted") fun SpaceViewSubscriptionContainer.isSharingLimitReached( spaceToUserPermissions: Flow> ) : Flow> { @@ -193,4 +205,19 @@ fun SpaceViewSubscriptionContainer.isSharingLimitReached( val isLimitReached = limit == 0 || count >= limit Pair(isLimitReached, limit) } -} \ No newline at end of file +} + +fun SpaceViewSubscriptionContainer.sharedSpaceCount( + spaceToUserPermissions: Flow> +) : Flow { + return combine( + observe(), + spaceToUserPermissions + ) { spaceViews, permissions -> + spaceViews.count { spaceView -> + val permission = permissions[spaceView.targetSpaceId] + spaceView.spaceAccessType == SHARED && permission == OWNER + } + } +} + diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/object/FetchObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/object/FetchObject.kt index 49649d4044..e6bb4f20bf 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/object/FetchObject.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/object/FetchObject.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -28,7 +29,8 @@ class FetchObject @Inject constructor( ) }, limit = 1, - keys = params.keys + keys = params.keys, + space = params.space ) return if (result.isNotEmpty() && result.first().isNotEmpty()) { ObjectWrapper.Basic(result.first()) @@ -38,6 +40,7 @@ class FetchObject @Inject constructor( } data class Params( + val space: SpaceId, val obj: Id, val keys: List = listOf( Relations.ID, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/objects/options/GetOptions.kt b/domain/src/main/java/com/anytypeio/anytype/domain/objects/options/GetOptions.kt index e141f1ec56..ae751bd0b6 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/objects/options/GetOptions.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/objects/options/GetOptions.kt @@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -53,6 +54,7 @@ class GetOptions( ) } repo.searchObjects( + space = SpaceId(params.space), sorts = emptyList(), filters = filters, limit = 0, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObject.kt index 1490ff399b..30e4acb6e5 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObject.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObject.kt @@ -12,7 +12,6 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.launch.GetDefaultObjectType -import com.anytypeio.anytype.domain.workspace.SpaceManager import javax.inject.Inject /** @@ -21,14 +20,14 @@ import javax.inject.Inject class CreateObject @Inject constructor( private val repo: BlockRepository, private val getDefaultObjectType: GetDefaultObjectType, - private val spaceManager: SpaceManager, dispatchers: AppCoroutineDispatchers ) : ResultInteractor(dispatchers.io) { override suspend fun doWork(params: Param): Result { if (params.type == null) { - val defType = getDefaultObjectType.run(Unit) + val defType = getDefaultObjectType.run(params.space) return createObject( + space = params.space, typeKey = defType.type, template = defType.defaultTemplate, internalFlags = params.internalFlags, @@ -36,6 +35,7 @@ class CreateObject @Inject constructor( ) } else { return createObject( + space = params.space, typeKey = params.type, template = params.template, internalFlags = params.internalFlags, @@ -45,16 +45,15 @@ class CreateObject @Inject constructor( } private suspend fun createObject( + space: SpaceId, typeKey: TypeKey, template: Id?, internalFlags: List, prefilled: Struct ): Result { - val spaceId = SpaceId(spaceManager.get()) - val command = Command.CreateObject( - space = spaceId, + space = space, typeKey = typeKey, template = template, prefilled = prefilled, @@ -72,10 +71,8 @@ class CreateObject @Inject constructor( ) } - /** - * DROID-2341 TODO provide custom space to params? - */ data class Param( + val space: SpaceId, val type: TypeKey? = null, val template: Id? = null, val internalFlags: List = emptyList(), diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObjectByTypeAndTemplate.kt b/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObjectByTypeAndTemplate.kt index 8620f61495..2cdec96c6e 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObjectByTypeAndTemplate.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/page/CreateObjectByTypeAndTemplate.kt @@ -45,6 +45,7 @@ class CreateObjectByTypeAndTemplate @Inject constructor( private suspend fun searchObjectType(params: Param): ObjectWrapper.Type? { try { val struct = repo.searchObjects( + space = params.space, limit = 1, keys = params.keys, sorts = params.sorts, @@ -65,16 +66,16 @@ class CreateObjectByTypeAndTemplate @Inject constructor( value = true ), DVFilter( - relation = Relations.IS_DELETED, + relation = Relations.IS_HIDDEN_DISCOVERY, condition = DVFilterCondition.NOT_EQUAL, value = true ), DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = listOf(params.space.id) + relation = Relations.IS_DELETED, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) - ), + ) ) return if (struct.isNotEmpty()) { ObjectWrapper.Type(struct.first()) diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt b/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt index 85e2dd35e4..55c6ea9640 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/relations/GetRelations.kt @@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.DVFilter import com.anytypeio.anytype.core_models.DVSort import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -18,6 +19,7 @@ class GetRelations( } private suspend fun proceedWithUseCase(params: Params) = repo.searchObjects( + space = params.space, keys = params.keys, filters = params.filters, sorts = params.sorts, @@ -29,6 +31,7 @@ class GetRelations( } data class Params( + val space: SpaceId, val sorts: List = emptyList(), val filters: List = emptyList(), val keys: List = emptyList(), diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/DataViewSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/DataViewSubscriptionContainer.kt index 48a0ab16a9..2901941349 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/DataViewSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/DataViewSubscriptionContainer.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.SubscriptionEvent +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.`object`.move import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.runCatchingL @@ -38,6 +39,7 @@ class DataViewSubscriptionContainer( fun observe(params: Params): Flow { return flow { val initial = repo.searchObjectsWithSubscription( + space = params.space, subscription = params.subscription, sorts = params.sorts.distinct(), filters = params.filters.distinct(), @@ -183,6 +185,7 @@ class DataViewSubscriptionContainer( } data class Params( + val space: SpaceId, val subscription: Id, val sorts: List, val filters: List, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectSearchSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectSearchSubscriptionContainer.kt index de1dde31c3..f3dad084f8 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectSearchSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectSearchSubscriptionContainer.kt @@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Subscription import com.anytypeio.anytype.core_models.SubscriptionEvent +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.`object`.move import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -26,6 +27,7 @@ class ObjectSearchSubscriptionContainer( private fun subscribe(subscriptions: List) = channel.subscribe(subscriptions) fun observe( + space: SpaceId, subscription: Id, sorts: List = emptyList(), filters: List = emptyList(), @@ -36,6 +38,7 @@ class ObjectSearchSubscriptionContainer( ): Flow { return flow { val initial = repo.searchObjectsWithSubscription( + space = space, subscription = subscription, sorts = sorts, filters = filters, @@ -144,11 +147,13 @@ class ObjectSearchSubscriptionContainer( } fun observe( + space: SpaceId, subscription: Id, targets: List, keys: List ): Flow> = flow { val initial = repo.searchObjectsByIdWithSubscription( + space = space, subscription = subscription, ids = targets, keys = keys @@ -157,10 +162,12 @@ class ObjectSearchSubscriptionContainer( } suspend fun get( + space: SpaceId, subscription: Id, targets: List, keys: List ): List = repo.searchObjectsByIdWithSubscription( + space = space, subscription = subscription, ids = targets, keys = keys diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionContainer.kt index 664a62135b..49a514c91d 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionContainer.kt @@ -5,11 +5,14 @@ import com.anytypeio.anytype.core_models.DVSort 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.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository +import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.`object`.move import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -20,12 +23,14 @@ class ObjectTypesSubscriptionContainer( private val repo: BlockRepository, private val channel: SubscriptionEventChannel, private val store: StoreOfObjectTypes, - private val dispatchers: AppCoroutineDispatchers + private val dispatchers: AppCoroutineDispatchers, + private val logger: Logger ) { fun observe(params: Params): Flow { return flow { val initial = repo.searchObjectsWithSubscription( + space = params.space, subscription = params.subscription, sorts = params.sorts, filters = params.filters, @@ -121,7 +126,11 @@ class ObjectTypesSubscriptionContainer( ) } ) - }.flowOn(dispatchers.io) + }.catch { + logger.logException(it, "Error in object types container") + }.flowOn( + context = dispatchers.io + ) } /** @@ -139,6 +148,7 @@ class ObjectTypesSubscriptionContainer( } data class Params( + val space: SpaceId, val subscription: Id, val sorts: List, val filters: List, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionManager.kt index 551663fd99..7481e50b6a 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionManager.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/ObjectTypesSubscriptionManager.kt @@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVFilter import com.anytypeio.anytype.core_models.DVFilterCondition import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.subscriptions.GlobalSubscription import com.anytypeio.anytype.domain.workspace.SpaceManager import kotlinx.coroutines.CoroutineScope @@ -65,6 +66,7 @@ class ObjectTypesSubscriptionManager ( companion object { fun buildParams(config: Config) = ObjectTypesSubscriptionContainer.Params( + space = SpaceId(config.space), subscription = ObjectTypesSubscriptionContainer.SUBSCRIPTION_ID, filters = listOf( DVFilter( diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/ProfileSubscriptionManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/ProfileSubscriptionManager.kt new file mode 100644 index 0000000000..53e2f8d647 --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/ProfileSubscriptionManager.kt @@ -0,0 +1,89 @@ +package com.anytypeio.anytype.domain.search + +import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId +import com.anytypeio.anytype.domain.account.AwaitAccountStartManager +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.config.ConfigStorage +import com.anytypeio.anytype.domain.debugging.Logger +import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams +import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer +import com.anytypeio.anytype.domain.subscriptions.GlobalSubscription +import javax.inject.Inject +import kotlin.math.log +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +interface ProfileSubscriptionManager : GlobalSubscription { + + fun observe(): Flow + fun onStart() + fun onStop() + + class Default @Inject constructor( + private val scope: CoroutineScope, + private val configStorage: ConfigStorage, + private val awaitAccountStartManager: AwaitAccountStartManager, + private val container: StorelessSubscriptionContainer, + private val dispatchers: AppCoroutineDispatchers, + private val logger: Logger + ) : ProfileSubscriptionManager { + + private val state = MutableStateFlow(null) + + override fun observe(): Flow { + return state.mapNotNull { it } + } + + override fun onStart() { + scope.launch { + awaitAccountStartManager + .state() + .mapNotNull { configStorage.getOrNull() } + .flatMapLatest { config -> + container.subscribe( + searchParams = StoreSearchByIdsParams( + subscription = GLOBAL_PROFILE_SUBSCRIPTION, + space = SpaceId(config.techSpace), + keys = listOf( + Relations.ID, + Relations.NAME, + Relations.ICON_EMOJI, + Relations.ICON_IMAGE, + Relations.ICON_OPTION, + Relations.SHARED_SPACES_LIMIT + ), + targets = listOf(config.profile) + ) + ).map { + it.firstOrNull() + } + } + .flowOn(dispatchers.io) + .catch { logger.logException(it, "Error in ProfileSubscriptionManager") } + .collect { + state.value = it + } + } + } + + override fun onStop() { + scope.launch(dispatchers.io) { + container.unsubscribe(listOf(GLOBAL_PROFILE_SUBSCRIPTION)) + } + } + + companion object { + const val GLOBAL_PROFILE_SUBSCRIPTION = "subscription.global.profile" + } + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionContainer.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionContainer.kt index 51b2876a17..7927d0370d 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionContainer.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionContainer.kt @@ -5,11 +5,14 @@ import com.anytypeio.anytype.core_models.DVSort 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.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository +import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.`object`.move import com.anytypeio.anytype.domain.objects.StoreOfRelations import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -20,12 +23,14 @@ class RelationsSubscriptionContainer( private val repo: BlockRepository, private val channel: SubscriptionEventChannel, private val store: StoreOfRelations, - private val dispatchers: AppCoroutineDispatchers + private val dispatchers: AppCoroutineDispatchers, + private val logger: Logger ) { fun observe(params: Params): Flow { return flow { val initial = repo.searchObjectsWithSubscription( + space = params.space, subscription = params.subscription, sorts = params.sorts, filters = params.filters, @@ -121,7 +126,11 @@ class RelationsSubscriptionContainer( ) } ) - }.flowOn(dispatchers.io) + }.catch { + logger.logException(it, "Error in storeless subscription container") + }.flowOn( + context = dispatchers.io + ) } @@ -141,6 +150,7 @@ class RelationsSubscriptionContainer( } data class Params( + val space: SpaceId, val subscription: Id, val sorts: List, val filters: List, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionManager.kt index 4f76009e31..cb7bc544b6 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionManager.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/RelationsSubscriptionManager.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Marketplace import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.subscriptions.GlobalSubscription import com.anytypeio.anytype.domain.workspace.SpaceManager import javax.inject.Inject @@ -27,12 +28,9 @@ class RelationsSubscriptionManager @Inject constructor( val pipeline get() = spaceManager.state().flatMapLatest { state -> when(state) { is SpaceManager.State.Space.Active -> { + // DROID-2916 TODO provide other spaces or add new subscription val params = buildParams( - spaces = listOf( - state.config.space, - state.config.techSpace, - Marketplace.MARKETPLACE_SPACE_ID - ) + space = SpaceId(state.config.space) ) container.observe(params) } @@ -69,7 +67,8 @@ class RelationsSubscriptionManager @Inject constructor( } companion object { - fun buildParams(spaces: List) = RelationsSubscriptionContainer.Params( + fun buildParams(space: SpaceId) = RelationsSubscriptionContainer.Params( + space = space, subscription = RelationsSubscriptionContainer.SUBSCRIPTION_ID, filters = listOf( DVFilter( @@ -86,11 +85,6 @@ class RelationsSubscriptionManager @Inject constructor( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.NOT_EQUAL, value = true - ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = spaces ) ), limit = 0, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjects.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjects.kt index 1b2604d2c2..774c6fd7ba 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjects.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjects.kt @@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.DVFilter import com.anytypeio.anytype.core_models.DVSort import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.block.repo.BlockRepository import javax.inject.Inject @@ -14,6 +15,7 @@ class SearchObjects @Inject constructor( override suspend fun run(params: Params) = safe { repo.searchObjects( + space = params.space, sorts = params.sorts, filters = params.filters, fulltext = params.fulltext, @@ -26,6 +28,7 @@ class SearchObjects @Inject constructor( } data class Params( + val space: SpaceId, val sorts: List = emptyList(), val filters: List = emptyList(), val fulltext: String = EMPTY_TEXT, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjectsByIdWithSubscription.kt b/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjectsByIdWithSubscription.kt index 6d1310b355..c5ffee3ee8 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjectsByIdWithSubscription.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/search/SearchObjectsByIdWithSubscription.kt @@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.search import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.SearchResult +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.ResultatInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -11,6 +12,7 @@ class SearchObjectsByIdWithSubscription( override suspend fun execute(params: Params): SearchResult { return repo.searchObjectsByIdWithSubscription( + space = params.space, subscription = params.subscription, ids = params.ids, keys = params.keys @@ -18,6 +20,7 @@ class SearchObjectsByIdWithSubscription( } class Params( + val space: SpaceId, val subscription: Id, val ids: List, val keys: List diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/sets/FindObjectSetForType.kt b/domain/src/main/java/com/anytypeio/anytype/domain/sets/FindObjectSetForType.kt index b90c159fa5..192a62b1cc 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/sets/FindObjectSetForType.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/sets/FindObjectSetForType.kt @@ -1,6 +1,7 @@ package com.anytypeio.anytype.domain.sets import com.anytypeio.anytype.core_models.* +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.BaseUseCase import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.sets.FindObjectSetForType.Params @@ -17,6 +18,7 @@ class FindObjectSetForType( override suspend fun run(params: Params) = safe { val results = repo.searchObjects( + space = params.space, limit = 1, filters = params.filters, sorts = emptyList(), @@ -38,7 +40,11 @@ class FindObjectSetForType( /** * @property [type] object type id */ - data class Params(val type: Id, val filters: List) + data class Params( + val space: SpaceId, + val type: Id, + val filters: List + ) sealed class Response { /** diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceView.kt b/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceView.kt index 57e0b7ac3f..71dda09080 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceView.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceView.kt @@ -9,17 +9,21 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor import com.anytypeio.anytype.domain.block.repo.BlockRepository +import com.anytypeio.anytype.domain.config.ConfigStorage import javax.inject.Inject class GetSpaceView @Inject constructor( private val repo: BlockRepository, + private val configStorage: ConfigStorage, dispatchers: AppCoroutineDispatchers ): ResultInteractor(dispatchers.io) { override suspend fun doWork(params: Params): ObjectWrapper.Basic? { when(params) { is Params.BySpaceViewId -> { + val techSpace = configStorage.getOrNull()?.techSpace ?: return null val result = repo.searchObjects( + space = SpaceId(techSpace), filters = buildList { add( DVFilter( @@ -39,6 +43,7 @@ class GetSpaceView @Inject constructor( } is Params.BySpaceId -> { val result = repo.searchObjects( + space = params.space, filters = buildList { add( DVFilter( diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceViews.kt b/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceViews.kt index 89c11cb186..b9771776ad 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceViews.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/spaces/GetSpaceViews.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.restrictions.SpaceStatus import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor @@ -17,9 +18,10 @@ import javax.inject.Inject class GetSpaceViews @Inject constructor( private val repo: BlockRepository, dispatchers: AppCoroutineDispatchers -): ResultInteractor>(dispatchers.io) { - override suspend fun doWork(params: Unit): List { +): ResultInteractor>(dispatchers.io) { + override suspend fun doWork(params: SpaceId): List { val result = repo.searchObjects( + space = params, keys = listOf( Relations.ID, Relations.TARGET_SPACE_ID, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/spaces/SpaceDeletedStatusWatcher.kt b/domain/src/main/java/com/anytypeio/anytype/domain/spaces/SpaceDeletedStatusWatcher.kt index 228cb74478..5ffecd0fc3 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/spaces/SpaceDeletedStatusWatcher.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/spaces/SpaceDeletedStatusWatcher.kt @@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.spaces import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.debugging.Logger @@ -36,7 +37,8 @@ class SpaceDeletedStatusWatcher @Inject constructor( .flatMapLatest { config -> container.subscribe( searchParams = StoreSearchByIdsParams( - subscription = GLOBAL_SPACE_VIEW_SUBSCRIPTION, + space = SpaceId(config.techSpace), + subscription = DELETED_SPACE_VIEW_SUBSCRIPTION, targets = listOf(config.spaceView), keys = buildList { add(Relations.ID) @@ -54,11 +56,8 @@ class SpaceDeletedStatusWatcher @Inject constructor( if (spaceView.spaceAccountStatus.isDeletedOrRemoving()) { logger.logWarning("Current space is deleted") val accountConfig = configStorage.getOrNull() - if (accountConfig != null) { - logger.logWarning("Account config found. Switching to default space.") - spaceManager.set(accountConfig.space) - } else { - logger.logWarning("Account config not found. Resetting space.") + if (accountConfig == null) { + logger.logWarning("Account config not found. Clearing space manager.") spaceManager.clear() } } @@ -72,7 +71,7 @@ class SpaceDeletedStatusWatcher @Inject constructor( fun onStop() { scope.launch(dispatchers.io) { - container.unsubscribe(listOf(GLOBAL_SPACE_VIEW_SUBSCRIPTION)) + container.unsubscribe(listOf(DELETED_SPACE_VIEW_SUBSCRIPTION)) with(jobs) { forEach { it.cancel() } clear() @@ -81,6 +80,6 @@ class SpaceDeletedStatusWatcher @Inject constructor( } companion object { - const val GLOBAL_SPACE_VIEW_SUBSCRIPTION = "subscription.global.space-view-deleted-status-watcher" + const val DELETED_SPACE_VIEW_SUBSCRIPTION = "subscription.global.space-view-deleted-status-watcher" } } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt index 78b149f072..6290837803 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt @@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.subscriptions import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager +import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher import javax.inject.Inject @@ -15,7 +16,8 @@ interface GlobalSubscriptionManager { private val types: ObjectTypesSubscriptionManager, private val relations: RelationsSubscriptionManager, private val permissions: UserPermissionProvider, - private val isSpaceDeleted: SpaceDeletedStatusWatcher + private val isSpaceDeleted: SpaceDeletedStatusWatcher, + private val profile: ProfileSubscriptionManager ) : GlobalSubscriptionManager { override fun onStart() { @@ -23,6 +25,7 @@ interface GlobalSubscriptionManager { relations.onStart() permissions.start() isSpaceDeleted.onStart() + profile.onStart() } override fun onStop() { @@ -30,6 +33,7 @@ interface GlobalSubscriptionManager { relations.onStop() permissions.stop() isSpaceDeleted.onStop() + profile.onStop() } } diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/templates/GetTemplates.kt b/domain/src/main/java/com/anytypeio/anytype/domain/templates/GetTemplates.kt index 1b2b8f1d1f..b87cfb7d2d 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/templates/GetTemplates.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/templates/GetTemplates.kt @@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.ResultInteractor @@ -29,6 +30,8 @@ class GetTemplates( return withContext(dispatchers.io) { try { repo.searchObjects( + // TODO provide space id to params + space = SpaceId(spaceManager.get()), filters = listOf( DVFilter( relation = Relations.IS_ARCHIVED, @@ -45,16 +48,16 @@ class GetTemplates( condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.TARGET_OBJECT_TYPE, condition = DVFilterCondition.EQUAL, value = params.type.id ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = spaceManager.get() - ), DVFilter( relation = Relations.TYPE_UNIQUE_KEY, condition = DVFilterCondition.EQUAL, diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/workspace/WorkspaceManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/workspace/WorkspaceManager.kt index 2ebd3ec913..b81cd50181 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/workspace/WorkspaceManager.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/workspace/WorkspaceManager.kt @@ -123,13 +123,4 @@ suspend fun SpaceManager.getSpaceWithTechSpace(): List { } else { listOf(get()) } -} - -suspend fun SpaceManager.getSpaceWithTechSpace(space: Id): List { - val config = getConfig(SpaceId(space)) - return if (config != null) { - listOf(config.space, config.techSpace) - } else { - listOf(get()) - } } \ No newline at end of file diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/GetProfileTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/GetProfileTest.kt index 4f67294c44..02c98b10a0 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/GetProfileTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/GetProfileTest.kt @@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.StubConfig import com.anytypeio.anytype.core_models.SubscriptionEvent +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.auth.interactor.GetProfile import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.ConfigStorage @@ -77,6 +78,7 @@ class GetProfileTest { repo.stub { onBlocking { searchObjectsByIdWithSubscription( + space = SpaceId(config.techSpace), subscription = subscription, keys = emptyList(), ids = listOf(config.profile) @@ -145,6 +147,7 @@ class GetProfileTest { repo.stub { onBlocking { searchObjectsByIdWithSubscription( + space = SpaceId(config.techSpace), subscription = subscription, keys = emptyList(), ids = listOf(config.profile) @@ -221,6 +224,7 @@ class GetProfileTest { repo.stub { onBlocking { searchObjectsByIdWithSubscription( + space = SpaceId(config.techSpace), subscription = subscription, keys = emptyList(), ids = listOf(config.profile) @@ -305,6 +309,7 @@ class GetProfileTest { repo.stub { onBlocking { searchObjectsByIdWithSubscription( + space = SpaceId(config.techSpace), subscription = subscription, keys = emptyList(), ids = listOf(config.profile) diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/misc/DataViewSubscriptionContainerTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/misc/DataViewSubscriptionContainerTest.kt index 6dbac34be4..2e4121b8ac 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/misc/DataViewSubscriptionContainerTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/misc/DataViewSubscriptionContainerTest.kt @@ -8,12 +8,14 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.SubscriptionEvent +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.objects.DefaultObjectStore import com.anytypeio.anytype.domain.search.DataViewState import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer import com.anytypeio.anytype.domain.search.SubscriptionEventChannel +import com.anytypeio.anytype.test_utils.MockDataFactory import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.runTest @@ -48,6 +50,10 @@ class DataViewSubscriptionContainerTest { Relations.LAYOUT ) + private val defaultSpaceId = SpaceId( + id = MockDataFactory.randomUuid() + ) + @Mock lateinit var channel: SubscriptionEventChannel @@ -93,6 +99,7 @@ class DataViewSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = defaultSpaceId, subscription = subscription1, limit = defaultLimit, offset = defaultOffset, @@ -146,6 +153,7 @@ class DataViewSubscriptionContainerTest { } val params = DataViewSubscriptionContainer.Params( + space = defaultSpaceId, subscription = subscription1, limit = defaultLimit, offset = defaultOffset, diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/misc/GetObjectTypeTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/misc/GetObjectTypeTest.kt index eca8a172fb..364f8dc851 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/misc/GetObjectTypeTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/misc/GetObjectTypeTest.kt @@ -3,6 +3,7 @@ package com.anytypeio.anytype.domain.misc import com.anytypeio.anytype.core_models.CoroutineTestRule import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -34,7 +35,13 @@ class GetObjectTypeTest { private lateinit var usecase: GetObjectTypes + private val defaultSpaceId = SpaceId( + id = MockDataFactory.randomUuid() + ) + + private val defaultParams = GetObjectTypes.Params( + space = defaultSpaceId, filters = emptyList(), keys = listOf(Relations.ID), sorts = emptyList(), @@ -85,6 +92,7 @@ class GetObjectTypeTest { assertEquals(firstTimeResult, secondTimeResult) verify(repo, times(2)).searchObjects( + space = defaultSpaceId, filters = defaultParams.filters, keys = defaultParams.keys, sorts = defaultParams.sorts, @@ -214,6 +222,7 @@ class GetObjectTypeTest { repo.stub { onBlocking { searchObjects( + space = defaultSpaceId, filters = emptyList(), keys = listOf(Relations.ID), sorts = emptyList(), diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/misc/ObjectSearchSubscriptionContainerTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/misc/ObjectSearchSubscriptionContainerTest.kt index d60257f599..269cd30c71 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/misc/ObjectSearchSubscriptionContainerTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/misc/ObjectSearchSubscriptionContainerTest.kt @@ -2,11 +2,13 @@ package com.anytypeio.anytype.domain.misc import app.cash.turbine.test import com.anytypeio.anytype.core_models.* +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.objects.DefaultObjectStore import com.anytypeio.anytype.domain.search.ObjectSearchSubscriptionContainer import com.anytypeio.anytype.domain.search.SubscriptionEventChannel +import com.anytypeio.anytype.test_utils.MockDataFactory import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.runTest @@ -33,6 +35,10 @@ class ObjectSearchSubscriptionContainerTest { private val defaultLimit = 0 private val defaultOffset = 0L + private val defaultSpaceId = SpaceId( + MockDataFactory.randomUuid() + ) + private val defaultKeys = listOf( Relations.ID, Relations.NAME, @@ -85,6 +91,7 @@ class ObjectSearchSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = defaultSpaceId, subscription = subscription1, limit = defaultLimit, offset = defaultOffset, @@ -139,6 +146,7 @@ class ObjectSearchSubscriptionContainerTest { runTest { container.observe( + space = defaultSpaceId, subscription1, limit = defaultLimit, offset = defaultOffset, diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectAsMentionOrLinkTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectAsMentionOrLinkTest.kt index 67d0d8fee8..cb2ff6ed1e 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectAsMentionOrLinkTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectAsMentionOrLinkTest.kt @@ -234,7 +234,7 @@ class CreateObjectAsMentionOrLinkTest { defaultTemplate: String? = null ) { getDefaultObjectType.stub { - onBlocking { run(Unit) } doReturn GetDefaultObjectType.Response( + onBlocking { run(SpaceId(spaceId)) } doReturn GetDefaultObjectType.Response( type = type, name = name, id = TypeId(MockDataFactory.randomString()), diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectTest.kt index 00990a0588..2b042f1efb 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/page/CreateObjectTest.kt @@ -52,12 +52,13 @@ class CreateObjectTest { lateinit var createObject: CreateObject + private val defaultSpaceId = SpaceId(MockDataFactory.randomUuid()) + @Before fun setup() { createObject = CreateObject( repo = repo, getDefaultObjectType = getDefaultObjectType, - spaceManager = spaceManager, dispatchers = dispatchers ) stubSpaceManager() @@ -74,6 +75,7 @@ class CreateObjectTest { //TESTING val params = CreateObject.Param( + space = defaultSpaceId, type = type, internalFlags = listOf( InternalFlags.ShouldSelectType, @@ -93,7 +95,7 @@ class CreateObjectTest { InternalFlags.ShouldSelectTemplate, InternalFlags.ShouldEmptyDelete ), - space = SpaceId(""), + space = defaultSpaceId, typeKey = appDefaultTypeKey ) verifyBlocking(repo, times(1)) { createObject(commands) } @@ -114,6 +116,7 @@ class CreateObjectTest { //TESTING val params = CreateObject.Param( + space = defaultSpaceId, type = type, internalFlags = listOf( InternalFlags.ShouldSelectType, @@ -132,7 +135,7 @@ class CreateObjectTest { InternalFlags.ShouldSelectTemplate, InternalFlags.ShouldEmptyDelete ), - space = SpaceId(""), + space = defaultSpaceId, typeKey = TypeKey(defaultType) ) verifyBlocking(repo, times(1)) { createObject(commands) } @@ -154,6 +157,7 @@ class CreateObjectTest { //TESTING val params = CreateObject.Param( + space = defaultSpaceId, type = type, internalFlags = listOf( InternalFlags.ShouldSelectType, @@ -172,7 +176,7 @@ class CreateObjectTest { InternalFlags.ShouldSelectTemplate, InternalFlags.ShouldEmptyDelete ), - space = SpaceId(""), + space = defaultSpaceId, typeKey = TypeKey(defaultType) ) verifyBlocking(repo, times(1)) { createObject(commands) } @@ -189,6 +193,7 @@ class CreateObjectTest { //TESTING val params = CreateObject.Param( + space = defaultSpaceId, type = TypeKey(type), internalFlags = listOf( InternalFlags.ShouldSelectType, @@ -208,7 +213,7 @@ class CreateObjectTest { InternalFlags.ShouldSelectTemplate, InternalFlags.ShouldEmptyDelete ), - space = SpaceId(""), + space = defaultSpaceId, typeKey = TypeKey(type) ) verifyBlocking(repo, times(1)) { createObject(commands) } @@ -225,6 +230,7 @@ class CreateObjectTest { //TESTING val params = CreateObject.Param( + space = defaultSpaceId, type = TypeKey(type), internalFlags = listOf( InternalFlags.ShouldSelectType, @@ -244,7 +250,7 @@ class CreateObjectTest { InternalFlags.ShouldSelectTemplate, InternalFlags.ShouldEmptyDelete ), - space = SpaceId(""), + space = defaultSpaceId, typeKey = TypeKey(type) ) verifyBlocking(repo, times(1)) { createObject(commands) } @@ -262,6 +268,7 @@ class CreateObjectTest { //TESTING val params = CreateObject.Param( + space = defaultSpaceId, type = TypeKey(type), internalFlags = listOf( InternalFlags.ShouldSelectType, @@ -282,7 +289,7 @@ class CreateObjectTest { InternalFlags.ShouldSelectTemplate, InternalFlags.ShouldEmptyDelete ), - space = SpaceId(""), + space = defaultSpaceId, typeKey = TypeKey(type) ) verifyBlocking(repo, times(1)) { createObject(commands) } @@ -294,7 +301,7 @@ class CreateObjectTest { template: String? = null, ) { getDefaultObjectType.stub { - onBlocking { run(Unit) } doReturn GetDefaultObjectType.Response( + onBlocking { run(defaultSpaceId) } doReturn GetDefaultObjectType.Response( type = type, name = name, id = TypeId(MockDataFactory.randomString()), @@ -319,9 +326,9 @@ class CreateObjectTest { } } - fun stubSpaceManager() { + private fun stubSpaceManager() { spaceManager.stub { - onBlocking { get() } doReturn "" + onBlocking { get() } doReturn defaultSpaceId.id } } } \ No newline at end of file diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/ObjectTypesSubscriptionContainerTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/ObjectTypesSubscriptionContainerTest.kt index 9d0a5cb19a..8c7704d4cc 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/ObjectTypesSubscriptionContainerTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/ObjectTypesSubscriptionContainerTest.kt @@ -5,9 +5,11 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.StubConfig import com.anytypeio.anytype.core_models.StubObjectType +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.common.DefaultCoroutineTestRule +import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionContainer import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager @@ -43,6 +45,9 @@ class ObjectTypesSubscriptionContainerTest { @Mock lateinit var repo: BlockRepository + @Mock + lateinit var logger: Logger + @Mock lateinit var channel: SubscriptionEventChannel @@ -70,7 +75,8 @@ class ObjectTypesSubscriptionContainerTest { repo = repo, channel = channel, store = store, - dispatchers = dispatchers + dispatchers = dispatchers, + logger = logger ) val manager = ObjectTypesSubscriptionManager( @@ -142,6 +148,7 @@ class ObjectTypesSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = SpaceId(defaultSpaceConfig.space), subscription = defaultSpaceSearchParams.subscription, sorts = defaultSpaceSearchParams.sorts, filters = defaultSpaceSearchParams.filters, @@ -164,6 +171,7 @@ class ObjectTypesSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = SpaceId(alternativeSpaceConfig.space), subscription = alternativeSpaceSearchParams.subscription, sorts = alternativeSpaceSearchParams.sorts, filters = alternativeSpaceSearchParams.filters, diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/RelationsSubscriptionContainerTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/RelationsSubscriptionContainerTest.kt index a34cbbab89..5471782ffc 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/RelationsSubscriptionContainerTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/RelationsSubscriptionContainerTest.kt @@ -6,9 +6,11 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.StubConfig import com.anytypeio.anytype.core_models.StubRelationObject +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.common.DefaultCoroutineTestRule +import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations import com.anytypeio.anytype.domain.search.RelationsSubscriptionContainer import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager @@ -44,6 +46,9 @@ class RelationsSubscriptionContainerTest { @Mock lateinit var repo: BlockRepository + @Mock + lateinit var logger: Logger + @Mock lateinit var channel: SubscriptionEventChannel @@ -71,7 +76,8 @@ class RelationsSubscriptionContainerTest { repo = repo, channel = channel, store = store, - dispatchers = dispatchers + dispatchers = dispatchers, + logger = logger ) val manager = RelationsSubscriptionManager ( @@ -81,19 +87,11 @@ class RelationsSubscriptionContainerTest { ) val defaultSpaceSearchParams = RelationsSubscriptionManager.buildParams( - spaces = listOf( - defaultSpaceConfig.space, - defaultSpaceConfig.techSpace, - Marketplace.MARKETPLACE_SPACE_ID, - ) + space = SpaceId(defaultSpaceConfig.space) ) val alternativeSpaceSearchParams = RelationsSubscriptionManager.buildParams( - spaces = listOf( - alternativeSpaceConfig.space, - alternativeSpaceConfig.techSpace, - Marketplace.MARKETPLACE_SPACE_ID, - ) + space = SpaceId(defaultSpaceConfig.space) ) val defaultSpaceTypes = buildList { @@ -151,6 +149,7 @@ class RelationsSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = SpaceId(defaultSpaceConfig.space), subscription = defaultSpaceSearchParams.subscription, sorts = defaultSpaceSearchParams.sorts, filters = defaultSpaceSearchParams.filters, @@ -173,6 +172,7 @@ class RelationsSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = SpaceId(alternativeSpaceConfig.space), subscription = alternativeSpaceSearchParams.subscription, sorts = alternativeSpaceSearchParams.sorts, filters = alternativeSpaceSearchParams.filters, diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/StorelessSubscriptionContainerTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/StorelessSubscriptionContainerTest.kt index 2672f9fb04..e0710a3e71 100644 --- a/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/StorelessSubscriptionContainerTest.kt +++ b/domain/src/test/java/com/anytypeio/anytype/domain/subscriptions/StorelessSubscriptionContainerTest.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.StubObject import com.anytypeio.anytype.core_models.StubObjectMinim import com.anytypeio.anytype.core_models.SubscriptionEvent +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.common.DefaultCoroutineTestRule @@ -50,7 +51,12 @@ class StorelessSubscriptionContainerTest { computation = UnconfinedTestDispatcher() ) + private val defaultSpaceId = SpaceId( + MockDataFactory.randomUuid() + ) + private val defaultSearchParams = StoreSearchParams( + space = defaultSpaceId, filters = emptyList(), sorts = emptyList(), subscription = MockDataFactory.randomUuid(), @@ -342,6 +348,7 @@ class StorelessSubscriptionContainerTest { repo.stub { onBlocking { searchObjectsWithSubscription( + space = defaultSpaceId, subscription = params.subscription, sorts = params.sorts, filters = params.filters, diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentModels.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentModels.kt index 670b8c3d46..eb6020db95 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentModels.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentModels.kt @@ -15,12 +15,13 @@ import com.anytypeio.anytype.core_models.ext.DateParser import com.anytypeio.anytype.core_models.primitives.RelationKey import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction +import com.anytypeio.anytype.domain.all_content.RestoreAllContentState import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel.Companion.DEFAULT_INITIAL_SORT import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel.Companion.DEFAULT_INITIAL_TAB import com.anytypeio.anytype.presentation.library.DependentData import com.anytypeio.anytype.presentation.mapper.objectIcon import com.anytypeio.anytype.presentation.objects.ObjectIcon +import com.anytypeio.anytype.presentation.objects.getDescriptionOrSnippet import com.anytypeio.anytype.presentation.objects.getProperName import com.anytypeio.anytype.presentation.objects.getProperType @@ -104,6 +105,11 @@ sealed class UiContentState { ) : UiContentState() } +sealed class UiItemsState{ + data object Empty : UiItemsState() + data class Content(val items: List) : UiItemsState() +} + // ITEMS sealed class UiContentItem { abstract val id: String @@ -151,6 +157,18 @@ sealed class UiContentItem { val editable: Boolean = true, ) : UiContentItem() + data object NewRelation : UiContentItem() { + override val id: String = "NewRelation" + } + + data object NewType : UiContentItem() { + override val id: String = "NewType" + } + + data object UnlinkedDescription : UiContentItem() { + override val id: String = "UnlinkedDescription" + } + companion object { const val TODAY_ID = "TodayId" const val YESTERDAY_ID = "YesterdayId" @@ -188,13 +206,27 @@ sealed class MenuSortsItem { } //endregion +//region BOTTOM_MENU +data class AllContentBottomMenu(val isOwnerOrEditor: Boolean = true) +//endregion + +//region SNACKBAR +sealed class UiSnackbarState { + data object Hidden : UiSnackbarState() + data class Visible(val message: String, val objId: Id) : UiSnackbarState() +} +//endregion + //region MAPPING -fun Key?.mapRelationKeyToSort(): AllContentSort { - return when (this) { - Relations.CREATED_DATE -> AllContentSort.ByDateCreated() - Relations.LAST_MODIFIED_DATE -> AllContentSort.ByDateUpdated() - Relations.NAME -> AllContentSort.ByName() - else -> DEFAULT_INITIAL_SORT + +fun RestoreAllContentState.Response.Success.mapToSort(): AllContentSort { + val sortType = if (isAsc) DVSortType.ASC else DVSortType.DESC + return when (activeSort) { + Relations.CREATED_DATE -> AllContentSort.ByDateCreated(sortType = sortType) + Relations.LAST_MODIFIED_DATE -> AllContentSort.ByDateUpdated(sortType = sortType) + Relations.NAME -> AllContentSort.ByName(sortType = sortType) + Relations.LAST_USED_DATE -> AllContentSort.ByDateUsed(sortType = sortType) + else -> AllContentSort.ByName(sortType = DVSortType.ASC) } } @@ -216,12 +248,12 @@ fun ObjectWrapper.Basic.toAllContentItem( val obj = this val typeUrl = obj.getProperType() val isProfile = typeUrl == MarketplaceObjectTypeIds.PROFILE - val layout = layout ?: ObjectType.Layout.BASIC + val layout = obj.layout ?: ObjectType.Layout.BASIC return UiContentItem.Item( id = obj.id, space = space, name = obj.getProperName(), - description = obj.description, + description = getDescriptionOrSnippet(), type = typeUrl, typeName = objectTypes.firstOrNull { type -> if (isProfile) { diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentSearchParams.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentSearchParams.kt index 478a729db7..fa2d80beff 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentSearchParams.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/models/AllContentSearchParams.kt @@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeys import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeysObjectType @@ -61,6 +62,7 @@ fun createSubscriptionParams( activeMode = activeMode ) return StoreSearchParams( + space = SpaceId(spaceId), filters = filters, sorts = sorts, keys = keys, diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt index c709819d0b..44f61f3e83 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt @@ -27,18 +27,21 @@ import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import com.anytypeio.anytype.domain.page.CreateObject import com.anytypeio.anytype.domain.search.SearchObjects import com.anytypeio.anytype.domain.workspace.RemoveObjectsFromWorkspace +import com.anytypeio.anytype.feature_allcontent.models.AllContentBottomMenu import com.anytypeio.anytype.feature_allcontent.models.AllContentMenuMode import com.anytypeio.anytype.feature_allcontent.models.AllContentSort import com.anytypeio.anytype.feature_allcontent.models.AllContentTab import com.anytypeio.anytype.feature_allcontent.models.MenuSortsItem import com.anytypeio.anytype.feature_allcontent.models.UiContentItem import com.anytypeio.anytype.feature_allcontent.models.UiContentState +import com.anytypeio.anytype.feature_allcontent.models.UiItemsState import com.anytypeio.anytype.feature_allcontent.models.UiMenuState +import com.anytypeio.anytype.feature_allcontent.models.UiSnackbarState import com.anytypeio.anytype.feature_allcontent.models.UiTabsState import com.anytypeio.anytype.feature_allcontent.models.UiTitleState import com.anytypeio.anytype.feature_allcontent.models.createSubscriptionParams import com.anytypeio.anytype.feature_allcontent.models.filtersForSearch -import com.anytypeio.anytype.feature_allcontent.models.mapRelationKeyToSort +import com.anytypeio.anytype.feature_allcontent.models.mapToSort import com.anytypeio.anytype.feature_allcontent.models.toAnalyticsModeType import com.anytypeio.anytype.feature_allcontent.models.toAnalyticsSortType import com.anytypeio.anytype.feature_allcontent.models.toAnalyticsTabType @@ -109,12 +112,14 @@ class AllContentViewModel( ) : ViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate { private val searchResultIds = MutableStateFlow>(emptyList()) - private val sortState = MutableStateFlow(DEFAULT_INITIAL_SORT) + private val sortState = MutableStateFlow(AllContentSort.ByName()) val uiTitleState = MutableStateFlow(DEFAULT_INITIAL_MODE) val uiTabsState = MutableStateFlow(UiTabsState()) val uiMenuState = MutableStateFlow(UiMenuState.Hidden) - val uiItemsState = MutableStateFlow>(emptyList()) + val uiItemsState = MutableStateFlow(UiItemsState.Empty) val uiContentState = MutableStateFlow(UiContentState.Idle()) + val uiBottomMenu = MutableStateFlow(AllContentBottomMenu()) + val uiSnackbarState = MutableStateFlow(UiSnackbarState.Hidden) val commands = MutableSharedFlow() @@ -155,6 +160,8 @@ class AllContentViewModel( userPermissionProvider .observe(space = vmParams.spaceId) .collect { + uiBottomMenu.value = + AllContentBottomMenu(isOwnerOrEditor = it?.isOwnerOrEditor() == true) permission.value = it } } @@ -167,9 +174,14 @@ class AllContentViewModel( val initialParams = restoreAllContentState.run( RestoreAllContentState.Params(vmParams.spaceId) ) - if (!initialParams.activeSort.isNullOrEmpty()) { - sortState.value = initialParams.activeSort.mapRelationKeyToSort() - restartSubscription.value++ + when (initialParams) { + RestoreAllContentState.Response.Empty -> { + //do nothing + } + is RestoreAllContentState.Response.Success -> { + sortState.value = initialParams.mapToSort() + restartSubscription.value++ + } } }.onFailure { e -> Timber.e(e, "Error restoring state") @@ -196,7 +208,7 @@ class AllContentViewModel( success = { searchResults -> Timber.d("Search objects by query:[$query], size: : ${searchResults.size}") if (searchResults.isEmpty()) { - uiItemsState.value = emptyList() + uiItemsState.value = UiItemsState.Empty uiContentState.value = UiContentState.Empty } else { searchResultIds.value = searchResults.map { it.id } @@ -218,7 +230,12 @@ class AllContentViewModel( restartSubscription.flatMapLatest { loadData() }.collectLatest { items -> - uiItemsState.value = items + if (items.isEmpty()) { + uiItemsState.value = UiItemsState.Empty + uiContentState.value = UiContentState.Empty + } else { + uiItemsState.value = UiItemsState.Content(items) + } } } } @@ -290,20 +307,25 @@ class AllContentViewModel( activeSort: AllContentSort, activeTab: AllContentTab ): List { + val isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true return when (activeTab) { AllContentTab.TYPES -> { val items = objectWrappers.toUiContentTypes( urlBuilder = urlBuilder, - isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true + isOwnerOrEditor = isOwnerOrEditor ) - items + buildList { + if (isOwnerOrEditor) add(UiContentItem.NewType) + addAll(items) + } } AllContentTab.RELATIONS -> { - val items = objectWrappers.toUiContentRelations( - isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true - ) - items + val items = objectWrappers.toUiContentRelations(isOwnerOrEditor = isOwnerOrEditor) + buildList { + if (isOwnerOrEditor) add(UiContentItem.NewRelation) + addAll(items) + } } else -> { @@ -311,7 +333,7 @@ class AllContentViewModel( space = vmParams.spaceId, urlBuilder = urlBuilder, objectTypes = storeOfObjectTypes.getAll(), - isOwnerOrEditor = permission.value?.isOwnerOrEditor() == true + isOwnerOrEditor = isOwnerOrEditor ) val result = when (activeSort) { is AllContentSort.ByDateCreated -> { @@ -330,7 +352,14 @@ class AllContentViewModel( items } } - result + if (uiTitleState.value == UiTitleState.OnlyUnlinked) { + buildList { + add(UiContentItem.UnlinkedDescription) + addAll(result) + } + } else { + result + } } } } @@ -422,6 +451,7 @@ class AllContentViewModel( spaces = listOf(vmParams.spaceId.id) ) return SearchObjects.Params( + space = vmParams.spaceId, filters = filters, keys = listOf(Relations.ID), fulltext = activeQuery @@ -484,14 +514,14 @@ class AllContentViewModel( } else -> { listOf( - MenuSortsItem.Sort( - sort = AllContentSort.ByName(isSelected = activeSort is AllContentSort.ByName) - ), MenuSortsItem.Sort( sort = AllContentSort.ByDateUpdated(isSelected = activeSort is AllContentSort.ByDateUpdated) ), MenuSortsItem.Sort( sort = AllContentSort.ByDateCreated(isSelected = activeSort is AllContentSort.ByDateCreated) + ), + MenuSortsItem.Sort( + sort = AllContentSort.ByName(isSelected = activeSort is AllContentSort.ByName) ) ) } @@ -531,7 +561,7 @@ class AllContentViewModel( tab.updateInitialState() shouldScrollToTopItems = true resetLimit() - uiItemsState.value = emptyList() + uiItemsState.value = UiItemsState.Empty uiTabsState.value = uiTabsState.value.copy(selectedTab = tab) restartSubscription.value++ viewModelScope.launch { @@ -545,7 +575,7 @@ class AllContentViewModel( fun onAllContentModeClicked(mode: AllContentMenuMode) { Timber.d("onAllContentModeClicked: $mode") shouldScrollToTopItems = true - uiItemsState.value = emptyList() + uiItemsState.value = UiItemsState.Empty uiTitleState.value = when (mode) { is AllContentMenuMode.AllContent -> UiTitleState.AllContent is AllContentMenuMode.Unlinked -> UiTitleState.OnlyUnlinked @@ -576,7 +606,7 @@ class AllContentViewModel( } } shouldScrollToTopItems = true - uiItemsState.value = emptyList() + uiItemsState.value = UiItemsState.Empty sortState.value = newSort proceedWithSortSaving(uiTabsState.value, newSort) restartSubscription.value++ @@ -712,7 +742,10 @@ class AllContentViewModel( objType: ObjectWrapper.Type? = null ) { val startTime = System.currentTimeMillis() - val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId) + val params = objType?.uniqueKey.getCreateObjectParams( + space = vmParams.spaceId, + objType?.defaultTemplateId + ) viewModelScope.launch { createObject.async(params).fold( onSuccess = { result -> @@ -733,10 +766,22 @@ class AllContentViewModel( } } - fun onTypeClicked(item: UiContentItem.Type) { + fun onTypeClicked(item: UiContentItem) { Timber.d("onTypeClicked: $item") - viewModelScope.launch { - commands.emit(Command.OpenTypeEditing(item)) + when (item) { + UiContentItem.NewType -> { + viewModelScope.launch { + commands.emit(Command.OpenTypeCreation) + } + } + is UiContentItem.Type -> { + viewModelScope.launch { + commands.emit(Command.OpenTypeEditing(item)) + } + } + else -> { + //do nothing + } } viewModelScope.sendEvent( analytics = analytics, @@ -744,24 +789,38 @@ class AllContentViewModel( ) } - fun onRelationClicked(item: UiContentItem.Relation) { + fun onRelationClicked(item: UiContentItem) { Timber.d("onRelationClicked: $item") - viewModelScope.launch { - commands.emit( - Command.OpenRelationEditing( - typeName = item.name, - id = item.id, - iconUnicode = item.format.simpleIcon() ?: 0, - readOnly = item.readOnly - ) - ) - } - viewModelScope.launch { - viewModelScope.sendEvent( - analytics = analytics, - eventName = libraryScreenRelation - ) + when (item) { + UiContentItem.NewRelation -> { + viewModelScope.launch { + commands.emit( + Command.OpenRelationCreation( + space = vmParams.spaceId.id + ) + ) + } + } + is UiContentItem.Relation -> { + viewModelScope.launch { + commands.emit( + Command.OpenRelationEditing( + typeName = item.name, + id = item.id, + iconUnicode = item.format.simpleIcon() ?: 0, + readOnly = item.readOnly + ) + ) + } + } + else -> { + //do nothing + } } + viewModelScope.sendEvent( + analytics = analytics, + eventName = libraryScreenRelation + ) } fun onStart() { @@ -782,7 +841,7 @@ class AllContentViewModel( viewModelScope.launch { userInput.value = DEFAULT_QUERY searchResultIds.value = emptyList() - uiItemsState.value = emptyList() + uiItemsState.value = UiItemsState.Empty uiContentState.value = UiContentState.Empty } } @@ -796,7 +855,11 @@ class AllContentViewModel( setObjectListIsArchived.async(params).fold( onSuccess = { ids -> Timber.d("Successfully archived object: $ids") - commands.emit(Command.SendToast.ObjectArchived(item.name)) + val name = item.name + uiSnackbarState.value = UiSnackbarState.Visible( + message = name.take(10), + objId = item.id + ) }, onFailure = { e -> Timber.e(e, "Error while archiving object") @@ -806,6 +869,29 @@ class AllContentViewModel( } } + fun proceedWithUndoMoveToBin(objectId: Id) { + val params = SetObjectListIsArchived.Params( + targets = listOf(objectId), + isArchived = false + ) + viewModelScope.launch { + setObjectListIsArchived.async(params).fold( + onSuccess = { ids -> + Timber.d("Successfully archived object: $ids") + uiSnackbarState.value = UiSnackbarState.Hidden + }, + onFailure = { e -> + Timber.e(e, "Error while un-archiving object") + commands.emit(Command.SendToast.Error("Error while un-archiving object")) + } + ) + } + } + + fun proceedWithDismissSnackbar() { + uiSnackbarState.value = UiSnackbarState.Hidden + } + /** * Updates the limit for the number of items fetched and triggers data reload. */ @@ -819,7 +905,7 @@ class AllContentViewModel( override fun onCleared() { super.onCleared() - uiItemsState.value = emptyList() + uiItemsState.value = UiItemsState.Empty resetLimit() } @@ -893,14 +979,14 @@ class AllContentViewModel( data class ObjectArchived(val name: String) : SendToast() } data class OpenTypeEditing(val item: UiContentItem.Type) : Command() - data class OpenTypeCreation(val name: String): Command() + data object OpenTypeCreation: Command() data class OpenRelationEditing( val typeName: String, val id: Id, val iconUnicode: Int, val readOnly: Boolean ) : Command() - data class OpenRelationCreation(val id: Id, val name: String, val space: Id): Command() + data class OpenRelationCreation(val space: Id): Command() data object OpenGlobalSearch : Command() data object ExitToVault : Command() data object Back : Command() @@ -913,7 +999,6 @@ class AllContentViewModel( const val DEFAULT_SEARCH_LIMIT = 100 val DEFAULT_INITIAL_MODE = UiTitleState.AllContent val DEFAULT_INITIAL_TAB = AllContentTab.PAGES - val DEFAULT_INITIAL_SORT = AllContentSort.ByName() val DEFAULT_QUERY = "" } } diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentMenu.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentMenu.kt index b63dfd33b4..6e95ae6740 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentMenu.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentMenu.kt @@ -132,9 +132,10 @@ private fun SortingBox(modifier: Modifier, subtitle: String, isExpanded: Boolean ) { Image( modifier = Modifier - .size(32.dp) + .padding(start = 10.dp) + .size(18.dp) .rotate(rotationAngle), - painter = painterResource(R.drawable.ic_menu_arrow_right), + painter = painterResource(R.drawable.ic_arrow_disclosure_18), contentDescription = "", colorFilter = tint(colorResource(id = R.color.glyph_selected)) ) diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentScreen.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentScreen.kt index 7e84d835f6..f3298428d2 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentScreen.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column @@ -26,11 +27,15 @@ import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SwipeToDismissBox import androidx.compose.material3.SwipeToDismissBoxValue import androidx.compose.material3.Text @@ -39,6 +44,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -59,14 +65,17 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_ui.common.DefaultPreviews import com.anytypeio.anytype.core_ui.extensions.simpleIcon +import com.anytypeio.anytype.core_ui.extensions.swapList import com.anytypeio.anytype.core_ui.foundation.DismissBackground import com.anytypeio.anytype.core_ui.foundation.Divider import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable +import com.anytypeio.anytype.core_ui.views.BodyRegular import com.anytypeio.anytype.core_ui.views.ButtonSize import com.anytypeio.anytype.core_ui.views.Caption1Regular import com.anytypeio.anytype.core_ui.views.PreviewTitle1Medium @@ -79,15 +88,19 @@ import com.anytypeio.anytype.core_ui.widgets.ListWidgetObjectIcon import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK import com.anytypeio.anytype.feature_allcontent.BuildConfig import com.anytypeio.anytype.feature_allcontent.R +import com.anytypeio.anytype.feature_allcontent.models.AllContentBottomMenu import com.anytypeio.anytype.feature_allcontent.models.AllContentMenuMode import com.anytypeio.anytype.feature_allcontent.models.AllContentSort import com.anytypeio.anytype.feature_allcontent.models.AllContentTab import com.anytypeio.anytype.feature_allcontent.models.UiContentItem import com.anytypeio.anytype.feature_allcontent.models.UiContentState +import com.anytypeio.anytype.feature_allcontent.models.UiItemsState import com.anytypeio.anytype.feature_allcontent.models.UiMenuState +import com.anytypeio.anytype.feature_allcontent.models.UiSnackbarState import com.anytypeio.anytype.feature_allcontent.models.UiTabsState import com.anytypeio.anytype.feature_allcontent.models.UiTitleState import com.anytypeio.anytype.presentation.objects.ObjectIcon +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -97,49 +110,34 @@ fun AllContentWrapperScreen( uiTitleState: UiTitleState, uiTabsState: UiTabsState, uiMenuState: UiMenuState, - uiItemsState: List, + uiSnackbarState: UiSnackbarState, + uiItemsState: UiItemsState, + uiBottomMenu: AllContentBottomMenu, onTabClick: (AllContentTab) -> Unit, onQueryChanged: (String) -> Unit, onModeClick: (AllContentMenuMode) -> Unit, onSortClick: (AllContentSort) -> Unit, onItemClicked: (UiContentItem.Item) -> Unit, - onTypeClicked: (UiContentItem.Type) -> Unit, - onRelationClicked: (UiContentItem.Relation) -> Unit, + onTypeClicked: (UiContentItem) -> Unit, + onRelationClicked: (UiContentItem) -> Unit, onBinClick: () -> Unit, canPaginate: Boolean, onUpdateLimitSearch: () -> Unit, uiContentState: UiContentState, - onHomeClicked: () -> Unit, onGlobalSearchClicked: () -> Unit, onAddDocClicked: () -> Unit, onCreateObjectLongClicked: () -> Unit, onBackClicked: () -> Unit, onBackLongClicked: () -> Unit, - moveToBin: (UiContentItem.Item) -> Unit + moveToBin: (UiContentItem.Item) -> Unit, + undoMoveToBin: (Id) -> Unit, + onDismissSnackbar: () -> Unit ) { - val lazyListState = rememberLazyListState() - - val canPaginateState = remember { mutableStateOf(false) } - LaunchedEffect(key1 = canPaginate) { - canPaginateState.value = canPaginate - } - - val shouldStartPaging = remember { - derivedStateOf { - canPaginateState.value && (lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index - ?: -9) >= (lazyListState.layoutInfo.totalItemsCount - 2) - } - } - - LaunchedEffect(key1 = shouldStartPaging.value) { - if (shouldStartPaging.value && uiContentState is UiContentState.Idle) { - onUpdateLimitSearch() - } - } AllContentMainScreen( uiTitleState = uiTitleState, uiTabsState = uiTabsState, + uiSnackbarState = uiSnackbarState, onTabClick = onTabClick, onQueryChanged = onQueryChanged, uiMenuState = uiMenuState, @@ -148,46 +146,71 @@ fun AllContentWrapperScreen( onItemClicked = onItemClicked, onBinClick = onBinClick, uiItemsState = uiItemsState, - lazyListState = lazyListState, uiContentState = uiContentState, onTypeClicked = onTypeClicked, - onHomeClicked = onHomeClicked, onGlobalSearchClicked = onGlobalSearchClicked, onAddDocClicked = onAddDocClicked, onCreateObjectLongClicked = onCreateObjectLongClicked, onBackClicked = onBackClicked, onBackLongClicked = onBackLongClicked, moveToBin = moveToBin, - onRelationClicked = onRelationClicked + onRelationClicked = onRelationClicked, + uiBottomMenu = uiBottomMenu, + undoMoveToBin = undoMoveToBin, + onDismissSnackbar = onDismissSnackbar, + canPaginate = canPaginate, + onUpdateLimitSearch = onUpdateLimitSearch ) } @Composable fun AllContentMainScreen( - uiItemsState: List, + uiItemsState: UiItemsState, uiTitleState: UiTitleState, uiTabsState: UiTabsState, uiMenuState: UiMenuState, + uiSnackbarState: UiSnackbarState, + uiBottomMenu: AllContentBottomMenu, onTabClick: (AllContentTab) -> Unit, onQueryChanged: (String) -> Unit, onModeClick: (AllContentMenuMode) -> Unit, onSortClick: (AllContentSort) -> Unit, onItemClicked: (UiContentItem.Item) -> Unit, - onTypeClicked: (UiContentItem.Type) -> Unit, - onRelationClicked: (UiContentItem.Relation) -> Unit, + onTypeClicked: (UiContentItem) -> Unit, + onRelationClicked: (UiContentItem) -> Unit, onBinClick: () -> Unit, - lazyListState: LazyListState, uiContentState: UiContentState, - onHomeClicked: () -> Unit, onGlobalSearchClicked: () -> Unit, onAddDocClicked: () -> Unit, onCreateObjectLongClicked: () -> Unit, onBackClicked: () -> Unit, onBackLongClicked: () -> Unit, - moveToBin: (UiContentItem.Item) -> Unit + moveToBin: (UiContentItem.Item) -> Unit, + undoMoveToBin: (Id) -> Unit, + onDismissSnackbar: () -> Unit, + canPaginate: Boolean, + onUpdateLimitSearch: () -> Unit, ) { var isSearchEmpty by remember { mutableStateOf(true) } + val snackBarHostState = remember { SnackbarHostState() } + + val snackBarText = stringResource(R.string.all_content_snackbar_title) + val undoText = stringResource(R.string.undo) + + LaunchedEffect(key1 = uiSnackbarState) { + if (uiSnackbarState is UiSnackbarState.Visible) { + ShowMoveToBinSnackbar( + message = "'${uiSnackbarState.message}' $snackBarText", + undo = undoText, + scope = this, + snackBarHostState = snackBarHostState, + objectId = uiSnackbarState.objId, + undoMoveToBin = undoMoveToBin, + onDismissSnackbar = onDismissSnackbar + ) + } + } Scaffold( modifier = Modifier @@ -207,12 +230,12 @@ fun AllContentMainScreen( ) { BottomMenu( modifier = Modifier.align(Alignment.BottomCenter), - onHomeClicked = onHomeClicked, onGlobalSearchClicked = onGlobalSearchClicked, onAddDocClicked = onAddDocClicked, onCreateObjectLongClicked = onCreateObjectLongClicked, onBackClicked = onBackClicked, - onBackLongClicked = onBackLongClicked + onBackLongClicked = onBackLongClicked, + uiBottomMenu = uiBottomMenu ) } }, @@ -262,8 +285,8 @@ fun AllContentMainScreen( modifier = contentModifier, contentAlignment = Alignment.Center ) { - when { - uiItemsState.isEmpty() -> { + when (uiItemsState) { + UiItemsState.Empty -> { when (uiContentState) { is UiContentState.Error -> { ErrorState(uiContentState.message) @@ -284,27 +307,31 @@ fun AllContentMainScreen( } } - else -> { + is UiItemsState.Content -> { ContentItems( uiItemsState = uiItemsState, onItemClicked = onItemClicked, onTypeClicked = onTypeClicked, uiContentState = uiContentState, - lazyListState = lazyListState, moveToBin = moveToBin, - onRelationClicked = onRelationClicked + onRelationClicked = onRelationClicked, + canPaginate = canPaginate, + onUpdateLimitSearch = onUpdateLimitSearch ) } } } + }, + snackbarHost = { + SnackbarHost(hostState = snackBarHostState) } ) } @Composable fun BottomMenu( + uiBottomMenu: AllContentBottomMenu, modifier: Modifier = Modifier, - onHomeClicked: () -> Unit, onGlobalSearchClicked: () -> Unit, onAddDocClicked: () -> Unit, onCreateObjectLongClicked: () -> Unit, @@ -317,42 +344,69 @@ fun BottomMenu( modifier = modifier, backClick = onBackClicked, backLongClick = onBackLongClicked, - onProfileClicked = onHomeClicked, searchClick = onGlobalSearchClicked, addDocClick = onAddDocClicked, - onCreateObjectLongClicked = onCreateObjectLongClicked + addDocLongClick = onCreateObjectLongClicked, + isOwnerOrEditor = uiBottomMenu.isOwnerOrEditor ) } @Composable private fun ContentItems( - uiItemsState: List, + uiItemsState: UiItemsState.Content, onItemClicked: (UiContentItem.Item) -> Unit, - onTypeClicked: (UiContentItem.Type) -> Unit, - onRelationClicked: (UiContentItem.Relation) -> Unit, + onTypeClicked: (UiContentItem) -> Unit, + onRelationClicked: (UiContentItem) -> Unit, uiContentState: UiContentState, - lazyListState: LazyListState, - moveToBin: (UiContentItem.Item) -> Unit + canPaginate: Boolean, + moveToBin: (UiContentItem.Item) -> Unit, + onUpdateLimitSearch: () -> Unit ) { + val items = remember { mutableStateListOf() } + items.swapList(uiItemsState.items) + val scope = rememberCoroutineScope() + val lazyListState = rememberLazyListState() + + val canPaginateState = remember { mutableStateOf(false) } + LaunchedEffect(key1 = canPaginate) { + canPaginateState.value = canPaginate + } + + val shouldStartPaging = remember { + derivedStateOf { + canPaginateState.value && (lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index + ?: -9) >= (lazyListState.layoutInfo.totalItemsCount - 2) + } + } + + LaunchedEffect(key1 = shouldStartPaging.value) { + if (shouldStartPaging.value && uiContentState is UiContentState.Idle) { + onUpdateLimitSearch() + } + } + LazyColumn( modifier = Modifier.fillMaxSize(), state = lazyListState ) { items( - count = uiItemsState.size, - key = { index -> uiItemsState[index].id }, + count = items.size, + key = { index -> items[index].id }, contentType = { index -> - when (uiItemsState[index]) { + when (items[index]) { is UiContentItem.Group -> "group" is UiContentItem.Item -> "item" is UiContentItem.Type -> "type" is UiContentItem.Relation -> "relation" + UiContentItem.NewRelation -> "new_relation" + UiContentItem.NewType -> "new_type" + UiContentItem.UnlinkedDescription -> "unlinked_description" } } ) { index -> - when (val item = uiItemsState[index]) { + when (val item = items[index]) { is UiContentItem.Group -> { Box( modifier = Modifier @@ -412,6 +466,29 @@ private fun ContentItems( item = item ) } + + UiContentItem.NewRelation -> { + AddItem( + modifier = Modifier + .clickable { onRelationClicked(item) }, + text = stringResource(id = R.string.all_content_new_relation) + ) + Divider(paddingStart = 16.dp, paddingEnd = 16.dp) + } + + UiContentItem.NewType -> { + AddItem( + modifier = Modifier + .clickable { onTypeClicked(item) }, + text = stringResource(id = R.string.all_content_new_type) + ) + Divider(paddingStart = 16.dp, paddingEnd = 16.dp) + } + + UiContentItem.UnlinkedDescription -> { + UnlinkedDescription() + Divider(paddingStart = 16.dp, paddingEnd = 16.dp) + } } } if (uiContentState is UiContentState.Paging) { @@ -442,6 +519,48 @@ private fun ContentItems( } } +@Composable +private fun LazyItemScope.UnlinkedDescription() { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .height(64.dp) + .animateItem(), + contentAlignment = Alignment.CenterStart + ) { + Text( + text = stringResource(id = R.string.all_content_unlinked_description), + style = Caption1Regular, + color = colorResource(id = R.color.text_secondary), + ) + } +} + +@Composable +private fun LazyItemScope.AddItem(modifier: Modifier, text: String) { + Box( + modifier = modifier + .fillMaxWidth() + .height(52.dp) + .padding(horizontal = 16.dp) + .animateItem(), + contentAlignment = Alignment.CenterStart + ) { + Image( + painter = painterResource(id = R.drawable.ic_default_plus), + contentDescription = text, + modifier = Modifier.size(24.dp) + ) + Text( + modifier = Modifier.padding(start = 34.dp), + text = text, + style = BodyRegular, + color = colorResource(id = R.color.text_secondary), + ) + } +} + @Composable private fun BoxScope.LoadingState() { val loadingAlpha by animateFloatAsState(targetValue = 1f, label = "") @@ -468,7 +587,7 @@ fun PreviewLoadingState() { @Composable fun PreviewMainScreen() { AllContentMainScreen( - uiItemsState = emptyList(), + uiItemsState = UiItemsState.Empty, uiTitleState = UiTitleState.AllContent, uiTabsState = UiTabsState( tabs = listOf( @@ -484,17 +603,21 @@ fun PreviewMainScreen() { onSortClick = {}, onItemClicked = {}, onBinClick = {}, - lazyListState = rememberLazyListState(), uiContentState = UiContentState.Error("Error message"), onTypeClicked = {}, - onHomeClicked = {}, onGlobalSearchClicked = {}, onAddDocClicked = {}, onCreateObjectLongClicked = {}, onBackClicked = {}, moveToBin = {}, onBackLongClicked = {}, - onRelationClicked = {} + onRelationClicked = {}, + uiBottomMenu = AllContentBottomMenu(isOwnerOrEditor = false), + uiSnackbarState = UiSnackbarState.Hidden, + undoMoveToBin = {}, + onDismissSnackbar = {}, + canPaginate = true, + onUpdateLimitSearch = {} ) } @@ -614,7 +737,10 @@ private fun Relation( @Composable private fun ErrorState(message: String) { - Column { + Column( + modifier = Modifier + .windowInsetsPadding(WindowInsets.ime) + ) { Text( modifier = Modifier .fillMaxWidth() @@ -644,7 +770,10 @@ private fun EmptyState(isSearchEmpty: Boolean) { } else { stringResource(R.string.allContent_empty_state_title) to stringResource(R.string.allContent_empty_state_description) } - Column { + Column( + modifier = Modifier + .windowInsetsPadding(WindowInsets.ime) + ) { Text( modifier = Modifier .fillMaxWidth(), @@ -712,6 +841,7 @@ fun SwipeToDismissListItems( ) { var isRemoved by remember { mutableStateOf(false) } val dismissState = rememberSwipeToDismissBoxState( + initialValue = SwipeToDismissBoxValue.Settled, confirmValueChange = { value -> if (value == SwipeToDismissBoxValue.EndToStart) { isRemoved = true @@ -723,6 +853,12 @@ fun SwipeToDismissListItems( positionalThreshold = { it * .5f } ) + if (dismissState.currentValue != SwipeToDismissBoxValue.Settled) { + LaunchedEffect(Unit) { + dismissState.snapTo(SwipeToDismissBoxValue.Settled) + } + } + LaunchedEffect(key1 = isRemoved) { if (isRemoved) { delay(animationDuration.toLong()) @@ -752,6 +888,35 @@ fun SwipeToDismissListItems( } } +private fun ShowMoveToBinSnackbar( + objectId: Id, + message: String, + undo: String, + scope: CoroutineScope, + snackBarHostState: SnackbarHostState, + undoMoveToBin: (Id) -> Unit, + onDismissSnackbar: () -> Unit +) { + scope.launch { + val result = snackBarHostState + .showSnackbar( + message = message, + actionLabel = undo, + duration = SnackbarDuration.Short, + withDismissAction = true + ) + when (result) { + SnackbarResult.ActionPerformed -> { + undoMoveToBin(objectId) + } + + SnackbarResult.Dismissed -> { + onDismissSnackbar() + } + } + } +} + @DefaultPreviews @Composable fun MtSwipeToDismissListItems() { diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentTopToolbar.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentTopToolbar.kt index 40870bbfdf..fc1dac2f6f 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentTopToolbar.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/ui/AllContentTopToolbar.kt @@ -101,14 +101,8 @@ fun AllContentTopBarContainer( ) { AllContentMenu( uiMenuState = uiMenuState, - onModeClick = { - onModeClick(it) - isMenuExpanded = false - }, - onSortClick = { - onSortClick(it) - isMenuExpanded = false - }, + onModeClick = onModeClick, + onSortClick = onSortClick, onBinClick = onBinClick ) } diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt index ce15154444..8cfcc1dc04 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt @@ -34,6 +34,7 @@ import androidx.core.graphics.toColorInt import coil.compose.rememberAsyncImagePainter import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_ui.R +import com.anytypeio.anytype.core_ui.features.SpaceIconView import com.anytypeio.anytype.core_ui.foundation.Dragger import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable import com.anytypeio.anytype.core_ui.views.Title3 @@ -129,11 +130,13 @@ private fun SpaceItem(space: GallerySpaceView, onSpaceClick: (GallerySpaceView) .noRippleThrottledClickable { onSpaceClick(space) }, verticalAlignment = Alignment.CenterVertically ) { - SpaceIcon( + SpaceIconView( icon = space.icon, - modifier = Modifier - .size(48.dp) - .clip(RoundedCornerShape(8.dp)) + modifier = Modifier, + mainSize = 48.dp, + onSpaceIconClick = { + // Do nothing + } ) Text( modifier = Modifier @@ -146,45 +149,6 @@ private fun SpaceItem(space: GallerySpaceView, onSpaceClick: (GallerySpaceView) } } -@Composable -private fun SpaceIcon( - icon: SpaceIconView, - modifier: Modifier -) { - when (icon) { - is SpaceIconView.Image -> { - Image( - painter = rememberAsyncImagePainter( - model = icon.url, - error = painterResource(id = R.drawable.ic_home_widget_space) - ), - contentDescription = "Custom image space icon", - contentScale = ContentScale.Crop, - modifier = modifier - .clip(RoundedCornerShape(4.dp)) - ) - } - - is SpaceIconView.Gradient -> { - val gradient = Brush.radialGradient( - colors = listOf( - Color(icon.from.toColorInt()), - Color(icon.to.toColorInt()) - ) - ) - Box( - modifier = modifier - .clip(CircleShape) - .background(gradient) - ) - } - - else -> { - // Draw nothing. - } - } -} - @Preview(showBackground = true) @Composable private fun GallerySpacesScreenPreview() { diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt index 20254c11a4..661cc67c1e 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.fold +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.gallery_experience.DownloadGalleryManifest import com.anytypeio.anytype.domain.gallery_experience.ImportExperience import com.anytypeio.anytype.domain.misc.UrlBuilder @@ -27,7 +28,6 @@ import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationNaviga import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationSpacesState import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationState import com.anytypeio.anytype.gallery_experience.models.GallerySpaceView -import com.anytypeio.anytype.presentation.spaces.SelectSpaceViewModel.Companion.MAX_SPACE_COUNT import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import com.anytypeio.anytype.presentation.spaces.spaceIcon import kotlinx.coroutines.flow.MutableSharedFlow @@ -45,7 +45,8 @@ class GalleryInstallationViewModel( private val urlBuilder: UrlBuilder, private val spaceGradientProvider: SpaceGradientProvider, private val userPermissionProvider: UserPermissionProvider, - private val eventProcessChannel: EventProcessImportChannel + private val eventProcessChannel: EventProcessImportChannel, + private val configStorage: ConfigStorage ) : ViewModel() { val mainState = MutableStateFlow(GalleryInstallationState.Loading) @@ -83,26 +84,33 @@ class GalleryInstallationViewModel( fun onInstallClicked() { viewModelScope.launch { - getSpaceViews.async(Unit).fold( - onSuccess = { spaces -> - Timber.d("GetSpaceViews success, spaceViews: $spaces") - val filteredSpaces = filterSpacesByPermissions(spaces) - spacesViewState.value = GalleryInstallationSpacesState( - spaces = filteredSpaces.map { - it.toView(urlBuilder, spaceGradientProvider) - }, - isNewButtonVisible = filteredSpaces.size < MAX_SPACE_COUNT - ) - command.emit(GalleryInstallationNavigation.Spaces) - }, - onFailure = { error -> - Timber.e(error, "GetSpaceViews failed") - errorState.emit("Get Spaces error: ${error.message}") - } - ) - analytics.sendEvent( - eventName = EventsDictionary.clickGalleryInstall - ) + val techSpace = configStorage.getOrNull()?.techSpace + if (techSpace != null) { + getSpaceViews.async( + SpaceId(techSpace) + ).fold( + onSuccess = { spaces -> + Timber.d("GetSpaceViews success, spaceViews: $spaces") + val filteredSpaces = filterSpacesByPermissions(spaces) + spacesViewState.value = GalleryInstallationSpacesState( + spaces = filteredSpaces.map { + it.toView(urlBuilder, spaceGradientProvider) + }, + isNewButtonVisible = true + ) + command.emit(GalleryInstallationNavigation.Spaces) + }, + onFailure = { error -> + Timber.e(error, "GetSpaceViews failed") + errorState.emit("Get Spaces error: ${error.message}") + } + ) + analytics.sendEvent( + eventName = EventsDictionary.clickGalleryInstall + ) + } else { + Timber.e("Tech space not found during gallery installation") + } } } diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt index f6f87eddc2..331f78366e 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt @@ -3,6 +3,7 @@ package com.anytypeio.anytype.gallery_experience.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.anytypeio.anytype.analytics.base.Analytics +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.gallery_experience.DownloadGalleryManifest import com.anytypeio.anytype.domain.gallery_experience.ImportExperience import com.anytypeio.anytype.domain.misc.UrlBuilder @@ -23,7 +24,8 @@ class GalleryInstallationViewModelFactory @Inject constructor( private val urlBuilder: UrlBuilder, private val spaceGradientProvider: SpaceGradientProvider, private val userPermissionProvider: UserPermissionProvider, - private val eventProcessChannel: EventProcessImportChannel + private val eventProcessChannel: EventProcessImportChannel, + private val configStorage: ConfigStorage ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { @@ -37,7 +39,8 @@ class GalleryInstallationViewModelFactory @Inject constructor( spaceGradientProvider = spaceGradientProvider, createSpace = createSpace, userPermissionProvider = userPermissionProvider, - eventProcessChannel = eventProcessChannel + eventProcessChannel = eventProcessChannel, + configStorage = configStorage ) as T } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f09c14b6cd..8e1514f37c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -middlewareVersion = "v0.36.0-rc8" +middlewareVersion = "v0.36.0-rc9" kotlinVersion = '2.0.0' kspVersion = "2.0.0-1.0.22" diff --git a/libs/build.gradle b/libs/build.gradle index 51bc8e0722..3b44a88010 100644 --- a/libs/build.gradle +++ b/libs/build.gradle @@ -9,7 +9,7 @@ afterEvaluate { artifact(file('lib.aar')) groupId 'io.anyproto' artifactId 'anytype-heart-android' - version = '0.30.0-snapshot' + version = '9e8c87fd4c10497a7f2b7c7b6c169f646d975980' } } } diff --git a/localization/src/main/res/values/strings.xml b/localization/src/main/res/values/strings.xml index 877c300798..1fdc96b9d0 100644 --- a/localization/src/main/res/values/strings.xml +++ b/localization/src/main/res/values/strings.xml @@ -1497,7 +1497,7 @@ Pick your unique name This is your unique name on the Anytype network, confirming your Membership. It acts as your personal domain and cannot be changed. Myself - .any + .any Min 7 characters This name is already taken! This name [%1$s] is up for grabs! @@ -1803,4 +1803,13 @@ Please provide specific details of your needs here. Object type removed Object archived + New relation + New type + Unlinked objects that do not have a direct link or backlink with other objects in the graph. + moved to bin + + Back button + Search objects button + Create object button + \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt index fe0e0678d6..f9f7216452 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt @@ -336,6 +336,7 @@ class BlockMiddleware( ) override suspend fun searchObjects( + space: SpaceId, sorts: List, filters: List, fulltext: String, @@ -343,6 +344,7 @@ class BlockMiddleware( limit: Int, keys: List ): List> = middleware.objectSearch( + space = space, sorts = sorts, filters = filters, fulltext = fulltext, @@ -356,6 +358,7 @@ class BlockMiddleware( ): List = middleware.objectSearchWithMeta(command) override suspend fun searchObjectsWithSubscription( + space: SpaceId, subscription: Id, sorts: List, filters: List, @@ -369,6 +372,7 @@ class BlockMiddleware( noDepSubscription: Boolean?, collection: Id? ): SearchResult = middleware.objectSearchSubscribe( + space = space, subscription = subscription, sorts = sorts, filters = filters, @@ -384,10 +388,12 @@ class BlockMiddleware( ) override suspend fun searchObjectsByIdWithSubscription( + space: SpaceId, subscription: Id, ids: List, keys: List ): SearchResult = middleware.objectIdsSubscribe( + space = space, subscription = subscription, ids = ids, keys = keys diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index 97863cd55b..25be777fcb 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -1049,11 +1049,13 @@ class Middleware @Inject constructor( @Throws(Exception::class) fun objectIdsSubscribe( + space: SpaceId, subscription: Id, ids: List, keys: List ): SearchResult { val request = Rpc.Object.SubscribeIds.Request( + spaceId = space.id, subId = subscription, keys = keys, ids = ids @@ -1227,6 +1229,7 @@ class Middleware @Inject constructor( @Throws(Exception::class) fun objectSearch( + space: SpaceId, sorts: List, filters: List, fulltext: String, @@ -1235,6 +1238,7 @@ class Middleware @Inject constructor( keys: List ): List> { val request = Rpc.Object.Search.Request( + spaceId = space.id, sorts = sorts.map { it.toMiddlewareModel() }, filters = filters.map { it.toMiddlewareModel() }, fullText = fulltext, @@ -1251,6 +1255,7 @@ class Middleware @Inject constructor( @Throws(Exception::class) fun objectSearchWithMeta(command: Command.SearchWithMeta): List { val request = Rpc.Object.SearchWithMeta.Request( + spaceId = command.space.id, sorts = command.sorts.map { it.toMiddlewareModel() }, filters = command.filters.map { it.toMiddlewareModel() }, fullText = command.query, @@ -1266,6 +1271,7 @@ class Middleware @Inject constructor( @Throws(Exception::class) fun objectSearchSubscribe( + space: SpaceId, subscription: Id, sorts: List, filters: List, @@ -1280,6 +1286,7 @@ class Middleware @Inject constructor( collection: Id? ): SearchResult { val request = Rpc.Object.SearchSubscribe.Request( + spaceId = space.id, subId = subscription, sorts = sorts.map { it.toMiddlewareModel() }, filters = filters.map { it.toMiddlewareModel() }, @@ -1289,7 +1296,6 @@ class Middleware @Inject constructor( beforeId = beforeId.orEmpty(), afterId = afterId.orEmpty(), source = source, - ignoreWorkspace = ignoreWorkspace?.toString() ?: "", noDepSubscription = noDepSubscription ?: false, collectionId = collection.orEmpty() ) @@ -1966,7 +1972,7 @@ class Middleware @Inject constructor( fun workspaceCreate(details: Struct): Id { val request = Rpc.Workspace.Create.Request( details = details, - useCase = Rpc.Object.ImportUseCase.Request.UseCase.EMPTY + useCase = Rpc.Object.ImportUseCase.Request.UseCase.GET_STARTED ) logRequestIfDebug(request) val (response, time) = measureTimedValue { service.workspaceCreate(request) } diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/MiddlewareProtobufLogger.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/MiddlewareProtobufLogger.kt index bd4d6710f3..82dfe718fd 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/MiddlewareProtobufLogger.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/MiddlewareProtobufLogger.kt @@ -21,32 +21,35 @@ interface MiddlewareProtobufLogger { private val featureToggles: FeatureToggles ) : MiddlewareProtobufLogger { + private val isConciseLogging: Boolean + get() = featureToggles.isConciseLogging + override fun logRequest(any: Any) { if (featureToggles.isLogMiddlewareInteraction) { - Timber.d("request -> ${any.toLogMessage()}") + Timber.d("request -> ${any.toLogMessage(isConciseLogging)}") } } override fun logResponse(any: Any) { if (featureToggles.isLogMiddlewareInteraction) { - Timber.d("response -> ${any.toLogMessage()}") + Timber.d("response -> ${any.toLogMessage(isConciseLogging)}") } } override fun logResponse(any: Any, time: Duration?) { - Timber.d("response -> ${any.toLogMessage()} [${time.format()}ms] ") + Timber.d("response -> ${any.toLogMessage(isConciseLogging)} [${time.format()}ms] ") } private fun Duration?.format(): Long? = this?.toLong(DurationUnit.MILLISECONDS) override fun logEvent(any: Any) { if (featureToggles.isLogMiddlewareInteraction) { - Timber.d("event -> ${any.toLogMessage()}") + Timber.d("event -> ${any.toLogMessage(isConciseLogging)}") } } - private fun Any.toLogMessage(): String { - return if (featureToggles.isConciseLogging) { + private fun Any.toLogMessage(isConcise: Boolean): String { + return if (isConcise) { this::class.java.canonicalName } else { "${this::class.java.canonicalName}:\n${ diff --git a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt index aa6bb063b6..d7a73e594a 100644 --- a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt +++ b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt @@ -458,16 +458,13 @@ class DefaultUserSettingsCache( } } - override suspend fun getAllContentSort(space: SpaceId): Pair { - return context.spacePrefsStore - .data - .map { preferences -> - val pref = preferences.preferences[space.id]?.allContent - val sortKey = pref?.sortKey.orEmpty() - val isAsc = pref?.isAscending ?: true - sortKey to isAsc - } - .first() + override suspend fun getAllContentSort(space: SpaceId): Pair? { + val flow = context.spacePrefsStore.data + val first = flow.first() + val pref = first.preferences[space.id]?.allContent + val sortKey = pref?.sortKey ?: return null + val isAsc = pref.isAscending ?: true + return sortKey to isAsc } override suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean) { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt index 9690f73855..0fca0f132a 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt @@ -469,6 +469,7 @@ class EditorViewModel( .flatMapLatest { config -> storelessSubscriptionContainer.subscribe( StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(config.profile), keys = listOf( @@ -3340,7 +3341,10 @@ class EditorViewModel( objType: ObjectWrapper.Type? ) { val startTime = System.currentTimeMillis() - val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId) + val params = objType?.uniqueKey.getCreateObjectParams( + space = vmParams.space, + objType?.defaultTemplateId + ) viewModelScope.launch { createObject.async(params = params).fold( onSuccess = { result -> @@ -4113,10 +4117,10 @@ class EditorViewModel( is ObjectRelationView.ObjectType.Base -> { viewModelScope.launch { val params = FindObjectSetForType.Params( + space = vmParams.space, type = relation.type, filters = ObjectSearchConstants.setsByObjectTypeFilters( - types = listOf(relation.type), - space = vmParams.space.id + types = listOf(relation.type) ) ) findObjectSetForType(params).process( @@ -5140,11 +5144,9 @@ class EditorViewModel( ) { viewModelScope.launch { val params = GetObjectTypes.Params( + space = vmParams.space, sorts = sorts, filters = ObjectSearchConstants.filterTypes( - spaces = buildList { - add(vmParams.space.id) - }, recommendedLayouts = SupportedLayouts.editorLayouts ), keys = ObjectSearchConstants.defaultKeysObjectType @@ -6024,7 +6026,7 @@ class EditorViewModel( fun onAddMentionNewPageClicked(mentionText: String) { Timber.d("onAddMentionNewPageClicked, mentionText:[$mentionText]") viewModelScope.launch { - getDefaultObjectType.async(Unit).fold( + getDefaultObjectType.async(vmParams.space).fold( onFailure = { Timber.e(it, "Error while getting default object type") sendToast("Error while getting default object type, couldn't create a new mention") @@ -6168,14 +6170,10 @@ class EditorViewModel( } val fullText = filter.removePrefix(MENTION_PREFIX) val params = SearchObjects.Params( + space = vmParams.space, limit = ObjectSearchViewModel.SEARCH_LIMIT, filters = ObjectSearchConstants.getFilterLinkTo( - ignore = context, - spaces = buildList { - add(vmParams.space.id) - val config = spaceManager.getConfig(vmParams.space) - if (config != null) add(config.techSpace) - }, + ignore = context ), sorts = ObjectSearchConstants.sortLinkTo, fulltext = fullText, @@ -6283,12 +6281,10 @@ class EditorViewModel( val params = GetObjectTypes.Params( sorts = emptyList(), filters = ObjectSearchConstants.filterTypes( - spaces = buildList { - add(vmParams.space.id) - }, recommendedLayouts = SupportedLayouts.createObjectLayouts ), - keys = ObjectSearchConstants.defaultKeysObjectType + keys = ObjectSearchConstants.defaultKeysObjectType, + space = vmParams.space ) getObjectTypes.async(params).fold( onFailure = { Timber.e(it, "Error while getting library object types") }, @@ -6417,7 +6413,7 @@ class EditorViewModel( fun proceedToCreateObjectAndAddToTextAsLink(name: String) { Timber.d("proceedToCreateObjectAndAddToTextAsLink, name:[$name]") viewModelScope.launch { - getDefaultObjectType.async(Unit).fold( + getDefaultObjectType.async(vmParams.space).fold( onFailure = { Timber.e(it, "Error while getting default object type") }, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt index 9dea75be43..f0d7c1096c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt @@ -687,7 +687,6 @@ sealed class BlockView : ViewType { override var cursor: Int? = null, override val searchFields: List = emptyList(), override val hint: String? = null, - val spaceGradient: SpaceIconView.Gradient? = null ) : Title(), Searchable { override fun getViewType() = HOLDER_PROFILE_TITLE } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt index e68dd9a5b5..ffb4cf519e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/render/DefaultBlockViewRenderer.kt @@ -1531,7 +1531,6 @@ class DefaultBlockViewRenderer @Inject constructor( image = details.details[root.id]?.iconImage?.takeIf { it.isNotBlank() }?.let { urlBuilder.medium(it) }, - spaceGradient = null, isFocused = resolveIsFocused(focus, block), cursor = cursor, coverColor = coverContainer.coverColor, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt index 183cd9ae1c..0e0c04f682 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt @@ -258,11 +258,12 @@ class VersionHistoryViewModel( private fun getSpaceMembers() { viewModelScope.launch { val filters = - ObjectSearchConstants.filterParticipants(spaces = listOf(vmParams.spaceId.id)) + ObjectSearchConstants.filterParticipants(vmParams.spaceId) objectSearch( SearchObjects.Params( filters = filters, - keys = ObjectSearchConstants.spaceMemberKeys + keys = ObjectSearchConstants.spaceMemberKeys, + space = vmParams.spaceId ) ).process( failure = { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt index 59742689de..c2bf4243da 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt @@ -568,6 +568,7 @@ class HomeScreenViewModel( .flatMapLatest { config -> storelessSubscriptionContainer.subscribe( StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(config.profile), keys = listOf( @@ -1367,7 +1368,10 @@ class HomeScreenViewModel( Timber.d("onCreateNewObjectClicked, type:[${objType?.uniqueKey}]") val startTime = System.currentTimeMillis() viewModelScope.launch { - val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId) + val params = objType?.uniqueKey.getCreateObjectParams( + space = SpaceId(spaceManager.get()), + objType?.defaultTemplateId + ) createObject.stream(params).collect { createObjectResponse -> createObjectResponse.fold( onSuccess = { result -> @@ -1452,7 +1456,7 @@ class HomeScreenViewModel( } } .onEach { (config, pinned) -> - val defaultObjectType = getDefaultObjectType.async(Unit).getOrNull()?.type + val defaultObjectType = getDefaultObjectType.async(SpaceId(config.space)).getOrNull()?.type val keys = buildSet { pinned.take(MAX_PINNED_TYPE_COUNT_FOR_APP_ACTIONS).forEach { typeId -> val wrapper = storeOfObjectTypes.get(typeId.id) @@ -1478,19 +1482,13 @@ class HomeScreenViewModel( } searchObjects( SearchObjects.Params( + space = SpaceId(config.space), keys = buildList { add(Relations.ID) add(Relations.UNIQUE_KEY) add(Relations.NAME) }, filters = buildList { - add( - DVFilter( - relation = Relations.SPACE_ID, - value = config.space, - condition = DVFilterCondition.EQUAL - ) - ) add( DVFilter( relation = Relations.LAYOUT, @@ -1704,6 +1702,10 @@ class HomeScreenViewModel( } } + fun onBackLongClicked() { + navigate(destination = Navigation.OpenSpaceSwitcher) + } + override fun onCleared() { super.onCleared() Timber.d("onCleared") @@ -1775,6 +1777,7 @@ class HomeScreenViewModel( viewModelScope.launch { createObject.async( params = CreateObject.Param( + space = SpaceId(spaceManager.get()), type = type.uniqueKey?.let { TypeKey(it) } @@ -1808,6 +1811,7 @@ class HomeScreenViewModel( viewModelScope.launch { createObject.async( params = CreateObject.Param( + space = SpaceId(spaceManager.get()), type = type.uniqueKey?.let { TypeKey(it) } @@ -2071,6 +2075,7 @@ class HomeScreenViewModel( data class OpenObject(val ctx: Id, val space: Id) : Navigation() data class OpenSet(val ctx: Id, val space: Id, val view: Id?) : Navigation() data class ExpandWidget(val subscription: Subscription, val space: Id) : Navigation() + data object OpenSpaceSwitcher: Navigation() data class OpenLibrary(val space: Id) : Navigation() data class OpenAllContent(val space: Id) : Navigation() } 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 6dc032f96f..117436f406 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 @@ -152,6 +152,7 @@ class LibraryViewModel( .flatMapLatest { config -> storelessSubscriptionContainer.subscribe( StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(config.profile), keys = listOf( @@ -204,8 +205,11 @@ class LibraryViewModel( objType: ObjectWrapper.Type? = null ) { val startTime = System.currentTimeMillis() - val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId) viewModelScope.launch { + val params = objType?.uniqueKey.getCreateObjectParams( + space = SpaceId(spaceManager.get()), + objType?.defaultTemplateId + ) createObject.async(params).fold( onSuccess = { result -> proceedWithOpeningObject(result.obj) 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 10db0aab6d..5dac6bc4c9 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 @@ -1,5 +1,7 @@ package com.anytypeio.anytype.presentation.library.delegates +import com.anytypeio.anytype.core_models.Marketplace.MARKETPLACE_SPACE_ID +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -44,6 +46,7 @@ class LibraryRelationsDelegate @Inject constructor( private fun buildSearchParams(): StoreSearchParams { return StoreSearchParams( + space = SpaceId(MARKETPLACE_SPACE_ID), subscription = SUB_LIBRARY_RELATIONS, keys = ObjectSearchConstants.defaultRelationKeys, filters = buildList { 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 f34b430f60..a57021a833 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 @@ -1,6 +1,7 @@ package com.anytypeio.anytype.presentation.library.delegates import com.anytypeio.anytype.core_models.Marketplace.MARKETPLACE_SPACE_ID +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -46,11 +47,10 @@ class LibraryTypesDelegate @Inject constructor( private fun buildSearchParams(): StoreSearchParams { return StoreSearchParams( + space = SpaceId(MARKETPLACE_SPACE_ID), subscription = SUB_LIBRARY_TYPES, keys = ObjectSearchConstants.defaultKeys, - filters = ObjectSearchConstants.filterTypes( - spaces = listOf(MARKETPLACE_SPACE_ID) - ) + filters = ObjectSearchConstants.filterTypes() ) } 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 12018fdfe6..7a021773b5 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,6 +4,7 @@ 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.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -60,17 +61,11 @@ class MyRelationsDelegate @Inject constructor( private fun buildSearchParams(space: Id): StoreSearchParams { return StoreSearchParams( + space = SpaceId(space), subscription = SUB_LIBRARY_MY_RELATIONS, keys = ObjectSearchConstants.defaultRelationKeys, filters = buildList { addAll(ObjectSearchConstants.filterMyRelations()) - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ) - ) } ) } 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 7a5ecacb85..3ec54c72cf 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 @@ -2,6 +2,7 @@ package com.anytypeio.anytype.presentation.library.delegates import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -57,13 +58,13 @@ class MyTypesDelegate @Inject constructor( private fun buildSearchParams(space: Id): StoreSearchParams { return StoreSearchParams( + space = SpaceId(space), subscription = SUB_LIBRARY_MY_TYPES, keys = ObjectSearchConstants.defaultKeys + listOf( Relations.SOURCE_OBJECT, Relations.RESTRICTIONS ), filters = ObjectSearchConstants.filterTypes( - spaces = listOf(space), excludeParticipant = false ) ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/BackLinkOrAddToObjectViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/BackLinkOrAddToObjectViewModel.kt index 0907eb642a..e37903943d 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/BackLinkOrAddToObjectViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/BackLinkOrAddToObjectViewModel.kt @@ -5,12 +5,12 @@ import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.Resultat import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.search.SearchObjects import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.domain.workspace.getSpaceWithTechSpace import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate import com.anytypeio.anytype.presentation.navigation.DefaultObjectView import com.anytypeio.anytype.presentation.objects.ObjectIcon @@ -52,12 +52,12 @@ class BackLinkOrAddToObjectViewModel( ) override suspend fun getSearchObjectsParams(ignore: Id?): SearchObjects.Params { - val spaces = spaceManager.getSpaceWithTechSpace() + // TODO DROID-2916 Provide space id to vm params return SearchObjects.Params( + space = SpaceId(spaceManager.get()), limit = SEARCH_LIMIT, filters = ObjectSearchConstants.filtersBackLinkOrAddToObject( - ignore = ignore, - spaces = spaces + ignore = ignore ), sorts = ObjectSearchConstants.sortBackLinkOrAddToObject, fulltext = EMPTY_QUERY, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt index 2a3f99b653..5ee6a80ec7 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectOrWebViewModel.kt @@ -14,7 +14,6 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes import com.anytypeio.anytype.domain.search.SearchObjects import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.domain.workspace.getSpaceWithTechSpace import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate import com.anytypeio.anytype.presentation.editor.Editor import com.anytypeio.anytype.presentation.extension.sendAnalyticsSearchResultEvent @@ -227,10 +226,11 @@ class LinkToObjectOrWebViewModel( } suspend fun getSearchObjectsParams(ignore: Id) = SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), limit = ObjectSearchViewModel.SEARCH_LIMIT, filters = ObjectSearchConstants.getFilterLinkTo( - ignore = ignore, - spaces = spaceManager.getSpaceWithTechSpace() + ignore = ignore ), sorts = ObjectSearchConstants.sortLinkTo, fulltext = ObjectSearchViewModel.EMPTY_QUERY, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectViewModel.kt index 22b452a3b5..11e72a4891 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/linking/LinkToObjectViewModel.kt @@ -5,12 +5,12 @@ import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.Resultat import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.search.SearchObjects import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.domain.workspace.getSpaceWithTechSpace import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate import com.anytypeio.anytype.presentation.navigation.DefaultObjectView import com.anytypeio.anytype.presentation.objects.SupportedLayouts @@ -38,10 +38,11 @@ class LinkToObjectViewModel( val commands = MutableSharedFlow(replay = 0) override suspend fun getSearchObjectsParams(ignore: Id?) = SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), limit = SEARCH_LIMIT, filters = ObjectSearchConstants.getFilterLinkTo( - ignore = ignore, - spaces = spaceManager.getSpaceWithTechSpace() + ignore = ignore ), sorts = ObjectSearchConstants.sortLinkTo, fulltext = EMPTY_QUERY, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt index a4b811cfc4..2f062c09b0 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt @@ -569,8 +569,6 @@ fun Viewer.Filter.Condition.toDomain(): DVFilterCondition = when (this) { suspend fun List.toGridRecordRows( showIcon: Boolean, columns: List, - relations: List, - details: Map, builder: UrlBuilder, store: ObjectStore, ): List { @@ -581,10 +579,8 @@ suspend fun List.toGridRecordRows( val row = columns.buildGridRow( showIcon = showIcon, obj = record, - relations = relations, store = store, - builder = builder, - details = details + builder = builder ) rows.add(row) } else { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/moving/MoveToViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/moving/MoveToViewModel.kt index bee9d9fc7b..40b40d12b7 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/moving/MoveToViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/moving/MoveToViewModel.kt @@ -131,9 +131,10 @@ class MoveToViewModel( private fun getObjectTypes(ctx: Id) { viewModelScope.launch { val params = GetObjectTypes.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = emptyList(), filters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceManager.get()), recommendedLayouts = SupportedLayouts.editorLayouts ), keys = ObjectSearchConstants.defaultKeysObjectType @@ -152,6 +153,8 @@ class MoveToViewModel( val filteredTypes = types.value.getOrDefault(emptyList()).map { objectType -> objectType.id } return SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), limit = SEARCH_LIMIT, filters = ObjectSearchConstants.filterMoveTo( ctx = ctx, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt index e361b4263f..30cde6a4ec 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt @@ -33,6 +33,7 @@ import com.anytypeio.anytype.core_utils.ext.msg import com.anytypeio.anytype.domain.auth.interactor.GetAccount import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.base.getOrThrow +import com.anytypeio.anytype.domain.config.TechSpaceProvider import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.ApproveLeaveSpaceRequest @@ -42,6 +43,7 @@ import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink import com.anytypeio.anytype.domain.multiplayer.MakeSpaceShareable import com.anytypeio.anytype.domain.multiplayer.RemoveSpaceMembers import com.anytypeio.anytype.domain.multiplayer.RevokeSpaceInviteLink +import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.StopSharingSpace import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.presentation.common.BaseViewModel @@ -49,17 +51,14 @@ import com.anytypeio.anytype.presentation.mapper.toView import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider import com.anytypeio.anytype.presentation.objects.SpaceMemberIconView import com.anytypeio.anytype.presentation.objects.toSpaceMembers -import com.anytypeio.anytype.presentation.objects.toSpaceView import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.getSpaceMembersSearchParams -import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.getSpaceViewSearchParams import javax.inject.Inject -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch import timber.log.Timber @@ -79,7 +78,8 @@ class ShareSpaceViewModel( private val getAccount: GetAccount, private val urlBuilder: UrlBuilder, private val analytics: Analytics, - private val membershipProvider: MembershipProvider + private val membershipProvider: MembershipProvider, + private val spaceViews: SpaceViewSubscriptionContainer ) : BaseViewModel() { private val _activeTier = MutableStateFlow(ActiveTierState.Init) @@ -129,23 +129,24 @@ class ShareSpaceViewModel( private fun proceedWithSubscriptions() { viewModelScope.launch { val account = getAccount.async(Unit).getOrNull()?.id - val spaceSearchParams = getSpaceViewSearchParams( - targetSpaceId = vmParams.space.id, - subscription = SHARE_SPACE_SPACE_SUBSCRIPTION - ) + val spaceViewFlow = spaceViews + .observe() + .mapNotNull { spaces -> + spaces.firstOrNull { it.targetSpaceId == vmParams.space.id } + } val spaceMembersSearchParams = getSpaceMembersSearchParams( - spaceId = vmParams.space.id, + space = vmParams.space, subscription = SHARE_SPACE_MEMBER_SUBSCRIPTION ) combine( - container.subscribe(spaceSearchParams), + spaceViewFlow, container.subscribe(spaceMembersSearchParams), isCurrentUserOwner, _activeTier.filterIsInstance() - ) { spaceResponse, membersResponse, isCurrentUserOwner, activeTier -> + ) { spaceView, membersResponse, isCurrentUserOwner, activeTier -> CombineResult( isCurrentUserOwner = isCurrentUserOwner, - spaceView = spaceResponse.toSpaceView(), + spaceView = spaceView, tierId = activeTier.tierId, spaceMembers = membersResponse.toSpaceMembers() ) @@ -551,7 +552,8 @@ class ShareSpaceViewModel( private val getSpaceInviteLink: GetSpaceInviteLink, private val permissions: UserPermissionProvider, private val analytics: Analytics, - private val membershipProvider: MembershipProvider + private val membershipProvider: MembershipProvider, + private val spaceViews: SpaceViewSubscriptionContainer ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T = ShareSpaceViewModel( @@ -569,7 +571,8 @@ class ShareSpaceViewModel( permissions = permissions, makeSpaceShareable = makeSpaceShareable, analytics = analytics, - membershipProvider = membershipProvider + membershipProvider = membershipProvider, + spaceViews = spaceViews ) as T } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/SpaceJoinRequestViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/SpaceJoinRequestViewModel.kt index e59b4e0fb6..c71818c038 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/SpaceJoinRequestViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/SpaceJoinRequestViewModel.kt @@ -287,9 +287,8 @@ class SpaceJoinRequestViewModel( private fun proceedWithSpaceMembers(space: SpaceId) { val searchMembersParams = SearchObjects.Params( - filters = filterParticipants( - spaces = listOf(space.id) - ), + space = space, + filters = filterParticipants(space = space), keys = ObjectSearchConstants.spaceMemberKeys ) viewModelScope.launch { @@ -312,6 +311,7 @@ class SpaceJoinRequestViewModel( val filters = ObjectSearchConstants.filterNewMember(vmParams.member) searchObjects( SearchObjects.Params( + space = vmParams.space, filters = filters, keys = ObjectSearchConstants.spaceMemberKeys, limit = 1 diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/DeepLinkToObjectDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/DeepLinkToObjectDelegate.kt index c8ba14616a..86d344d7ff 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/DeepLinkToObjectDelegate.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/DeepLinkToObjectDelegate.kt @@ -32,7 +32,14 @@ interface DeepLinkToObjectDelegate { space: SpaceId, switchSpaceIfObjectFound: Boolean ) : Result { - val wrapper = fetchObject.async(params = FetchObject.Params(obj = obj)).getOrNull() + val wrapper = fetchObject + .async( + params = FetchObject.Params( + obj = obj, + space = space + ) + ) + .getOrNull() if (wrapper != null) { val permission = userPermissionProvider.get(space = space) return if (permission != null && permission.isAtLeastReader()) { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/CreateObjectViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/CreateObjectViewModel.kt index 47a0ee738d..f5a7ef388c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/CreateObjectViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/CreateObjectViewModel.kt @@ -6,15 +6,21 @@ import androidx.lifecycle.viewModelScope import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Key import com.anytypeio.anytype.core_models.ObjectType +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeKey import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.page.CreateObject +import com.anytypeio.anytype.domain.workspace.SpaceManager +import javax.inject.Inject import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch import timber.log.Timber -class CreateObjectViewModel(private val createObject: CreateObject) : ViewModel() { +class CreateObjectViewModel( + private val createObject: CreateObject, + private val spaceManager: SpaceManager +) : ViewModel() { val createObjectStatus = MutableSharedFlow(replay = 0) private val jobs = mutableListOf() @@ -24,8 +30,11 @@ class CreateObjectViewModel(private val createObject: CreateObject) : ViewModel( } private fun onCreatePage(type: Key) { - val params = CreateObject.Param(type = TypeKey(type)) jobs += viewModelScope.launch { + val params = CreateObject.Param( + type = TypeKey(type), + space = SpaceId(spaceManager.get()) + ) createObject.execute(params).fold( onFailure = { e -> Timber.e(e, "Error while creating a new object with type:$type") @@ -57,13 +66,17 @@ class CreateObjectViewModel(private val createObject: CreateObject) : ViewModel( data class Error(val msg: String) : State() } - class Factory( - private val createObject: CreateObject + class Factory @Inject constructor( + private val createObject: CreateObject, + private val spaceManager: SpaceManager ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { - return CreateObjectViewModel(createObject = createObject) as T + return CreateObjectViewModel( + createObject = createObject, + spaceManager = spaceManager + ) as T } } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt index db6591610a..a25b48dabe 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt @@ -11,6 +11,7 @@ import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes @@ -132,7 +133,9 @@ class ObjectTypeChangeViewModel( isWithFiles: Boolean ) { viewModelScope.launch { - getDefaultObjectType.execute(Unit).fold( + getDefaultObjectType.execute( + SpaceId(spaceManager.get()) + ).fold( onFailure = { e -> Timber.e(e, "Error while getting user settings") }, @@ -257,10 +260,10 @@ class ObjectTypeChangeViewModel( } val marketplaceTypes = getObjectTypes.run( GetObjectTypes.Params( + space = SpaceId(Marketplace.MARKETPLACE_SPACE_ID), filters = buildList { addAll( ObjectSearchConstants.filterTypes( - spaces = listOf(Marketplace.MARKETPLACE_SPACE_ID), recommendedLayouts = SupportedLayouts.editorLayouts ) ) @@ -288,8 +291,9 @@ class ObjectTypeChangeViewModel( recommendedLayouts: List ) = getObjectTypes.run( GetObjectTypes.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), filters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceManager.get()), recommendedLayouts = recommendedLayouts, excludeParticipant = !setup.isSetSource ), diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeExtensions.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeExtensions.kt index 81eb680ca4..09eb9c6bf0 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeExtensions.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeExtensions.kt @@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds.BOOKMARK import com.anytypeio.anytype.core_models.ObjectTypeIds.COLLECTION import com.anytypeio.anytype.core_models.ObjectTypeIds.SET import com.anytypeio.anytype.core_models.ObjectWrapper +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeKey import com.anytypeio.anytype.core_models.restrictions.DataViewRestriction import com.anytypeio.anytype.domain.page.CreateObject @@ -98,7 +99,10 @@ fun ObjectState.DataView.isCreateObjectAllowed(objectType: ObjectWrapper.Type? = * * @return [CreateObject.Param] with the necessary parameters for creating an object. */ -fun Key?.getCreateObjectParams(defaultTemplate: Id?): CreateObject.Param { +fun Key?.getCreateObjectParams( + space: SpaceId, + defaultTemplate: Id? +): CreateObject.Param { val key = this val flags = buildList { add(InternalFlags.ShouldEmptyDelete) @@ -113,6 +117,7 @@ fun Key?.getCreateObjectParams(defaultTemplate: Id?): CreateObject.Param { } return CreateObject.Param( + space = space, type = key?.let { TypeKey(it) }, internalFlags = flags, template = defaultTemplate diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt index 8f88dc5c99..dca5f73081 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt @@ -13,6 +13,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.objects.ObjectStore import com.anytypeio.anytype.presentation.number.NumberParser import com.anytypeio.anytype.core_models.ext.DateParser +import com.anytypeio.anytype.presentation.extension.MAX_SNIPPET_SIZE import com.anytypeio.anytype.presentation.relations.model.DefaultObjectRelationValueView import com.anytypeio.anytype.presentation.sets.model.FileView import com.anytypeio.anytype.presentation.sets.model.ObjectView @@ -357,4 +358,45 @@ suspend fun ObjectWrapper.Basic.objects( fun ObjectWrapper.File.getProperName(): String { return "${name.orEmpty()}.$fileExt" +} + +fun ObjectWrapper.Basic.getDescriptionOrSnippet(): String? { + return when (layout) { + ObjectType.Layout.NOTE -> description + else -> { + if (!description.isNullOrBlank()) { + description + } else { + snippet?.replace("\n", " ")?.take(MAX_SNIPPET_SIZE) + } + } + } +} + +fun List.setTypeRelationIconsAsNone(): List { + return this.map { view -> + if (view.relationKey == Relations.TYPE) { + handleTypeRelation(view) + } else { + view + } + } +} + +private fun handleTypeRelation(view: DefaultObjectRelationValueView): DefaultObjectRelationValueView { + return when (view) { + is DefaultObjectRelationValueView.Object -> { + view.copy( + objects = view.objects.map { obj -> updateObjectIcon(obj) } + ) + } + else -> view + } +} + +private fun updateObjectIcon(obj: ObjectView): ObjectView { + return when (obj) { + is ObjectView.Default -> obj.copy(icon = ObjectIcon.None) + is ObjectView.Deleted -> obj + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/SelectObjectTypeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/SelectObjectTypeViewModel.kt index 1e2ebe06ca..a18aec9831 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/SelectObjectTypeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/SelectObjectTypeViewModel.kt @@ -85,14 +85,10 @@ class SelectObjectTypeViewModel( query.onStart { emit(EMPTY_QUERY) }.flatMapLatest { query -> val types = getObjectTypes.stream( GetObjectTypes.Params( + // TODO DROID-2916 Merge with marketplace object types query results + space = vmParams.space, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), filters = ObjectSearchConstants.filterTypes( - spaces = buildList { - add(vmParams.space.id) - if (query.isNotEmpty()) { - add(Marketplace.MARKETPLACE_SPACE_ID) - } - }, recommendedLayouts = SupportedLayouts.createObjectLayouts, excludedTypeKeys = vmParams.excludedTypeKeys ), @@ -220,7 +216,9 @@ class SelectObjectTypeViewModel( } viewModelScope.launch { - getDefaultObjectType.async(Unit).fold( + getDefaultObjectType.async( + params = vmParams.space + ).fold( onSuccess = { response -> defaultObjectTypePipeline.emit(response.type) }, @@ -413,7 +411,7 @@ class SelectObjectTypeViewModel( private fun proceedWithCreatingNote(text: String) { viewModelScope.launch { val startTime = System.currentTimeMillis() - val defaultObjectType = getDefaultObjectType.async(Unit).getOrNull()?.type?.let { + val defaultObjectType = getDefaultObjectType.async(vmParams.space).getOrNull()?.type?.let { if (it.key != ObjectTypeUniqueKeys.COLLECTION && it.key != ObjectTypeUniqueKeys.SET) it else @@ -453,16 +451,7 @@ class SelectObjectTypeViewModel( } fun onResume() { - viewModelScope.launch { - analytics.sendEvent( - eventName = EventsDictionary.screenVault, - props = Props( - map = mapOf( - EventsPropertiesKey.type to EventsDictionary.Type.menu - ) - ) - ) - } + // TODO add analytics? } class Factory @Inject constructor( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/LimitObjectTypeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/LimitObjectTypeViewModel.kt index f8ef54f5fa..31b084fcd1 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/LimitObjectTypeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/LimitObjectTypeViewModel.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.core_models.DVFilterCondition import com.anytypeio.anytype.core_models.EMPTY_QUERY import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction import com.anytypeio.anytype.domain.search.SearchObjects import com.anytypeio.anytype.domain.misc.UrlBuilder @@ -57,12 +58,9 @@ class LimitObjectTypeViewModel( viewModelScope.launch { searchObjects( SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), filters = listOf( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = spaceManager.get() - ), DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.EQUAL, @@ -83,6 +81,11 @@ class LimitObjectTypeViewModel( condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.RESTRICTIONS, condition = DVFilterCondition.NOT_IN, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt index 533b8c1a6c..732940bc72 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt @@ -80,7 +80,6 @@ suspend fun DVViewer.render( coverImageHashProvider: CoverImageHashProvider, useFallbackView: Boolean = false, objects: List, - details: Map, dataViewRelations: List, store: ObjectStore, objectOrderIds: List = emptyList(), @@ -91,7 +90,6 @@ suspend fun DVViewer.render( buildGridView( dataViewRelations = dataViewRelations, objects = objects, - details = details, builder = builder, store = store, objectOrderIds = objectOrderIds @@ -102,7 +100,6 @@ suspend fun DVViewer.render( id = id, items = buildGalleryViews( objectIds = objects, - details = details, relations = dataViewRelations, coverImageHashProvider = coverImageHashProvider, urlBuilder = builder, @@ -137,7 +134,6 @@ suspend fun DVViewer.render( buildGridView( dataViewRelations = dataViewRelations, objects = objects, - details = details, builder = builder, store = store, objectOrderIds = objectOrderIds @@ -164,7 +160,6 @@ private fun List.sortObjects(objectOrderIds: List): Lis private suspend fun DVViewer.buildGridView( dataViewRelations: List, objects: List, - details: Map, builder: UrlBuilder, store: ObjectStore, objectOrderIds: List @@ -183,8 +178,6 @@ private suspend fun DVViewer.buildGridView( objects.toGridRecordRows( showIcon = !hideIcon, columns = columns, - relations = visibleRelations, - details = details, builder = builder, store = store ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt index f5e047564f..560e065028 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBase.kt @@ -10,6 +10,7 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.primitives.RelationKey +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.relations.GetRelations import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace @@ -127,6 +128,8 @@ abstract class RelationAddViewModelBase( query: String ): List { val params = GetRelations.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = defaultObjectSearchSorts(), filters = buildList { addAll(filterMarketplaceRelations()) @@ -158,16 +161,11 @@ abstract class RelationAddViewModelBase( query: String ): List { val params = GetRelations.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = defaultObjectSearchSorts(), filters = buildList { addAll(filterMyRelations()) - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = spaceManager.get() - ) - ) add( DVFilter( relation = Relations.RELATION_KEY, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/object/ObjectValueViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/object/ObjectValueViewModel.kt index d652fc7516..23d78b1da6 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/object/ObjectValueViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/object/ObjectValueViewModel.kt @@ -146,6 +146,7 @@ class ObjectValueViewModel( } } return SearchObjects.Params( + space = viewModelParams.space, keys = searchKeys, filters = searchFilters, fulltext = if (isEditableRelation) query else SearchObjects.EMPTY_TEXT diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/tagstatus/TagOrStatusValueViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/tagstatus/TagOrStatusValueViewModel.kt index 8842dfd159..58a4f697dd 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/tagstatus/TagOrStatusValueViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/value/tagstatus/TagOrStatusValueViewModel.kt @@ -63,11 +63,12 @@ class TagOrStatusValueViewModel( val relation = relations.getOrNull(relation = viewModelParams.relationKey) ?: return@launch setupIsRelationNotEditable(relation) val searchParams = StoreSearchParams( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), subscription = SUB_MY_OPTIONS, keys = ObjectSearchConstants.keysRelationOptions, filters = ObjectSearchConstants.filterRelationOptions( - relationKey = viewModelParams.relationKey, - space = spaceManager.get() + relationKey = viewModelParams.relationKey ) ) combine( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/GlobalSearchViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/GlobalSearchViewModel.kt index 0e0989a6b7..8be5317108 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/GlobalSearchViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/GlobalSearchViewModel.kt @@ -268,12 +268,13 @@ class GlobalSearchViewModel( saveSearch = true, relatedObjectId = relatedObjectId, command = Command.SearchWithMeta( + space = space, query = query, limit = DEFAULT_SEARCH_LIMIT, offset = 0, keys = DEFAULT_KEYS, filters = buildList { - addAll(filterSearchObjects(vmParams.space.id)) + addAll(filterSearchObjects()) add( DVFilter( relation = Relations.ID, @@ -287,8 +288,7 @@ class GlobalSearchViewModel( }, sorts = ObjectSearchConstants.sortsSearchObjects, withMetaRelationDetails = false, - withMeta = false, - space = space + withMeta = false ) ) } @@ -303,7 +303,7 @@ class GlobalSearchViewModel( limit = DEFAULT_SEARCH_LIMIT, offset = 0, keys = DEFAULT_KEYS, - filters = ObjectSearchConstants.filterSearchObjects(space.id), + filters = ObjectSearchConstants.filterSearchObjects(), sorts = ObjectSearchConstants.sortsSearchObjects, withMetaRelationDetails = true, withMeta = true, 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 c4addf1254..cb00646dee 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 @@ -12,6 +12,7 @@ import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeKey import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.presentation.objects.SupportedLayouts @@ -22,7 +23,7 @@ import com.anytypeio.anytype.presentation.objects.SupportedLayouts object ObjectSearchConstants { //region SEARCH OBJECTS - fun filterSearchObjects(space: Id? = null) = buildList { + fun filterSearchObjects() = buildList { add( DVFilter( relation = Relations.IS_ARCHIVED, @@ -37,6 +38,13 @@ object ObjectSearchConstants { value = true ) ) + add( + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ) + ) add( DVFilter( relation = Relations.IS_DELETED, @@ -58,15 +66,6 @@ object ObjectSearchConstants { value = SupportedLayouts.globalSearchLayouts.map { it.code.toDouble() } ) ) - if (!space.isNullOrEmpty()) { - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ) - ) - } } val sortsSearchObjects = listOf( @@ -82,7 +81,7 @@ object ObjectSearchConstants { //region LINK TO fun getFilterLinkTo( - ignore: Id?, spaces: List + ignore: Id? ) = listOf( DVFilter( relation = Relations.IS_ARCHIVED, @@ -94,6 +93,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -113,11 +117,6 @@ object ObjectSearchConstants { relation = Relations.ID, condition = DVFilterCondition.NOT_EQUAL, value = ignore - ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = spaces ) ) @@ -143,6 +142,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -199,6 +203,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -246,7 +255,6 @@ object ObjectSearchConstants { //region ADD OBJECT TO FILTER fun filterAddObjectToFilter( - space: Id, limitObjectTypes: List ) = buildList { add( @@ -263,6 +271,13 @@ object ObjectSearchConstants { value = true ) ) + add( + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ) + ) add( DVFilter( relation = Relations.IS_DELETED, @@ -277,13 +292,6 @@ object ObjectSearchConstants { value = ObjectTypeUniqueKeys.TEMPLATE ) ) - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ) - ) // TODO check these filters if (limitObjectTypes.isEmpty()) { add( @@ -304,7 +312,7 @@ object ObjectSearchConstants { } } - fun filterAddObjectToFilterByLayout(space: Id, layouts: List) = buildList { + fun filterAddObjectToFilterByLayout(layouts: List) = buildList { add( DVFilter( relation = Relations.IS_ARCHIVED, @@ -321,16 +329,16 @@ object ObjectSearchConstants { ) add( DVFilter( - relation = Relations.IS_DELETED, + relation = Relations.IS_HIDDEN_DISCOVERY, condition = DVFilterCondition.NOT_EQUAL, value = true ) ) add( DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space + relation = Relations.IS_DELETED, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) ) add( @@ -352,7 +360,7 @@ object ObjectSearchConstants { //endregion //region TAB FAVORITES - fun filterTabFavorites(space: Id) = listOf( + fun filterTabFavorites() = listOf( DVFilter( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.NOT_EQUAL , @@ -363,6 +371,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -378,11 +391,6 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = ObjectTypeUniqueKeys.TEMPLATE ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = space - ), DVFilter( relation = Relations.IS_FAVORITE, condition = DVFilterCondition.EQUAL, @@ -396,7 +404,6 @@ object ObjectSearchConstants { //region TAB RECENT fun filterTabRecent( - space: Id, spaceCreationDateInSeconds: Long? = null ) = buildList { add( @@ -413,6 +420,13 @@ object ObjectSearchConstants { value = true ) ) + add( + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ) + ) add( DVFilter( relation = Relations.IS_DELETED, @@ -451,13 +465,6 @@ object ObjectSearchConstants { ) ) } - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ) - ) } val sortTabRecent = listOf( @@ -469,9 +476,7 @@ object ObjectSearchConstants { ) ) - fun filterTabRecentLocal( - space: Id - ) = listOf( + fun filterTabRecentLocal() = listOf( DVFilter( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.NOT_EQUAL, @@ -482,6 +487,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -501,11 +511,6 @@ object ObjectSearchConstants { relation = Relations.LAST_OPENED_DATE, condition = DVFilterCondition.NOT_EQUAL, value = null - ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space ) ) @@ -523,7 +528,7 @@ object ObjectSearchConstants { //endregion //region TAB SETS - fun filterTabSets(space: Id) = listOf( + fun filterTabSets() = listOf( DVFilter( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.NOT_EQUAL, @@ -539,15 +544,15 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.EQUAL, value = ObjectType.Layout.SET.code.toDouble() - ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space ) ) @@ -562,7 +567,7 @@ object ObjectSearchConstants { //endregion //region TAB ARCHIVE - fun filterTabArchive(space: Id) = listOf( + fun filterTabArchive() = listOf( DVFilter( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.EQUAL, @@ -579,9 +584,9 @@ object ObjectSearchConstants { value = true ), DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) ) @@ -595,7 +600,7 @@ object ObjectSearchConstants { //endregion //region BACK LINK OR ADD TO OBJECT - fun filtersBackLinkOrAddToObject(ignore: Id?, spaces: List) = listOf( + fun filtersBackLinkOrAddToObject(ignore: Id?) = listOf( DVFilter( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.NOT_EQUAL, @@ -606,6 +611,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -625,11 +635,6 @@ object ObjectSearchConstants { relation = Relations.ID, condition = DVFilterCondition.NOT_EQUAL, value = ignore - ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = spaces ) ) @@ -747,7 +752,6 @@ object ObjectSearchConstants { //region OBJECT TYPES fun filterTypes( - spaces: List, recommendedLayouts: List = emptyList(), excludedTypeKeys: List = emptyList(), excludeParticipant: Boolean = true @@ -770,16 +774,16 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.EQUAL, value = ObjectType.Layout.OBJECT_TYPE.code.toDouble() ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = spaces - ), DVFilter( relation = Relations.UNIQUE_KEY, condition = DVFilterCondition.NOT_EMPTY @@ -829,7 +833,10 @@ object ObjectSearchConstants { } } - fun filterParticipants(spaces: List) : List = buildList { + fun filterParticipants( + space: SpaceId, + hiddenDiscovery: Boolean = true + ) : List = buildList { add( DVFilter( relation = Relations.IS_ARCHIVED, @@ -851,6 +858,15 @@ object ObjectSearchConstants { value = true ) ) + if (hiddenDiscovery) { + add( + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ) + ) + } add( DVFilter( relation = Relations.LAYOUT, @@ -861,8 +877,8 @@ object ObjectSearchConstants { add( DVFilter( relation = Relations.SPACE_ID, - condition = DVFilterCondition.IN, - value = spaces + condition = DVFilterCondition.EQUAL, + value = space.id ) ) } @@ -891,14 +907,7 @@ object ObjectSearchConstants { ) } - fun defaultDataViewFilters(space: Id) = buildList { - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ) - ) + fun defaultDataViewFilters() = buildList { add( DVFilter( relation = Relations.LAYOUT, @@ -915,6 +924,13 @@ object ObjectSearchConstants { value = true, ) ) + add( + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ) + ) add( DVFilter( relation = Relations.IS_DELETED, @@ -999,6 +1015,11 @@ object ObjectSearchConstants { relation = Relations.IS_HIDDEN, condition = DVFilterCondition.NOT_EQUAL, value = true + ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) ) @@ -1024,18 +1045,13 @@ object ObjectSearchConstants { value = true ), DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = MARKETPLACE_SPACE_ID + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) ) - fun collectionFilters(space: Id) = listOf( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ), + fun collectionFilters() = listOf( DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.EQUAL, @@ -1051,6 +1067,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -1083,6 +1104,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.IN, @@ -1101,7 +1127,7 @@ object ObjectSearchConstants { ) ) - fun setsByObjectTypeFilters(types: List, space: Id) = listOf( + fun setsByObjectTypeFilters(types: List) = listOf( DVFilter( relation = Relations.IS_ARCHIVED, condition = DVFilterCondition.NOT_EQUAL, @@ -1117,16 +1143,16 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.LAYOUT, condition = DVFilterCondition.IN, value = ObjectType.Layout.SET.code.toDouble() ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space - ), DVFilter( relation = Relations.SET_OF, condition = DVFilterCondition.IN, @@ -1134,7 +1160,7 @@ object ObjectSearchConstants { ) ) - fun filterRelationOptions(relationKey: Key, space: Id) : List = listOf( + fun filterRelationOptions(relationKey: Key) : List = listOf( DVFilter( relation = Relations.RELATION_KEY, condition = DVFilterCondition.EQUAL, @@ -1161,9 +1187,9 @@ object ObjectSearchConstants { value = true ), DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true ) ) @@ -1183,6 +1209,11 @@ object ObjectSearchConstants { condition = DVFilterCondition.NOT_EQUAL, value = true ), + DVFilter( + relation = Relations.IS_HIDDEN_DISCOVERY, + condition = DVFilterCondition.NOT_EQUAL, + value = true + ), DVFilter( relation = Relations.IS_DELETED, condition = DVFilterCondition.NOT_EQUAL, @@ -1244,8 +1275,13 @@ object ObjectSearchConstants { //region SPACE VIEW - fun getSpaceViewSearchParams(subscription: String, targetSpaceId: Id): StoreSearchParams { + fun getSpaceViewSearchParams( + techSpaceId: Id, + subscription: String, + targetSpaceId: Id + ): StoreSearchParams { return StoreSearchParams( + space = SpaceId(techSpaceId), subscription = subscription, keys = spaceViewKeys, limit = 1, @@ -1261,14 +1297,20 @@ object ObjectSearchConstants { ) } - fun getSpaceMembersSearchParams(subscription: String, spaceId: Id): StoreSearchParams { + fun getSpaceMembersSearchParams( + subscription: String, + space: SpaceId, + includeRequests: Boolean = true + ): StoreSearchParams { return StoreSearchParams( + space = space, subscription = subscription, - filters = filterParticipants( - spaces = listOf(spaceId) - ), sorts = listOf(sortByName()), - keys = spaceMemberKeys + keys = spaceMemberKeys, + filters = filterParticipants( + space = space, + hiddenDiscovery = !includeRequests + ), ) } //endregion diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt index 4cdd553c45..6c517922d2 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt @@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_utils.common.EventWrapper import com.anytypeio.anytype.core_utils.ext.cancel import com.anytypeio.anytype.core_utils.ui.TextInputDialogBottomBehaviorApplier @@ -119,9 +120,10 @@ open class ObjectSearchViewModel( protected fun getObjectTypes() { jobs += viewModelScope.launch { val params = GetObjectTypes.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = emptyList(), filters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceManager.get()), excludeParticipant = false ), keys = ObjectSearchConstants.defaultKeysObjectType @@ -244,8 +246,10 @@ open class ObjectSearchViewModel( } open suspend fun getSearchObjectsParams(ignore: Id?) = SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), limit = SEARCH_LIMIT, - filters = ObjectSearchConstants.filterSearchObjects(space = spaceManager.get()), + filters = ObjectSearchConstants.filterSearchObjects(), sorts = ObjectSearchConstants.sortsSearchObjects, fulltext = EMPTY_QUERY, keys = buildList { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/GalleryViewMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/GalleryViewMapper.kt index 22112882a2..0e887dcd00 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/GalleryViewMapper.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/GalleryViewMapper.kt @@ -1,7 +1,5 @@ package com.anytypeio.anytype.presentation.sets -import com.anytypeio.anytype.core_models.Block -import com.anytypeio.anytype.core_models.CoverType import com.anytypeio.anytype.core_models.DVViewer import com.anytypeio.anytype.core_models.DVViewerRelation import com.anytypeio.anytype.core_models.Id @@ -17,8 +15,8 @@ import com.anytypeio.anytype.domain.objects.StoreOfRelations import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider import com.anytypeio.anytype.presentation.editor.cover.CoverView import com.anytypeio.anytype.presentation.mapper.objectIcon -import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.objects.getProperName +import com.anytypeio.anytype.presentation.objects.setTypeRelationIconsAsNone import com.anytypeio.anytype.presentation.objects.values import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper import com.anytypeio.anytype.presentation.relations.CoverContainer @@ -29,7 +27,6 @@ import com.anytypeio.anytype.presentation.sets.model.Viewer suspend fun DVViewer.buildGalleryViews( objectIds: List, relations: List, - details: Map, coverImageHashProvider: CoverImageHashProvider, urlBuilder: UrlBuilder, objectStore: ObjectStore, @@ -90,7 +87,7 @@ private suspend fun ObjectWrapper.Basic.mapToDefaultItem( urlBuilder = urlBuilder, settings = viewerRelations, storeOfObjects = store - ), + ).setTypeRelationIconsAsNone(), hideIcon = hideIcon, name = obj.getProperName(), icon = obj.objectIcon(urlBuilder) @@ -126,7 +123,7 @@ private suspend fun ObjectWrapper.Basic.mapToCoverItem( urlBuilder = urlBuilder, settings = dvViewer.viewerRelations, storeOfObjects = store - ), + ).setTypeRelationIconsAsNone(), hideIcon = dvViewer.hideIcon, name = obj.getProperName(), icon = obj.objectIcon(urlBuilder), diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ListViewMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ListViewMapper.kt index c749010b84..0be6743fd6 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ListViewMapper.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ListViewMapper.kt @@ -11,6 +11,7 @@ import com.anytypeio.anytype.presentation.mapper.objectIcon import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.objects.getProperName import com.anytypeio.anytype.presentation.objects.relationsFilteredByHiddenAndDescription +import com.anytypeio.anytype.presentation.objects.setTypeRelationIconsAsNone import com.anytypeio.anytype.presentation.sets.model.Viewer suspend fun DVViewer.buildListViews( @@ -37,7 +38,7 @@ suspend fun DVViewer.buildListViews( urlBuilder = urlBuilder, settings = viewerRelations, storeOfObjects = store - ), + ).setTypeRelationIconsAsNone(), name = obj.getProperName(), icon = obj.objectIcon(urlBuilder), description = description, @@ -57,7 +58,7 @@ suspend fun DVViewer.buildListViews( urlBuilder = urlBuilder, settings = viewerRelations, storeOfObjects = store - ), + ).setTypeRelationIconsAsNone(), name = obj.getProperName(), done = obj.done ?: false, description = description @@ -76,7 +77,7 @@ suspend fun DVViewer.buildListViews( urlBuilder = urlBuilder, settings = viewerRelations, storeOfObjects = store - ), + ).setTypeRelationIconsAsNone(), name = obj.getProperName(), icon = obj.objectIcon(urlBuilder), description = description, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt index c774cc9f52..5993e708f3 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt @@ -396,6 +396,7 @@ class ObjectSetViewModel( if (config != null) { storelessSubscriptionContainer.subscribe( StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(config.profile), keys = listOf( @@ -487,12 +488,12 @@ class ObjectSetViewModel( Timber.d("subscribeToObjectState, NEW COLLECTION STATE") if (query.state.isInitialized) { dataViewSubscription.startObjectCollectionSubscription( + space = vmParams.space.id, + context = vmParams.ctx, collection = vmParams.ctx, state = query.state, currentViewerId = query.currentViewerId, offset = query.offset, - context = vmParams.ctx, - space = vmParams.space.id, dataViewRelationLinks = query.state.dataViewContent.relationLinks ) } else { @@ -504,11 +505,11 @@ class ObjectSetViewModel( Timber.d("subscribeToObjectState, NEW SET STATE") if (query.state.isInitialized) { dataViewSubscription.startObjectSetSubscription( + space = vmParams.space.id, + context = vmParams.ctx, state = query.state, currentViewerId = query.currentViewerId, offset = query.offset, - context = context, - space = vmParams.space.id, dataViewRelationLinks = query.state.dataViewContent.relationLinks ) } else { @@ -724,7 +725,6 @@ class ObjectSetViewModel( builder = urlBuilder, objects = dataViewState.objects, dataViewRelations = relations, - details = objectState.details, store = objectStore, storeOfRelations = storeOfRelations ) @@ -776,7 +776,6 @@ class ObjectSetViewModel( builder = urlBuilder, objects = dataViewState.objects, dataViewRelations = relations, - details = objectState.details, store = objectStore, objectOrderIds = objectOrderIds, storeOfRelations = storeOfRelations @@ -1598,7 +1597,10 @@ class ObjectSetViewModel( Timber.d("onAddNewDocumentClicked, objType:[$objType]") val startTime = System.currentTimeMillis() - val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId) + val params = objType?.uniqueKey.getCreateObjectParams( + space = vmParams.space, + objType?.defaultTemplateId + ) jobs += viewModelScope.launch { createObject.async(params).fold( onSuccess = { result -> @@ -2106,10 +2108,10 @@ class ObjectSetViewModel( private suspend fun fetchAndProcessObjectTypes(selectedType: Id, widgetState: TypeTemplatesWidgetUI.Data) { val filters = ObjectSearchConstants.filterTypes( - spaces = listOf(vmParams.space.id), recommendedLayouts = SupportedLayouts.createObjectLayouts ) val params = GetObjectTypes.Params( + space = vmParams.space, filters = filters, keys = ObjectSearchConstants.defaultKeysObjectType ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt index 4703ec39f0..20eebd54eb 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt @@ -29,8 +29,6 @@ import timber.log.Timber suspend fun List.buildGridRow( showIcon: Boolean, obj: ObjectWrapper.Basic, - relations: List, - details: Map, builder: UrlBuilder, store: ObjectStore ): Viewer.GridView.Row { @@ -42,178 +40,211 @@ suspend fun List.buildGridRow( val done = obj.done val layout = obj.layout val space = requireNotNull(obj.spaceId) + val objectIcon = obj.objectIcon(builder) val cells = mutableListOf() this.map { column -> - if (column.key == Relations.NAME) { - // Drawing name column rows without content. - cells.add( - CellView.Description( - id = obj.id, - relationKey = column.key, - text = "", - space = requireNotNull(obj.spaceId) + when (column.key) { + Relations.NAME -> { + cells.add( + CellView.Description( + id = obj.id, + relationKey = column.key, + text = "", + space = requireNotNull(obj.spaceId) + ) ) - ) - } else { - // TODO refact - if (column.format == ColumnView.Format.EMOJI) return@map - cells.add( - when (column.format) { - ColumnView.Format.SHORT_TEXT, ColumnView.Format.LONG_TEXT -> { - CellView.Description( - id = obj.id, - relationKey = column.key, - text = obj.getValue(column.key).orEmpty(), - space = space - ) - } - ColumnView.Format.NUMBER -> { - val value = obj.getValue(column.key) - CellView.Number( - id = obj.id, - relationKey = column.key, - number = NumberParser.parse(value), - space = space - ) - } - ColumnView.Format.DATE -> { - val value = obj.getValue(column.key) - CellView.Date( - id = obj.id, - relationKey = column.key, - timeInSecs = DateParser.parse(value), - dateFormat = column.getDateRelationFormat(), - space = space - ) - } - ColumnView.Format.FILE -> { - val files = buildList { - obj.getValues(column.key).forEach { id -> - val wrapper = store.get(id) - if (wrapper != null) { - add( - FileView( - id = id, - name = wrapper.name.orEmpty(), - mime = wrapper.fileMimeType.orEmpty(), - ext = wrapper.fileExt.orEmpty(), - icon = ObjectIcon.File( + } + + Relations.TYPE -> { + val objects = obj.map.buildObjectViews( + columnKey = column.key, + builder = builder, + store = store, + withIcon = false + ) + cells.add( + CellView.Object( + id = obj.id, + relationKey = column.key, + objects = objects, + space = space + ) + ) + } + + else -> { + // TODO refact + if (column.format == ColumnView.Format.EMOJI) return@map + cells.add( + when (column.format) { + ColumnView.Format.SHORT_TEXT, ColumnView.Format.LONG_TEXT -> { + CellView.Description( + id = obj.id, + relationKey = column.key, + text = obj.getValue(column.key).orEmpty(), + space = space + ) + } + + ColumnView.Format.NUMBER -> { + val value = obj.getValue(column.key) + CellView.Number( + id = obj.id, + relationKey = column.key, + number = NumberParser.parse(value), + space = space + ) + } + + ColumnView.Format.DATE -> { + val value = obj.getValue(column.key) + CellView.Date( + id = obj.id, + relationKey = column.key, + timeInSecs = DateParser.parse(value), + dateFormat = column.getDateRelationFormat(), + space = space + ) + } + + ColumnView.Format.FILE -> { + val files = buildList { + obj.getValues(column.key).forEach { id -> + val wrapper = store.get(id) + if (wrapper != null) { + add( + FileView( + id = id, + name = wrapper.name.orEmpty(), mime = wrapper.fileMimeType.orEmpty(), - fileName = wrapper.name.orEmpty(), - extensions = wrapper.fileExt.orEmpty(), + ext = wrapper.fileExt.orEmpty(), + icon = ObjectIcon.File( + mime = wrapper.fileMimeType.orEmpty(), + fileName = wrapper.name.orEmpty(), + extensions = wrapper.fileExt.orEmpty(), + ) ) ) - ) + } } } + CellView.File( + id = obj.id, + relationKey = column.key, + files = files, + space = space + ) } - CellView.File( - id = obj.id, - relationKey = column.key, - files = files, - space = space - ) - } - ColumnView.Format.CHECKBOX -> { - CellView.Checkbox( - id = obj.id, - relationKey = column.key, - isChecked = obj.getValue(column.key) ?: false, - space = space - ) - } - ColumnView.Format.URL -> { - CellView.Url( - id = obj.id, - relationKey = column.key, - url = obj.getValue(column.key).orEmpty(), - space = space - ) - } - ColumnView.Format.EMAIL -> { - CellView.Email( - id = obj.id, - relationKey = column.key, - email = obj.getValue(column.key).orEmpty(), - space = space - ) - } - ColumnView.Format.PHONE -> { - CellView.Phone( - id = obj.id, - relationKey = column.key, - phone = obj.getValue(column.key).orEmpty(), - space = space - ) - } - ColumnView.Format.OBJECT -> { - val objects = obj.map.buildObjectViews( - columnKey = column.key, - builder = builder, - store = store - ) - CellView.Object( - id = obj.id, - relationKey = column.key, - objects = objects, - space = space - ) - } - ColumnView.Format.TAG -> { - val values = obj.getValue>(column.key) ?: emptyList() - val options = values.mapNotNull { - val wrapper = store.get(it) - if (wrapper != null && !wrapper.isEmpty()) { - ObjectWrapper.Option(wrapper.map) - } else { - null - } + + ColumnView.Format.CHECKBOX -> { + CellView.Checkbox( + id = obj.id, + relationKey = column.key, + isChecked = obj.getValue(column.key) ?: false, + space = space + ) } - val tags = obj.map.buildTagViews( - options = options, - relationKey = column.key - ) - CellView.Tag( - id = obj.id, - relationKey = column.key, - tags = tags, - space = space - ) - } - ColumnView.Format.STATUS -> { - val value : Id? = obj.getValue(column.key).let { value -> - when(value) { - is Id -> value - is List<*> -> value.typeOf().firstOrNull() - else -> null - } + + ColumnView.Format.URL -> { + CellView.Url( + id = obj.id, + relationKey = column.key, + url = obj.getValue(column.key).orEmpty(), + space = space + ) } - val options = buildList { - if (value != null) { - val wrapper = store.get(value) + + ColumnView.Format.EMAIL -> { + CellView.Email( + id = obj.id, + relationKey = column.key, + email = obj.getValue(column.key).orEmpty(), + space = space + ) + } + + ColumnView.Format.PHONE -> { + CellView.Phone( + id = obj.id, + relationKey = column.key, + phone = obj.getValue(column.key).orEmpty(), + space = space + ) + } + + ColumnView.Format.OBJECT -> { + val objects = obj.map.buildObjectViews( + columnKey = column.key, + builder = builder, + store = store + ) + CellView.Object( + id = obj.id, + relationKey = column.key, + objects = objects, + space = space + ) + } + + ColumnView.Format.TAG -> { + val values = obj.getValue>(column.key) ?: emptyList() + val options = values.mapNotNull { + val wrapper = store.get(it) if (wrapper != null && !wrapper.isEmpty()) { - add( - ObjectWrapper.Option(wrapper.map) - ) - } } + ObjectWrapper.Option(wrapper.map) + } else { + null + } + } + val tags = obj.map.buildTagViews( + options = options, + relationKey = column.key + ) + CellView.Tag( + id = obj.id, + relationKey = column.key, + tags = tags, + space = space + ) + } + + ColumnView.Format.STATUS -> { + val value: Id? = obj.getValue(column.key).let { value -> + when (value) { + is Id -> value + is List<*> -> value.typeOf().firstOrNull() + else -> null + } + } + val options = buildList { + if (value != null) { + val wrapper = store.get(value) + if (wrapper != null && !wrapper.isEmpty()) { + add( + ObjectWrapper.Option(wrapper.map) + ) + } + } + } + val status = obj.map.buildStatusViews( + options = options, + relationKey = column.key + ) + CellView.Status( + id = obj.id, + relationKey = column.key, + status = status, + space = space + ) + } + + else -> { + TODO() } - val status = obj.map.buildStatusViews( - options = options, - relationKey = column.key - ) - CellView.Status( - id = obj.id, - relationKey = column.key, - status = status, - space = space - ) } - else -> { - TODO() - } - } - ) + ) + } } } @@ -227,6 +258,7 @@ suspend fun List.buildGridRow( layout = layout, isChecked = done, showIcon = showIcon, + objectIcon = objectIcon ) } @@ -292,7 +324,8 @@ fun Struct.buildRelationValueObjectViews( suspend fun Struct.buildObjectViews( columnKey: Id, store: ObjectStore, - builder: UrlBuilder + builder: UrlBuilder, + withIcon: Boolean = true ): List { val objects = mutableListOf() val value = this.getOrDefault(columnKey, null) @@ -302,11 +335,16 @@ suspend fun Struct.buildObjectViews( if (wrapper.isDeleted == true) { objects.add(ObjectView.Deleted(id = value)) } else { + val icon = if (withIcon) { + wrapper.objectIcon(builder) + } else { + ObjectIcon.None + } objects.add( ObjectView.Default( id = value, name = wrapper.getProperName(), - icon = wrapper.objectIcon(builder), + icon = icon, types = wrapper.type ) ) @@ -321,11 +359,16 @@ suspend fun Struct.buildObjectViews( if (wrapper.isDeleted == true) { objects.add(ObjectView.Deleted(id = id)) } else { + val icon = if (withIcon) { + wrapper.objectIcon(builder) + } else { + ObjectIcon.None + } objects.add( ObjectView.Default( id = id, name = wrapper.getProperName(), - icon = wrapper.objectIcon(builder), + icon = icon, types = wrapper.type ) ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt index 630009574c..6675f62b5e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/filter/FilterViewModel.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_models.RelationFormat +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_utils.ext.typeOf import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer @@ -381,10 +382,11 @@ open class FilterViewModel( viewModelScope.launch { searchObjects( SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = ObjectSearchConstants.sortAddObjectToFilter, filters = ObjectSearchConstants.filterAddObjectToFilter( - limitObjectTypes = limitObjectTypes, - space = spaceManager.get() + limitObjectTypes = limitObjectTypes ), fulltext = SearchObjects.EMPTY_TEXT, offset = SearchObjects.INIT_OFFSET, @@ -414,10 +416,11 @@ open class FilterViewModel( viewModelScope.launch { searchObjects( SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = ObjectSearchConstants.sortAddObjectToFilter, filters = ObjectSearchConstants.filterAddObjectToFilterByLayout( - layouts = layouts, - space = spaceManager.get() + layouts = layouts ), fulltext = SearchObjects.EMPTY_TEXT, offset = SearchObjects.INIT_OFFSET, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt index 08d3cd6571..dde5e9f32d 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/model/Viewer.kt @@ -45,6 +45,7 @@ sealed class Viewer { val cells: List = emptyList(), val layout: ObjectType.Layout? = null, val showIcon: Boolean, + val objectIcon: ObjectIcon ) companion object { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/subscription/DataViewSubscription.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/subscription/DataViewSubscription.kt index 9a555dc1ac..d06499d7c9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/subscription/DataViewSubscription.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/subscription/DataViewSubscription.kt @@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.DVSort import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.RelationLink +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.search.DataViewState import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer import com.anytypeio.anytype.presentation.relations.ObjectSetConfig @@ -66,12 +67,13 @@ class DefaultDataViewSubscription( } val filters = buildList { addAll(activeViewer.filters.updateFormatForSubscription(relationLinks = dataViewRelationLinks)) - addAll(defaultDataViewFilters(space= space)) + addAll(defaultDataViewFilters()) } val dataViewLinksKeys = state.dataViewContent.relationLinks.map { it.key } val keys = ObjectSearchConstants.defaultDataViewKeys + dataViewLinksKeys val params = DataViewSubscriptionContainer.Params( + space = SpaceId(space), collection = collection, subscription = getDataViewSubscriptionId(context), sorts = activeViewer.sorts.updateWithRelationFormat(relationLinks = dataViewRelationLinks), @@ -119,12 +121,13 @@ class DefaultDataViewSubscription( val filters = buildList { addAll(activeViewer.filters.updateFormatForSubscription(relationLinks = dataViewRelationLinks)) - addAll(defaultDataViewFilters(space = space)) + addAll(defaultDataViewFilters()) } val dataViewLinksKeys = state.dataViewContent.relationLinks.map { it.key } val keys = ObjectSearchConstants.defaultDataViewKeys + dataViewLinksKeys val params = DataViewSubscriptionContainer.Params( + space = SpaceId(space), subscription = getDataViewSubscriptionId(context), sorts = activeViewer.sorts.updateWithRelationFormat(relationLinks = dataViewRelationLinks), filters = filters, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/FilesStorageViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/FilesStorageViewModel.kt index 66d3d7d5fc..f35dd7096b 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/FilesStorageViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/FilesStorageViewModel.kt @@ -9,6 +9,7 @@ import com.anytypeio.anytype.analytics.base.sendEvent import com.anytypeio.anytype.core_models.FileLimits import com.anytypeio.anytype.core_models.FileLimitsEvent import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_utils.ext.bytesToHumanReadableSizeLocal import com.anytypeio.anytype.core_utils.ext.cancel import com.anytypeio.anytype.core_utils.ext.msg @@ -205,6 +206,7 @@ class FilesStorageViewModel( val profileId = config.profile spaceManager.observe() val subscribeParams = StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = SPACE_STORAGE_SUBSCRIPTION_ID, targets = listOf(spaceId, profileId), keys = listOf( @@ -317,11 +319,11 @@ class FilesStorageViewModel( } sealed class Event { - object OnOffloadFilesClicked : Event() + data object OnOffloadFilesClicked : Event() } sealed class Command { - object OpenOffloadFilesScreen : Command() + data object OpenOffloadFilesScreen : Command() } class Factory @Inject constructor( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt index 1d1edc7d68..3d95747f9b 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt @@ -51,7 +51,9 @@ class PersonalizationSettingsViewModel( init { viewModelScope.launch { - getDefaultObjectType.execute(Unit).fold( + getDefaultObjectType.execute( + params = SpaceId(spaceManager.get()) + ).fold( onFailure = { e -> Timber.e(e, "Error while getting user settings") }, @@ -110,19 +112,14 @@ class PersonalizationSettingsViewModel( } searchObjects( SearchObjects.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), keys = buildList { add(Relations.ID) add(Relations.UNIQUE_KEY) add(Relations.NAME) }, filters = buildList { - add( - DVFilter( - relation = Relations.SPACE_ID, - value = spaceManager.get(), - condition = DVFilterCondition.EQUAL - ) - ) add( DVFilter( relation = Relations.LAYOUT, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModel.kt index 8690447c48..438a8352e6 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModel.kt @@ -23,6 +23,7 @@ import com.anytypeio.anytype.core_utils.ext.throttleFirst import com.anytypeio.anytype.domain.auth.interactor.GetAccount import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.base.fold +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -59,7 +60,8 @@ class SpacesStorageViewModel( private val getAccount: GetAccount, private val storelessSubscriptionContainer: StorelessSubscriptionContainer, private val membershipProvider: MembershipProvider, - private val userPermissionProvider: UserPermissionProvider + private val userPermissionProvider: UserPermissionProvider, + private val configStorage: ConfigStorage ) : BaseViewModel() { private val _activeTier = MutableStateFlow(ActiveTierState.Init) @@ -117,21 +119,28 @@ class SpacesStorageViewModel( private fun subscribeToSpaces() { jobs += viewModelScope.launch { - val subscribeParams = createStoreSearchParams() - combine( - _nodeUsageInfo, - storelessSubscriptionContainer.subscribe(subscribeParams) - ) { nodeUsageInfo, spaces -> - createSpacesStorageScreenState(nodeUsageInfo, spaces) + val techSpace = configStorage.getOrNull()?.techSpace + if (techSpace != null) { + val subscribeParams = createStoreSearchParams( + techSpace = SpaceId(techSpace) + ) + combine( + _nodeUsageInfo, + storelessSubscriptionContainer.subscribe(subscribeParams) + ) { nodeUsageInfo, spaces -> + createSpacesStorageScreenState(nodeUsageInfo, spaces) + }.flowOn(appCoroutineDispatchers.io) + .catch { Timber.e(it, "Error while getting spaces") } + .collect { _viewState.value = it } + } else { + Timber.e("Tech space was missing") } - .flowOn(appCoroutineDispatchers.io) - .catch { Timber.e(it, "Error while getting spaces") } - .collect { _viewState.value = it } } } - private fun createStoreSearchParams(): StoreSearchParams { + private fun createStoreSearchParams(techSpace: SpaceId): StoreSearchParams { return StoreSearchParams( + space = techSpace, subscription = SPACES_STORAGE_SUBSCRIPTION_ID, keys = listOf( Relations.ID, @@ -298,6 +307,7 @@ class SpacesStorageViewModel( } else { val config = spaceManager.getConfig() ?: return@launch val params = StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = PROFILE_SUBSCRIPTION_ID, keys = listOf(Relations.ID, Relations.NAME), targets = listOf(config.profile) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModelFactory.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModelFactory.kt index 10f4a3cae6..400e945572 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModelFactory.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/SpacesStorageViewModelFactory.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModelProvider import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.domain.auth.interactor.GetAccount import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.workspace.InterceptFileLimitEvents @@ -23,7 +24,8 @@ class SpacesStorageViewModelFactory @Inject constructor( private val storelessSubscriptionContainer: StorelessSubscriptionContainer, private val getAccount: GetAccount, private val membershipProvider: MembershipProvider, - private val userPermissionProvider: UserPermissionProvider + private val userPermissionProvider: UserPermissionProvider, + private val configStorage: ConfigStorage ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create( @@ -38,6 +40,7 @@ class SpacesStorageViewModelFactory @Inject constructor( getAccount = getAccount, membershipProvider = membershipProvider, userPermissionProvider = userPermissionProvider, + configStorage = configStorage, vmParams = vmParams ) as T } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sharing/AddToAnytypeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sharing/AddToAnytypeViewModel.kt index 826d059142..f68150a190 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sharing/AddToAnytypeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sharing/AddToAnytypeViewModel.kt @@ -24,6 +24,7 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_utils.ext.msg import com.anytypeio.anytype.domain.account.AwaitAccountStartManager import com.anytypeio.anytype.domain.base.fold +import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.device.FileSharer import com.anytypeio.anytype.domain.download.ProcessCancel import com.anytypeio.anytype.domain.media.FileDrop @@ -69,12 +70,17 @@ class AddToAnytypeViewModel( private val permissions: Permissions, private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate, private val fileDrop: FileDrop, - private val eventProcessChannel: EventProcessDropFilesChannel + private val eventProcessChannel: EventProcessDropFilesChannel, + private val configStorage: ConfigStorage ) : BaseViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate { private val selectedSpaceId = MutableStateFlow(NO_VALUE) - private val spaces: Flow> = getSpaceViews.asFlow(Unit) + private val spaces: Flow> = getSpaceViews.asFlow( + SpaceId( + configStorage.getOrNull()?.techSpace.orEmpty() + ) + ) val navigation = MutableSharedFlow() val spaceViews = MutableStateFlow>(emptyList()) @@ -489,7 +495,8 @@ class AddToAnytypeViewModel( private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate, private val fileDrop: FileDrop, private val eventProcessChannel: EventProcessDropFilesChannel, - private val processCancel: ProcessCancel + private val processCancel: ProcessCancel, + private val configStorage: ConfigStorage ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { @@ -505,7 +512,8 @@ class AddToAnytypeViewModel( permissions = permissions, analyticSpaceHelperDelegate = analyticSpaceHelperDelegate, fileDrop = fileDrop, - eventProcessChannel = eventProcessChannel + eventProcessChannel = eventProcessChannel, + configStorage = configStorage ) as T } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/CreateSpaceViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/CreateSpaceViewModel.kt index 802841ccaf..f0c4c0c709 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/CreateSpaceViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/CreateSpaceViewModel.kt @@ -10,6 +10,7 @@ import com.anytypeio.anytype.analytics.base.sendEvent import com.anytypeio.anytype.analytics.props.Props import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.SystemColor import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.spaces.CreateSpace @@ -32,13 +33,11 @@ class CreateSpaceViewModel( private var spaceGradientId = spaceGradientProvider.randomId() - val spaceGradient : MutableStateFlow + val spaceGradient : MutableStateFlow init { - val gradient = spaceGradientProvider.get(spaceGradientId.toDouble()) - val view = SpaceIconView.Gradient( - from = gradient.from, - to = gradient.to + val view = SpaceIconView.Placeholder( + color = SystemColor.entries.random() ) spaceGradient = MutableStateFlow(view) @@ -108,13 +107,9 @@ class CreateSpaceViewModel( } private fun proceedWithResettingRandomSpaceGradient() { - spaceGradientId = spaceGradientProvider.randomId() - val gradient = spaceGradientProvider.get(spaceGradientId.toDouble()) - val view = SpaceIconView.Gradient( - from = gradient.from, - to = gradient.to + spaceGradient.value = SpaceIconView.Placeholder( + color = SystemColor.entries.random() ) - spaceGradient.value = view } class Factory @Inject constructor( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SelectSpaceViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SelectSpaceViewModel.kt index 5b6db8fa59..27ed8eca49 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SelectSpaceViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SelectSpaceViewModel.kt @@ -5,7 +5,9 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.analytics.base.EventsDictionary +import com.anytypeio.anytype.analytics.base.EventsPropertiesKey import com.anytypeio.anytype.analytics.base.sendEvent +import com.anytypeio.anytype.analytics.props.Props import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations @@ -50,34 +52,6 @@ class SelectSpaceViewModel( val commands = MutableSharedFlow() val jobs = mutableListOf() - private val profile = spaceManager - .observe() - .flatMapLatest { config -> - container.subscribe( - StoreSearchByIdsParams( - subscription = SELECT_SPACE_PROFILE_SUBSCRIPTION, - keys = listOf( - Relations.ID, - Relations.NAME, - Relations.ICON_IMAGE, - Relations.ICON_EMOJI, - Relations.ICON_OPTION - ), - targets = listOf(config.profile) - ) - ).map { results -> - if (results.isNotEmpty()) - results.first() - else { - ObjectWrapper.Basic( - mapOf( - Relations.ID to config.profile - ) - ) - } - } - } - private val spaces: Flow> = spaceViewContainer .observe() .map { results -> @@ -128,10 +102,7 @@ class SelectSpaceViewModel( val (active, others) = spaceViews.partition { view -> view.view.isSelected } addAll(active) addAll(others) - val numberOfSpaces = count { view -> view is SelectSpaceView.Space } - if (numberOfSpaces < MAX_SPACE_COUNT) { - add(SelectSpaceView.Create) - } + add(SelectSpaceView.Create) } } .catch { @@ -146,6 +117,16 @@ class SelectSpaceViewModel( fun onStart() { buildUI() + viewModelScope.launch { + analytics.sendEvent( + eventName = EventsDictionary.screenVault, + props = Props( + map = mapOf( + EventsPropertiesKey.type to EventsDictionary.Type.menu + ) + ) + ) + } } fun onStop() { @@ -180,13 +161,8 @@ class SelectSpaceViewModel( } fun onCreateSpaceClicked() { - val count = views.value.count { view -> view is SelectSpaceView.Space } - if (count >= MAX_SPACE_COUNT) { - sendToast(SPACE_COUNT_EXCEEDED_ERROR) - } else { - viewModelScope.launch { - commands.emit(Command.CreateSpace) - } + viewModelScope.launch { + commands.emit(Command.CreateSpace) } } @@ -194,7 +170,6 @@ class SelectSpaceViewModel( viewModelScope.launch { container.unsubscribe( subscriptions = listOf( - SELECT_SPACE_PROFILE_SUBSCRIPTION, SELECT_SPACE_SUBSCRIPTION ) ) @@ -226,9 +201,6 @@ class SelectSpaceViewModel( companion object { const val SELECT_SPACE_SUBSCRIPTION = "select_space_subscription.spaces" - const val SELECT_SPACE_PROFILE_SUBSCRIPTION = "select_space_subscription.profile" - const val MAX_SPACE_COUNT = 10 - const val SPACE_COUNT_EXCEEDED_ERROR = "Space max count exceeded. You cannot create more." } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceIconView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceIconView.kt index 41080af3e7..6eda3b1abb 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceIconView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceIconView.kt @@ -11,8 +11,6 @@ sealed class SpaceIconView { val color: SystemColor = SystemColor.YELLOW, val name: String = "" ): SpaceIconView() - @Deprecated("To be deleted") - class Gradient(val from: String, val to: String) : SpaceIconView() data class Image(val url: Url) : SpaceIconView() } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt index 84c90bdff8..b9c22a5b66 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/spaces/SpaceSettingsViewModel.kt @@ -34,7 +34,9 @@ import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionCon import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.multiplayer.isSharingLimitReached +import com.anytypeio.anytype.domain.multiplayer.sharedSpaceCount import com.anytypeio.anytype.domain.payments.GetMembershipStatus +import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager import com.anytypeio.anytype.domain.spaces.DeleteSpace import com.anytypeio.anytype.domain.spaces.SetSpaceDetails import com.anytypeio.anytype.domain.workspace.SpaceManager @@ -43,6 +45,7 @@ import javax.inject.Inject import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import timber.log.Timber @@ -61,7 +64,8 @@ class SpaceSettingsViewModel( private val spaceViewContainer: SpaceViewSubscriptionContainer, private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer, private val getMembership: GetMembershipStatus, - private val uploadFile: UploadFile + private val uploadFile: UploadFile, + private val profileContainer: ProfileSubscriptionManager ): BaseViewModel() { val commands = MutableSharedFlow() @@ -87,8 +91,14 @@ class SpaceSettingsViewModel( combine( spaceViewContainer.observe(params.space), userPermissionProvider.observe(params.space), - spaceViewContainer.isSharingLimitReached(userPermissionProvider.all()) - ) { spaceView, permission, shareLimitReached -> + profileContainer + .observe() + .map { wrapper -> + wrapper.getValue(Relations.SHARED_SPACES_LIMIT)?.toInt() ?: 0 + }, + spaceViewContainer.sharedSpaceCount(userPermissionProvider.all()) + ) { spaceView, permission, sharedSpaceLimit: Int, sharedSpaceCount: Int -> + Timber.d("Got shared space limit: $sharedSpaceLimit, shared space count: $sharedSpaceCount") val store = activeSpaceMemberSubscriptionContainer.get(params.space) val requests: Int = if (store is ActiveSpaceMemberSubscriptionContainer.Store.Data) { store.members.count { it.status == ParticipantStatus.JOINING } @@ -113,12 +123,12 @@ class SpaceSettingsViewModel( createdBy = createdBy, spaceId = params.space.id, network = config?.network.orEmpty(), - isDeletable = resolveIsSpaceDeletable(spaceView), + isDeletable = true, spaceType = spaceView.spaceAccessType?.asSpaceType() ?: UNKNOWN_SPACE_TYPE, permissions = permission ?: SpaceMemberPermissions.NO_PERMISSIONS, shareLimitReached = ShareLimitsState( - shareLimitReached = shareLimitReached.first, - sharedSpacesLimit = shareLimitReached.second + shareLimitReached = sharedSpaceCount >= sharedSpaceLimit, + sharedSpacesLimit = sharedSpaceLimit ), requests = requests ) @@ -129,9 +139,6 @@ class SpaceSettingsViewModel( } } - private fun resolveIsSpaceDeletable(spaceView: ObjectWrapper.SpaceView) = - spaceView.spaceAccessType != null && spaceView.spaceAccessType != SpaceAccessType.DEFAULT - fun onNameSet(name: String) { Timber.d("onNameSet") if (name.isEmpty()) return @@ -254,7 +261,8 @@ class SpaceSettingsViewModel( eventName = EventsDictionary.deleteSpace, props = Props(mapOf(EventsPropertiesKey.type to "Private")) ) - fallbackToPersonalSpaceAfterDeletion(personalSpaceId) + spaceManager.clear() + commands.emit(Command.ExitToVault) }, onFailure = { Timber.e(it, "Error while deleting space") @@ -267,11 +275,6 @@ class SpaceSettingsViewModel( } } - private suspend fun fallbackToPersonalSpaceAfterDeletion(personalSpaceId: Id) { - spaceManager.set(personalSpaceId) - isDismissed.value = true - } - private fun proceedWithSpaceDebug() { viewModelScope.launch { debugSpaceShareDownloader @@ -391,6 +394,7 @@ class SpaceSettingsViewModel( data class ShareSpaceDebug(val filepath: Filepath) : Command() data class SharePrivateSpace(val space: SpaceId) : Command() data class ManageSharedSpace(val space: SpaceId) : Command() + data object ExitToVault : Command() data object ShowDeleteSpaceWarning : Command() data object ShowLeaveSpaceWarning : Command() data object ShowShareLimitReachedError : Command() @@ -413,7 +417,8 @@ class SpaceSettingsViewModel( private val userPermissionProvider: UserPermissionProvider, private val activeSpaceMemberSubscriptionContainer: ActiveSpaceMemberSubscriptionContainer, private val getMembership: GetMembershipStatus, - private val uploadFile: UploadFile + private val uploadFile: UploadFile, + private val profileContainer: ProfileSubscriptionManager ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create( @@ -433,7 +438,8 @@ class SpaceSettingsViewModel( userPermissionProvider = userPermissionProvider, activeSpaceMemberSubscriptionContainer = activeSpaceMemberSubscriptionContainer, getMembership = getMembership, - uploadFile = uploadFile + uploadFile = uploadFile, + profileContainer = profileContainer ) as T } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt index 59a8f2c4cf..63f16d2857 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt @@ -188,7 +188,7 @@ class SplashViewModel( when (result) { CreateObjectByTypeAndTemplate.Result.ObjectTypeNotFound -> { commands.emit(Command.Toast(ERROR_CREATE_OBJECT)) - proceedWithDashboardNavigation() + proceedWithVaultNavigation() } is CreateObjectByTypeAndTemplate.Result.Success -> { val target = result.objectId @@ -221,7 +221,7 @@ class SplashViewModel( fun onDeepLinkLaunch(deeplink: String) { Timber.d("onDeepLinkLaunch, deeplink:[$deeplink]") viewModelScope.launch { - proceedWithDashboardNavigation(deeplink) + proceedWithVaultNavigation(deeplink) } } @@ -232,7 +232,7 @@ class SplashViewModel( ).process( failure = { Timber.e(it, "Error while getting last opened object") - proceedWithDashboardNavigation() + proceedWithVaultNavigation() }, success = { response -> when (response) { @@ -257,17 +257,17 @@ class SplashViewModel( ) } } else { - proceedWithDashboardNavigation() + proceedWithVaultNavigation() } } - else -> proceedWithDashboardNavigation() + else -> proceedWithVaultNavigation() } } ) } } - private suspend fun proceedWithDashboardNavigation(deeplink: String? = null) { + private suspend fun proceedWithVaultNavigation(deeplink: String? = null) { val space = getLastOpenedSpace.async(Unit).getOrNull() if (space != null) { commands.emit(Command.NavigateToWidgets(deeplink)) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/ObjectTypeTemplatesContainer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/ObjectTypeTemplatesContainer.kt index cbc3c58121..62f2a577ec 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/ObjectTypeTemplatesContainer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/templates/ObjectTypeTemplatesContainer.kt @@ -37,6 +37,7 @@ class DefaultObjectTypeTemplatesContainer( emptyFlow() } else { val params = StoreSearchParams( + space = space, subscription = subscription, sorts = listOf( DVSort( @@ -66,11 +67,6 @@ class DefaultObjectTypeTemplatesContainer( condition = DVFilterCondition.EQUAL, value = type ), - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = space.id - ), DVFilter( relation = Relations.ID, condition = DVFilterCondition.NOT_EMPTY diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt index 3ed6925d18..9b95628c47 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.restrictions.SpaceStatus import com.anytypeio.anytype.domain.base.fold import com.anytypeio.anytype.domain.base.onSuccess +import com.anytypeio.anytype.domain.misc.DeepLinkResolver import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.spaces.SaveCurrentSpace @@ -25,11 +26,19 @@ import com.anytypeio.anytype.domain.vault.SetVaultSettings import com.anytypeio.anytype.domain.vault.SetVaultSpaceOrder import com.anytypeio.anytype.domain.wallpaper.GetSpaceWallpapers import com.anytypeio.anytype.domain.workspace.SpaceManager +import com.anytypeio.anytype.presentation.BuildConfig import com.anytypeio.anytype.presentation.common.BaseViewModel +import com.anytypeio.anytype.presentation.home.Command +import com.anytypeio.anytype.presentation.home.OpenObjectNavigation +import com.anytypeio.anytype.presentation.home.navigation +import com.anytypeio.anytype.presentation.navigation.DeepLinkToObjectDelegate +import com.anytypeio.anytype.presentation.navigation.NavigationViewModel import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import com.anytypeio.anytype.presentation.spaces.SpaceIconView import com.anytypeio.anytype.presentation.spaces.spaceIcon +import com.anytypeio.anytype.presentation.widgets.collection.Subscription import javax.inject.Inject +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine @@ -46,8 +55,9 @@ class VaultViewModel( private val setVaultSettings: SetVaultSettings, private val observeVaultSettings: ObserveVaultSettings, private val setVaultSpaceOrder: SetVaultSpaceOrder, - private val analytics: Analytics -) : BaseViewModel() { + private val analytics: Analytics, + private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate, +) : NavigationViewModel(), DeepLinkToObjectDelegate by deepLinkToObjectDelegate { val spaces = MutableStateFlow>(emptyList()) val commands = MutableSharedFlow(replay = 0) @@ -64,6 +74,7 @@ class VaultViewModel( space.spaceLocalStatus == SpaceStatus.OK && !space.spaceAccountStatus.isDeletedOrRemoving() } + .distinctBy { it.id } .map { space -> VaultSpaceView( space = space, @@ -113,18 +124,7 @@ class VaultViewModel( fun onSettingsClicked() { viewModelScope.launch { - val entrySpaceView = spaces.value.find { space -> - space.space.spaceAccessType == SpaceAccessType.DEFAULT - } - if (entrySpaceView != null && entrySpaceView.space.targetSpaceId != null) { - commands.emit( - Command.OpenProfileSettings( - space = SpaceId(requireNotNull(entrySpaceView.space.targetSpaceId)) - ) - ) - } else { - Timber.w("Entry space not found") - } + commands.emit(Command.OpenProfileSettings) } } @@ -140,7 +140,8 @@ class VaultViewModel( viewModelScope.launch { commands.emit(Command.CreateNewSpace) } } - fun onResume() { + fun onResume(deeplink: DeepLinkResolver.Action? = null) { + Timber.d("onResume") viewModelScope.launch { analytics.sendEvent( eventName = EventsDictionary.screenVault, @@ -163,6 +164,53 @@ class VaultViewModel( } } } + viewModelScope.launch { + when (deeplink) { + is DeepLinkResolver.Action.Import.Experience -> { + commands.emit( + Command.Deeplink.GalleryInstallation( + deepLinkType = deeplink.type, + deepLinkSource = deeplink.source + ) + ) + } + + is DeepLinkResolver.Action.Invite -> { + delay(1000) + commands.emit(Command.Deeplink.Invite(deeplink.link)) + } + is DeepLinkResolver.Action.Unknown -> { + if (BuildConfig.DEBUG) { + sendToast("Could not resolve deeplink") + } + } + is DeepLinkResolver.Action.DeepLinkToObject -> { + val result = onDeepLinkToObject( + obj = deeplink.obj, + space = deeplink.space, + switchSpaceIfObjectFound = true + ) + when(result) { + is DeepLinkToObjectDelegate.Result.Error -> { + commands.emit(Command.Deeplink.DeepLinkToObjectNotWorking) + } + is DeepLinkToObjectDelegate.Result.Success -> { + proceedWithNavigation(result.obj.navigation()) + } + } + } + is DeepLinkResolver.Action.DeepLinkToMembership -> { + commands.emit( + Command.Deeplink.MembershipScreen( + tierId = deeplink.tierId + ) + ) + } + else -> { + Timber.d("No deep link") + } + } + } } private suspend fun proceedWithSavingCurrentSpace(targetSpace: String) { @@ -178,6 +226,31 @@ class VaultViewModel( ) } + private fun proceedWithNavigation(navigation: OpenObjectNavigation) { + when(navigation) { + is OpenObjectNavigation.OpenDataView -> { + navigate( + Navigation.OpenSet( + ctx = navigation.target, + space = navigation.space, + view = null + ) + ) + } + is OpenObjectNavigation.OpenEditor -> { + navigate( + Navigation.OpenObject( + ctx = navigation.target, + space = navigation.space + ) + ) + } + is OpenObjectNavigation.UnexpectedLayoutError -> { + sendToast("Unexpected layout: ${navigation.layout}") + } + } + } + class Factory @Inject constructor( private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer, private val getSpaceWallpapers: GetSpaceWallpapers, @@ -188,7 +261,8 @@ class VaultViewModel( private val setVaultSettings: SetVaultSettings, private val setVaultSpaceOrder: SetVaultSpaceOrder, private val observeVaultSettings: ObserveVaultSettings, - private val analytics: Analytics + private val analytics: Analytics, + private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create( @@ -203,7 +277,8 @@ class VaultViewModel( setVaultSettings = setVaultSettings, setVaultSpaceOrder = setVaultSpaceOrder, observeVaultSettings = observeVaultSettings, - analytics = analytics + analytics = analytics, + deepLinkToObjectDelegate = deepLinkToObjectDelegate ) as T } @@ -216,7 +291,22 @@ class VaultViewModel( sealed class Command { data object EnterSpaceHomeScreen: Command() data object CreateNewSpace: Command() - data class OpenProfileSettings(val space: SpaceId): Command() + data object OpenProfileSettings: Command() data object ShowIntroduceVault : Command() + + sealed class Deeplink : Command() { + data object DeepLinkToObjectNotWorking: Deeplink() + data class Invite(val link: String) : Deeplink() + data class GalleryInstallation( + val deepLinkType: String, + val deepLinkSource: String + ) : Deeplink() + data class MembershipScreen(val tierId: String?) : Deeplink() + } + } + + sealed class Navigation { + data class OpenObject(val ctx: Id, val space: Id) : Navigation() + data class OpenSet(val ctx: Id, val space: Id, val view: Id?) : Navigation() } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/DataViewListWidgetContainer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/DataViewListWidgetContainer.kt index fc5afa9478..9cd43fa867 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/DataViewListWidgetContainer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/DataViewListWidgetContainer.kt @@ -10,6 +10,7 @@ import com.anytypeio.anytype.core_models.ObjectView import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.ext.content +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.misc.UrlBuilder @@ -317,6 +318,7 @@ fun ObjectView.parseDataViewStoreSearchParams( val dataViewKeys = dv.relationLinks.map { it.key } val defaultKeys = ObjectSearchConstants.defaultDataViewKeys return StoreSearchParams( + space = SpaceId(config.space), subscription =subscription, sorts = view.sorts, keys = buildList { @@ -327,9 +329,7 @@ fun ObjectView.parseDataViewStoreSearchParams( filters = buildList { addAll(view.filters) addAll( - ObjectSearchConstants.defaultDataViewFilters( - space = config.space - ) + ObjectSearchConstants.defaultDataViewFilters() ) }, limit = limit, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/ListWidgetContainer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/ListWidgetContainer.kt index 3bb1285b37..e54382b1d2 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/ListWidgetContainer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/ListWidgetContainer.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.core_models.ObjectView import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.RelationFormat import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams import com.anytypeio.anytype.domain.library.StoreSearchParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer @@ -90,6 +91,7 @@ class ListWidgetContainer( .flatMapLatest { order -> storage.subscribe( StoreSearchByIdsParams( + space = SpaceId(widget.config.space), subscription = subscription, keys = keys, targets = order.keys @@ -110,6 +112,7 @@ class ListWidgetContainer( Timber.e(it, "Failed to load favorite objects") } } + BundledWidgetSourceIds.RECENT -> { val spaceView = getSpaceView.async( GetSpaceView.Params.BySpaceViewId(widget.config.spaceView) @@ -127,6 +130,7 @@ class ListWidgetContainer( ) } } + else -> { storage.subscribe(buildParams()).map { objects -> buildWidgetViewWithElements( @@ -191,39 +195,45 @@ class ListWidgetContainer( limit: Int, customFavoritesOrder: List = emptyList(), spaceCreationDateInSeconds: Long? = null - ) : StoreSearchParams = when (subscription) { + ): StoreSearchParams = when (subscription) { BundledWidgetSourceIds.RECENT -> { StoreSearchParams( + space = SpaceId(space), subscription = subscription, sorts = ObjectSearchConstants.sortTabRecent, filters = ObjectSearchConstants.filterTabRecent( - space = space, spaceCreationDateInSeconds = spaceCreationDateInSeconds ), keys = keys, limit = limit ) } + BundledWidgetSourceIds.RECENT_LOCAL -> { StoreSearchParams( + space = SpaceId(space), subscription = subscription, sorts = ObjectSearchConstants.sortTabRecentLocal, - filters = ObjectSearchConstants.filterTabRecentLocal(space), + filters = ObjectSearchConstants.filterTabRecentLocal(), keys = keys, limit = limit ) } + BundledWidgetSourceIds.SETS -> { StoreSearchParams( + space = SpaceId(space), subscription = subscription, sorts = ObjectSearchConstants.sortTabSets, - filters = ObjectSearchConstants.filterTabSets(space), + filters = ObjectSearchConstants.filterTabSets(), keys = keys, limit = limit ) } + BundledWidgetSourceIds.FAVORITE -> { StoreSearchParams( + space = SpaceId(space), subscription = subscription, sorts = buildList { if (customFavoritesOrder.isNotEmpty()) { @@ -237,29 +247,34 @@ class ListWidgetContainer( ) } }, - filters = ObjectSearchConstants.filterTabFavorites(space), + filters = ObjectSearchConstants.filterTabFavorites(), keys = keys, limit = limit ) } + BundledWidgetSourceIds.COLLECTIONS -> { StoreSearchParams( + space = SpaceId(space), subscription = subscription, sorts = collectionsSorts, - filters = ObjectSearchConstants.collectionFilters(space), + filters = ObjectSearchConstants.collectionFilters(), keys = keys, limit = limit ) } + Subscriptions.SUBSCRIPTION_ARCHIVED -> { StoreSearchParams( + space = SpaceId(space), subscription = subscription, sorts = ObjectSearchConstants.sortTabArchive, - filters = ObjectSearchConstants.filterTabArchive(space), + filters = ObjectSearchConstants.filterTabArchive(), keys = keys, limit = limit ) } + else -> throw IllegalStateException("Unexpected subscription: $subscription") } @@ -270,7 +285,7 @@ class ListWidgetContainer( } } -fun ObjectView.orderOfRootObjects(root: Id) : Map { +fun ObjectView.orderOfRootObjects(root: Id): Map { val parent = blocks.find { it.id == root } return if (parent != null) { val order = parent.children.withIndex().associate { (index, id) -> id to index } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SelectWidgetTypeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SelectWidgetTypeViewModel.kt index 491197b8d7..b4b5ee1944 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SelectWidgetTypeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SelectWidgetTypeViewModel.kt @@ -61,12 +61,16 @@ class SelectWidgetTypeViewModel( ) } } else { - val objectLayout = ObjectType.Layout.values().find { it.code == sourceLayout } + val objectLayout = ObjectType.Layout.entries.find { it.code == sourceLayout } if (objectLayout.isDataView()) { views.value = listOf( WidgetTypeView.View().setIsSelected(currentType), WidgetTypeView.Link().setIsSelected(currentType) ) + } else if (objectLayout == ObjectType.Layout.PARTICIPANT) { + views.value = listOf( + WidgetTypeView.Link().setIsSelected(currentType) + ) } else { views.value = views.value.map { view -> view.setIsSelected(currentType) } } @@ -92,12 +96,16 @@ class SelectWidgetTypeViewModel( ) } } else { - val objectLayout = ObjectType.Layout.values().find { it.code == layout } + val objectLayout = ObjectType.Layout.entries.find { it.code == layout } if (objectLayout.isDataView()) { views.value = listOf( WidgetTypeView.View(isSelected = false), WidgetTypeView.Link(isSelected = false) ) + } else if (objectLayout == ObjectType.Layout.PARTICIPANT) { + views.value = listOf( + WidgetTypeView.Link(isSelected = true) + ) } else { views.value = listOf( WidgetTypeView.Tree(isSelected = false), diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SpaceWidgetContainer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SpaceWidgetContainer.kt index 2d0d890a8d..16b0db68fa 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SpaceWidgetContainer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/SpaceWidgetContainer.kt @@ -40,6 +40,7 @@ class SpaceWidgetContainer @Inject constructor( combine( container.subscribe( StoreSearchByIdsParams( + space = SpaceId(config.techSpace), subscription = SPACE_WIDGET_SUBSCRIPTION, targets = listOf(config.spaceView), keys = buildList { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/TreeWidgetContainer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/TreeWidgetContainer.kt index ed583991d0..862cc24618 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/TreeWidgetContainer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/TreeWidgetContainer.kt @@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectTypeIds import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.misc.UrlBuilder @@ -77,6 +78,7 @@ class TreeWidgetContainer( }.flatMapLatest { rootLevelObjects -> container.subscribe( StoreSearchByIdsParams( + space = SpaceId(widget.config.space), subscription = widget.id, keys = keys, targets = if (!isWidgetCollapsed) { @@ -118,6 +120,7 @@ class TreeWidgetContainer( is Widget.Source.Default -> { container.subscribe( StoreSearchByIdsParams( + space = SpaceId(widget.config.space), subscription = widget.id, keys = keys, targets = if (!isWidgetCollapsed) { @@ -166,6 +169,7 @@ class TreeWidgetContainer( .flatMapLatest { order -> container.subscribe( StoreSearchByIdsParams( + space = SpaceId(widget.config.space), subscription = widget.source.id, targets = order.keys.toList(), keys = keys diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt index cb90266f87..365e8ae200 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt @@ -200,6 +200,7 @@ class CollectionViewModel( .flatMapLatest { config -> container.subscribe( StoreSearchByIdsParams( + space = SpaceId(config.space), subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(config.profile), keys = listOf( @@ -223,10 +224,10 @@ class CollectionViewModel( private suspend fun objectTypes(): StateFlow> { val params = GetObjectTypes.Params( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), sorts = emptyList(), - filters = ObjectSearchConstants.filterTypes( - spaces = listOf(vmParams.spaceId.id) - ), + filters = ObjectSearchConstants.filterTypes(), keys = ObjectSearchConstants.defaultKeysObjectType ) return getObjectTypes.asFlow(params).stateIn(viewModelScope) @@ -264,6 +265,8 @@ class CollectionViewModel( private suspend fun buildSearchParams(): StoreSearchParams { return StoreSearchParams( + // TODO DROID-2916 Provide space id to vm params + space = SpaceId(spaceManager.get()), subscription = subscription.id, keys = subscription.keys, filters = subscription.space(vmParams.spaceId.id), @@ -290,10 +293,10 @@ class CollectionViewModel( ?.toLong() subscriptionFlow( StoreSearchParams( + space = SpaceId(config.space), subscription = subscription.id, keys = subscription.keys, filters = ObjectSearchConstants.filterTabRecent( - space = config.space, spaceCreationDateInSeconds = spaceCreationDateInSeconds ), sorts = subscription.sorts, @@ -881,8 +884,11 @@ class CollectionViewModel( ) val startTime = System.currentTimeMillis() - val params = objType?.uniqueKey.getCreateObjectParams(objType?.defaultTemplateId) viewModelScope.launch { + val params = objType?.uniqueKey.getCreateObjectParams( + space = SpaceId(spaceManager.get()), + objType?.defaultTemplateId + ) createObject.execute(params).fold( onSuccess = { result -> sendAnalyticsObjectCreateEvent( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/Subscription.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/Subscription.kt index 68d3c487e8..081fab6daf 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/Subscription.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/Subscription.kt @@ -21,7 +21,7 @@ sealed class Subscription( SUBSCRIPTION_DEFAULT_KEYS + Relations.LAST_MODIFIED_DATE, ObjectSearchConstants.sortTabRecent, ObjectSearchConstants.limitTabRecent, - space = { space -> ObjectSearchConstants.filterTabRecent(space) } + space = { space -> ObjectSearchConstants.filterTabRecent() } ) data object RecentLocal : Subscription( @@ -29,7 +29,7 @@ sealed class Subscription( SUBSCRIPTION_DEFAULT_KEYS + Relations.LAST_OPENED_DATE, ObjectSearchConstants.sortTabRecentLocal, ObjectSearchConstants.limitTabRecent, - space = { space -> ObjectSearchConstants.filterTabRecentLocal(space) } + space = { space -> ObjectSearchConstants.filterTabRecentLocal() } ) data object Bin : Subscription( @@ -37,7 +37,7 @@ sealed class Subscription( SUBSCRIPTION_DEFAULT_KEYS, ObjectSearchConstants.sortTabArchive, 0, - space = { space -> ObjectSearchConstants.filterTabArchive(space) } + space = { space -> ObjectSearchConstants.filterTabArchive() } ) data object Sets : Subscription( @@ -45,7 +45,7 @@ sealed class Subscription( SUBSCRIPTION_DEFAULT_KEYS, ObjectSearchConstants.sortTabSets, 0, - space = { space -> ObjectSearchConstants.filterTabSets(space) } + space = { space -> ObjectSearchConstants.filterTabSets() } ) data object Collections : Subscription( @@ -53,7 +53,7 @@ sealed class Subscription( SUBSCRIPTION_DEFAULT_KEYS, ObjectSearchConstants.sortTabSets, 0, - space = { space -> ObjectSearchConstants.collectionFilters(space) } + space = { space -> ObjectSearchConstants.collectionFilters() } ) data object Favorites : Subscription( @@ -61,7 +61,7 @@ sealed class Subscription( SUBSCRIPTION_DEFAULT_KEYS, emptyList(), 0, - space = { space -> ObjectSearchConstants.filterTabFavorites(space) } + space = { space -> ObjectSearchConstants.filterTabFavorites() } ) data object Files : Subscription( diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/ObjectStateSetViewTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/ObjectStateSetViewTest.kt index 36b4bd47e5..2405b3b317 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/ObjectStateSetViewTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/ObjectStateSetViewTest.kt @@ -9,6 +9,7 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.StubObject +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.presentation.relations.ObjectSetConfig import com.anytypeio.anytype.presentation.search.ObjectSearchConstants import com.anytypeio.anytype.presentation.sets.DataViewViewState @@ -337,12 +338,11 @@ class ObjectStateSetViewTest : ObjectSetViewModelTestSetup() { advanceUntilIdle() verifyBlocking(repo, times(1)) { searchObjectsWithSubscription( + eq(SpaceId(mockObjectSet.spaceId)), eq(mockObjectSet.subscriptionId), eq(listOf()), eq( - mockObjectSet.filters + ObjectSearchConstants.defaultDataViewFilters( - space = spaceConfig.space - ) + mockObjectSet.filters + ObjectSearchConstants.defaultDataViewFilters() ), eq(ObjectSearchConstants.defaultDataViewKeys + mockObjectSet.dvKeys), eq(listOf(type2.id)), diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt index 43db3ead99..62a392dc99 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/editor/editor/EditorPresentationTestSetup.kt @@ -777,7 +777,9 @@ open class EditorPresentationTestSetup { template: String? = null ) { getDefaultObjectType.stub { - onBlocking { async(Unit) } doReturn Resultat.success( + onBlocking { async( + params = SpaceId(defaultSpace) + ) } doReturn Resultat.success( GetDefaultObjectType.Response( id = TypeId(id), type = TypeKey(type), diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt index 3fdbd9fabe..866cc78e7d 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt @@ -512,8 +512,9 @@ class VersionHistoryViewModelTest { private fun stubSpaceMembers() { val filters = - ObjectSearchConstants.filterParticipants(spaces = listOf(vmParams.spaceId.id)) + ObjectSearchConstants.filterParticipants(vmParams.spaceId) val params = SearchObjects.Params( + space = vmParams.spaceId, filters = filters, keys = ObjectSearchConstants.spaceMemberKeys ) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt index 9413b87c06..ac4ae85e38 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModelTest.kt @@ -25,6 +25,7 @@ import com.anytypeio.anytype.core_models.StubWidgetBlock import com.anytypeio.anytype.core_models.UNKNOWN_SPACE_TYPE import com.anytypeio.anytype.core_models.WidgetSession import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions +import com.anytypeio.anytype.core_models.primitives.Space import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeId import com.anytypeio.anytype.core_models.primitives.TypeKey @@ -1275,6 +1276,7 @@ class HomeScreenViewModelTest { onBlocking { subscribe( StoreSearchByIdsParams( + space = SpaceId(defaultSpaceConfig.space), subscription = HomeScreenViewModel.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(defaultSpaceConfig.spaceView), keys = listOf(Relations.ID, Relations.ICON_EMOJI, Relations.ICON_IMAGE) @@ -1838,6 +1840,7 @@ class HomeScreenViewModelTest { verifyBlocking(storelessSubscriptionContainer, times(1)) { subscribe( StoreSearchByIdsParams( + space = Space(defaultSpaceConfig.space), subscription = favoriteSource.id, keys = ListWidgetContainer.keys, targets = emptyList() @@ -2386,12 +2389,11 @@ class HomeScreenViewModelTest { ) val firstTimeParams = StoreSearchParams( + space = SpaceId(defaultSpaceConfig.space), subscription = widgetBlock.id, filters = buildList { addAll( - ObjectSearchConstants.defaultDataViewFilters( - space = defaultSpaceConfig.space - ) + ObjectSearchConstants.defaultDataViewFilters() ) }, sorts = emptyList(), @@ -2460,6 +2462,7 @@ class HomeScreenViewModelTest { } verify(storelessSubscriptionContainer, times(1)).subscribe( StoreSearchByIdsParams( + space = SpaceId(defaultSpaceConfig.techSpace), subscription = HomeScreenViewModel.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(defaultSpaceConfig.profile), keys = listOf( @@ -2673,6 +2676,7 @@ class HomeScreenViewModelTest { onBlocking { subscribe( StoreSearchByIdsParams( + space = SpaceId(defaultSpaceConfig.space), subscription = subscription, keys = keys, targets = targets @@ -2710,6 +2714,7 @@ class HomeScreenViewModelTest { onBlocking { subscribe( StoreSearchByIdsParams( + space = SpaceId(defaultSpaceConfig.techSpace), subscription = HomeScreenViewModel.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(defaultSpaceConfig.spaceView), keys = listOf(Relations.ID, Relations.ICON_EMOJI, Relations.ICON_IMAGE) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/home/TreeWidgetContainerTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/home/TreeWidgetContainerTest.kt index 7d41a5d8a1..b59d3caf46 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/home/TreeWidgetContainerTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/home/TreeWidgetContainerTest.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.StubConfig import com.anytypeio.anytype.core_models.StubObject +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.config.Gateway import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams @@ -127,6 +128,7 @@ class TreeWidgetContainerTest { verifyBlocking(storelessSubscriptionContainer, times(1)) { subscribe( StoreSearchByIdsParams( + space = SpaceId(config.space), subscription = widget.id, targets = links.map { it.id }, keys = TreeWidgetContainer.keys @@ -209,6 +211,7 @@ class TreeWidgetContainerTest { verifyBlocking(storelessSubscriptionContainer, times(1)) { subscribe( StoreSearchByIdsParams( + space = SpaceId(config.space), subscription = widget.id, targets = links.map { it.id }, keys = TreeWidgetContainer.keys @@ -437,6 +440,7 @@ class TreeWidgetContainerTest { verifyBlocking(storelessSubscriptionContainer, times(1)) { subscribe( StoreSearchByIdsParams( + space = SpaceId(config.space), subscription = widget.id, targets = emptyList(), keys = TreeWidgetContainer.keys @@ -499,6 +503,7 @@ class TreeWidgetContainerTest { verifyBlocking(storelessSubscriptionContainer, times(1)) { subscribe( StoreSearchByIdsParams( + space = SpaceId(config.space), subscription = widget.id, targets = emptyList(), keys = TreeWidgetContainer.keys @@ -517,6 +522,7 @@ class TreeWidgetContainerTest { on { subscribe( StoreSearchByIdsParams( + space = SpaceId(config.space), subscription = widget.id, targets = targets, keys = TreeWidgetContainer.keys diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt index 180624c07c..72d29625dd 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/relations/RelationAddViewModelBaseTest.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.DVFilterCondition import com.anytypeio.anytype.core_models.Marketplace.MARKETPLACE_SPACE_ID import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.StubRelationObject +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.relations.GetRelations @@ -76,16 +77,10 @@ class RelationAddViewModelBaseTest { repo.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), sorts = ObjectSearchConstants.defaultObjectSearchSorts(), filters = buildList { addAll(ObjectSearchConstants.filterMyRelations()) - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = spaceId - ) - ) add( DVFilter( relation = Relations.RELATION_KEY, @@ -104,6 +99,7 @@ class RelationAddViewModelBaseTest { repo.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), sorts = ObjectSearchConstants.defaultObjectSearchSorts(), filters = buildList { addAll(ObjectSearchConstants.filterMarketplaceRelations()) @@ -194,16 +190,10 @@ class RelationAddViewModelBaseTest { repo.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), sorts = ObjectSearchConstants.defaultObjectSearchSorts(), filters = buildList { addAll(ObjectSearchConstants.filterMyRelations()) - add( - DVFilter( - relation = Relations.SPACE_ID, - condition = DVFilterCondition.EQUAL, - value = spaceId - ) - ) add( DVFilter( relation = Relations.RELATION_KEY, @@ -222,6 +212,7 @@ class RelationAddViewModelBaseTest { repo.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), sorts = ObjectSearchConstants.defaultObjectSearchSorts(), filters = buildList { addAll(ObjectSearchConstants.filterMarketplaceRelations()) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/TagAndStatusTests.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/TagAndStatusTests.kt index ddafe5f5c4..3aeb8e7f4a 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/TagAndStatusTests.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/TagAndStatusTests.kt @@ -10,6 +10,7 @@ import com.anytypeio.anytype.domain.config.Gateway import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.objects.DefaultObjectStore import com.anytypeio.anytype.presentation.mapper.toViewerColumns +import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.relations.ObjectSetConfig import com.anytypeio.anytype.presentation.sets.model.CellView import com.anytypeio.anytype.presentation.sets.model.ColumnView @@ -128,9 +129,7 @@ class TagAndStatusTests { val result = columns.buildGridRow( obj = ObjectWrapper.Basic(records), - relations = dataViewRelations, builder = UrlBuilder(gateway), - details = emptyMap(), showIcon = false, store = store ) @@ -140,6 +139,7 @@ class TagAndStatusTests { name = "", type = "Type111", showIcon = false, + objectIcon = ObjectIcon.Empty.Page, cells = listOf( CellView.Description( id = recordId, @@ -265,9 +265,7 @@ class TagAndStatusTests { val result = columns.buildGridRow( obj = ObjectWrapper.Basic(records), - relations = dataViewRelations, builder = UrlBuilder(gateway), - details = emptyMap(), showIcon = false, store = store ) @@ -277,6 +275,7 @@ class TagAndStatusTests { name = "", type = "Type111", showIcon = false, + objectIcon = ObjectIcon.Empty.Page, cells = listOf( CellView.Description( id = recordId, diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetConvertToCollectionTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetConvertToCollectionTest.kt index 828cb25102..e8d9b111a3 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetConvertToCollectionTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetConvertToCollectionTest.kt @@ -3,11 +3,13 @@ package com.anytypeio.anytype.presentation.sets.main import app.cash.turbine.turbineScope import com.anytypeio.anytype.core_models.Event import com.anytypeio.anytype.core_models.Payload +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.presentation.collections.MockSet import com.anytypeio.anytype.presentation.relations.ObjectSetConfig import com.anytypeio.anytype.presentation.search.ObjectSearchConstants import com.anytypeio.anytype.presentation.sets.ObjectSetViewModel import com.anytypeio.anytype.presentation.sets.state.ObjectState +import kotlin.test.assertEquals import kotlin.test.assertIs import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceUntilIdle @@ -44,31 +46,49 @@ class ObjectSetConvertToCollectionTest : ObjectSetViewModelTestSetup() { @Test fun `should start collection subscription after changing from set to collection`() = runTest { turbineScope { - // SETUP - stubSpaceManager(defaultSpace) - stubInterceptEvents() - stubNetworkMode() - stubObjectToCollection() - stubInterceptThreadStatus() - stubOpenObject( - doc = listOf(mockObjectSet.header, mockObjectSet.title, mockObjectSet.dataView), - details = mockObjectSet.details - ) - stubSubscriptionResults( - subscription = mockObjectSet.subscriptionId, - spaceId = mockObjectSet.spaceId, - storeOfRelations = storeOfRelations, - keys = mockObjectSet.dvKeys, - sources = listOf(mockObjectSet.setOf), - dvFilters = mockObjectSet.filters, - objects = listOf(mockObjectSet.obj1, mockObjectSet.obj2) - ) + + // SETUP + stubSpaceManager(defaultSpace) + stubInterceptEvents() + stubNetworkMode() + stubObjectToCollection() + stubInterceptThreadStatus() + stubOpenObject( + doc = listOf(mockObjectSet.header, mockObjectSet.title, mockObjectSet.dataView), + details = mockObjectSet.details + ) + stubSubscriptionResults( + subscription = mockObjectSet.subscriptionId, + spaceId = mockObjectSet.spaceId, + storeOfRelations = storeOfRelations, + keys = mockObjectSet.dvKeys, + sources = listOf(mockObjectSet.setOf), + dvFilters = mockObjectSet.filters, + objects = listOf(mockObjectSet.obj1, mockObjectSet.obj2) + ) val stateFlow = stateReducer.state.testIn(backgroundScope) // TESTING - proceedWithStartingViewModel() + // Making sure space ids are not mixed up: + + assertEquals( + expected = defaultSpace, + actual = mockObjectSet.spaceId + ) + + assertEquals( + expected = mockObjectSet.space, + actual = mockObjectSet.spaceId + ) + + assertEquals( + expected = defaultSpace, + actual = spaceManager.getConfig()?.space + ) + + proceedWithStartingViewModel() val firstState = stateFlow.awaitItem() assertIs(firstState) @@ -98,22 +118,19 @@ class ObjectSetConvertToCollectionTest : ObjectSetViewModelTestSetup() { verifyBlocking(repo, times(1)) { searchObjectsWithSubscription( - eq(mockObjectSet.subscriptionId), - eq(listOf()), - eq( - mockObjectSet.filters + ObjectSearchConstants.defaultDataViewFilters( - space = mockObjectSet.space - ) - ), - eq(ObjectSearchConstants.defaultDataViewKeys + mockObjectSet.dvKeys), - eq(listOf()), - eq(0L), - eq(ObjectSetConfig.DEFAULT_LIMIT), - eq(null), - eq(null), - eq(null), - eq(null), - eq(mockObjectSet.root) + SpaceId(mockObjectSet.space), + mockObjectSet.subscriptionId, + listOf(), + mockObjectSet.filters + ObjectSearchConstants.defaultDataViewFilters(), + ObjectSearchConstants.defaultDataViewKeys + mockObjectSet.dvKeys, + listOf(), + 0L, + ObjectSetConfig.DEFAULT_LIMIT, + null, + null, + null, + null, + collection = mockObjectSet.root ) } } diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt index 7c2dd83888..d1d0ba9281 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt @@ -105,7 +105,7 @@ import org.mockito.kotlin.stub open class ObjectSetViewModelTestSetup { val root: Id = "context-${RandomString.make()}" - val defaultSpace = MockDataFactory.randomUuid() + val defaultSpace = "DEFAULT_SPACE_ID" @OptIn(ExperimentalCoroutinesApi::class) @get:Rule @@ -368,13 +368,16 @@ open class ObjectSetViewModelTestSetup { suspend fun stubSpaceManager(space: Id) { repo.stub { - onBlocking { getSpaceConfig(space) } doReturn spaceConfig + onBlocking { getSpaceConfig(space) } doReturn spaceConfig.copy( + space = space + ) spaceManager.set(space) } } fun stubProfileIcon() { val searchParams = StoreSearchByIdsParams( + space = SpaceId(spaceConfig.techSpace), subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, targets = listOf(spaceConfig.profile), keys = listOf( @@ -411,11 +414,10 @@ open class ObjectSetViewModelTestSetup { dependencies = dependencies ) ).`when`(repo).searchObjectsWithSubscription( + space = SpaceId(spaceId), subscription = subscription, collection = collection, - filters = dvFilters.updateFormatForSubscription(dvRelationLinks) + ObjectSearchConstants.defaultDataViewFilters( - space = spaceId - ), + filters = dvFilters.updateFormatForSubscription(dvRelationLinks) + ObjectSearchConstants.defaultDataViewFilters(), sorts = dvSorts, keys = dvKeys, source = sources, @@ -471,7 +473,7 @@ open class ObjectSetViewModelTestSetup { template: Id? = null ) { getDefaultObjectType.stub { - onBlocking { run(Unit) } doReturn GetDefaultObjectType.Response( + onBlocking { run(SpaceId(spaceConfig.space)) } doReturn GetDefaultObjectType.Response( type = type, name = name, id = id, diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt index d66eec4eec..a17e0c209e 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/types/ObjectTypeChangeViewModelTest.kt @@ -11,6 +11,7 @@ import com.anytypeio.anytype.core_models.ObjectTypeIds import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.StubObjectType import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType +import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes import com.anytypeio.anytype.domain.block.repo.BlockRepository @@ -81,9 +82,7 @@ class ObjectTypeChangeViewModelTest { getDefaultObjectType = GetDefaultObjectType( userSettingsRepository = userSettingsRepository, blockRepository = blockRepository, - dispatchers = dispatchers, - spaceManager = spaceManager, - configStorage = configStorage + dispatchers = dispatchers ) } @@ -113,7 +112,6 @@ class ObjectTypeChangeViewModelTest { val vm = givenViewModel() val expectedMyTypesFilters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceId), recommendedLayouts = SupportedLayouts.editorLayouts + SupportedLayouts.fileLayouts ) @@ -132,6 +130,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -156,7 +155,6 @@ class ObjectTypeChangeViewModelTest { val vm = givenViewModel() val expectedMyTypesFilters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceId), recommendedLayouts = SupportedLayouts.editorLayouts + SupportedLayouts.fileLayouts ) val expectedMyTypeKeys = ObjectSearchConstants.defaultKeysObjectType @@ -165,7 +163,6 @@ class ObjectTypeChangeViewModelTest { val expectedMarketplaceTypeFilters = buildList { addAll( ObjectSearchConstants.filterTypes( - spaces = listOf(MARKETPLACE_SPACE_ID), recommendedLayouts = SupportedLayouts.editorLayouts ) ) @@ -185,6 +182,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -214,6 +212,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -227,6 +226,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(MARKETPLACE_SPACE_ID), filters = expectedMarketplaceTypeFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -251,7 +251,6 @@ class ObjectTypeChangeViewModelTest { val vm = givenViewModel() val expectedMyTypesFilters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceId), recommendedLayouts = SupportedLayouts.editorLayouts + SupportedLayouts.fileLayouts ) val expectedMyTypeKeys = ObjectSearchConstants.defaultKeysObjectType @@ -260,7 +259,6 @@ class ObjectTypeChangeViewModelTest { val expectedMarketplaceTypeFilters = buildList { addAll( ObjectSearchConstants.filterTypes( - spaces = listOf(MARKETPLACE_SPACE_ID), recommendedLayouts = SupportedLayouts.editorLayouts ) ) @@ -282,6 +280,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -297,6 +296,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(MARKETPLACE_SPACE_ID), filters = expectedMarketplaceTypeFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -310,6 +310,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -325,6 +326,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(MARKETPLACE_SPACE_ID), filters = expectedMarketplaceTypeFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -352,6 +354,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -365,6 +368,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(MARKETPLACE_SPACE_ID), filters = expectedMarketplaceTypeFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -384,6 +388,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -397,6 +402,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(MARKETPLACE_SPACE_ID), filters = expectedMarketplaceTypeFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -412,8 +418,7 @@ class ObjectTypeChangeViewModelTest { // SETUP - val space = "space-id" - stubSpaceManager(space) + stubSpaceManager(spaceId) val marketplaceType1 = StubObjectType() val marketplaceType2 = StubObjectType() val marketplaceType3 = StubObjectType(id = MarketplaceObjectTypeIds.PAGE) @@ -424,7 +429,6 @@ class ObjectTypeChangeViewModelTest { val expectedInstalledTypeUniqueKey = ObjectTypeIds.PAGE val expectedMyTypesFilters = ObjectSearchConstants.filterTypes( - spaces = listOf(space), recommendedLayouts = SupportedLayouts.editorLayouts + SupportedLayouts.fileLayouts ) val expectedMyTypeKeys = ObjectSearchConstants.defaultKeysObjectType @@ -433,7 +437,6 @@ class ObjectTypeChangeViewModelTest { val expectedMarketplaceTypeFilters = buildList { addAll( ObjectSearchConstants.filterTypes( - spaces = listOf(MARKETPLACE_SPACE_ID), recommendedLayouts = SupportedLayouts.editorLayouts + SupportedLayouts.fileLayouts ) ) @@ -453,6 +456,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -468,6 +472,7 @@ class ObjectTypeChangeViewModelTest { blockRepository.stub { onBlocking { searchObjects( + space = SpaceId(spaceId), filters = expectedMarketplaceTypeFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -487,7 +492,7 @@ class ObjectTypeChangeViewModelTest { onBlocking { val command = Command.AddObjectToSpace( objectId = marketplaceType3.id, - space = space + space = spaceId ) addObjectToSpace(command) } doReturn Pair( @@ -513,6 +518,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, @@ -547,7 +553,7 @@ class ObjectTypeChangeViewModelTest { addObjectToSpace( Command.AddObjectToSpace( objectId = marketplaceType3.id, - space = space + space = spaceId ) ) } @@ -563,7 +569,6 @@ class ObjectTypeChangeViewModelTest { val vm = givenViewModel() val expectedMyTypesFilters = ObjectSearchConstants.filterTypes( - spaces = listOf(spaceId), recommendedLayouts = SupportedLayouts.editorLayouts ) @@ -582,6 +587,7 @@ class ObjectTypeChangeViewModelTest { verifyBlocking(blockRepository, times(1)) { searchObjects( + space = SpaceId(spaceId), filters = expectedMyTypesFilters, sorts = ObjectSearchConstants.defaultObjectTypeSearchSorts(), limit = 0, diff --git a/protocol/src/main/proto/changes.proto b/protocol/src/main/proto/changes.proto index 784325be76..bba0701a3a 100644 --- a/protocol/src/main/proto/changes.proto +++ b/protocol/src/main/proto/changes.proto @@ -180,3 +180,52 @@ message Change { string name = 2; } } + + +message StoreChange { + repeated StoreChangeContent changeSet = 1; +} + +message StoreChangeContent { + oneof change { + DocumentCreate create = 1; + DocumentModify modify = 2; + DocumentDelete delete = 3; + } +} + +message DocumentCreate { + string collection = 1; + string documentId = 2; + // json + string value = 3; +} + +message DocumentModify { + string collection = 1; + string documentId = 2; + repeated KeyModify keys = 4; +} + +message KeyModify { + // key path; example: [user, email] + repeated string keyPath = 1; + // modify op: set, unset, inc, etc. + ModifyOp modifyOp = 3; + // json value; example: '"new@email.com"' + string modifyValue = 4; +} + +enum ModifyOp { + Set = 0; + Unset = 1; + Inc = 2; + AddToSet = 3; + Pull = 4; +} + +message DocumentDelete { + string collection = 1; + string documentId = 2; +} + diff --git a/protocol/src/main/proto/commands.proto b/protocol/src/main/proto/commands.proto index f5fa385814..4b7749803c 100644 --- a/protocol/src/main/proto/commands.proto +++ b/protocol/src/main/proto/commands.proto @@ -1413,6 +1413,7 @@ message Rpc { string templateId = 3; string spaceId = 4; string objectTypeUniqueKey = 5; + bool withChat = 6; } message Response { @@ -1439,6 +1440,7 @@ message Rpc { message Request { google.protobuf.Struct details = 1; string spaceId = 2; + bool withChat = 3; } message Response { @@ -1516,6 +1518,7 @@ message Rpc { string templateId = 3; // optional template id for creating from template repeated anytype.model.InternalFlag internalFlags = 4; string spaceId = 5; + bool withChat = 6; } message Response { @@ -1571,12 +1574,14 @@ message Rpc { string url = 3; google.protobuf.Struct details = 4; bool addPageContent = 5; + bool withChat = 6; } message Response { Error error = 1; string objectId = 2; google.protobuf.Struct details = 3; + string chatId = 4; message Error { Code code = 1; @@ -1604,6 +1609,7 @@ message Rpc { message Error { Code code = 1; string description = 2; + enum Code { NULL = 0; UNKNOWN_ERROR = 1; @@ -1762,6 +1768,7 @@ message Rpc { // deprecated in favor of SearchWithMeta message Search { message Request { + string spaceId = 8; repeated anytype.model.Block.Content.Dataview.Filter filters = 1; repeated anytype.model.Block.Content.Dataview.Sort sorts = 2; string fullText = 3; @@ -1790,6 +1797,7 @@ message Rpc { } message SearchWithMeta { message Request { + string spaceId = 11; repeated anytype.model.Block.Content.Dataview.Filter filters = 1; repeated anytype.model.Block.Content.Dataview.Sort sorts = 2; string fullText = 3; @@ -1868,6 +1876,7 @@ message Rpc { message SearchSubscribe { message Request { + string spaceId = 15; // (optional) subscription identifier // client can provide some string or middleware will generate it automatically // if subId is already registered on middleware, the new query will replace previous subscription @@ -1890,7 +1899,6 @@ message Rpc { repeated string source = 10; - string ignoreWorkspace = 12; // disable dependent subscription bool noDepSubscription = 13; string collectionId = 14; @@ -1920,6 +1928,72 @@ message Rpc { } } + message CrossSpaceSearchSubscribe { + message Request { + // (optional) subscription identifier + // client can provide some string or middleware will generate it automatically + // if subId is already registered on middleware, the new query will replace previous subscription + string subId = 1; + // filters + repeated anytype.model.Block.Content.Dataview.Filter filters = 2; + // sorts + repeated anytype.model.Block.Content.Dataview.Sort sorts = 3; + // (required) needed keys in details for return, for object fields mw will return (and subscribe) objects as dependent + repeated string keys = 7; + + repeated string source = 10; + + // disable dependent subscription + bool noDepSubscription = 13; + string collectionId = 14; + } + + message Response { + Error error = 1; + + repeated google.protobuf.Struct records = 2; + repeated google.protobuf.Struct dependencies = 3; + + string subId = 4; + + Event.Object.Subscription.Counters counters = 5; + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + // ... + } + } + } + } + + message CrossSpaceSearchUnsubscribe { + message Request { + string subId = 1; + } + + message Response { + Error error = 1; + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + // ... + } + } + } + } + message GroupsSubscribe { message Request { string spaceId = 6; @@ -1952,6 +2026,7 @@ message Rpc { message SubscribeIds { message Request { + string spaceId = 13; // (optional) subscription identifier // client can provide some string or middleware will generate it automatically // if subId is already registered on middleware, the new query will replace previous subscription @@ -1962,7 +2037,6 @@ message Rpc { // (required) needed keys in details for return, for object fields mw will return (and subscribe) objects as dependent repeated string keys = 3; - string ignoreWorkspace = 11; // disable dependent subscription bool noDepSubscription = 12; } @@ -6471,6 +6545,42 @@ message Rpc { } } } + + message AnystoreObjectChanges { + message Request { + string objectId = 1; + OrderBy orderBy = 2; + + enum OrderBy { + ORDER_ID = 0; + ITERATION_ORDER = 1; + } + } + + message Response { + Error error = 1; + repeated Change changes = 2; + bool wrongOrder = 3; + + message Change { + string changeId = 1; + string orderId = 2; + string error = 3; + google.protobuf.Struct change = 4; + } + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + } + } + } + } } message Metrics { @@ -6894,6 +7004,11 @@ message Rpc { string email = 1; bool subscribeToNewsletter = 2; + + bool insiderTipsAndTutorials = 3; + + // if we are coming from the onboarding list + bool isOnboardingList = 4; } message Response { diff --git a/protocol/src/main/proto/models.proto b/protocol/src/main/proto/models.proto index 8534bb002b..899a580b59 100644 --- a/protocol/src/main/proto/models.proto +++ b/protocol/src/main/proto/models.proto @@ -51,9 +51,9 @@ enum SmartBlockType { NotificationObject = 0x217; DevicesObject = 0x218; - ChatObject = 0x219; // Container for any-store based chats ChatDerivedObject = 0x220; // Any-store based object for chat + AccountObject = 0x221; // Container for account data in tech space } message Search { @@ -805,7 +805,7 @@ message Relation { string description = 14; // on-store fields, injected only locally - Scope scope = 20; // scope from which this relation have been aggregated + Scope scope = 20; // deprecated, to be removed string creator = 21; // creator profile id int64 revision = 22; // revision of system relation. Used to check if we should change relation content or not @@ -1359,4 +1359,4 @@ message ChatMessage { repeated string ids = 1; // List of user IDs } } -} \ No newline at end of file +} diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt index 3bddc30a35..28c4579585 100644 --- a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt +++ b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt @@ -208,47 +208,6 @@ fun Section(name: String) { } } -@Composable -fun Pincode( - onClick: () -> Unit -) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .height(52.dp) - .clickable(onClick = onClick) - ) { - Image( - painterResource(R.drawable.ic_pin_code), - contentDescription = "Pincode icon", - modifier = Modifier.padding( - start = 20.dp - ) - ) - Text( - text = stringResource(R.string.pin_code), - color = colorResource(R.color.text_primary), - modifier = Modifier.padding( - start = 12.dp - ) - ) - Box( - modifier = Modifier.weight(1.0f, true), - contentAlignment = Alignment.CenterEnd - ) { - Row { - Text( - text = stringResource(R.string.off), - fontSize = 17.sp, - color = colorResource(R.color.text_secondary), - modifier = Modifier.padding(end = 10.dp) - ) - Arrow() - } - } - } -} - @Composable fun Action( name: String, @@ -441,10 +400,7 @@ fun ProfileImageBlock( when (icon) { is ProfileIconView.Image -> { Image( - painter = rememberAsyncImagePainter( - model = icon.url, - error = painterResource(id = R.drawable.ic_home_widget_space) - ), + painter = rememberAsyncImagePainter(model = icon.url), contentDescription = "Custom image profile", contentScale = ContentScale.Crop, modifier = Modifier diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt index 2f79e4735e..908e28062e 100644 --- a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt +++ b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt @@ -26,6 +26,7 @@ import com.anytypeio.anytype.domain.search.PROFILE_SUBSCRIPTION_ID import com.anytypeio.anytype.presentation.common.BaseViewModel import com.anytypeio.anytype.presentation.extension.sendScreenSettingsDeleteEvent import com.anytypeio.anytype.core_models.membership.MembershipStatus +import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider import com.anytypeio.anytype.presentation.profile.ProfileIconView import com.anytypeio.anytype.presentation.profile.profileIcon @@ -39,14 +40,14 @@ import timber.log.Timber class ProfileSettingsViewModel( private val analytics: Analytics, - private val deleteAccount: DeleteAccount, private val container: StorelessSubscriptionContainer, private val setObjectDetails: SetObjectDetails, private val configStorage: ConfigStorage, private val urlBuilder: UrlBuilder, private val setImageIcon: SetDocumentImageIcon, private val membershipProvider: MembershipProvider, - private val getNetworkMode: GetNetworkMode + private val getNetworkMode: GetNetworkMode, + private val profileContainer: ProfileSubscriptionManager ) : BaseViewModel() { private val jobs = mutableListOf() @@ -56,25 +57,10 @@ class ProfileSettingsViewModel( val membershipStatusState = MutableStateFlow(null) val showMembershipState = MutableStateFlow(null) - private val profileId = configStorage.get().profile - - val profileData = container.subscribe( - StoreSearchByIdsParams( - subscription = PROFILE_SUBSCRIPTION_ID, - keys = listOf( - Relations.ID, - Relations.NAME, - Relations.ICON_IMAGE, - Relations.ICON_EMOJI, - Relations.ICON_OPTION - ), - targets = listOf(profileId) - ) - ).map { result -> - val obj = result.firstOrNull() + val profileData = profileContainer.observe().map { obj -> AccountProfile.Data( - name = obj?.name.orEmpty(), - icon = obj?.profileIcon(urlBuilder) ?: ProfileIconView.Placeholder(null) + name = obj.name.orEmpty(), + icon = obj.profileIcon(urlBuilder) ) }.stateIn( viewModelScope, @@ -110,39 +96,24 @@ class ProfileSettingsViewModel( fun onNameChange(name: String) { Timber.d("onNameChange, name:[$name]") viewModelScope.launch { - setObjectDetails.execute( - SetObjectDetails.Params( - ctx = profileId, - details = mapOf(Relations.NAME to name) - ) - ).fold( - onFailure = { - Timber.e(it, "Error while updating object details") - }, - onSuccess = { - // do nothing - } - ) - } - } - - fun onDeleteAccountClicked() { - Timber.d("onDeleteAccountClicked, ") - jobs += viewModelScope.launch { - deleteAccount(BaseUseCase.None).process( - success = { - sendEvent( - analytics = analytics, - eventName = EventsDictionary.deleteAccount + val profile = configStorage.getOrNull()?.profile + if (profile != null) { + setObjectDetails.execute( + SetObjectDetails.Params( + ctx = profile, + details = mapOf(Relations.NAME to name) ) - Timber.d("Successfully deleted account, status") - }, - failure = { - Timber.e(it, "Error while deleting account").also { - sendToast("Error while deleting account") + ).fold( + onFailure = { + Timber.e(it, "Error while updating object details") + }, + onSuccess = { + // do nothing } - } - ) + ) + } else { + Timber.w("Config storage missing") + } } } @@ -152,14 +123,9 @@ class ProfileSettingsViewModel( forEach { it.cancel() } clear() } - viewModelScope.launch { - container.unsubscribe( - listOf(PROFILE_SUBSCRIPTION_ID) - ) - } } - fun onPickedImageFromDevice(path: String, space: Id) { + fun onPickedImageFromDevice(path: String) { viewModelScope.launch { val config = configStorage.getOrNull() if (config != null) { @@ -167,7 +133,7 @@ class ProfileSettingsViewModel( SetImageIcon.Params( target = config.profile, path = path, - spaceId = SpaceId(config.space) + spaceId = SpaceId(config.techSpace) ) ).process( failure = { @@ -183,12 +149,6 @@ class ProfileSettingsViewModel( } } - fun proceedWithAccountDeletion() { - viewModelScope.launch { - analytics.sendScreenSettingsDeleteEvent() - } - } - sealed class AccountProfile { data object Idle: AccountProfile() class Data( @@ -198,7 +158,6 @@ class ProfileSettingsViewModel( } class Factory( - private val deleteAccount: DeleteAccount, private val analytics: Analytics, private val container: StorelessSubscriptionContainer, private val setObjectDetails: SetObjectDetails, @@ -206,12 +165,12 @@ class ProfileSettingsViewModel( private val urlBuilder: UrlBuilder, private val setDocumentImageIcon: SetDocumentImageIcon, private val membershipProvider: MembershipProvider, - private val getNetworkMode: GetNetworkMode + private val getNetworkMode: GetNetworkMode, + private val profileSubscriptionManager: ProfileSubscriptionManager ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { return ProfileSettingsViewModel( - deleteAccount = deleteAccount, analytics = analytics, container = container, setObjectDetails = setObjectDetails, @@ -219,7 +178,8 @@ class ProfileSettingsViewModel( urlBuilder = urlBuilder, setImageIcon = setDocumentImageIcon, membershipProvider = membershipProvider, - getNetworkMode = getNetworkMode + getNetworkMode = getNetworkMode, + profileContainer = profileSubscriptionManager ) as T } } diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt index 7501e3f49d..f9305299f5 100644 --- a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt +++ b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt @@ -212,8 +212,7 @@ fun RemoteStorageScreen( SpaceIconView( icon = data.spaceIcon ?: SpaceIconView.Placeholder(), onSpaceIconClick = {}, - mainSize = 48.dp, - gradientSize = 36.dp + mainSize = 48.dp ) Column( modifier = Modifier @@ -298,7 +297,7 @@ private fun Header( } object MockFileStorage { - val mockSpaceIcon = SpaceIconView.Gradient(from = "#EEDEAE", to = "#B93252") + val mockSpaceIcon = SpaceIconView.Placeholder() val mockSpaceName = "Anton’s space" val mockSpaceInfraUsage = "212 MB of 1 GB used" val mockSpaceInfraPercent = 0.9F diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt index ea80c49452..4ba728155a 100644 --- a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt +++ b/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt @@ -74,8 +74,7 @@ fun SpaceHeader( if (isEditEnabled) { isSpaceIconMenuExpanded.value = !isSpaceIconMenuExpanded.value } - }, - gradientCornerRadius = 4.dp + } ) MaterialTheme( shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(16.dp))