diff --git a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt index bd75109141..c264eee086 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt @@ -53,7 +53,6 @@ import com.anytypeio.anytype.di.feature.cover.UnsplashModule import com.anytypeio.anytype.di.feature.discussions.DaggerDiscussionComponent import com.anytypeio.anytype.di.feature.gallery.DaggerGalleryInstallationComponent import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent -import com.anytypeio.anytype.di.feature.library.DaggerLibraryComponent import com.anytypeio.anytype.di.feature.membership.DaggerMembershipComponent import com.anytypeio.anytype.di.feature.membership.DaggerMembershipUpdateComponent import com.anytypeio.anytype.di.feature.multiplayer.DaggerRequestJoinSpaceComponent @@ -106,7 +105,6 @@ import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationVie import com.anytypeio.anytype.presentation.common.BaseViewModel import com.anytypeio.anytype.presentation.editor.EditorViewModel import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel -import com.anytypeio.anytype.presentation.library.LibraryViewModel import com.anytypeio.anytype.presentation.multiplayer.RequestJoinSpaceViewModel import com.anytypeio.anytype.presentation.multiplayer.ShareSpaceViewModel import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestViewModel @@ -738,14 +736,6 @@ class ComponentManager( .create(findComponentDependencies()) } - val libraryComponent = ComponentWithParams { (ctx, params) : Pair -> - DaggerLibraryComponent.builder() - .withContext(ctx) - .withParams(params) - .withDependencies(findComponentDependencies()) - .build() - } - val backLinkOrAddToObjectComponent = ComponentWithParams { ctx: Id -> DaggerBacklinkOrAddToObjectComponent.builder() .withContext(ctx) 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 deleted file mode 100644 index 852bd439cf..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/library/LibraryDI.kt +++ /dev/null @@ -1,218 +0,0 @@ -package com.anytypeio.anytype.di.feature.library - -import android.content.Context -import androidx.lifecycle.ViewModelProvider -import com.anytypeio.anytype.analytics.base.Analytics -import com.anytypeio.anytype.core_utils.di.scope.PerScreen -import com.anytypeio.anytype.di.common.ComponentDependencies -import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers -import com.anytypeio.anytype.domain.block.repo.BlockRepository -import com.anytypeio.anytype.domain.config.ConfigStorage -import com.anytypeio.anytype.domain.config.UserSettingsRepository -import com.anytypeio.anytype.domain.debugging.Logger -import com.anytypeio.anytype.domain.launch.GetDefaultObjectType -import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer -import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.domain.`object`.SetObjectDetails -import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes -import com.anytypeio.anytype.domain.page.CreateObject -import com.anytypeio.anytype.domain.search.SubscriptionEventChannel -import com.anytypeio.anytype.domain.templates.GetTemplates -import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace -import com.anytypeio.anytype.domain.workspace.RemoveObjectsFromWorkspace -import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate -import com.anytypeio.anytype.presentation.library.LibraryListDelegate -import com.anytypeio.anytype.presentation.library.LibraryResourceManager -import com.anytypeio.anytype.presentation.library.LibraryViewModel -import com.anytypeio.anytype.presentation.library.delegates.LibraryRelationsDelegate -import com.anytypeio.anytype.presentation.library.delegates.LibraryTypesDelegate -import com.anytypeio.anytype.presentation.library.delegates.MyRelationsDelegate -import com.anytypeio.anytype.presentation.library.delegates.MyTypesDelegate -import com.anytypeio.anytype.ui.library.LibraryFragment -import dagger.Binds -import dagger.BindsInstance -import dagger.Component -import dagger.Module -import dagger.Provides - -@Component( - dependencies = [LibraryDependencies::class], - modules = [ - LibraryModule::class, - LibraryModule.Declarations::class - ] -) -@PerScreen -interface LibraryComponent { - - @Component.Builder - interface Builder { - fun withDependencies(dependencies: LibraryDependencies): Builder - - @BindsInstance - fun withContext(context: Context): Builder - - @BindsInstance - fun withParams(params: LibraryViewModel.Params): Builder - - fun build(): LibraryComponent - } - - fun inject(fragment: LibraryFragment) -} - -@Module -object LibraryModule { - - @PerScreen - @Provides - @JvmStatic - fun provideMyTypesDelegate( - container: StorelessSubscriptionContainer, - spaceManager: SpaceManager, - urlBuilder: UrlBuilder, - dispatchers: AppCoroutineDispatchers - ): LibraryListDelegate { - return MyTypesDelegate( - container = container, - spaceManager = spaceManager, - urlBuilder = urlBuilder, - dispatchers = dispatchers - ) - } - - @PerScreen - @Provides - @JvmStatic - fun provideLibTypesDelegate( - container: StorelessSubscriptionContainer, - urlBuilder: UrlBuilder, - dispatchers: AppCoroutineDispatchers - ): LibraryListDelegate { - return LibraryTypesDelegate(container, urlBuilder, dispatchers) - } - - @PerScreen - @Provides - @JvmStatic - fun provideMyRelationsDelegate( - container: StorelessSubscriptionContainer, - spaceManager: SpaceManager, - urlBuilder: UrlBuilder, - dispatchers: AppCoroutineDispatchers - ): LibraryListDelegate { - return MyRelationsDelegate( - container = container, - spaceManager = spaceManager, - urlBuilder = urlBuilder, - dispatchers = dispatchers - ) - } - - @PerScreen - @Provides - @JvmStatic - fun provideLibRelationsDelegate( - container: StorelessSubscriptionContainer, - urlBuilder: UrlBuilder, - dispatchers: AppCoroutineDispatchers - ): LibraryListDelegate { - return LibraryRelationsDelegate(container, urlBuilder, dispatchers) - } - - @Provides - @PerScreen - @JvmStatic - fun addObjectToWorkspace( - repo: BlockRepository, - dispatchers: AppCoroutineDispatchers - ): AddObjectToWorkspace = AddObjectToWorkspace( - repo = repo, - dispatchers = dispatchers - ) - - @Provides - @PerScreen - @JvmStatic - fun removeObjectFromWorkspace( - repo: BlockRepository, - dispatchers: AppCoroutineDispatchers - ): RemoveObjectsFromWorkspace = RemoveObjectsFromWorkspace(repo, dispatchers) - - @JvmStatic - @Provides - @PerScreen - fun getCreateObject( - repo: BlockRepository, - getDefaultObjectType: GetDefaultObjectType, - dispatchers: AppCoroutineDispatchers, - ): CreateObject = CreateObject( - repo = repo, - getDefaultObjectType = getDefaultObjectType, - dispatchers = dispatchers - ) - - @JvmStatic - @Provides - @PerScreen - fun provideGetDefaultPageType( - userSettingsRepository: UserSettingsRepository, - blockRepository: BlockRepository, - dispatchers: AppCoroutineDispatchers - ): GetDefaultObjectType = GetDefaultObjectType( - userSettingsRepository = userSettingsRepository, - blockRepository = blockRepository, - dispatchers = dispatchers - ) - - @JvmStatic - @Provides - @PerScreen - fun provideGetTemplates( - repo: BlockRepository, - spaceManager: SpaceManager, - dispatchers: AppCoroutineDispatchers - ): GetTemplates = GetTemplates( - repo = repo, - spaceManager = spaceManager, - dispatchers = dispatchers - ) - - @Provides - @PerScreen - @JvmStatic - fun objectSetDetails( - repo: BlockRepository, - dispatchers: AppCoroutineDispatchers - ): SetObjectDetails = SetObjectDetails(repo = repo, dispatchers = dispatchers) - - @Module - interface Declarations { - - @PerScreen - @Binds - fun bindViewModelFactory(factory: LibraryViewModel.Factory): ViewModelProvider.Factory - - @PerScreen - @Binds - fun bindResourceManager(manager: LibraryResourceManager.Impl): LibraryResourceManager - - } - -} - -interface LibraryDependencies : ComponentDependencies { - fun blockRepository(): BlockRepository - fun urlBuilder(): UrlBuilder - fun channel(): SubscriptionEventChannel - fun dispatchers(): AppCoroutineDispatchers - fun userSettingsRepository(): UserSettingsRepository - fun analytics(): Analytics - fun spaceManager(): SpaceManager - fun config(): ConfigStorage - fun logger(): Logger - fun container(): StorelessSubscriptionContainer - fun storeOfTypes (): StoreOfObjectTypes - fun analyticSpaceHelperDelegate(): AnalyticSpaceHelperDelegate -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt index 52a46fd1d8..50c6959350 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt @@ -23,7 +23,6 @@ import com.anytypeio.anytype.di.feature.auth.DeletedAccountDependencies import com.anytypeio.anytype.di.feature.discussions.DiscussionComponentDependencies import com.anytypeio.anytype.di.feature.gallery.GalleryInstallationComponentDependencies import com.anytypeio.anytype.di.feature.home.HomeScreenDependencies -import com.anytypeio.anytype.di.feature.library.LibraryDependencies import com.anytypeio.anytype.di.feature.membership.MembershipComponentDependencies import com.anytypeio.anytype.di.feature.membership.MembershipUpdateComponentDependencies import com.anytypeio.anytype.di.feature.multiplayer.RequestJoinSpaceDependencies @@ -90,7 +89,6 @@ import javax.inject.Singleton ) interface MainComponent : AppearanceDependencies, - LibraryDependencies, HomeScreenDependencies, CollectionDependencies, CreateObjectTypeDependencies, @@ -164,11 +162,6 @@ abstract class ComponentDependenciesModule { @ComponentDependenciesKey(AppearanceDependencies::class) abstract fun provideAppearanceDependencies(component: MainComponent): ComponentDependencies - @Binds - @IntoMap - @ComponentDependenciesKey(LibraryDependencies::class) - abstract fun provideLibraryDependencies(component: MainComponent): ComponentDependencies - @Binds @IntoMap @ComponentDependenciesKey(HomeScreenDependencies::class) diff --git a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt index 5883edc8b3..34c38727f8 100644 --- a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt +++ b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt @@ -13,7 +13,6 @@ import com.anytypeio.anytype.ui.allcontent.AllContentFragment import com.anytypeio.anytype.ui.auth.account.DeletedAccountFragment import com.anytypeio.anytype.ui.editor.EditorFragment import com.anytypeio.anytype.ui.editor.EditorModalFragment -import com.anytypeio.anytype.ui.library.LibraryFragment import com.anytypeio.anytype.ui.relations.RelationCreateFromScratchForObjectFragment import com.anytypeio.anytype.ui.relations.RelationEditFragment import com.anytypeio.anytype.ui.search.GlobalSearchFragment @@ -245,13 +244,6 @@ class Navigator : AppNavigation { }) } - override fun openLibrary(space: Id) { - navController?.navigate( - R.id.libraryFragment, - LibraryFragment.args(space) - ) - } - override fun openRemoteFilesManageScreen(subscription: Id, space: Id) { navController?.navigate( resId = R.id.remoteStorageFragment, 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 d2a211d507..16eebbd36e 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 @@ -27,11 +27,11 @@ 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.feature_allcontent.models.AllContentTab import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModelFactory import com.anytypeio.anytype.feature_allcontent.ui.AllContentNavigation.ALL_CONTENT_MAIN import com.anytypeio.anytype.feature_allcontent.ui.AllContentWrapperScreen -import com.anytypeio.anytype.presentation.library.LibraryViewModel import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.widgets.collection.Subscription import com.anytypeio.anytype.ui.base.navigation @@ -65,7 +65,7 @@ class AllContentFragment : BaseComposeFragment(), ObjectTypeSelectionListener { setFragmentResultListener(REQUEST_KEY_UNINSTALL_TYPE) { _, bundle -> val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_ID)) val name = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_NAME)) - vm.uninstallObject(id, LibraryViewModel.LibraryItem.TYPE, name) + vm.uninstallObject(id, AllContentTab.TYPES, name) } setFragmentResultListener(REQUEST_KEY_MODIFY_TYPE) { _, bundle -> val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_ID)) @@ -76,7 +76,7 @@ class AllContentFragment : BaseComposeFragment(), ObjectTypeSelectionListener { setFragmentResultListener(REQUEST_KEY_UNINSTALL_RELATION) { _, bundle -> val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_ID)) val name = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_NAME)) - vm.uninstallObject(id, LibraryViewModel.LibraryItem.RELATION, name) + vm.uninstallObject(id, AllContentTab.RELATIONS, name) } setFragmentResultListener(REQUEST_KEY_MODIFY_RELATION) { _, bundle -> val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_ID)) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt index 9756cbd5bc..4827609e40 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt @@ -54,7 +54,6 @@ class NavigationRouter( is AppNavigation.Command.OpenTemplates -> navigation.openTemplatesModal( typeId = command.typeId ) - is AppNavigation.Command.OpenLibrary -> navigation.openLibrary(command.space) is AppNavigation.Command.MigrationErrorScreen -> navigation.migrationErrorScreen() else -> Timber.d("Nav command ignored: $command") } 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 10f35a5559..85b5df821f 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 @@ -46,7 +46,6 @@ import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.views.UXBody import com.anytypeio.anytype.presentation.home.InteractionMode -import com.anytypeio.anytype.presentation.profile.ProfileIconView import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction import com.anytypeio.anytype.presentation.widgets.FromIndex import com.anytypeio.anytype.presentation.widgets.ToIndex @@ -60,7 +59,6 @@ import com.anytypeio.anytype.ui.widgets.types.AllContentWidgetCard import com.anytypeio.anytype.ui.widgets.types.BinWidgetCard import com.anytypeio.anytype.ui.widgets.types.DataViewListWidgetCard import com.anytypeio.anytype.ui.widgets.types.GalleryWidgetCard -import com.anytypeio.anytype.ui.widgets.types.LibraryWidgetCard import com.anytypeio.anytype.ui.widgets.types.LinkWidgetCard import com.anytypeio.anytype.ui.widgets.types.ListWidgetCard import com.anytypeio.anytype.ui.widgets.types.SpaceChatWidgetCard @@ -87,7 +85,6 @@ fun HomeScreen( onToggleExpandedWidgetState: (WidgetId) -> Unit, onExitEditMode: () -> Unit, onSearchClicked: () -> Unit, - onLibraryClicked: () -> Unit, onCreateNewObjectClicked: () -> Unit, onCreateNewObjectLongClicked: () -> Unit, onBackClicked: () -> Unit, @@ -113,7 +110,6 @@ fun HomeScreen( mode = mode, onChangeWidgetView = onChangeWidgetView, onEditWidgets = onEditWidgets, - onLibraryClicked = onLibraryClicked, onSpaceWidgetClicked = onSpaceWidgetClicked, onMove = onMove, onObjectCheckboxClicked = onObjectCheckboxClicked, @@ -185,7 +181,6 @@ private fun WidgetList( mode: InteractionMode, onChangeWidgetView: (WidgetId, ViewId) -> Unit, onEditWidgets: () -> Unit, - onLibraryClicked: () -> Unit, onMove: (List, FromIndex, ToIndex) -> Unit, onObjectCheckboxClicked: (Id, Boolean) -> Unit, onSpaceWidgetClicked: () -> Unit, @@ -429,15 +424,6 @@ private fun WidgetList( onWidgetClicked = { onBundledWidgetHeaderClicked(item.id) } ) } - is WidgetView.Library -> { - LibraryWidgetCard( - onDropDownMenuAction = { action -> - onWidgetMenuAction(item.id, action) - }, - onClick = onLibraryClicked, - mode = mode - ) - } is WidgetView.Action.EditWidgets -> { Box( Modifier 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 b1df7c4813..049b16ec06 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 @@ -35,7 +35,6 @@ import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Navigation import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction import com.anytypeio.anytype.ui.base.navigation import com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment -import com.anytypeio.anytype.ui.library.LibraryFragment import com.anytypeio.anytype.ui.multiplayer.RequestJoinSpaceFragment import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment import com.anytypeio.anytype.ui.objects.creation.ObjectTypeSelectionFragment @@ -102,9 +101,6 @@ class HomeScreenFragment : BaseComposeFragment(), onChangeWidgetView = vm::onChangeCurrentWidgetView, onToggleExpandedWidgetState = vm::onToggleCollapsedWidgetState, onSearchClicked = vm::onSearchIconClicked, - onLibraryClicked = { - vm.onLibraryClicked() - }, onCreateNewObjectClicked = throttledClick( onClick = { vm.onCreateNewObjectClicked() } ), @@ -343,14 +339,6 @@ class HomeScreenFragment : BaseComposeFragment(), space = destination.space ) } - is Navigation.OpenLibrary -> runCatching { - findNavController().navigate( - R.id.libraryFragment, - args = LibraryFragment.args(destination.space) - ) - }.onFailure { e -> - Timber.e(e, "Error while opening space library from widgets") - } is Navigation.OpenAllContent -> { runCatching { navigation().openAllContent(space = destination.space) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryFragment.kt deleted file mode 100644 index be81bed202..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryFragment.kt +++ /dev/null @@ -1,243 +0,0 @@ -package com.anytypeio.anytype.ui.library - -import android.os.Build -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.MaterialTheme -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.core.os.bundleOf -import androidx.fragment.app.setFragmentResultListener -import androidx.fragment.app.viewModels -import androidx.navigation.fragment.findNavController -import com.anytypeio.anytype.BuildConfig -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_models.Id -import com.anytypeio.anytype.core_models.primitives.SpaceId -import com.anytypeio.anytype.core_ui.extensions.simpleIcon -import com.anytypeio.anytype.core_utils.ext.arg -import com.anytypeio.anytype.core_utils.ext.safeNavigate -import com.anytypeio.anytype.core_utils.ext.subscribe -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.presentation.library.LibraryViewModel -import com.anytypeio.anytype.presentation.objects.ObjectIcon -import com.anytypeio.anytype.ui.editor.EditorFragment -import com.anytypeio.anytype.ui.relations.REQUEST_KEY_MODIFY_RELATION -import com.anytypeio.anytype.ui.relations.REQUEST_KEY_UNINSTALL_RELATION -import com.anytypeio.anytype.ui.relations.REQUEST_UNINSTALL_RELATION_ARG_ID -import com.anytypeio.anytype.ui.relations.REQUEST_UNINSTALL_RELATION_ARG_NAME -import com.anytypeio.anytype.ui.relations.RelationCreateFromScratchForObjectFragment -import com.anytypeio.anytype.ui.relations.RelationEditFragment -import com.anytypeio.anytype.ui.sets.ObjectSetFragment -import com.anytypeio.anytype.ui.settings.typography -import com.anytypeio.anytype.ui.types.create.CreateObjectTypeFragment -import com.anytypeio.anytype.ui.types.create.REQUEST_CREATE_OBJECT -import com.anytypeio.anytype.ui.types.edit.REQUEST_KEY_MODIFY_TYPE -import com.anytypeio.anytype.ui.types.edit.REQUEST_KEY_UNINSTALL_TYPE -import com.anytypeio.anytype.ui.types.edit.REQUEST_UNINSTALL_TYPE_ARG_ICON -import com.anytypeio.anytype.ui.types.edit.REQUEST_UNINSTALL_TYPE_ARG_ID -import com.anytypeio.anytype.ui.types.edit.REQUEST_UNINSTALL_TYPE_ARG_NAME -import com.anytypeio.anytype.ui.types.edit.TypeEditFragment -import javax.inject.Inject -import kotlinx.coroutines.FlowPreview -import timber.log.Timber - -@Deprecated("legacy") -class LibraryFragment : BaseComposeFragment() { - - @Inject - lateinit var factory: LibraryViewModel.Factory - - private val vm by viewModels { factory } - - private val space get() = arg(ARG_SPACE_ID_KEY) - - @OptIn(ExperimentalAnimationApi::class) - @FlowPreview - @ExperimentalMaterialApi - @ExperimentalComposeUiApi - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View { - return ComposeView(requireContext()).apply { - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - MaterialTheme(typography = typography) { - LibraryScreen( - configuration = LibraryConfiguration(), - viewModel = vm, - onBackPressed = { - findNavController().popBackStack() - }, - onCreateObjectLongClicked = {}, - onBackLongPressed = { - runCatching { - findNavController().navigate(R.id.actionExitToSpaceWidgets) - }.onFailure { - Timber.e(it, "Error while opening space switcher from library") - } - } - ) - } - } - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - subscribe(vm.toasts) { toast(it) } - subscribe(vm.navigation) { - when (it) { - is LibraryViewModel.Navigation.OpenTypeCreation -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.openTypeCreationScreen, - CreateObjectTypeFragment.args(it.name) - ) - } - is LibraryViewModel.Navigation.OpenTypeEditing -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.openTypeEditingScreen, - TypeEditFragment.args( - typeName = it.view.name, - id = it.view.id, - iconUnicode = (it.view.icon as? ObjectIcon.Basic.Emoji)?.unicode ?: "", - readOnly = it.view.readOnly - ) - ) - } - is LibraryViewModel.Navigation.OpenRelationCreation -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.openRelationCreationScreen, - RelationCreateFromScratchForObjectFragment.args( - ctx = "", - query = it.name, - space = space - ) - ) - } - is LibraryViewModel.Navigation.OpenRelationEditing -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.openRelationEditingScreen, - RelationEditFragment.args( - typeName = it.view.name, - id = it.view.id, - iconUnicode = it.view.format.simpleIcon() ?: 0, - readOnly = it.view.readOnly - ) - ) - } - is LibraryViewModel.Navigation.Back -> { - findNavController().popBackStack() - } - is LibraryViewModel.Navigation.Search -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.pageSearchFragment - ) - } - is LibraryViewModel.Navigation.OpenEditor -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.objectNavigation, - EditorFragment.args( - ctx = it.id, - space = space - ) - ) - } - is LibraryViewModel.Navigation.ExitToVault -> { - runCatching { - findNavController().navigate(R.id.actionOpenVault) - }.onFailure { e -> - Timber.e(e, "Error while exiting to vault from space library") - } - } - is LibraryViewModel.Navigation.OpenSetOrCollection -> { - findNavController().safeNavigate( - R.id.libraryFragment, - R.id.dataViewNavigation, - bundleOf( - ObjectSetFragment.CONTEXT_ID_KEY to it.id, - ObjectSetFragment.SPACE_ID_KEY to space - ) - ) - } - } - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setFragmentResultListener(REQUEST_KEY_UNINSTALL_TYPE) { _, bundle -> - val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_ID)) - val name = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_NAME)) - vm.uninstallObject(id, LibraryViewModel.LibraryItem.TYPE, name) - } - setFragmentResultListener(REQUEST_KEY_MODIFY_TYPE) { _, bundle -> - val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_ID)) - val name = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_NAME)) - val icon = requireNotNull(bundle.getString(REQUEST_UNINSTALL_TYPE_ARG_ICON)) - vm.updateObject(id, name, icon) - } - setFragmentResultListener(REQUEST_KEY_UNINSTALL_RELATION) { _, bundle -> - val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_ID)) - val name = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_NAME)) - vm.uninstallObject(id, LibraryViewModel.LibraryItem.RELATION, name) - } - setFragmentResultListener(REQUEST_KEY_MODIFY_RELATION) { _, bundle -> - val id = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_ID)) - val name = requireNotNull(bundle.getString(REQUEST_UNINSTALL_RELATION_ARG_NAME)) - vm.updateObject( - id = id, - name = name, - icon = null - ) - } - setFragmentResultListener(REQUEST_CREATE_OBJECT) { _, _ -> - vm.onObjectCreated() - } - } - - override fun injectDependencies() { - componentManager() - .libraryComponent - .get( - Pair( - requireContext(), - LibraryViewModel.Params( - space = SpaceId(space) - ) - ) - ) - .inject(this) - } - - override fun releaseDependencies() { - componentManager().libraryComponent.release() - } - - override fun onApplyWindowRootInsets(view: View) { - if (BuildConfig.USE_EDGE_TO_EDGE && Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK) { - // Do nothing. - } else { - super.onApplyWindowRootInsets(view) - } - } - - companion object { - const val ARG_SPACE_ID_KEY = "arg.library.space-id" - fun args(space: Id) = bundleOf(ARG_SPACE_ID_KEY to space) - } -} \ No newline at end of file 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 deleted file mode 100644 index aa07170ddb..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreen.kt +++ /dev/null @@ -1,199 +0,0 @@ -@file:OptIn(ExperimentalAnimationApi::class) - -package com.anytypeio.anytype.ui.library - -import android.os.Build -import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.AnimatedVisibilityScope -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.animation.core.FastOutLinearInEasing -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.TweenSpec -import androidx.compose.animation.core.VisibilityThreshold -import androidx.compose.animation.core.spring -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.ime -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.unit.IntSize -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.anytypeio.anytype.BuildConfig -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu -import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK -import com.anytypeio.anytype.presentation.library.LibraryEvent -import com.anytypeio.anytype.presentation.library.LibraryViewModel -import com.anytypeio.anytype.ui.library.views.LibraryTabs -import com.anytypeio.anytype.ui.library.views.LibraryTabsContent -import kotlinx.coroutines.FlowPreview - - -@ExperimentalAnimationApi -@ExperimentalComposeUiApi -@ExperimentalMaterialApi -@FlowPreview -@Composable -fun LibraryScreen( - configuration: LibraryConfiguration, - viewModel: LibraryViewModel, - onBackPressed: () -> Unit, - onBackLongPressed: () -> Unit, - onCreateObjectLongClicked: () -> Unit -) { - - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val effects by viewModel.effects.collectAsStateWithLifecycle() - - val pagerState = rememberPagerState( - initialPage = INITIAL_TAB, - pageCount = { 2 } - ) - val modifier = Modifier - .background(color = colorResource(id = R.color.background_primary)) - - val screenState = remember { mutableStateOf(ScreenState.CONTENT) } - - Scaffold( - bottomBar = { - Box( - modifier = modifier - .then( - if (BuildConfig.USE_EDGE_TO_EDGE && Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK) - Modifier - .windowInsetsPadding(WindowInsets.navigationBars) - else - Modifier - ) - .fillMaxWidth() - ) { - Menu( - viewModel, - modifier = Modifier.align(Alignment.BottomCenter), - screenState = screenState, - onCreateObjectLongClicked = onCreateObjectLongClicked, - onBackLongClicked = onBackLongPressed - ) - } - } - ) { paddingValues -> - Column( - modifier = modifier - .padding(paddingValues) - .then( - if (BuildConfig.USE_EDGE_TO_EDGE && Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK) - Modifier.windowInsetsPadding(WindowInsets.systemBars) - else - Modifier - ), - ) { - LibraryTabs( - modifier = modifier, - pagerState = pagerState, - configuration = configuration, - screenState = screenState, - ) - LibraryTabsContent( - modifier = modifier, - pagerState = pagerState, - configuration = listOf(configuration.types, configuration.relations), - state = uiState, - vmEventStream = viewModel::eventStream, - vmAnalyticsStream = viewModel::analyticsStream, - screenState = screenState, - effects = effects - ) - } - } - - BackHandler { - if (screenState.value == ScreenState.SEARCH) { - screenState.value = ScreenState.CONTENT - } else { - onBackPressed.invoke() - } - } - -} - -@Composable -fun Menu( - viewModel: LibraryViewModel, - modifier: Modifier = Modifier, - screenState: MutableState, - onCreateObjectLongClicked: () -> Unit = {}, - onBackLongClicked: () -> Unit -) { - val isImeVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0 - if (isImeVisible) return - BottomNavigationMenu( - modifier = modifier, - backClick = { - if (screenState.value == ScreenState.SEARCH) { - screenState.value = ScreenState.CONTENT - } else { - viewModel.eventStream(LibraryEvent.BottomMenu.Back) - } - }, - backLongClick = { - onBackLongClicked() - }, - searchClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Search) }, - addDocClick = { viewModel.eventStream(LibraryEvent.BottomMenu.CreateObject) }, - addDocLongClick = onCreateObjectLongClicked, - isOwnerOrEditor = false - ) -} - -@Composable -fun WrapWithLibraryAnimation( - visible: Boolean, - content: @Composable AnimatedVisibilityScope.() -> Unit -) { - val animationSpecFade = TweenSpec( - easing = FastOutLinearInEasing, - durationMillis = FADE_DURATION_MILLIS - ) - val animationSpecSlide = spring( - stiffness = Spring.StiffnessMediumLow, - visibilityThreshold = IntSize.VisibilityThreshold - ) - AnimatedVisibility( - visible = visible, - enter = fadeIn(animationSpecFade) + expandVertically(animationSpecSlide), - exit = fadeOut(animationSpecFade) + shrinkVertically(animationSpecSlide) - ) { content() } -} - -enum class ScreenState { - CONTENT, - SEARCH; - - fun visible() = this == CONTENT -} - -private const val INITIAL_TAB = 0 -private const val FADE_DURATION_MILLIS = 50 \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreenConfig.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreenConfig.kt deleted file mode 100644 index e91d6405f4..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/LibraryScreenConfig.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.anytypeio.anytype.ui.library - -import androidx.annotation.StringRes -import androidx.compose.ui.Alignment -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R - -data class LibraryConfiguration( - val types: LibraryScreenConfig = LibraryScreenConfig.Types(), - val relations: LibraryScreenConfig = LibraryScreenConfig.Relations() -) - -sealed class LibraryScreenConfig( - @StringRes val mainTitle: Int, - @StringRes val mainBtnTitle: Int, - @StringRes val description: Int, - val listConfig: List, - val index: Int, - val titleAlignment: Alignment.Horizontal, - val titlePaddingEnd: Dp, - val titlePaddingStart: Dp -) { - class Types : LibraryScreenConfig( - R.string.library_title_types, - R.string.library_button_create_type, - R.string.library_description_types, - listOf(LibraryListConfig.Types, LibraryListConfig.TypesLibrary), - 0, - Alignment.End, - 0.dp, - 16.dp - ) - - class Relations : LibraryScreenConfig( - R.string.library_title_relations, - R.string.library_button_create_relation, - R.string.library_description_relations, - listOf(LibraryListConfig.Relations, LibraryListConfig.RelationsLibrary), - 1, - Alignment.Start, - 16.dp, - 0.dp - ) -} - -sealed class LibraryListConfig( - @StringRes val title: Int, - val subtitleTabOffset: Dp, -) { - object Types : LibraryListConfig( - R.string.library_subtitle_types, 0.dp - ) - - object TypesLibrary : LibraryListConfig( - R.string.library_subtitle_library, (-14).dp - ) - - object Relations : LibraryListConfig( - R.string.library_subtitle_relations, 0.dp - ) - - object RelationsLibrary : LibraryListConfig( - R.string.library_subtitle_library, (-14).dp - ) - -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/styles/LibraryTextStyles.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/styles/LibraryTextStyles.kt deleted file mode 100644 index 8fbda55292..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/styles/LibraryTextStyles.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.anytypeio.anytype.ui.library.styles - -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp -import com.anytypeio.anytype.R -import androidx.compose.ui.text.TextStyle as TextStyle - -val fonts = FontFamily( - Font(R.font.inter_regular), - Font(R.font.inter_bold, weight = FontWeight.Bold), - Font(R.font.inter_medium, weight = FontWeight.Medium), - Font(R.font.inter_semibold, weight = FontWeight.SemiBold) -) - -val TabTitleStyle = TextStyle( - fontFamily = fonts, - fontSize = 15.sp, - fontWeight = FontWeight.SemiBold -) \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabModifier.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabModifier.kt deleted file mode 100644 index 0b5c4a99ff..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabModifier.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.anytypeio.anytype.ui.library.views - -import androidx.compose.animation.core.FastOutSlowInEasing -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.material.TabPosition -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp - -@Composable -fun Modifier.libraryTabOffset( - currentTabPosition: TabPosition, - tabWidth: Dp -): Modifier { - val currentTabWidth = animateDpAsState( - targetValue = tabWidth, - animationSpec = tween( - durationMillis = ANIMATION_LENGTH, - easing = FastOutSlowInEasing - ) - ) - - val targetValue = if (currentTabPosition.left == 0.dp) { - (currentTabPosition.left + currentTabPosition.right - tabWidth - TAB_OFFSET.dp) - } else { - (currentTabPosition.left) - } - - val indicatorOffset = animateDpAsState( - targetValue = targetValue, - animationSpec = tween( - durationMillis = ANIMATION_LENGTH, - easing = FastOutSlowInEasing - ) - ) - return fillMaxWidth() - .wrapContentSize(Alignment.BottomStart) - .offset(x = indicatorOffset.value) - .height(INDICATOR_HEIGHT.dp) - .width(currentTabWidth.value + TAB_OFFSET.dp) -} - -private const val TAB_OFFSET = 32 -private const val INDICATOR_HEIGHT = 1 -private const val ANIMATION_LENGTH = 150 \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabs.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabs.kt deleted file mode 100644 index 1c72fd380e..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabs.kt +++ /dev/null @@ -1,142 +0,0 @@ -package com.anytypeio.anytype.ui.library.views - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.pager.PagerState -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.LocalRippleConfiguration -import androidx.compose.material.RippleConfiguration -import androidx.compose.material.Tab -import androidx.compose.material.TabRow -import androidx.compose.material.TabRowDefaults -import androidx.compose.material.Text -import androidx.compose.material.ripple.RippleAlpha -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateListOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.TextLayoutResult -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R -import com.anytypeio.anytype.ui.library.LibraryConfiguration -import com.anytypeio.anytype.ui.library.LibraryScreenConfig -import com.anytypeio.anytype.ui.library.ScreenState -import com.anytypeio.anytype.ui.library.WrapWithLibraryAnimation -import com.anytypeio.anytype.ui.library.styles.TabTitleStyle -import kotlinx.coroutines.launch - -@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterialApi::class) -@Composable -fun LibraryTabs( - modifier: Modifier, - pagerState: PagerState, - configuration: LibraryConfiguration, - screenState: MutableState -) = WrapWithLibraryAnimation(visible = screenState.value.visible()) { - val coroutineScope = rememberCoroutineScope() - - val density = LocalDensity.current - val tabWidths = remember { - val tabWidthStateList = mutableStateListOf(0.dp, 0.dp) - tabWidthStateList - } - - TabRow( - modifier = modifier, - selectedTabIndex = pagerState.currentPage, - backgroundColor = colorResource(id = R.color.background_primary), - divider = {}, - indicator = { tabPositions -> - TabRowDefaults.Indicator( - modifier = Modifier - .libraryTabOffset( - currentTabPosition = tabPositions[pagerState.currentPage], - tabWidth = tabWidths[pagerState.currentPage] - ), - color = colorResource(id = R.color.black) - ) - }, - tabs = { - CompositionLocalProvider(LocalRippleConfiguration provides LibraryRippleTheme) { - LibraryTab( - modifier = modifier, - config = configuration.types, - pagerState = pagerState, - onClick = { - coroutineScope.launch { - pagerState.animateScrollToPage(0) - } - }, - onTextLayout = { tlResult -> - tabWidths[0] = with(density) { tlResult.size.width.toDp() } - } - ) - LibraryTab( - modifier = modifier, - config = configuration.relations, - pagerState = pagerState, - onClick = { - coroutineScope.launch { - pagerState.animateScrollToPage(1) - } - }, - onTextLayout = { tlResult -> - tabWidths[1] = with(density) { tlResult.size.width.toDp() } - } - ) - } - } - ) -} - -@OptIn(ExperimentalMaterialApi::class) -private val LibraryRippleTheme = RippleConfiguration(color = Color.Unspecified, rippleAlpha = RippleAlpha(0f, 0f, 0f, 0f)) - -@Composable -fun LibraryTab( - modifier: Modifier, - config: LibraryScreenConfig, - pagerState: PagerState, - onClick: () -> Unit, - onTextLayout: (TextLayoutResult) -> Unit -) { - - Tab( - modifier = modifier, - selectedContentColor = colorResource(id = R.color.glyph_selected), - unselectedContentColor = colorResource(id = R.color.glyph_active), - text = { - Column( - horizontalAlignment = config.titleAlignment, - modifier = Modifier - .fillMaxWidth() - .padding( - start = config.titlePaddingStart, - end = config.titlePaddingEnd, - ) - ) { - Text( - text = stringResource(id = config.mainTitle), - style = TabTitleStyle.copy( - color = if (pagerState.currentPage == config.index) { - colorResource(id = R.color.glyph_selected) - } else { - colorResource(id = R.color.glyph_active) - } - ), - onTextLayout = onTextLayout::invoke - ) - } - }, - selected = pagerState.currentPage == config.index, - onClick = onClick, - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt deleted file mode 100644 index 68a8931110..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTabsContent.kt +++ /dev/null @@ -1,147 +0,0 @@ -package com.anytypeio.anytype.ui.library.views - -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.PagerState -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.views.ButtonPrimary -import com.anytypeio.anytype.core_ui.views.ButtonSize -import com.anytypeio.anytype.core_ui.views.HeadlineTitle -import com.anytypeio.anytype.presentation.library.LibraryAnalyticsEvent -import com.anytypeio.anytype.presentation.library.LibraryEvent -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryViewModel -import com.anytypeio.anytype.ui.library.LibraryScreenConfig -import com.anytypeio.anytype.ui.library.ScreenState -import com.anytypeio.anytype.ui.library.WrapWithLibraryAnimation -import com.anytypeio.anytype.ui.library.views.list.LibraryListView -import kotlinx.coroutines.FlowPreview - -@ExperimentalAnimationApi -@FlowPreview -@Composable -fun LibraryTabsContent( - modifier: Modifier, - pagerState: PagerState, - configuration: List, - state: LibraryScreenState, - vmEventStream: (LibraryEvent) -> Unit, - vmAnalyticsStream: (LibraryAnalyticsEvent.Ui) -> Unit, - screenState: MutableState, - effects: LibraryViewModel.Effect, -) { - HorizontalPager( - modifier = modifier, - state = pagerState - ) { page -> - val dataTabs = when (configuration[page]) { - is LibraryScreenConfig.Types -> { - state.types - } - is LibraryScreenConfig.Relations -> { - state.relations - } - } - TabContentScreen( - modifier = modifier, - config = configuration[page], - tabs = dataTabs, - vmEventStream = vmEventStream, - vmAnalyticsStream = vmAnalyticsStream, - screenState = screenState, - effects = effects - ) - } -} - -@ExperimentalAnimationApi -@FlowPreview -@Composable -fun TabContentScreen( - modifier: Modifier, - config: LibraryScreenConfig, - tabs: LibraryScreenState.Tabs, - vmEventStream: (LibraryEvent) -> Unit, - vmAnalyticsStream: (LibraryAnalyticsEvent.Ui) -> Unit, - screenState: MutableState, - effects: LibraryViewModel.Effect -) { - Column( - modifier = modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Top, - ) { - Header(config, vmEventStream, screenState) - LibraryListView( - libraryListConfig = config.listConfig, - tabs = tabs, - vmEventStream = vmEventStream, - vmAnalyticsStream = vmAnalyticsStream, - screenState = screenState, - effects = effects - ) - } - -} - -@Composable -private fun Header( - config: LibraryScreenConfig, - vmEventStream: (LibraryEvent) -> Unit, - screenState: MutableState -) = WrapWithLibraryAnimation(visible = screenState.value.visible()) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - text = stringResource(config.description), - style = HeadlineTitle.copy( - color = colorResource(id = R.color.text_primary) - ), - textAlign = TextAlign.Center, - modifier = Modifier.padding( - top = 58.dp, - start = HeaderDefaults.HeaderPadding, - end = HeaderDefaults.HeaderPadding - ) - ) - Box(Modifier.height(14.dp)) - ButtonPrimary( - onClick = { - when (config) { - is LibraryScreenConfig.Types -> { - vmEventStream.invoke(LibraryEvent.Type.Create()) - } - is LibraryScreenConfig.Relations -> { - vmEventStream.invoke(LibraryEvent.Relation.Create()) - } - } - }, - modifier = Modifier.padding(bottom = 48.dp), - text = stringResource(config.mainBtnTitle), - size = ButtonSize.Medium.apply { - contentPadding = PaddingValues(28.dp, 10.dp, 28.dp, 10.dp) - } - ) - } -} - -private object HeaderDefaults { - val HeaderPadding = 20.dp -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTextField.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTextField.kt deleted file mode 100644 index bc128117b0..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/LibraryTextField.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.anytypeio.anytype.ui.library.views - -import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.defaultMinSize -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.LocalTextStyle -import androidx.compose.material.MaterialTheme -import androidx.compose.material.TextFieldColors -import androidx.compose.material.TextFieldDefaults -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.takeOrElse -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.VisualTransformation -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.ui.library.views.LibraryTextFieldDefaults.ContentPaddingEnd -import com.anytypeio.anytype.ui.library.views.LibraryTextFieldDefaults.OffsetXSearchText - -@Composable -fun LibraryTextField( - value: String, - onValueChange: (String) -> Unit, - modifier: Modifier = Modifier, - enabled: Boolean = true, - readOnly: Boolean = false, - textStyle: TextStyle = LocalTextStyle.current, - label: @Composable (() -> Unit)? = null, - placeholder: @Composable (() -> Unit)? = null, - leadingIcon: @Composable (() -> Unit)? = null, - trailingIcon: @Composable (() -> Unit)? = null, - isError: Boolean = false, - visualTransformation: VisualTransformation = VisualTransformation.None, - keyboardOptions: KeyboardOptions = KeyboardOptions.Default, - keyboardActions: KeyboardActions = KeyboardActions.Default, - singleLine: Boolean = false, - maxLines: Int = Int.MAX_VALUE, - interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - shape: Shape = MaterialTheme.shapes.small, - colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors() -) { - // If color is not provided via text style, use content color as a default - val textColor = textStyle.color.takeOrElse { - colors.textColor(enabled).value - } - val mergedTextStyle = textStyle.merge(TextStyle(color = textColor)) - - @OptIn(ExperimentalMaterialApi::class) - BasicTextField( - value = value, - modifier = if (label != null) { - modifier.semantics(mergeDescendants = true) {} - } else { - modifier - } - .background(colors.backgroundColor(enabled).value, shape) - .defaultMinSize( - minWidth = TextFieldDefaults.MinWidth, - minHeight = LibraryTextFieldDefaults.MinHeight - ).offset( - x = OffsetXSearchText, - ), - onValueChange = onValueChange, - enabled = enabled, - readOnly = readOnly, - textStyle = mergedTextStyle, - cursorBrush = SolidColor(colors.cursorColor(isError).value), - visualTransformation = visualTransformation, - keyboardOptions = keyboardOptions, - keyboardActions = keyboardActions, - interactionSource = interactionSource, - singleLine = singleLine, - maxLines = maxLines, - decorationBox = @Composable { innerTextField -> - TextFieldDefaults.OutlinedTextFieldDecorationBox( - value = value, - visualTransformation = visualTransformation, - innerTextField = innerTextField, - placeholder = placeholder, - label = label, - leadingIcon = leadingIcon, - trailingIcon = trailingIcon, - singleLine = singleLine, - enabled = enabled, - isError = isError, - interactionSource = interactionSource, - colors = colors, - contentPadding = PaddingValues( - start = 0.dp, - top = 0.dp, - end = ContentPaddingEnd, - bottom = 0.dp - ), - border = { - TextFieldDefaults.BorderBox( - enabled, - isError, - interactionSource, - colors, - shape - ) - } - ) - } - ) -} - -@Immutable -object LibraryTextFieldDefaults { - val MinHeight = 36.dp - val ContentPaddingEnd = 16.dp - val OffsetXSearchText = (-12).dp -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryList.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryList.kt deleted file mode 100644 index 44329b5a51..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryList.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.anytypeio.anytype.ui.library.views.list - -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.colorResource -import com.anytypeio.anytype.R -import com.anytypeio.anytype.presentation.library.LibraryAnalyticsEvent -import com.anytypeio.anytype.presentation.library.LibraryEvent -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryViewModel -import com.anytypeio.anytype.ui.library.LibraryListConfig -import com.anytypeio.anytype.ui.library.ScreenState - -@ExperimentalAnimationApi -@Composable -fun LibraryListView( - libraryListConfig: List, - tabs: LibraryScreenState.Tabs, - vmEventStream: (LibraryEvent) -> Unit, - vmAnalyticsStream: (LibraryAnalyticsEvent.Ui) -> Unit, - screenState: MutableState, - effects: LibraryViewModel.Effect, -) { - val pagerState = rememberPagerState( - initialPage = INITIAL_TAB, - pageCount = { 2 } - ) - val modifier = Modifier.background( - color = colorResource(id = R.color.background_primary) - ) - Column { - LibraryListTabs(pagerState, libraryListConfig, modifier) - LibraryListTabsContent( - modifier = modifier, - pagerState = pagerState, - configuration = libraryListConfig, - tabs = tabs, - vmEventStream = vmEventStream, - vmAnalyticsStream = vmAnalyticsStream, - screenState = screenState, - effects = effects - ) - } -} - -private const val INITIAL_TAB = 0 \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt deleted file mode 100644 index f62a81125a..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListSearchWidget.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.anytypeio.anytype.ui.library.views.list - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Text -import androidx.compose.material.TextFieldDefaults -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.runtime.MutableState -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusEvent -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.views.UXBody -import com.anytypeio.anytype.presentation.library.LibraryEvent -import com.anytypeio.anytype.ui.library.LibraryListConfig -import com.anytypeio.anytype.ui.library.ScreenState -import com.anytypeio.anytype.ui.library.views.LibraryTextField -import com.anytypeio.anytype.ui.library.views.list.LibraryListSearchWidgetDefaults.CornerRadius -import com.anytypeio.anytype.ui.library.views.list.LibraryListSearchWidgetDefaults.Height -import com.anytypeio.anytype.ui.library.views.list.LibraryListSearchWidgetDefaults.LeadingIconOffset -import com.anytypeio.anytype.ui.library.views.list.LibraryListSearchWidgetDefaults.PaddingVertical - -@Composable -fun LibraryListSearchWidget( - vmEventStream: (LibraryEvent) -> Unit, - config: LibraryListConfig, - modifier: Modifier, - animationStartState: MutableState, - screenState: MutableState, - input: MutableState -) { - LibraryTextField( - value = input.value, - onValueChange = { - input.value = it - vmEventStream.invoke( - config.toEvent(input.value) - ) - }, - shape = RoundedCornerShape(CornerRadius), - modifier = modifier - .padding(vertical = PaddingVertical) - .height(Height) - .onFocusEvent { - if (it.isFocused && animationStartState.value.not()) { - animationStartState.value = true - screenState.value = ScreenState.SEARCH - } - }, - textStyle = UXBody, - placeholder = { - Text( - text = stringResource(id = R.string.search), - style = UXBody - ) - }, - colors = TextFieldDefaults.outlinedTextFieldColors( - textColor = colorResource(id = R.color.text_primary), - backgroundColor = colorResource(id = R.color.shape_transparent), - disabledBorderColor = Color.Transparent, - errorBorderColor = Color.Transparent, - focusedBorderColor = Color.Transparent, - unfocusedBorderColor = Color.Transparent, - placeholderColor = colorResource(id = R.color.glyph_active), - cursorColor = colorResource(id = R.color.orange) - ), - singleLine = true, - maxLines = 1, - leadingIcon = { - Image( - painterResource(id = R.drawable.ic_search), - "", - modifier = Modifier.offset(x = LeadingIconOffset) - ) - } - ) -} - -fun LibraryListConfig.toEvent(query: String): LibraryEvent.Query = when (this) { - LibraryListConfig.Relations -> LibraryEvent.Query.MyRelations(query) - LibraryListConfig.RelationsLibrary -> LibraryEvent.Query.LibraryRelations(query) - LibraryListConfig.Types -> LibraryEvent.Query.MyTypes(query) - LibraryListConfig.TypesLibrary -> LibraryEvent.Query.LibraryTypes(query) -} - -@Immutable -private object LibraryListSearchWidgetDefaults { - val Height = 36.dp - val PaddingVertical = 6.dp - val CornerRadius = 10.dp - val LeadingIconOffset = 8.dp -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabs.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabs.kt deleted file mode 100644 index 2b590ae55d..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabs.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.anytypeio.anytype.ui.library.views.list - -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.pager.PagerState -import androidx.compose.material.ScrollableTabRow -import androidx.compose.material.Tab -import androidx.compose.material.Text -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.LocalRippleConfiguration -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.views.HeadlineSubheading -import com.anytypeio.anytype.ui.library.LibraryListConfig -import kotlinx.coroutines.launch - -@OptIn(ExperimentalMaterial3Api::class) -@ExperimentalAnimationApi -@Composable -fun LibraryListTabs( - pagerState: PagerState, - configuration: List, - modifier: Modifier, -) { - val scope = rememberCoroutineScope() - ScrollableTabRow( - selectedTabIndex = pagerState.currentPage, - backgroundColor = colorResource(id = R.color.background_primary), - indicator = {}, - divider = {}, - edgePadding = 0.dp, - modifier = modifier.padding(start = 4.dp), - tabs = { - CompositionLocalProvider(LocalRippleConfiguration provides null) { - configuration.forEachIndexed { index, it -> - LibraryListTab( - config = it, - pagerState = pagerState, - onClick = { - scope.launch { - pagerState.animateScrollToPage(index) - } - }, - index = index, - modifier - ) - } - } - } - ) -} - - -@Composable -fun LibraryListTab( - config: LibraryListConfig, - pagerState: PagerState, - onClick: () -> Unit, - index: Int, - modifier: Modifier -) { - Tab( - selectedContentColor = colorResource(id = R.color.glyph_selected), - unselectedContentColor = colorResource(id = R.color.glyph_active), - modifier = modifier.wrapContentWidth(), - text = { - Text( - text = stringResource(id = config.title), - style = HeadlineSubheading.copy( - color = if (pagerState.currentPage == index) { - colorResource(id = R.color.glyph_selected) - } else { - colorResource(id = R.color.glyph_active) - } - ), - modifier = modifier - .wrapContentWidth() - .offset(x = config.subtitleTabOffset), - ) - }, - selected = pagerState.currentPage == index, - onClick = onClick, - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt deleted file mode 100644 index d646ea6826..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/LibraryListTabsContent.kt +++ /dev/null @@ -1,316 +0,0 @@ -package com.anytypeio.anytype.ui.library.views.list - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.PagerState -import androidx.compose.material.Divider -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.foundation.noRippleClickable -import com.anytypeio.anytype.core_ui.views.UXBody -import com.anytypeio.anytype.presentation.library.DependentData -import com.anytypeio.anytype.presentation.library.LibraryAnalyticsEvent -import com.anytypeio.anytype.presentation.library.LibraryEvent -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryView -import com.anytypeio.anytype.presentation.library.LibraryViewModel -import com.anytypeio.anytype.ui.library.LibraryListConfig -import com.anytypeio.anytype.ui.library.ScreenState -import com.anytypeio.anytype.ui.library.views.list.LibraryListDefaults.SearchBarPadding -import com.anytypeio.anytype.ui.library.views.list.LibraryListDefaults.SearchCancelPaddingStart -import com.anytypeio.anytype.ui.library.views.list.LibraryListDefaults.SearchCancelPaddingTop -import com.anytypeio.anytype.ui.library.views.list.items.CreateNewRelationItem -import com.anytypeio.anytype.ui.library.views.list.items.CreateNewTypeItem -import com.anytypeio.anytype.ui.library.views.list.items.ItemDefaults -import com.anytypeio.anytype.ui.library.views.list.items.LibRelationItem -import com.anytypeio.anytype.ui.library.views.list.items.LibTypeItem -import com.anytypeio.anytype.ui.library.views.list.items.LibraryObjectEmptyItem -import com.anytypeio.anytype.ui.library.views.list.items.MyRelationItem -import com.anytypeio.anytype.ui.library.views.list.items.MyTypeItem - -@ExperimentalAnimationApi -@Composable -fun LibraryListTabsContent( - modifier: Modifier, - pagerState: PagerState, - configuration: List, - tabs: LibraryScreenState.Tabs, - vmEventStream: (LibraryEvent) -> Unit, - vmAnalyticsStream: (LibraryAnalyticsEvent.Ui) -> Unit, - screenState: MutableState, - effects: LibraryViewModel.Effect, -) { - - val keyboardController = LocalSoftwareKeyboardController.current - val focusManager = LocalFocusManager.current - val animationStartState = remember { - mutableStateOf(false) - } - val input = remember { mutableStateOf(String()) } - - HorizontalPager( - modifier = modifier, - state = pagerState, - userScrollEnabled = screenState.value == ScreenState.CONTENT - ) { index -> - val data = when (configuration[index]) { - is LibraryListConfig.Types, is LibraryListConfig.Relations -> { - tabs.my - } - is LibraryListConfig.TypesLibrary, is LibraryListConfig.RelationsLibrary -> { - tabs.lib - } - } - val itemsListState = rememberLazyListState() - Column( - modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Top - ) { - Row( - modifier = Modifier.padding(start = SearchBarPadding, end = SearchBarPadding) - ) { - LaunchedEffect(key1 = effects) { - if (effects is LibraryViewModel.Effect.ObjectCreated) { - input.value = "" - vmEventStream.invoke( - configuration[index].toEvent(input.value) - ) - animationStartState.value = false - keyboardController?.hide() - focusManager.clearFocus() - screenState.value = ScreenState.CONTENT - itemsListState.animateScrollToItem(0) - } - } - LibraryListSearchWidget( - vmEventStream = vmEventStream, - config = configuration[index], - modifier = Modifier.weight(1f), - screenState = screenState, - animationStartState = animationStartState, - input = input - ) - SearchCancel( - modifier = Modifier - .padding(start = SearchCancelPaddingStart, top = SearchCancelPaddingTop) - .noRippleClickable { - input.value = "" - vmEventStream.invoke( - configuration[index].toEvent(input.value) - ) - keyboardController?.hide() - focusManager.clearFocus() - animationStartState.value = false - screenState.value = ScreenState.CONTENT - }, - visible = screenState.value.visible().not() - ) - } - LibraryList(data, vmEventStream, screenState, itemsListState) - } - } - attachAnalytics(pagerState, configuration, vmAnalyticsStream) -} - -@Composable -private fun attachAnalytics( - pagerState: PagerState, - configuration: List, - vmAnalyticsStream: (LibraryAnalyticsEvent.Ui) -> Unit -) { - LaunchedEffect(pagerState) { - snapshotFlow { pagerState.currentPage }.collect { page -> - when (configuration[page]) { - is LibraryListConfig.Types -> { - vmAnalyticsStream.invoke(LibraryAnalyticsEvent.Ui.TabView.Types) - } - is LibraryListConfig.Relations -> { - vmAnalyticsStream.invoke(LibraryAnalyticsEvent.Ui.TabView.Relations) - } - is LibraryListConfig.TypesLibrary -> { - vmAnalyticsStream.invoke(LibraryAnalyticsEvent.Ui.TabView.LibTypes) - } - is LibraryListConfig.RelationsLibrary -> { - vmAnalyticsStream.invoke(LibraryAnalyticsEvent.Ui.TabView.LibRelations) - } - } - } - } -} - -@Composable -private fun SearchCancel(modifier: Modifier = Modifier, visible: Boolean = false) { - AnimatedVisibility(visible = visible) { - Text( - modifier = modifier, - text = stringResource(id = R.string.cancel), - style = UXBody.copy( - color = colorResource(id = R.color.glyph_active) - ) - ) - } - -} - -@Composable -private fun LibraryList( - data: LibraryScreenState.Tabs.TabData, - vmEventStream: (LibraryEvent) -> Unit, - screenState: MutableState, - itemsListState: LazyListState, -) { - - val itemModifier = Modifier - .fillMaxWidth() - .height(ItemDefaults.ITEM_HEIGHT) - - LazyColumn(modifier = Modifier.fillMaxSize(), state = itemsListState) { - items( - count = data.items.size, - key = { index -> "library-item-${data.items[index].id}" }, - itemContent = { ix -> - when (val item = data.items[ix]) { - is LibraryView.LibraryTypeView -> { - LibTypeItem( - name = item.name, - icon = item.icon, - installed = item.dependentData is DependentData.Model, - modifier = itemModifier, - onClick = { - vmEventStream.invoke( - LibraryEvent.ToggleInstall.Type(item) - ) - } - ) - } - is LibraryView.MyTypeView -> { - MyTypeItem( - name = item.name, - icon = item.icon, - readOnly = item.readOnly, - modifier = itemModifier.clickable(item.editable) { - vmEventStream.invoke( - LibraryEvent.Type.Edit(item) - ) - } - ) - } - is LibraryView.LibraryRelationView -> { - LibRelationItem( - modifier = itemModifier, - name = item.name, - format = item.format, - installed = item.dependentData is DependentData.Model, - onClick = { - vmEventStream.invoke( - LibraryEvent.ToggleInstall.Relation(item) - ) - } - ) - } - is LibraryView.MyRelationView -> { - MyRelationItem( - modifier = itemModifier.clickable(item.editable) { - vmEventStream.invoke( - LibraryEvent.Relation.Edit(item) - ) - }, - name = item.name, - readOnly = item.readOnly, - format = item.format - ) - } - is LibraryView.CreateNewTypeView -> { - CreateNewTypeItem( - modifier = itemModifier.clickable { - vmEventStream.invoke( - LibraryEvent.Type.Create(item.name) - ) - }, - name = item.name - ) - } - is LibraryView.CreateNewRelationView -> { - CreateNewRelationItem( - modifier = itemModifier.clickable { - vmEventStream.invoke( - LibraryEvent.Relation.Create(item.name) - ) - }, - name = item.name - ) - } - is LibraryView.LibraryTypesPlaceholderView -> { - LibraryObjectEmptyItem(LibraryObjectTypes.TYPES.type, item.name) - } - is LibraryView.LibraryRelationsPlaceholderView -> { - LibraryObjectEmptyItem(LibraryObjectTypes.RELATIONS.type, item.name) - } - is LibraryView.UnknownView -> { - // do nothing - } - } - if (ix < data.items.lastIndex) { - LibraryDivider() - } - if (ix == data.items.lastIndex && screenState.value.visible()) { - Spacer(modifier = Modifier.height(48.dp)) - } - } - ) - } -} - -@Composable -private fun LibraryDivider() { - Divider( - thickness = LibraryListDefaults.DividerThickness, - modifier = Modifier.padding( - start = LibraryListDefaults.DividerPadding, - end = LibraryListDefaults.DividerPadding - ), - color = colorResource(id = R.color.shape_primary) - ) -} - -@Immutable -internal object LibraryListDefaults { - val ItemPadding = 20.dp - val DividerPadding = 20.dp - val DividerThickness = 0.5.dp - val SearchBarPadding = 20.dp - val SearchCancelPaddingStart = 8.dp - val SearchCancelPaddingTop = 12.dp -} - -enum class LibraryObjectTypes(val type: String) { - TYPES("types"), RELATIONS("relations") -} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt b/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt deleted file mode 100644 index 0cb6ed2eaa..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/library/views/list/items/Items.kt +++ /dev/null @@ -1,290 +0,0 @@ -package com.anytypeio.anytype.ui.library.views.list.items - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_models.RelationFormat -import com.anytypeio.anytype.core_ui.extensions.simpleIcon -import com.anytypeio.anytype.core_ui.foundation.noRippleClickable - -import com.anytypeio.anytype.core_ui.views.UXBody -import com.anytypeio.anytype.core_ui.widgets.ObjectIconWidget -import com.anytypeio.anytype.presentation.objects.ObjectIcon -import com.anytypeio.anytype.ui.library.views.list.LibraryListDefaults -import com.anytypeio.anytype.ui.library.views.list.items.ItemDefaults.TEXT_PADDING_START - -@Composable -fun MyTypeItem( - name: String, - icon: ObjectIcon?, - readOnly: Boolean = false, - modifier: Modifier -) { - Row( - modifier.padding( - start = LibraryListDefaults.ItemPadding, - end = LibraryListDefaults.ItemPadding - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically - ) { - Icon(icon = icon) - Text( - text = name, - color = colorResource(id = R.color.text_primary), - modifier = Modifier - .padding(start = TEXT_PADDING_START), - style = UXBody - ) - Spacer(modifier = Modifier.weight(1f)) - if (readOnly) { - Image( - painter = painterResource(id = R.drawable.ic_object_locked), - contentDescription = "", - ) - } - } -} - -@Composable -fun LibTypeItem( - name: String, - icon: ObjectIcon?, - installed: Boolean = false, - modifier: Modifier, - onClick: () -> Unit -) { - Row( - modifier.padding( - start = LibraryListDefaults.ItemPadding, - end = LibraryListDefaults.ItemPadding - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically - ) { - Icon(icon = icon) - Text( - text = name, - color = colorResource(id = R.color.text_primary), - modifier = Modifier - .padding(start = TEXT_PADDING_START), - style = UXBody - ) - Spacer(modifier = Modifier.weight(1f)) - val installedImageRes = if (installed) { - R.drawable.ic_type_installed - } else { - R.drawable.ic_type_not_installed - } - Image( - painter = painterResource(id = installedImageRes), - contentDescription = installedImageRes.toString(), - modifier = Modifier.noRippleClickable(enabled = installed.not()) { - onClick() - } - ) - } -} - -@Composable -fun MyRelationItem( - modifier: Modifier, - name: String, - format: RelationFormat, - readOnly: Boolean = false, -) { - Row( - modifier.padding( - start = LibraryListDefaults.ItemPadding, - end = LibraryListDefaults.ItemPadding - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically - ) { - format.simpleIcon()?.let { - Image(painter = painterResource(id = it), contentDescription = "") - } - Text( - text = name, - color = colorResource(id = R.color.text_primary), - modifier = Modifier - .padding(start = TEXT_PADDING_START), - style = UXBody - ) - Spacer(modifier = Modifier.weight(1f)) - if (readOnly) { - Image( - painter = painterResource(id = R.drawable.ic_object_locked), - contentDescription = "" - ) - } - } -} - -@Composable -fun LibRelationItem( - modifier: Modifier, - name: String, - format: RelationFormat, - installed: Boolean, - onClick: () -> Unit -) { - Row( - modifier.padding( - start = LibraryListDefaults.ItemPadding, - end = LibraryListDefaults.ItemPadding - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically - ) { - format.simpleIcon()?.let { - Image(painter = painterResource(id = it), contentDescription = "") - } - Text( - text = name, - color = colorResource(id = R.color.text_primary), - modifier = Modifier - .padding(start = TEXT_PADDING_START), - style = UXBody - ) - Spacer(modifier = Modifier.weight(1f)) - val installedImageRes = if (installed) { - R.drawable.ic_type_installed - } else { - R.drawable.ic_type_not_installed - } - Image( - painter = painterResource(id = installedImageRes), - contentDescription = installedImageRes.toString(), - Modifier.noRippleClickable(enabled = installed.not()) { - onClick() - } - ) - } -} - -@Composable -fun CreateNewTypeItem( - modifier: Modifier, - name: String, -) { - Row( - modifier.padding( - start = LibraryListDefaults.ItemPadding, - end = LibraryListDefaults.ItemPadding - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(id = R.drawable.ic_default_plus), - contentDescription = "", - ) - Text( - text = stringResource( - id = R.string.library_create_new_type, - formatArgs = arrayOf(name) - ), - color = colorResource(id = R.color.text_primary), - modifier = Modifier.padding(start = TEXT_PADDING_START), - style = UXBody - ) - } -} - -@Composable -fun LibraryObjectEmptyItem(objectType: String, name: String) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .fillMaxWidth() - .padding(top = 48.dp) - ) { - Text( - text = stringResource( - id = R.string.library_objects_empty, - formatArgs = arrayOf(objectType, name) - ), - style = UXBody, - color = colorResource(id = R.color.text_primary), - textAlign = TextAlign.Center, - modifier = Modifier.padding(bottom = 9.dp) - ) - Text( - text = stringResource( - id = R.string.library_objects_empty_action - ), - color = colorResource(id = R.color.text_secondary), - style = UXBody, - textAlign = TextAlign.Center - ) - } -} - -@Composable -fun CreateNewRelationItem( - modifier: Modifier, - name: String, -) { - Row( - modifier.padding( - start = LibraryListDefaults.ItemPadding, - end = LibraryListDefaults.ItemPadding - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(id = R.drawable.ic_default_plus), - contentDescription = "", - ) - Text( - text = stringResource( - id = R.string.library_create_new_relation, - formatArgs = arrayOf(name) - ), - color = colorResource(id = R.color.text_primary), - modifier = Modifier.padding(start = TEXT_PADDING_START), - style = UXBody, - ) - } -} - -@Composable -fun Icon(icon: ObjectIcon?) { - icon?.let { - AndroidView( - factory = { ctx -> - ObjectIconWidget(ctx) - }, - modifier = Modifier.size(20.dp), - update = { - it.setIcon(icon) - } - ) - } -} - - -@Immutable -object ItemDefaults { - val ITEM_HEIGHT = 52.dp - val TEXT_PADDING_START = 10.dp -} diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LibraryWidgetCard.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LibraryWidgetCard.kt deleted file mode 100644 index 361a47a930..0000000000 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/types/LibraryWidgetCard.kt +++ /dev/null @@ -1,107 +0,0 @@ -package com.anytypeio.anytype.ui.widgets.types - -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -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 -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.views.HeadlineSubheading -import com.anytypeio.anytype.presentation.home.InteractionMode -import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction -import com.anytypeio.anytype.ui.widgets.menu.WidgetMenu - -@OptIn(ExperimentalFoundationApi::class) -@Composable -fun LibraryWidgetCard( - mode: InteractionMode, - onClick: () -> Unit, - onDropDownMenuAction: (DropDownMenuAction) -> Unit, -) { - val haptic = LocalHapticFeedback.current - val isCardMenuExpanded = remember { - mutableStateOf(false) - } - val isHeaderMenuExpanded = remember { - mutableStateOf(false) - } - Box( - modifier = Modifier - .fillMaxWidth() - .padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 6.dp) - .alpha(if (isCardMenuExpanded.value || isHeaderMenuExpanded.value) 0.8f else 1f) - .background( - shape = RoundedCornerShape(16.dp), - color = colorResource(id = R.color.dashboard_card_background) - ) - .then( - if (mode is InteractionMode.Default) - Modifier.combinedClickable( - onClick = { - onClick() - }, - onLongClick = { - isCardMenuExpanded.value = !isCardMenuExpanded.value - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - }, - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) - else - Modifier - ) - ) { - Box( - Modifier - .padding(vertical = 6.dp) - .height(40.dp) - ) { - Image( - painter = painterResource(id = R.drawable.ic_widget_library), - contentDescription = "Bin icon", - modifier = Modifier - .align(Alignment.CenterStart) - .padding(start = 14.dp) - ) - Text( - text = stringResource(id = R.string.library), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .align(Alignment.CenterStart) - .padding(start = 42.dp, end = 16.dp), - style = HeadlineSubheading, - color = colorResource(id = R.color.text_primary), - ) - } - WidgetMenu( - isExpanded = isCardMenuExpanded, - onDropDownMenuAction = onDropDownMenuAction, - canRemove = false, - canChangeType = false, - canChangeSource = false, - canEmptyBin = false, - canEditWidgets = mode is InteractionMode.Default, - canAddBelow = false - ) - } -} \ No newline at end of file diff --git a/app/src/main/res/navigation/graph.xml b/app/src/main/res/navigation/graph.xml index 80ec366d0c..535ae1ba48 100644 --- a/app/src/main/res/navigation/graph.xml +++ b/app/src/main/res/navigation/graph.xml @@ -460,32 +460,6 @@ app:destination="@id/selectSpaceScreen"/> - - - - - - - - { + when (tab) { + AllContentTab.TYPES -> { commands.emit(Command.SendToast.TypeRemoved(name)) } - LibraryItem.RELATION -> { + AllContentTab.RELATIONS -> { commands.emit(Command.SendToast.RelationRemoved(name)) } + else -> { + //do nothing + } } } ) @@ -1014,4 +1016,8 @@ class AllContentViewModel( val DEFAULT_INITIAL_TAB = AllContentTab.PAGES val DEFAULT_QUERY = "" } + + enum class LibraryItem { + TYPE, RELATION + } } 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 e26208a8ba..4ba0801718 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 @@ -1775,19 +1775,6 @@ class HomeScreenViewModel( } } - fun onLibraryClicked() { - viewModelScope.launch { - val space = spaceManager.get() - if (space.isNotEmpty()) { - navigation( - Navigation.OpenLibrary(space) - ) - } else { - Timber.w("Space is missing: ${space}") - } - } - } - fun onSearchIconClicked() { viewModelScope.launch { commands.emit( @@ -2127,7 +2114,6 @@ class HomeScreenViewModel( 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/LibraryEvents.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryEvents.kt deleted file mode 100644 index db9485d37b..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryEvents.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.anytypeio.anytype.presentation.library - -sealed class LibraryEvent { - - sealed class BottomMenu : LibraryEvent() { - object Back : BottomMenu() - object Search : BottomMenu() - object CreateObject : BottomMenu() - object OpenProfile : BottomMenu() - } - - sealed class Query(open val query: String) : LibraryEvent() { - class MyTypes(override val query: String) : Query(query) - class LibraryTypes(override val query: String) : Query(query) - class MyRelations(override val query: String) : Query(query) - class LibraryRelations(override val query: String) : Query(query) - } - - sealed class ToggleInstall(open val item: LibraryView) : LibraryEvent() { - class Type(override val item: LibraryView) : ToggleInstall(item) - class Relation(override val item: LibraryView) : ToggleInstall(item) - } - - sealed class Type : LibraryEvent() { - class Create(val name: String = "") : Type() - class Edit(val item: LibraryView.MyTypeView) : Type() - } - - sealed class Relation : LibraryEvent() { - class Create(val name: String = "") : Relation() - class Edit(val item: LibraryView.MyRelationView) : Relation() - } - -} - -sealed class LibraryAnalyticsEvent { - sealed class Ui { - object Idle : Ui() - sealed class TabView(val type: String, val view: String) : Ui() { - object Types : TabView(type = TypeType, view = ViewYour) - object Relations : TabView(type = TypeRelation, view = ViewYour) - object LibTypes : TabView(type = TypeType, view = ViewLibrary) - object LibRelations : TabView(type = TypeRelation, view = ViewLibrary) - } - } -} - -private const val TypeType = "type" -private const val TypeRelation = "relation" -private const val ViewYour = "your" -private const val ViewLibrary = "library" \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt deleted file mode 100644 index 88920bf466..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryListDelegate.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.anytypeio.anytype.presentation.library - -import com.anytypeio.anytype.core_models.ObjectWrapper -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.debounce -import kotlinx.coroutines.flow.distinctUntilChanged - -interface LibraryListDelegate { - - val queryFlow: MutableStateFlow - val itemsFlow: Flow - - fun itemsFlow(): Flow> - - @FlowPreview - fun queryFlow() = queryFlow - .debounce(DEBOUNCE_TIMEOUT) - .distinctUntilChanged() - - suspend fun unsubscribe() - -} - -fun List.filterByQuery(query: String): List { - return filter { it.name.contains(query.trim(), true) } -} - -private const val DEBOUNCE_TIMEOUT = 100L \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryQueryListeners.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryQueryListeners.kt deleted file mode 100644 index 985996c73c..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryQueryListeners.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.anytypeio.anytype.presentation.library - -interface QueryListenerMyTypes { - fun onQueryMyTypes(string: String) -} - -interface QueryListenerMyRelations { - fun onQueryMyRelations(string: String) -} - -interface QueryListenerLibTypes { - fun onQueryLibTypes(string: String) -} - -interface QueryListenerLibRelations { - fun onQueryLibRelations(string: String) -} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryResourceManager.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryResourceManager.kt deleted file mode 100644 index a04941551d..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryResourceManager.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.anytypeio.anytype.presentation.library - -import android.content.Context -import android.content.res.Resources -import com.anytypeio.anytype.presentation.R -import javax.inject.Inject - -interface LibraryResourceManager { - - fun messageRelationAdded(name: String): String - fun messageRelationRemoved(name: String): String - fun messageTypeAdded(name: String): String - fun messageTypeRemoved(name: String): String - - val errorMessage: String - - class Impl @Inject constructor( - val context: Context - ) : LibraryResourceManager { - - private val resources: Resources = context.resources - - override fun messageRelationAdded(name: String) = - resources.getString(R.string.library_relation_added, name) - - override fun messageRelationRemoved(name: String) = - resources.getString(R.string.library_relation_removed, name) - - override fun messageTypeAdded(name: String) = - resources.getString(R.string.library_type_added, name) - - - override fun messageTypeRemoved(name: String) = - resources.getString(R.string.library_type_removed, name) - - override val errorMessage: String = - resources.getString(R.string.library_something_went_wrong) - - } - -} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryScreenState.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryScreenState.kt deleted file mode 100644 index ca2de0ad07..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryScreenState.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.anytypeio.anytype.presentation.library - - -class LibraryScreenState( - val types: Tabs.Types, - val relations: Tabs.Relations -) { - sealed class Tabs( - val my: TabData, - val lib: TabData - ) { - class Types( - myTypes: TabData, - libTypes: TabData - ) : Tabs(myTypes, libTypes) - - class Relations( - myRelations: TabData, - libRelations: TabData - ) : Tabs(myRelations, libRelations) - - data class TabData( - val items: List = emptyList() - ) - - } -} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryView.kt deleted file mode 100644 index 006f791633..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryView.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.anytypeio.anytype.presentation.library - -import com.anytypeio.anytype.core_models.Id -import com.anytypeio.anytype.core_models.Key -import com.anytypeio.anytype.core_models.RelationFormat -import com.anytypeio.anytype.presentation.objects.ObjectIcon - -sealed interface DependentData { - - class Model( - val item: LibraryView, - ) : DependentData - - object None : DependentData - -} - -sealed interface LibraryView { - val id: Id - val name: String - val dependentData: DependentData - - class MyTypeView( - override val id: Id, - override val name: String, - val icon: ObjectIcon? = null, - val sourceObject: Id? = null, - val uniqueKey: Key? = null, - val readOnly: Boolean = true, - val editable: Boolean = true, - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - data class LibraryTypeView( - override val id: Id, - override val name: String, - val icon: ObjectIcon? = null, - val uniqueKey: Key? = null, - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - class MyRelationView( - override val id: Id, - override val name: String, - val format: RelationFormat, - val sourceObject: Id? = null, - val readOnly: Boolean = true, - val editable: Boolean = true, - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - data class LibraryRelationView( - override val id: Id, - override val name: String, - val format: RelationFormat, - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - class UnknownView( - override val id: Id, - override val name: String = "", - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - class CreateNewTypeView( - override val id: Id = "", - override val name: String = "", - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - class CreateNewRelationView( - override val id: Id = "", - override val name: String = "", - override val dependentData: DependentData = DependentData.None - ) : LibraryView - - class LibraryTypesPlaceholderView( - override val id: Id = "", - override val name: String = "", - override val dependentData: DependentData = DependentData.None, - ) : LibraryView - - class LibraryRelationsPlaceholderView( - override val id: Id = "", - override val name: String = "", - override val dependentData: DependentData = DependentData.None, - ) : LibraryView - -} \ No newline at end of file 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 deleted file mode 100644 index c17dcb27cc..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/LibraryViewModel.kt +++ /dev/null @@ -1,584 +0,0 @@ -package com.anytypeio.anytype.presentation.library - -import androidx.lifecycle.ViewModel -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.EventsDictionary.libraryScreenRelation -import com.anytypeio.anytype.analytics.base.EventsDictionary.libraryScreenType -import com.anytypeio.anytype.analytics.base.EventsDictionary.libraryView -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 -import com.anytypeio.anytype.core_models.primitives.SpaceId -import com.anytypeio.anytype.core_utils.ext.allUniqueBy -import com.anytypeio.anytype.core_utils.ext.orNull -import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers -import com.anytypeio.anytype.domain.base.fold -import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams -import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer -import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.domain.`object`.SetObjectDetails -import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes -import com.anytypeio.anytype.domain.page.CreateObject -import com.anytypeio.anytype.domain.workspace.AddObjectToWorkspace -import com.anytypeio.anytype.domain.workspace.RemoveObjectsFromWorkspace -import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.presentation.BuildConfig -import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate -import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectCreateEvent -import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Companion.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION -import com.anytypeio.anytype.presentation.home.OpenObjectNavigation -import com.anytypeio.anytype.presentation.home.navigation -import com.anytypeio.anytype.presentation.library.delegates.LibraryRelationsDelegate -import com.anytypeio.anytype.presentation.library.delegates.LibraryTypesDelegate -import com.anytypeio.anytype.presentation.library.delegates.MyRelationsDelegate -import com.anytypeio.anytype.presentation.library.delegates.MyTypesDelegate -import com.anytypeio.anytype.presentation.navigation.NavigationViewModel -import com.anytypeio.anytype.presentation.objects.getCreateObjectParams -import com.anytypeio.anytype.presentation.profile.ProfileIconView -import com.anytypeio.anytype.presentation.profile.profileIcon -import javax.inject.Inject -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.collectIndexed -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch -import timber.log.Timber - -class LibraryViewModel( - private val params: Params, - private val myTypesDelegate: MyTypesDelegate, - private val libraryTypesDelegate: LibraryTypesDelegate, - private val myRelationsDelegate: MyRelationsDelegate, - private val libraryRelationsDelegate: LibraryRelationsDelegate, - private val addObjectToWorkspace: AddObjectToWorkspace, - private val removeObjectsFromWorkspace: RemoveObjectsFromWorkspace, - private val resourceManager: LibraryResourceManager, - private val setObjectDetails: SetObjectDetails, - private val createObject: CreateObject, - private val analytics: Analytics, - private val spaceManager: SpaceManager, - private val storelessSubscriptionContainer: StorelessSubscriptionContainer, - private val appCoroutineDispatchers: AppCoroutineDispatchers, - private val urlBuilder: UrlBuilder, - private val storeOfObjectTypes: StoreOfObjectTypes, - private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate -) : NavigationViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate { - - val icon = MutableStateFlow(ProfileIconView.Loading) - - private val uiEvents = MutableStateFlow(LibraryEvent.Query.MyTypes("")) - private val analyticsEvents = MutableStateFlow( - LibraryAnalyticsEvent.Ui.Idle - ) - - val effects = MutableStateFlow(Effect.Idle) - - val uiState: StateFlow = combine( - myTypesDelegate.itemsFlow, - libraryTypesDelegate.itemsFlow, - myRelationsDelegate.itemsFlow, - libraryRelationsDelegate.itemsFlow - ) { myTypes, libTypes, myRel, libRel -> - - val libTypesItems = updateInstalledValueForTypes( - libTypes, - myTypes - ) - val libRelItems = updateInstalledValueForRelations( - libRel, - myRel - ) - - LibraryScreenState( - types = LibraryScreenState.Tabs.Types(myTypes, libTypesItems), - relations = LibraryScreenState.Tabs.Relations(myRel, libRelItems) - ) - - }.stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(STOP_SUBSCRIPTION_TIMEOUT), - initialValue = LibraryScreenState( - types = LibraryScreenState.Tabs.Types( - myTypes = LibraryScreenState.Tabs.TabData(), - libTypes = LibraryScreenState.Tabs.TabData() - ), - relations = LibraryScreenState.Tabs.Relations( - myRelations = LibraryScreenState.Tabs.TabData(), - libRelations = LibraryScreenState.Tabs.TabData() - ) - ) - ) - - init { - Timber.i("LibraryViewModel, init") - proceedWithObservingProfileIcon() - viewModelScope.launch { - uiEvents.collect { - when (it) { - is LibraryEvent.Query -> proceedQueryEvent(it) - is LibraryEvent.ToggleInstall -> proceedWithToggleInstall(it.item) - is LibraryEvent.Type -> proceedWithTypeActions(it) - is LibraryEvent.Relation -> proceedWithRelationActions(it) - is LibraryEvent.BottomMenu -> proceedWithBottomMenuActions(it) - } - } - } - viewModelScope.launch { - analyticsEvents.filterIsInstance() - .collectIndexed { index, it -> - val route = if (index == 0) ROUTE_OUTER else ROUTE_INNER - proceedWithViewAnalytics(it, route) - } - } - } - - private fun proceedWithObservingProfileIcon() { - viewModelScope.launch { - spaceManager - .observe() - .flatMapLatest { config -> - storelessSubscriptionContainer.subscribe( - StoreSearchByIdsParams( - space = SpaceId(config.techSpace), - subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, - targets = listOf(config.profile), - keys = listOf( - Relations.ID, - Relations.NAME, - Relations.ICON_EMOJI, - Relations.ICON_IMAGE, - Relations.ICON_OPTION - ) - ) - ).map { result -> - val obj = result.firstOrNull() - obj?.profileIcon(urlBuilder) ?: ProfileIconView.Placeholder(null) - } - } - .catch { Timber.e(it, "Error while observing space icon") } - .flowOn(appCoroutineDispatchers.io) - .collect { icon.value = it } - } - } - - private fun proceedWithViewAnalytics(it: LibraryAnalyticsEvent.Ui.TabView, route: String) { - viewModelScope.sendEvent( - analytics = analytics, - eventName = libraryView, - props = Props( - mapOf( - "type" to it.type, - "view" to it.view, - "route" to route - ) - ) - ) - } - - private fun proceedWithBottomMenuActions(it: LibraryEvent.BottomMenu) { - when (it) { - is LibraryEvent.BottomMenu.Back -> navigate(Navigation.Back()) - is LibraryEvent.BottomMenu.Search -> navigate(Navigation.Search()) - is LibraryEvent.BottomMenu.CreateObject -> proceedWithCreateDoc() - is LibraryEvent.BottomMenu.OpenProfile -> navigate(Navigation.ExitToVault) - } - } - - fun onCreateObjectOfTypeClicked(objType: ObjectWrapper.Type) { - proceedWithCreateDoc(objType) - } - - private fun proceedWithCreateDoc( - objType: ObjectWrapper.Type? = null - ) { - val startTime = System.currentTimeMillis() - viewModelScope.launch { - val params = objType?.uniqueKey.getCreateObjectParams( - space = SpaceId(spaceManager.get()), - objType?.defaultTemplateId - ) - createObject.async(params).fold( - onSuccess = { - result -> proceedWithOpeningObject(result.obj) - sendAnalyticsObjectCreateEvent( - analytics = analytics, - route = EventsDictionary.Routes.allContentRoute, - startTime = startTime, - objType = objType ?: storeOfObjectTypes.getByKey(result.typeKey.key), - view = EventsDictionary.View.viewHome, - spaceParams = provideParams(spaceManager.get()) - ) - }, - onFailure = { e -> Timber.e(e, "Error while creating a new object") } - ) - } - } - - private fun proceedWithOpeningObject(obj: ObjectWrapper.Basic) { - when (val navigation = obj.navigation()) { - is OpenObjectNavigation.OpenDataView -> { - navigate(Navigation.OpenSetOrCollection(navigation.target)) - } - is OpenObjectNavigation.OpenEditor -> { - navigate(Navigation.OpenEditor(navigation.target)) - } - is OpenObjectNavigation.OpenDiscussion -> { - sendToast("not implemented") - } - is OpenObjectNavigation.UnexpectedLayoutError -> { - sendToast("Unexpected layout: ${navigation.layout}") - } - OpenObjectNavigation.NonValidObject -> { - sendToast("Object id is missing") - } - } - } - - private fun proceedQueryEvent(event: LibraryEvent.Query) { - when (event) { - is LibraryEvent.Query.MyTypes -> { - myTypesDelegate.onQueryMyTypes(event.query) - } - is LibraryEvent.Query.LibraryTypes -> { - libraryTypesDelegate.onQueryLibTypes(event.query) - } - is LibraryEvent.Query.MyRelations -> { - myRelationsDelegate.onQueryMyRelations(event.query) - } - is LibraryEvent.Query.LibraryRelations -> { - libraryRelationsDelegate.onQueryLibRelations(event.query) - } - } - } - - private fun proceedWithToggleInstall(item: LibraryView) { - when (val dependentData = item.dependentData) { - is DependentData.Model -> uninstallObject(item, dependentData.item.id) - is DependentData.None -> installObject(item) - } - } - - private fun proceedWithTypeActions(event: LibraryEvent.Type) { - when (event) { - is LibraryEvent.Type.Create -> { - navigate(Navigation.OpenTypeCreation(event.name)) - } - is LibraryEvent.Type.Edit -> { - viewModelScope.sendEvent( - analytics = analytics, - eventName = libraryScreenType, - props = Props( - map = mapOf("objectType" to event.item.id) - ) - ) - navigate(Navigation.OpenTypeEditing(event.item)) - } - } - } - - private fun proceedWithRelationActions(event: LibraryEvent.Relation) { - when (event) { - is LibraryEvent.Relation.Create -> navigate(Navigation.OpenRelationCreation(event.name)) - is LibraryEvent.Relation.Edit -> { - viewModelScope.sendEvent( - analytics = analytics, - eventName = libraryScreenRelation, - props = Props( - map = mapOf("relationKey" to event.item.id) - ) - ) - navigate(Navigation.OpenRelationEditing(event.item)) - } - } - } - - private fun installObject(item: LibraryView) { - viewModelScope.launch { - addObjectToWorkspace( - AddObjectToWorkspace.Params( - space = spaceManager.get(), - objects = listOf (item.id) - ) - ).proceed( - success = { - when (item) { - is LibraryView.LibraryRelationView -> { - sendToast(resourceManager.messageRelationAdded(item.name)) - } - is LibraryView.LibraryTypeView -> { - sendToast(resourceManager.messageTypeAdded(item.name)) - } - else -> { - Timber.e("Unsupported item type: $item") - } - } - }, - failure = { - Timber.e(it, "Error while adding relation to workspace.") - sendToast(resourceManager.errorMessage) - } - ) - } - } - - private fun uninstallObject(item: LibraryView, id: Id) { - viewModelScope.launch { - removeObjectsFromWorkspace.execute( - RemoveObjectsFromWorkspace.Params(listOf(id)) - ).fold( - onFailure = { - Timber.e(it, "Error while removing relation from workspace.") - sendToast(resourceManager.errorMessage) - }, - onSuccess = { - when (item) { - is LibraryView.LibraryRelationView -> { - sendToast(resourceManager.messageRelationRemoved(item.name)) - } - is LibraryView.LibraryTypeView -> { - sendToast(resourceManager.messageTypeRemoved(item.name)) - } - else -> { - Timber.e("Unsupported item type: $item") - } - } - } - ) - } - } - - fun uninstallObject(id: Id, type: LibraryItem, name: String) { - viewModelScope.launch { - removeObjectsFromWorkspace.execute( - RemoveObjectsFromWorkspace.Params(listOf(id)) - ).fold( - onFailure = { - Timber.e(it, "Error while uninstalling object") - sendToast(resourceManager.errorMessage) - }, - onSuccess = { - val message = when (type) { - LibraryItem.TYPE -> resourceManager.messageTypeRemoved(name) - LibraryItem.RELATION -> resourceManager.messageRelationRemoved(name) - } - sendToast(message) - } - ) - } - } - - fun eventStream(event: LibraryEvent) { - uiEvents.value = event - } - - fun analyticsStream(event: LibraryAnalyticsEvent.Ui) { - analyticsEvents.value = event - } - - private fun updateInstalledValueForTypes( - libTypes: LibraryScreenState.Tabs.TabData, - myTypes: LibraryScreenState.Tabs.TabData - ): LibraryScreenState.Tabs.TabData { - if (BuildConfig.DEBUG) { - assert(libTypes.items.allUniqueBy { it.id }) - assert(myTypes.items.allUniqueBy { it.id }) - } - val myTypeViews = myTypes - .items - .filterIsInstance() - - return libTypes.copy( - items = libTypes.items.map { libType -> - if (libType is LibraryView.LibraryTypeView) { - with( - myTypeViews.find { it.uniqueKey == libType.uniqueKey } - ) { - libType.copy( - dependentData = if (this != null) { - DependentData.Model(item = this) - } else { - DependentData.None - } - ) - } - } else { - libType - } - }.distinctBy { view -> view.id } - ) - } - - private fun updateInstalledValueForRelations( - libRelations: LibraryScreenState.Tabs.TabData, - myRelations: LibraryScreenState.Tabs.TabData - ): LibraryScreenState.Tabs.TabData { - if (BuildConfig.DEBUG) { - assert(libRelations.items.allUniqueBy { it.id }) - assert(myRelations.items.allUniqueBy { it.id }) - } - - val updatedLibraryRelations = updateLibraryRelationItems( - libraryItems = libRelations.items, - myRelationItems = myRelations.items - ) - return libRelations.copy( - items = updatedLibraryRelations.distinctBy { view -> view.id } - ) - } - - private fun updateLibraryRelationItems( - libraryItems: List, - myRelationItems: List - ): List { - return libraryItems.map { libraryItem -> - if (libraryItem !is LibraryView.LibraryRelationView) { - return@map libraryItem - } - val relationInstalled = myRelationItems.firstOrNull { myRelationItem -> - (myRelationItem as? LibraryView.MyRelationView)?.sourceObject == libraryItem.id - } - val dependedData = if (relationInstalled != null) { - DependentData.Model(item = relationInstalled) - } else { - DependentData.None - } - libraryItem.copy(dependentData = dependedData) - } - } - - fun updateObject(id: String, name: String, icon: String?) { - viewModelScope.launch { - setObjectDetails.execute( - SetObjectDetails.Params( - ctx = id, - details = mapOf( - Relations.NAME to name, - Relations.ICON_EMOJI to icon.orNull(), - ) - ) - ).fold( - onFailure = { - Timber.e(it, "Error while updating object details") - sendToast(resourceManager.errorMessage) - }, - onSuccess = { - // do nothing - } - ) - } - } - - fun onObjectCreated() { - effects.value = Effect.ObjectCreated() - } - - override fun onCleared() { - GlobalScope.launch { - myRelationsDelegate.unsubscribe() - libraryRelationsDelegate.unsubscribe() - myTypesDelegate.unsubscribe() - libraryTypesDelegate.unsubscribe() - } - super.onCleared() - } - - class Factory @Inject constructor( - private val params: Params, - private val myTypesDelegate: MyTypesDelegate, - private val libraryTypesDelegate: LibraryTypesDelegate, - private val myRelationsDelegate: MyRelationsDelegate, - private val libraryRelationsDelegate: LibraryRelationsDelegate, - private val addObjectToWorkspace: AddObjectToWorkspace, - private val removeObjectsFromWorkspace: RemoveObjectsFromWorkspace, - private val resourceManager: LibraryResourceManager, - private val setObjectDetails: SetObjectDetails, - private val createObject: CreateObject, - private val analytics: Analytics, - private val spaceManager: SpaceManager, - private val storelessSubscriptionContainer: StorelessSubscriptionContainer, - private val appCoroutineDispatchers: AppCoroutineDispatchers, - private val urlBuilder: UrlBuilder, - private val storeOfObjectTypes: StoreOfObjectTypes, - private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate - ) : ViewModelProvider.Factory { - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T { - return LibraryViewModel( - params = params, - myTypesDelegate = myTypesDelegate, - libraryTypesDelegate = libraryTypesDelegate, - myRelationsDelegate = myRelationsDelegate, - libraryRelationsDelegate = libraryRelationsDelegate, - addObjectToWorkspace = addObjectToWorkspace, - removeObjectsFromWorkspace = removeObjectsFromWorkspace, - resourceManager = resourceManager, - setObjectDetails = setObjectDetails, - createObject = createObject, - analytics = analytics, - spaceManager = spaceManager, - storelessSubscriptionContainer = storelessSubscriptionContainer, - appCoroutineDispatchers = appCoroutineDispatchers, - urlBuilder = urlBuilder, - storeOfObjectTypes = storeOfObjectTypes, - analyticSpaceHelperDelegate = analyticSpaceHelperDelegate - ) as T - } - } - - class Params(val space: SpaceId) - - sealed class Navigation { - class OpenTypeCreation( - val name: String = "" - ) : Navigation() - - class OpenRelationCreation( - val name: String = "" - ) : Navigation() - - class OpenTypeEditing( - val view: LibraryView.MyTypeView - ) : Navigation() - - class OpenRelationEditing( - val view: LibraryView.MyRelationView - ) : Navigation() - - object ExitToVault: Navigation() - - class Back : Navigation() - - class Search : Navigation() - - class OpenEditor(val id: Id) : Navigation() - - class OpenSetOrCollection(val id: Id) : Navigation() - } - - sealed class Effect { - class ObjectCreated : Effect() - object Idle : Effect() - } - - enum class LibraryItem { - TYPE, RELATION - } - -} - -private const val STOP_SUBSCRIPTION_TIMEOUT = 1_000L -private const val ROUTE_INNER = "inner" -private const val ROUTE_OUTER = "outer" \ No newline at end of file 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 deleted file mode 100644 index 5dac6bc4c9..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryRelationsDelegate.kt +++ /dev/null @@ -1,74 +0,0 @@ -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 -import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.presentation.library.LibraryListDelegate -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryView -import com.anytypeio.anytype.presentation.library.QueryListenerLibRelations -import com.anytypeio.anytype.presentation.library.filterByQuery -import com.anytypeio.anytype.presentation.objects.toLibraryViews -import com.anytypeio.anytype.presentation.search.ObjectSearchConstants -import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine - -class LibraryRelationsDelegate @Inject constructor( - private val container: StorelessSubscriptionContainer, - private val urlBuilder: UrlBuilder, - private val dispatchers: AppCoroutineDispatchers -) : LibraryListDelegate, QueryListenerLibRelations { - - override val queryFlow: MutableStateFlow = MutableStateFlow("") - - override fun onQueryLibRelations(string: String) { - queryFlow.value = string - } - - override val itemsFlow: Flow = combine( - itemsFlow(), - queryFlow() - ) { items, query -> - LibraryScreenState.Tabs.TabData( - items - .toLibraryViews(urlBuilder) - .filterByQuery(query) - .optAddEmptyPlaceholder(query) - ) - } - - override fun itemsFlow() = container.subscribe(buildSearchParams()) - - private fun buildSearchParams(): StoreSearchParams { - return StoreSearchParams( - space = SpaceId(MARKETPLACE_SPACE_ID), - subscription = SUB_LIBRARY_RELATIONS, - keys = ObjectSearchConstants.defaultRelationKeys, - filters = buildList { - addAll(ObjectSearchConstants.filterMarketplaceRelations()) - } - ) - } - - override suspend fun unsubscribe() = with(dispatchers.io) { - container.unsubscribe(listOf(SUB_LIBRARY_RELATIONS)) - } - -} - -private fun List.optAddEmptyPlaceholder(query: String): List { - val q = query.trim() - val result = this - return if (q.isNotEmpty() && result.isEmpty()) { - listOf(LibraryView.LibraryRelationsPlaceholderView(name = q)) - } else { - result - } -} - -private const val SUB_LIBRARY_RELATIONS = "subscription.library_relations" \ No newline at end of file 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 deleted file mode 100644 index a57021a833..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/LibraryTypesDelegate.kt +++ /dev/null @@ -1,73 +0,0 @@ -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 -import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.presentation.library.LibraryListDelegate -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryView -import com.anytypeio.anytype.presentation.library.QueryListenerLibTypes -import com.anytypeio.anytype.presentation.library.filterByQuery -import com.anytypeio.anytype.presentation.objects.SupportedLayouts -import com.anytypeio.anytype.presentation.objects.toLibraryViews -import com.anytypeio.anytype.presentation.search.ObjectSearchConstants -import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine - -class LibraryTypesDelegate @Inject constructor( - private val container: StorelessSubscriptionContainer, - private val urlBuilder: UrlBuilder, - private val dispatchers: AppCoroutineDispatchers -) : LibraryListDelegate, QueryListenerLibTypes { - - override val queryFlow: MutableStateFlow = MutableStateFlow("") - - override fun onQueryLibTypes(string: String) { - queryFlow.value = string - } - - override val itemsFlow: Flow = combine( - itemsFlow(), - queryFlow() - ) { items, query -> - LibraryScreenState.Tabs.TabData( - items - .toLibraryViews(urlBuilder) - .filterByQuery(query) - .optAddEmptyPlaceholder(query) - ) - } - - override fun itemsFlow() = container.subscribe(buildSearchParams()) - - private fun buildSearchParams(): StoreSearchParams { - return StoreSearchParams( - space = SpaceId(MARKETPLACE_SPACE_ID), - subscription = SUB_LIBRARY_TYPES, - keys = ObjectSearchConstants.defaultKeys, - filters = ObjectSearchConstants.filterTypes() - ) - } - - override suspend fun unsubscribe() = with(dispatchers.io) { - container.unsubscribe(listOf(SUB_LIBRARY_TYPES)) - } - -} - -private fun List.optAddEmptyPlaceholder(query: String): List { - val q = query.trim() - val result = this - return if (q.isNotEmpty() && result.isEmpty()) { - listOf(LibraryView.LibraryTypesPlaceholderView(name = q)) - } else { - result - } -} - -private const val SUB_LIBRARY_TYPES = "subscription.library_types" \ No newline at end of file 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 deleted file mode 100644 index 7a021773b5..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyRelationsDelegate.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.anytypeio.anytype.presentation.library.delegates - -import com.anytypeio.anytype.core_models.DVFilter -import com.anytypeio.anytype.core_models.DVFilterCondition -import com.anytypeio.anytype.core_models.Id -import com.anytypeio.anytype.core_models.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 -import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.presentation.library.LibraryListDelegate -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryView -import com.anytypeio.anytype.presentation.library.QueryListenerMyRelations -import com.anytypeio.anytype.presentation.library.filterByQuery -import com.anytypeio.anytype.presentation.objects.toLibraryViews -import com.anytypeio.anytype.presentation.search.ObjectSearchConstants -import javax.inject.Inject -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapMerge -import kotlinx.coroutines.flow.flow - -class MyRelationsDelegate @Inject constructor( - private val container: StorelessSubscriptionContainer, - private val spaceManager: SpaceManager, - private val urlBuilder: UrlBuilder, - private val dispatchers: AppCoroutineDispatchers -) : LibraryListDelegate, QueryListenerMyRelations { - - override val queryFlow: MutableStateFlow = MutableStateFlow("") - - override fun onQueryMyRelations(string: String) { - queryFlow.value = string - } - - @FlowPreview - override val itemsFlow: Flow = combine( - itemsFlow(), - queryFlow() - ) { items, query -> - LibraryScreenState.Tabs.TabData( - items - .toLibraryViews(urlBuilder) - .filterByQuery(query) - .optAddCreateRelationView(query) - ) - } - - @FlowPreview - override fun itemsFlow() = flow { - emit(spaceManager.get()) - }.flatMapMerge { space: Id -> - val searchParams = buildSearchParams(space) - container.subscribe(searchParams) - } - - private fun buildSearchParams(space: Id): StoreSearchParams { - return StoreSearchParams( - space = SpaceId(space), - subscription = SUB_LIBRARY_MY_RELATIONS, - keys = ObjectSearchConstants.defaultRelationKeys, - filters = buildList { - addAll(ObjectSearchConstants.filterMyRelations()) - } - ) - } - - override suspend fun unsubscribe() = with(dispatchers.io) { - container.unsubscribe(listOf(SUB_LIBRARY_MY_RELATIONS)) - } - -} - -private fun List.optAddCreateRelationView(query: String): List { - val q = query.trim() - val result = this - return if (q.isNotEmpty() && result.none { it.name.lowercase() == q.lowercase() }) { - buildList { - add(LibraryView.CreateNewRelationView(name = q)) - addAll(result) - } - } else { - result - } -} - -private const val SUB_LIBRARY_MY_RELATIONS = "subscription.library_my_relations" \ No newline at end of file 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 deleted file mode 100644 index 3ec54c72cf..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/library/delegates/MyTypesDelegate.kt +++ /dev/null @@ -1,92 +0,0 @@ -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 -import com.anytypeio.anytype.domain.misc.UrlBuilder -import com.anytypeio.anytype.domain.workspace.SpaceManager -import com.anytypeio.anytype.presentation.library.LibraryListDelegate -import com.anytypeio.anytype.presentation.library.LibraryScreenState -import com.anytypeio.anytype.presentation.library.LibraryView -import com.anytypeio.anytype.presentation.library.QueryListenerMyTypes -import com.anytypeio.anytype.presentation.library.filterByQuery -import com.anytypeio.anytype.presentation.objects.toLibraryViews -import com.anytypeio.anytype.presentation.search.ObjectSearchConstants -import javax.inject.Inject -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapMerge -import kotlinx.coroutines.flow.flow - -class MyTypesDelegate @Inject constructor( - private val container: StorelessSubscriptionContainer, - private val spaceManager: SpaceManager, - private val urlBuilder: UrlBuilder, - private val dispatchers: AppCoroutineDispatchers -) : LibraryListDelegate, QueryListenerMyTypes { - - override val queryFlow: MutableStateFlow = MutableStateFlow("") - - override fun onQueryMyTypes(string: String) { - queryFlow.value = string - } - - @FlowPreview - override val itemsFlow: Flow = combine( - itemsFlow(), queryFlow() - ) { items, query -> - LibraryScreenState.Tabs.TabData( - items - .toLibraryViews(urlBuilder) - .filterByQuery(query) - .optAddCreateTypeView(query) - ) - } - - @FlowPreview - override fun itemsFlow() = flow { - emit(spaceManager.get()) - }.flatMapMerge { space: Id -> - val searchParams = buildSearchParams(space = space) - container.subscribe(searchParams) - } - - 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( - excludeParticipant = false - ) - ) - } - - override suspend fun unsubscribe() = with(dispatchers.io) { - container.unsubscribe(listOf(SUB_LIBRARY_MY_TYPES)) - } - -} - -private fun List.optAddCreateTypeView(query: String): List { - val q = query.trim() - val result = this - return if (q.isNotEmpty() && result.none { it.name.lowercase() == q.lowercase() }) { - buildList { - add(LibraryView.CreateNewTypeView(name = q)) - addAll(result) - } - } else { - result - } -} - -private const val SUB_LIBRARY_MY_TYPES = "subscription.library_my_types" \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt index f4356c2d5b..f62610b87d 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt @@ -45,8 +45,6 @@ interface AppNavigation { fun deletedAccountScreen(deadline: Long) - fun openLibrary(space: Id) - fun logout() fun migrationErrorScreen() @@ -97,8 +95,6 @@ interface AppNavigation { data class DeletedAccountScreen(val deadline: Long) : Command() data class OpenTemplates(val typeId: Id) : Command() - - data class OpenLibrary(val space: Id): Command() } interface Provider { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt index 0555949914..910b22338a 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperMapper.kt @@ -1,48 +1,20 @@ package com.anytypeio.anytype.presentation.objects import com.anytypeio.anytype.core_models.Id -import com.anytypeio.anytype.core_models.Marketplace import com.anytypeio.anytype.core_models.MarketplaceObjectTypeIds import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ObjectTypeUniqueKeys import com.anytypeio.anytype.core_models.ObjectWrapper -import com.anytypeio.anytype.core_models.Relations -import com.anytypeio.anytype.core_models.Relations.SOURCE_OBJECT import com.anytypeio.anytype.core_models.ext.DateParser -import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction import com.anytypeio.anytype.core_utils.ext.readableFileSize import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.presentation.extension.getProperObjectName -import com.anytypeio.anytype.presentation.library.LibraryView import com.anytypeio.anytype.presentation.linking.LinkToItemView import com.anytypeio.anytype.presentation.mapper.objectIcon import com.anytypeio.anytype.presentation.navigation.DefaultObjectView import com.anytypeio.anytype.presentation.sets.filter.CreateFilterView import com.anytypeio.anytype.presentation.widgets.collection.CollectionView -@Deprecated("To be deleted") -fun List.toView( - urlBuilder: UrlBuilder, - objectTypes: List -): List = - this.map { obj -> - val typeUrl = obj.getProperType() - val layout = obj.getProperLayout() - DefaultObjectView( - id = obj.id, - name = obj.getProperName(), - type = typeUrl, - typeName = getProperTypeName( - id = typeUrl, - types = objectTypes - ), - description = obj.description, - layout = layout, - icon = obj.objectIcon(urlBuilder), - space = requireNotNull(obj.spaceId) - ) - } - fun List.toViews( urlBuilder: UrlBuilder, objectTypes: List @@ -79,57 +51,6 @@ fun ObjectWrapper.Basic.toView( ) } -fun List.toLibraryViews( - urlBuilder: UrlBuilder -): List = map { obj -> - val space = obj.getValue(Relations.SPACE_ID) - when (obj.layout) { - ObjectType.Layout.OBJECT_TYPE -> { - if (space == Marketplace.MARKETPLACE_SPACE_ID) { - LibraryView.LibraryTypeView( - id = obj.id, - name = obj.name.orEmpty(), - icon = obj.objectIcon(urlBuilder), - uniqueKey = obj.uniqueKey - ) - } else { - LibraryView.MyTypeView( - id = obj.id, - name = obj.name.orEmpty(), - icon = obj.objectIcon(urlBuilder), - sourceObject = obj.map[SOURCE_OBJECT]?.toString(), - uniqueKey = obj.uniqueKey, - readOnly = obj.restrictions.contains(ObjectRestriction.DELETE), - editable = !obj.restrictions.contains(ObjectRestriction.DETAILS) - ) - } - } - ObjectType.Layout.RELATION -> { - val relation = ObjectWrapper.Relation(obj.map) - if (space == Marketplace.MARKETPLACE_SPACE_ID) { - LibraryView.LibraryRelationView( - id = obj.id, - name = obj.name.orEmpty(), - format = relation.format - ) - } else { - LibraryView.MyRelationView( - id = obj.id, - name = obj.name.orEmpty(), - format = relation.format, - sourceObject = obj.map[SOURCE_OBJECT]?.toString(), - readOnly = obj.restrictions.contains(ObjectRestriction.DELETE), - editable = !obj.restrictions.contains(ObjectRestriction.DETAILS) - ) - } - } - else -> LibraryView.UnknownView( - id = obj.id, - name = obj.name.orEmpty() - ) - } -} - fun List.toLinkToView( urlBuilder: UrlBuilder, objectTypes: List diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/WidgetView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/WidgetView.kt index 23a59c66cf..15d9f4558a 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/WidgetView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/WidgetView.kt @@ -136,11 +136,6 @@ sealed class WidgetView { } } - data object Library : WidgetView() { - override val id: Id get() = "id.button.library" - override val isLoading: Boolean = false - } - sealed class Action : WidgetView() { data object EditWidgets : Action() { override val id: Id get() = "id.action.edit-widgets" diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/ObjectWrapperExtensionsKtTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/ObjectWrapperExtensionsKtTest.kt index cb0c39a723..d2d2a45ab2 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/ObjectWrapperExtensionsKtTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/mapper/ObjectWrapperExtensionsKtTest.kt @@ -4,7 +4,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.domain.misc.UrlBuilder -import com.anytypeio.anytype.presentation.objects.toView +import com.anytypeio.anytype.presentation.objects.toViews import com.anytypeio.anytype.test_utils.MockDataFactory import kotlin.test.assertEquals import kotlin.test.assertNull @@ -92,7 +92,7 @@ class ObjectWrapperExtensionsKtTest { ) - val result = listOf(obj).toView(urlBuilder, objectTypes = listOf()) + val result = listOf(obj).toViews(urlBuilder, objectTypes = listOf()) assertEquals( expected = "OMr2Y", @@ -116,7 +116,10 @@ class ObjectWrapperExtensionsKtTest { ) - val result = listOf(obj).toView(urlBuilder, objectTypes = listOf()) + val result = listOf(obj).toViews( + urlBuilder = urlBuilder, + objectTypes = listOf() + ) assertEquals( expected = "LmL7R", @@ -141,7 +144,7 @@ class ObjectWrapperExtensionsKtTest { ) - val result = listOf(obj).toView(urlBuilder, objectTypes = listOf()) + val result = listOf(obj).toViews(urlBuilder, objectTypes = listOf()) assertEquals( expected = "Anytype is next-generation sof",