mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-1622 Set | Enhancement | View, menu (#312)
This commit is contained in:
parent
fd120cd894
commit
b9a90778bd
39 changed files with 741 additions and 2347 deletions
|
@ -59,6 +59,7 @@ import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
|||
import com.anytypeio.anytype.presentation.sets.ObjectSetViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.sets.state.DefaultObjectStateReducer
|
||||
import com.anytypeio.anytype.presentation.sets.subscription.DefaultDataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate
|
||||
import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.test_utils.MockDataFactory
|
||||
|
@ -139,6 +140,9 @@ abstract class TestObjectSetSetup {
|
|||
@Mock
|
||||
lateinit var templatesContainer: ObjectTypeTemplatesContainer
|
||||
|
||||
@Mock
|
||||
lateinit var viewerDelegate: ViewerDelegate
|
||||
|
||||
private lateinit var getTemplates: GetTemplates
|
||||
private lateinit var getDefaultPageType: GetDefaultPageType
|
||||
|
||||
|
@ -259,7 +263,8 @@ abstract class TestObjectSetSetup {
|
|||
updateDataViewViewer = updateDataViewViewer,
|
||||
templatesContainer = templatesContainer,
|
||||
setObjectListIsArchived = setObjectListIsArchived,
|
||||
duplicateObjects = duplicateObjects
|
||||
duplicateObjects = duplicateObjects,
|
||||
viewerDelegate = viewerDelegate
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,11 @@ import com.anytypeio.anytype.di.feature.AddObjectRelationValueModule
|
|||
import com.anytypeio.anytype.di.feature.AuthModule
|
||||
import com.anytypeio.anytype.di.feature.CreateAccountModule
|
||||
import com.anytypeio.anytype.di.feature.CreateBookmarkModule
|
||||
import com.anytypeio.anytype.di.feature.CreateDataViewViewerModule
|
||||
import com.anytypeio.anytype.di.feature.CreateObjectModule
|
||||
import com.anytypeio.anytype.di.feature.DaggerBacklinkOrAddToObjectComponent
|
||||
import com.anytypeio.anytype.di.feature.DaggerSplashComponent
|
||||
import com.anytypeio.anytype.di.feature.DataViewRelationValueModule
|
||||
import com.anytypeio.anytype.di.feature.DebugSettingsModule
|
||||
import com.anytypeio.anytype.di.feature.EditDataViewViewerModule
|
||||
import com.anytypeio.anytype.di.feature.EditorSessionModule
|
||||
import com.anytypeio.anytype.di.feature.EditorUseCaseModule
|
||||
import com.anytypeio.anytype.di.feature.KeychainLoginModule
|
||||
|
@ -23,7 +21,6 @@ import com.anytypeio.anytype.di.feature.KeychainPhraseModule
|
|||
import com.anytypeio.anytype.di.feature.LinkToObjectModule
|
||||
import com.anytypeio.anytype.di.feature.LinkToObjectOrWebModule
|
||||
import com.anytypeio.anytype.di.feature.MainEntryModule
|
||||
import com.anytypeio.anytype.di.feature.ManageViewerModule
|
||||
import com.anytypeio.anytype.di.feature.ModifyViewerSortModule
|
||||
import com.anytypeio.anytype.di.feature.MoveToModule
|
||||
import com.anytypeio.anytype.di.feature.ObjectAppearanceIconModule
|
||||
|
@ -451,22 +448,6 @@ class ComponentManager(
|
|||
.build()
|
||||
}
|
||||
|
||||
val createDataViewViewerComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.createDataViewViewerSubComponent()
|
||||
.module(CreateDataViewViewerModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val editDataViewViewerComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.editDataViewViewerComponent()
|
||||
.module(EditDataViewViewerModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val dataViewRelationValueComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
|
@ -539,14 +520,6 @@ class ComponentManager(
|
|||
.build()
|
||||
}
|
||||
|
||||
val manageViewerComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
.manageViewerComponent()
|
||||
.module(ManageViewerModule)
|
||||
.build()
|
||||
}
|
||||
|
||||
val objectsSetSettingsComponent = DependentComponentMap { ctx ->
|
||||
objectSetComponent
|
||||
.get(ctx)
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.sets.CreateDataViewViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.CreateDataViewViewerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Subcomponent(modules = [CreateDataViewViewerModule::class])
|
||||
@PerModal
|
||||
interface CreateDataViewViewerSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: CreateDataViewViewerModule): Builder
|
||||
fun build(): CreateDataViewViewerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: CreateDataViewViewerFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object CreateDataViewViewerModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideCreateDataViewViewerViewModelFactory(
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
addDataViewViewer: AddDataViewViewer,
|
||||
analytics: Analytics,
|
||||
objectState: MutableStateFlow<ObjectState>
|
||||
): CreateDataViewViewerViewModel.Factory = CreateDataViewViewerViewModel.Factory(
|
||||
dispatcher = dispatcher,
|
||||
addDataViewViewer = addDataViewViewer,
|
||||
analytics = analytics,
|
||||
objectState = objectState
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideAddDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): AddDataViewViewer = AddDataViewViewer(repo = repo)
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.*
|
||||
import com.anytypeio.anytype.presentation.sets.EditDataViewViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetPaginator
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.EditDataViewViewerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Subcomponent(modules = [EditDataViewViewerModule::class])
|
||||
@PerModal
|
||||
interface EditDataViewViewerSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: EditDataViewViewerModule): Builder
|
||||
fun build(): EditDataViewViewerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: EditDataViewViewerFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object EditDataViewViewerModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideEditDataViewViewerViewModelFactory(
|
||||
renameDataViewViewer: RenameDataViewViewer,
|
||||
deleteDataViewViewer: DeleteDataViewViewer,
|
||||
duplicateDataViewViewer: DuplicateDataViewViewer,
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
state: MutableStateFlow<ObjectState>,
|
||||
objectSetSession: ObjectSetSession,
|
||||
paginator: ObjectSetPaginator,
|
||||
analytics: Analytics
|
||||
): EditDataViewViewerViewModel.Factory = EditDataViewViewerViewModel.Factory(
|
||||
renameDataViewViewer = renameDataViewViewer,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
duplicateDataViewViewer = duplicateDataViewViewer,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
objectState = state,
|
||||
objectSetSession = objectSetSession,
|
||||
paginator = paginator,
|
||||
analytics = analytics
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideRenameDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): RenameDataViewViewer = RenameDataViewViewer(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideDuplicateDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): DuplicateDataViewViewer = DuplicateDataViewViewer(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideDeleteDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): DeleteDataViewViewer = DeleteDataViewViewer(repo = repo)
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package com.anytypeio.anytype.di.feature;
|
||||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerModal
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetDataViewViewerPosition
|
||||
import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.ui.sets.modals.ManageViewerFragment
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Subcomponent(modules = [ManageViewerModule::class])
|
||||
@PerModal
|
||||
interface ManageViewerSubComponent {
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
fun module(module: ManageViewerModule): Builder
|
||||
fun build(): ManageViewerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: ManageViewerFragment)
|
||||
}
|
||||
|
||||
@Module
|
||||
object ManageViewerModule {
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideManageViewerViewModelFactory(
|
||||
state: MutableStateFlow<ObjectState>,
|
||||
session: ObjectSetSession,
|
||||
dispatcher: Dispatcher<Payload>,
|
||||
analytics: Analytics,
|
||||
deleteDataViewViewer: DeleteDataViewViewer,
|
||||
setDataViewViewerPosition: SetDataViewViewerPosition
|
||||
): ManageViewerViewModel.Factory = ManageViewerViewModel.Factory(
|
||||
objectState = state,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
analytics = analytics,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
setDataViewViewerPosition = setDataViewViewerPosition
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideDeleteDataViewViewerUseCase(
|
||||
repo: BlockRepository
|
||||
): DeleteDataViewViewer = DeleteDataViewViewer(repo = repo)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerModal
|
||||
fun provideSetDataViewViewerPosition(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): SetDataViewViewerPosition = SetDataViewViewerPosition(
|
||||
repo = repo,
|
||||
dispatchers = dispatchers
|
||||
)
|
||||
}
|
|
@ -23,7 +23,12 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
|||
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import com.anytypeio.anytype.domain.cover.SetDocCoverImage
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DuplicateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RenameDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetDataViewViewerPosition
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.event.interactor.EventChannel
|
||||
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
|
||||
|
@ -81,6 +86,8 @@ import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
|||
import com.anytypeio.anytype.presentation.sets.state.ObjectStateReducer
|
||||
import com.anytypeio.anytype.presentation.sets.subscription.DataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.subscription.DefaultDataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.DefaultViewerDelegate
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate
|
||||
import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer
|
||||
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
|
||||
import com.anytypeio.anytype.presentation.util.DefaultCopyFileToCacheDirectory
|
||||
|
@ -110,13 +117,10 @@ interface ObjectSetSubComponent {
|
|||
fun objectSetRecordComponent(): ObjectSetRecordSubComponent.Builder
|
||||
fun objectSetCreateBookmarkRecordComponent(): ObjectSetCreateBookmarkRecordSubComponent.Builder
|
||||
fun viewerFilterBySubComponent(): ViewerFilterSubComponent.Builder
|
||||
fun createDataViewViewerSubComponent(): CreateDataViewViewerSubComponent.Builder
|
||||
fun editDataViewViewerComponent(): EditDataViewViewerSubComponent.Builder
|
||||
|
||||
fun dataViewObjectRelationValueComponent(): DataViewObjectRelationValueSubComponent.Builder
|
||||
fun setOrCollectionRelationValueComponent() : SetOrCollectionRelationValueSubComponent.Builder
|
||||
|
||||
fun manageViewerComponent(): ManageViewerSubComponent.Builder
|
||||
fun objectSetSettingsComponent(): ObjectSetSettingsSubComponent.Builder
|
||||
fun viewerCardSizeSelectComponent(): ViewerCardSizeSelectSubcomponent.Builder
|
||||
fun viewerImagePreviewSelectComponent(): ViewerImagePreviewSelectSubcomponent.Builder
|
||||
|
@ -214,7 +218,8 @@ object ObjectSetModule {
|
|||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
duplicateObjects: DuplicateObjects,
|
||||
templatesContainer: ObjectTypeTemplatesContainer,
|
||||
setObjectListIsArchived: SetObjectListIsArchived
|
||||
setObjectListIsArchived: SetObjectListIsArchived,
|
||||
viewerDelegate: ViewerDelegate
|
||||
): ObjectSetViewModelFactory = ObjectSetViewModelFactory(
|
||||
openObjectSet = openObjectSet,
|
||||
closeBlock = closeBlock,
|
||||
|
@ -249,7 +254,8 @@ object ObjectSetModule {
|
|||
updateDataViewViewer = updateDataViewViewer,
|
||||
duplicateObjects = duplicateObjects,
|
||||
templatesContainer = templatesContainer,
|
||||
setObjectListIsArchived = setObjectListIsArchived
|
||||
setObjectListIsArchived = setObjectListIsArchived,
|
||||
viewerDelegate = viewerDelegate
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
@ -630,4 +636,67 @@ object ObjectSetModule {
|
|||
defaultProvider: DefaultCoverImageHashProvider
|
||||
): CoverImageHashProvider
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideAddDataViewViewerUseCase(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): AddDataViewViewer = AddDataViewViewer(repo = repo, dispatchers = dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideRenameDataViewViewerUseCase(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): RenameDataViewViewer = RenameDataViewViewer(repo = repo, dispatchers = dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDuplicateDataViewViewerUseCase(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): DuplicateDataViewViewer = DuplicateDataViewViewer(repo = repo, dispatchers = dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideDeleteDataViewViewerUseCase(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): DeleteDataViewViewer = DeleteDataViewViewer(repo = repo, dispatchers = dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideSetDataViewViewerPositionUseCase(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): SetDataViewViewerPosition = SetDataViewViewerPosition(repo = repo, dispatchers = dispatchers)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideViewerDelegate(
|
||||
session: ObjectSetSession,
|
||||
addDataViewViewer: AddDataViewViewer,
|
||||
renameDataViewViewer: RenameDataViewViewer,
|
||||
duplicateDataViewViewer: DuplicateDataViewViewer,
|
||||
deleteDataViewViewer: DeleteDataViewViewer,
|
||||
setDataViewViewerPosition: SetDataViewViewerPosition,
|
||||
analytics: Analytics,
|
||||
dispatcher: Dispatcher<Payload>
|
||||
): ViewerDelegate = DefaultViewerDelegate(
|
||||
session = session,
|
||||
addDataViewViewer = addDataViewViewer,
|
||||
renameDataViewViewer = renameDataViewViewer,
|
||||
duplicateDataViewViewer = duplicateDataViewViewer,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
setDataViewViewerPosition = setDataViewViewerPosition,
|
||||
analytics = analytics,
|
||||
dispatcher = dispatcher
|
||||
)
|
||||
}
|
|
@ -52,6 +52,7 @@ import com.anytypeio.anytype.core_ui.views.ButtonPrimarySmallIcon
|
|||
import com.anytypeio.anytype.core_ui.widgets.FeaturedRelationGroupWidget
|
||||
import com.anytypeio.anytype.core_ui.widgets.ObjectTypeTemplatesWidget
|
||||
import com.anytypeio.anytype.core_ui.widgets.StatusBadgeWidget
|
||||
import com.anytypeio.anytype.core_ui.widgets.dv.ViewersWidget
|
||||
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
import com.anytypeio.anytype.core_ui.widgets.toolbar.DataViewInfo
|
||||
import com.anytypeio.anytype.core_utils.OnSwipeListener
|
||||
|
@ -73,6 +74,7 @@ import com.anytypeio.anytype.databinding.FragmentObjectSetBinding
|
|||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverGradient
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi
|
||||
import com.anytypeio.anytype.presentation.sets.DataViewViewState
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetCommand
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetViewModel
|
||||
|
@ -93,9 +95,6 @@ import com.anytypeio.anytype.ui.relations.RelationTextValueFragment
|
|||
import com.anytypeio.anytype.ui.relations.RelationTextValueFragment.TextValueEditReceiver
|
||||
import com.anytypeio.anytype.ui.relations.RelationValueBaseFragment
|
||||
import com.anytypeio.anytype.ui.relations.RelationValueDVFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.CreateDataViewViewerFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.EditDataViewViewerFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.ManageViewerFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.ObjectSetSettingsFragment
|
||||
import com.anytypeio.anytype.ui.sets.modals.SetObjectCreateRecordFragmentBase
|
||||
import com.anytypeio.anytype.ui.sets.modals.sort.ViewerSortFragment
|
||||
|
@ -340,6 +339,16 @@ open class ObjectSetFragment :
|
|||
}
|
||||
|
||||
observeSelectingTemplate()
|
||||
|
||||
binding.viewersWidget.apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setContent {
|
||||
ViewersWidget(
|
||||
state = vm.viewersWidgetState.collectAsStateWithLifecycle().value,
|
||||
action = vm::onViewersWidgetAction
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupWindowInsetAnimation() {
|
||||
|
@ -877,24 +886,6 @@ open class ObjectSetFragment :
|
|||
)
|
||||
)
|
||||
}
|
||||
is ObjectSetCommand.Modal.CreateViewer -> {
|
||||
val fr = CreateDataViewViewerFragment.new(
|
||||
ctx = command.ctx,
|
||||
target = command.target
|
||||
)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.EditDataViewViewer -> {
|
||||
val fr = EditDataViewViewerFragment.new(
|
||||
ctx = command.ctx,
|
||||
viewer = command.viewer
|
||||
)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.ManageViewer -> {
|
||||
val fr = ManageViewerFragment.new(ctx = command.ctx, dv = command.dataview)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.OpenSettings -> {
|
||||
val fr = ObjectSetSettingsFragment.new(
|
||||
ctx = command.ctx,
|
||||
|
@ -1109,6 +1100,9 @@ open class ObjectSetFragment :
|
|||
vm.templatesWidgetState.value.showWidget -> {
|
||||
vm.onDismissTemplatesWidget()
|
||||
}
|
||||
vm.viewersWidgetState.value.showWidget -> {
|
||||
vm.onViewersWidgetAction(ViewersWidgetUi.Action.Dismiss)
|
||||
}
|
||||
else -> {
|
||||
vm.onSystemBackPressed()
|
||||
}
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
package com.anytypeio.anytype.ui.sets.modals
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.core_utils.ext.*
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.databinding.FragmentCreateDataViewViewerBinding
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.sets.CreateDataViewViewerViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
class CreateDataViewViewerFragment : BaseBottomSheetFragment<FragmentCreateDataViewViewerBinding>() {
|
||||
|
||||
val ctx get() = arg<String>(CTX_KEY)
|
||||
val target get() = arg<String>(TARGET_KEY)
|
||||
|
||||
@Inject
|
||||
lateinit var factory: CreateDataViewViewerViewModel.Factory
|
||||
private val vm: CreateDataViewViewerViewModel by viewModels { factory }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
with(lifecycleScope) {
|
||||
subscribe(binding.btnCreateViewer.clicks()) {
|
||||
vm.onAddViewer(
|
||||
name = binding.viewerNameInput.text.toString(),
|
||||
ctx = ctx,
|
||||
target = target
|
||||
)
|
||||
}
|
||||
subscribe(binding.gridContainer.clicks()) { vm.onGridClicked() }
|
||||
subscribe(binding.galleryContainer.clicks()) { vm.onGalleryClicked() }
|
||||
subscribe(binding.listContainer.clicks()) { vm.onListClicked() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
with(lifecycleScope) {
|
||||
jobs += subscribe(vm.state) { render(it) }
|
||||
}
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
private fun render(state: CreateDataViewViewerViewModel.ViewState) {
|
||||
when (state) {
|
||||
CreateDataViewViewerViewModel.ViewState.Init -> {
|
||||
binding.isListChosen.invisible()
|
||||
binding.isTableChosen.visible()
|
||||
binding.isGalleryChosen.invisible()
|
||||
}
|
||||
CreateDataViewViewerViewModel.ViewState.Completed -> {
|
||||
dismiss()
|
||||
}
|
||||
is CreateDataViewViewerViewModel.ViewState.Error -> {
|
||||
toast(state.msg)
|
||||
}
|
||||
CreateDataViewViewerViewModel.ViewState.Gallery -> {
|
||||
binding.isListChosen.invisible()
|
||||
binding.isTableChosen.invisible()
|
||||
binding.isGalleryChosen.visible()
|
||||
}
|
||||
CreateDataViewViewerViewModel.ViewState.Grid -> {
|
||||
binding.isListChosen.invisible()
|
||||
binding.isTableChosen.visible()
|
||||
binding.isGalleryChosen.invisible()
|
||||
}
|
||||
|
||||
CreateDataViewViewerViewModel.ViewState.List -> {
|
||||
binding.isListChosen.visible()
|
||||
binding.isTableChosen.invisible()
|
||||
binding.isGalleryChosen.invisible()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().createDataViewViewerComponent.get(ctx).inject(this)
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {
|
||||
componentManager().createDataViewViewerComponent.release(ctx)
|
||||
}
|
||||
|
||||
override fun inflateBinding(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
): FragmentCreateDataViewViewerBinding = FragmentCreateDataViewViewerBinding.inflate(
|
||||
inflater, container, false
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun new(ctx: String, target: String) = CreateDataViewViewerFragment().apply {
|
||||
arguments = bundleOf(
|
||||
CTX_KEY to ctx, TARGET_KEY to target
|
||||
)
|
||||
}
|
||||
|
||||
private const val CTX_KEY = "arg.create-data-view-viewer.context"
|
||||
private const val TARGET_KEY = "arg.create-data-view-viewer.target"
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
package com.anytypeio.anytype.ui.sets.modals
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_ui.menu.DataViewEditViewPopupMenu
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.core_ui.reactive.textChanges
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
import com.anytypeio.anytype.core_utils.ext.gone
|
||||
import com.anytypeio.anytype.core_utils.ext.hideKeyboard
|
||||
import com.anytypeio.anytype.core_utils.ext.invisible
|
||||
import com.anytypeio.anytype.core_utils.ext.subscribe
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ext.visible
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.databinding.FragmentEditDataViewViewerBinding
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.sets.EditDataViewViewerViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
class
|
||||
EditDataViewViewerFragment : BaseBottomSheetFragment<FragmentEditDataViewViewerBinding>() {
|
||||
|
||||
private val ctx: Id get() = arg(CTX_KEY)
|
||||
private val viewer: Id get() = arg(VIEWER_KEY)
|
||||
|
||||
@Inject
|
||||
lateinit var factory: EditDataViewViewerViewModel.Factory
|
||||
private val vm: EditDataViewViewerViewModel by viewModels { factory }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
with(lifecycleScope) {
|
||||
subscribe(binding.viewerNameInput.textChanges()) { name ->
|
||||
vm.onViewerNameChanged(name = name.toString())
|
||||
}
|
||||
subscribe(binding.btnDone.clicks()) {
|
||||
vm.onDoneClicked(ctx, viewer)
|
||||
}
|
||||
subscribe(binding.threeDotsButton.clicks()) { vm.onMenuClicked(viewer) }
|
||||
subscribe(binding.gridContainer.clicks()) { vm.onGridClicked() }
|
||||
subscribe(binding.galleryContainer.clicks()) { vm.onGalleryClicked() }
|
||||
subscribe(binding.listContainer.clicks()) { vm.onListClicked() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
with(lifecycleScope) {
|
||||
jobs += subscribe(vm.viewState) { render(it) }
|
||||
jobs += subscribe(vm.isDismissed) { isDismissed ->
|
||||
if (isDismissed) {
|
||||
binding.viewerNameInput.apply {
|
||||
clearFocus()
|
||||
hideKeyboard()
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
jobs += subscribe(vm.isLoading) { isLoading ->
|
||||
if (isLoading) binding.progressBar.visible() else binding.progressBar.gone()
|
||||
}
|
||||
jobs += subscribe(vm.toasts) { toast(it) }
|
||||
jobs += subscribe(vm.popupCommands) { cmd ->
|
||||
DataViewEditViewPopupMenu(
|
||||
requireContext(),
|
||||
binding.threeDotsButton,
|
||||
cmd.isDeletionAllowed
|
||||
).apply {
|
||||
setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.duplicate -> vm.onDuplicateClicked(ctx = ctx, viewer = viewer)
|
||||
R.id.delete -> vm.onDeleteClicked(ctx = ctx, viewer = viewer)
|
||||
}
|
||||
true
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
super.onStart()
|
||||
vm.onStart(viewer)
|
||||
}
|
||||
|
||||
private fun render(state: EditDataViewViewerViewModel.ViewState) {
|
||||
when (state) {
|
||||
EditDataViewViewerViewModel.ViewState.Init -> {
|
||||
with(binding) {
|
||||
viewerNameInput.text = null
|
||||
isListChosen.invisible()
|
||||
isTableChosen.invisible()
|
||||
isGalleryChosen.invisible()
|
||||
}
|
||||
}
|
||||
is EditDataViewViewerViewModel.ViewState.Name -> {
|
||||
binding.viewerNameInput.setText(state.name)
|
||||
}
|
||||
EditDataViewViewerViewModel.ViewState.Completed -> {
|
||||
dismiss()
|
||||
}
|
||||
is EditDataViewViewerViewModel.ViewState.Error -> {
|
||||
toast(state.msg)
|
||||
}
|
||||
EditDataViewViewerViewModel.ViewState.Gallery -> {
|
||||
with(binding) {
|
||||
isListChosen.invisible()
|
||||
isTableChosen.invisible()
|
||||
isGalleryChosen.visible()
|
||||
}
|
||||
}
|
||||
EditDataViewViewerViewModel.ViewState.Grid -> {
|
||||
with(binding) {
|
||||
isListChosen.invisible()
|
||||
isTableChosen.visible()
|
||||
isGalleryChosen.invisible()
|
||||
}
|
||||
}
|
||||
|
||||
EditDataViewViewerViewModel.ViewState.List -> {
|
||||
with(binding) {
|
||||
isListChosen.visible()
|
||||
isTableChosen.invisible()
|
||||
isGalleryChosen.invisible()
|
||||
}
|
||||
}
|
||||
EditDataViewViewerViewModel.ViewState.Kanban -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().editDataViewViewerComponent.get(ctx).inject(this)
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {
|
||||
componentManager().editDataViewViewerComponent.release(ctx)
|
||||
}
|
||||
|
||||
override fun inflateBinding(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
): FragmentEditDataViewViewerBinding = FragmentEditDataViewViewerBinding.inflate(
|
||||
inflater, container, false
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val CTX_KEY = "arg.edit-data-view-viewer.ctx"
|
||||
const val VIEWER_KEY = "arg.edit-data-view-viewer.viewer"
|
||||
|
||||
fun new(
|
||||
ctx: Id,
|
||||
viewer: Id
|
||||
): EditDataViewViewerFragment = EditDataViewViewerFragment().apply {
|
||||
arguments = bundleOf(
|
||||
CTX_KEY to ctx,
|
||||
VIEWER_KEY to viewer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
package com.anytypeio.anytype.ui.sets.modals
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_ui.features.sets.ManageViewerDoneAdapter
|
||||
import com.anytypeio.anytype.core_ui.features.sets.ManageViewerEditAdapter
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.core_ui.tools.DefaultDragAndDropBehavior
|
||||
import com.anytypeio.anytype.core_utils.ext.*
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.core_utils.ui.OnStartDragListener
|
||||
import com.anytypeio.anytype.databinding.FragmentManageViewerBinding
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class ManageViewerFragment : BaseBottomSheetFragment<FragmentManageViewerBinding>(),
|
||||
OnStartDragListener {
|
||||
|
||||
private val manageViewerAdapter by lazy {
|
||||
ManageViewerDoneAdapter(
|
||||
onViewerClicked = { view -> vm.onViewerClicked(ctx = ctx, view = view) }
|
||||
)
|
||||
}
|
||||
|
||||
private val manageViewerEditAdapter by lazy {
|
||||
ManageViewerEditAdapter(
|
||||
onDragListener = this,
|
||||
onButtonMoreClicked = vm::onViewerActionClicked,
|
||||
onDeleteView = {
|
||||
vm.onDeleteView(
|
||||
ctx = ctx,
|
||||
dv = dv,
|
||||
view = it
|
||||
)
|
||||
},
|
||||
onDeleteActiveView = { toast(R.string.toast_active_view_delete) }
|
||||
)
|
||||
}
|
||||
|
||||
private val ctx: Id get() = arg(CTX_KEY)
|
||||
private val dv: Id get() = arg(DATA_VIEW_KEY)
|
||||
|
||||
@Inject
|
||||
lateinit var factory: ManageViewerViewModel.Factory
|
||||
|
||||
private val vm: ManageViewerViewModel by viewModels { factory }
|
||||
|
||||
private val dndItemTouchHelper: ItemTouchHelper by lazy { ItemTouchHelper(dndBehavior) }
|
||||
private val dndBehavior by lazy {
|
||||
DefaultDragAndDropBehavior(
|
||||
onItemMoved = { from, to -> manageViewerEditAdapter.onItemMove(from, to) },
|
||||
onItemDropped = { newPosition ->
|
||||
vm.onOrderChanged(
|
||||
ctx = ctx,
|
||||
dv = dv,
|
||||
newOrder = manageViewerEditAdapter.order,
|
||||
newPosition = newPosition
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.dataViewViewerRecycler.apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
with(lifecycleScope) {
|
||||
subscribe(binding.btnEditViewers.clicks()) { vm.onButtonEditClicked() }
|
||||
subscribe(binding.btnAddNewViewer.clicks()) { vm.onButtonAddClicked() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
lifecycleScope.launch {
|
||||
jobs += subscribe(vm.commands) { observe(it) }
|
||||
jobs += subscribe(vm.toasts) { toast(it) }
|
||||
jobs += subscribe(vm.views) {
|
||||
manageViewerAdapter.update(it)
|
||||
manageViewerEditAdapter.update(it)
|
||||
}
|
||||
jobs += subscribe(vm.isDismissed) { isDismissed ->
|
||||
if (isDismissed) dismiss()
|
||||
}
|
||||
jobs += subscribe(vm.isEditEnabled) { isEditEnabled ->
|
||||
if (isEditEnabled) {
|
||||
with(binding) {
|
||||
btnEditViewers.setText(R.string.done)
|
||||
btnAddNewViewer.invisible()
|
||||
dataViewViewerRecycler.apply {
|
||||
adapter = manageViewerEditAdapter
|
||||
dndItemTouchHelper.attachToRecyclerView(this)
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
with(binding) {
|
||||
btnEditViewers.setText(R.string.edit)
|
||||
btnAddNewViewer.visible()
|
||||
dataViewViewerRecycler.apply {
|
||||
adapter = manageViewerAdapter
|
||||
dndItemTouchHelper.attachToRecyclerView(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
private fun observe(command: ManageViewerViewModel.Command) {
|
||||
when (command) {
|
||||
is ManageViewerViewModel.Command.OpenEditScreen -> {
|
||||
val dialog = EditDataViewViewerFragment.new(
|
||||
ctx = ctx,
|
||||
viewer = command.id
|
||||
)
|
||||
dialog.show(parentFragmentManager, null)
|
||||
}
|
||||
ManageViewerViewModel.Command.OpenCreateScreen -> {
|
||||
val dialog = CreateDataViewViewerFragment.new(
|
||||
ctx = ctx,
|
||||
target = dv
|
||||
)
|
||||
dialog.show(parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().manageViewerComponent.get(ctx).inject(this)
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {
|
||||
componentManager().manageViewerComponent.release(ctx)
|
||||
}
|
||||
|
||||
override fun inflateBinding(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
): FragmentManageViewerBinding = FragmentManageViewerBinding.inflate(
|
||||
inflater, container, false
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun new(ctx: Id, dv: Id): ManageViewerFragment = ManageViewerFragment().apply {
|
||||
arguments = bundleOf(CTX_KEY to ctx, DATA_VIEW_KEY to dv)
|
||||
}
|
||||
|
||||
const val CTX_KEY = "arg.manage-data-view-viewer.ctx"
|
||||
const val DATA_VIEW_KEY = "arg.manage-data-view-viewer.dataview"
|
||||
}
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--typography, buttons 05.04-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/dragger"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="4dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="6dp"/>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Titles.1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="18dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/new_view" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Captions.1.Regular"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginTop="23dp"
|
||||
android:text="@string/name" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/viewerNameInput"
|
||||
style="@style/TextView.ContentStyle.Headline.Heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:background="@null"
|
||||
android:hint="@string/new_view"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
android:imeOptions="actionDone"
|
||||
android:textColorHint="@color/text_secondary"
|
||||
tools:text="View"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextView.UXStyle.Captions.1.Regular"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginTop="27dp"
|
||||
android:text="@string/viewer_as" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/gridContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_grid" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_table" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isTableChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/galleryContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_gallery" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_gallery" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isGalleryChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen"
|
||||
android:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/listContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_list" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_list" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isListChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen"
|
||||
android:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<com.anytypeio.anytype.core_ui.views.ButtonPrimaryLarge
|
||||
android:id="@+id/btnCreateViewer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/create" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,281 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--typography, buttons 05.04-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/dragger"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="4dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="6dp" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp">
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Titles.1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:text="@string/edit_view" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/threeDotsButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_action_more" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextView.UXStyle.Captions.1.Regular"
|
||||
android:layout_marginTop="23dp"
|
||||
android:text="@string/name"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/viewerNameInput"
|
||||
style="@style/TextView.ContentStyle.Headline.Heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:background="@null"
|
||||
android:hint="@string/untitled"
|
||||
android:imeOptions="actionDone"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColorHint="@color/text_secondary" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextView.UXStyle.Captions.1.Regular"
|
||||
android:layout_marginTop="27dp"
|
||||
android:text="@string/viewer_as"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/gridContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_grid" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_table" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isTableChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/galleryContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_gallery" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_gallery" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isGalleryChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen"
|
||||
android:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/listContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_list" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_list" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isListChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen"
|
||||
android:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_create_viewer_kanban" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="44dp"
|
||||
android:text="@string/viewer_kanban" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/isKanbanChosen"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:src="@drawable/ic_viewer_chosen"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Captions.1.Regular"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:text="@string/soon"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textAllCaps="true" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/shape_primary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/btnDoneContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.views.ButtonPrimaryLarge
|
||||
android:id="@+id/btnDone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/done" />
|
||||
|
||||
<ProgressBar
|
||||
android:visibility="gone"
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:indeterminateTint="@color/white"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--typography, buttons 05.04-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="@dimen/modal_rect_margin_top"
|
||||
android:contentDescription="@string/content_description_modal_icon"
|
||||
android:src="@drawable/sheet_top" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnEditViewers"
|
||||
style="@style/TextView.UXStyle.Body"
|
||||
android:textColor="@color/glyph_active"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/edit" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextView.UXStyle.Titles.1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/views" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnAddNewViewer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:contentDescription="@string/content_description_plus_button"
|
||||
android:paddingTop="@dimen/dp_10"
|
||||
android:paddingEnd="17dp"
|
||||
android:paddingStart="@dimen/dp_12"
|
||||
android:paddingBottom="@dimen/dp_10"
|
||||
android:src="@drawable/ic_dv_modal_plus"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dataViewViewerRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
tools:listitem="@layout/item_dv_manage_viewer" />
|
||||
|
||||
</LinearLayout>
|
|
@ -156,4 +156,12 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/viewersWidget"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
|
@ -53,6 +53,8 @@ dependencies {
|
|||
implementation libs.composeToolingPreview
|
||||
debugImplementation libs.composeTooling
|
||||
implementation libs.coilCompose
|
||||
implementation libs.composeConstraintLayout
|
||||
implementation libs.composeReorderable
|
||||
|
||||
testImplementation libs.fragmentTesting
|
||||
testImplementation project(':test:android-utils')
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
package com.anytypeio.anytype.core_ui.features.sets
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.common.AbstractAdapter
|
||||
import com.anytypeio.anytype.core_ui.common.AbstractViewHolder
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemDvManageViewerBinding
|
||||
import com.anytypeio.anytype.core_ui.databinding.ItemDvManageViewerDoneBinding
|
||||
import com.anytypeio.anytype.core_ui.tools.SupportDragAndDropBehavior
|
||||
import com.anytypeio.anytype.core_utils.ext.gone
|
||||
import com.anytypeio.anytype.core_utils.ext.invisible
|
||||
import com.anytypeio.anytype.core_utils.ext.shift
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ext.visible
|
||||
import com.anytypeio.anytype.core_utils.ui.ItemTouchHelperViewHolder
|
||||
import com.anytypeio.anytype.core_utils.ui.OnStartDragListener
|
||||
import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel.ViewerView
|
||||
|
||||
class ManageViewerEditAdapter(
|
||||
private val onDragListener: OnStartDragListener,
|
||||
private val onButtonMoreClicked: (ViewerView) -> Unit,
|
||||
private val onDeleteView: (ViewerView) -> Unit,
|
||||
private val onDeleteActiveView: () -> Unit
|
||||
) : AbstractAdapter<ViewerView>(emptyList()), SupportDragAndDropBehavior {
|
||||
|
||||
val order: List<String> get() = items.map { it.id }
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
iewType: Int
|
||||
): ViewHolder = ViewHolder(
|
||||
binding = ItemDvManageViewerBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
).apply {
|
||||
binding.dndDragger.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) onDragListener.onStartDrag(this)
|
||||
false
|
||||
}
|
||||
binding.icRemove.setOnClickListener {
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
onDeleteView(items[pos])
|
||||
}
|
||||
}
|
||||
binding.btnActionMore.setOnClickListener {
|
||||
val pos = bindingAdapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
onButtonMoreClicked(items[pos])
|
||||
}
|
||||
}
|
||||
binding.icRemoveInactive.setOnClickListener {
|
||||
onDeleteActiveView()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
|
||||
val update = ArrayList(items).shift(fromPosition, toPosition)
|
||||
items = update
|
||||
notifyItemMoved(fromPosition, toPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
val binding: ItemDvManageViewerBinding
|
||||
) : AbstractViewHolder<ViewerView>(binding.root), ItemTouchHelperViewHolder {
|
||||
|
||||
val untitled = binding.root.context.getString(R.string.untitled)
|
||||
|
||||
override fun bind(item: ViewerView) {
|
||||
binding.title.text = item.name.ifEmpty {
|
||||
untitled
|
||||
}
|
||||
if (item.isActive) {
|
||||
binding.icRemove.gone()
|
||||
binding.icRemoveInactive.visible()
|
||||
} else {
|
||||
binding.icRemove.visible()
|
||||
binding.icRemoveInactive.gone()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemSelected() {
|
||||
}
|
||||
|
||||
override fun onItemClear() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ManageViewerDoneAdapter(
|
||||
private val onViewerClicked: (ViewerView) -> Unit
|
||||
) : AbstractAdapter<ViewerView>(emptyList()) {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
iewType: Int
|
||||
): ViewHolder = ViewHolder(
|
||||
binding = ItemDvManageViewerDoneBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
).apply {
|
||||
itemView.setOnClickListener {
|
||||
onViewerClicked(items[bindingAdapterPosition])
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
val binding: ItemDvManageViewerDoneBinding
|
||||
) : AbstractViewHolder<ViewerView>(binding.root) {
|
||||
|
||||
private val title = binding.title
|
||||
private val icChecked = binding.iconChecked
|
||||
val untitled = binding.root.context.getString(R.string.untitled)
|
||||
|
||||
override fun bind(item: ViewerView) {
|
||||
title.text = item.name.ifEmpty {
|
||||
untitled
|
||||
}
|
||||
if (item.isActive) {
|
||||
icChecked.visible()
|
||||
} else {
|
||||
icChecked.invisible()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import com.anytypeio.anytype.core_ui.extensions.throttledClick
|
||||
|
||||
@Composable
|
||||
fun Modifier.noRippleClickable(
|
||||
|
@ -23,4 +24,21 @@ fun Modifier.noRippleClickable(
|
|||
onClickLabel = onClickLabel,
|
||||
role = role,
|
||||
onClick = onClick,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun Modifier.noRippleThrottledClickable(
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
indication: Indication? = null,
|
||||
enabled: Boolean = true,
|
||||
onClickLabel: String? = null,
|
||||
role: Role? = null,
|
||||
onClick: () -> Unit,
|
||||
) = clickable(
|
||||
interactionSource = interactionSource,
|
||||
indication = indication,
|
||||
enabled = enabled,
|
||||
onClickLabel = onClickLabel,
|
||||
role = role,
|
||||
onClick = throttledClick(onClick),
|
||||
)
|
|
@ -750,7 +750,7 @@ private fun TemplateItemRectangles() {
|
|||
}
|
||||
}
|
||||
|
||||
private enum class DragStates {
|
||||
enum class DragStates {
|
||||
VISIBLE,
|
||||
DISMISSED
|
||||
}
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets.dv
|
||||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.ModalBottomSheetLayout
|
||||
import androidx.compose.material.ModalBottomSheetValue
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
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.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import androidx.constraintlayout.compose.Visibility
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.foundation.Divider
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
|
||||
import com.anytypeio.anytype.core_ui.views.Caption2Regular
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineSubheading
|
||||
import com.anytypeio.anytype.core_ui.views.Title1
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.Delete
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.Dismiss
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.DoneMode
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.Edit
|
||||
import com.anytypeio.anytype.presentation.sets.ViewersWidgetUi.Action.EditMode
|
||||
import org.burnoutcrew.reorderable.ReorderableItem
|
||||
import org.burnoutcrew.reorderable.detectReorder
|
||||
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
||||
import org.burnoutcrew.reorderable.reorderable
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun ViewersWidget(
|
||||
state: ViewersWidgetUi,
|
||||
action: (ViewersWidgetUi.Action) -> Unit
|
||||
) {
|
||||
val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
|
||||
|
||||
LaunchedEffect(key1 = state, block = {
|
||||
if (state.showWidget) sheetState.show() else sheetState.hide()
|
||||
})
|
||||
|
||||
DisposableEffect(
|
||||
key1 = (sheetState.targetValue == ModalBottomSheetValue.Hidden
|
||||
&& sheetState.isVisible)
|
||||
) {
|
||||
onDispose {
|
||||
if (sheetState.currentValue == ModalBottomSheetValue.Hidden) {
|
||||
action(Dismiss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModalBottomSheetLayout(
|
||||
sheetState = sheetState,
|
||||
sheetBackgroundColor = Color.Transparent,
|
||||
sheetShape = RoundedCornerShape(16.dp),
|
||||
sheetContent = {
|
||||
ViewersWidgetContent(state, action)
|
||||
},
|
||||
content = {
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.4f))
|
||||
.noRippleThrottledClickable { action.invoke(Dismiss) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ViewersWidgetContent(
|
||||
state: ViewersWidgetUi,
|
||||
action: (ViewersWidgetUi.Action) -> Unit
|
||||
) {
|
||||
val currentState by rememberUpdatedState(state)
|
||||
|
||||
val views = remember { mutableStateOf(currentState.items) }
|
||||
views.value = currentState.items
|
||||
|
||||
val isEditing = remember { mutableStateOf(currentState.isEditing) }
|
||||
isEditing.value = currentState.isEditing
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.shadow(
|
||||
elevation = 40.dp,
|
||||
spotColor = Color(0x40000000),
|
||||
ambientColor = Color(0x40000000)
|
||||
)
|
||||
.padding(start = 8.dp, end = 8.dp, bottom = 31.dp)
|
||||
.background(
|
||||
color = colorResource(id = R.color.background_secondary),
|
||||
shape = RoundedCornerShape(size = 16.dp)
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(bottom = 16.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterStart),
|
||||
) {
|
||||
if (currentState.isEditing) {
|
||||
ActionText(
|
||||
text = stringResource(id = R.string.done),
|
||||
click = { action(DoneMode) }
|
||||
)
|
||||
} else {
|
||||
ActionText(
|
||||
text = stringResource(id = R.string.edit),
|
||||
click = { action(EditMode) }
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.align(Alignment.Center)) {
|
||||
Text(
|
||||
text = stringResource(R.string.views),
|
||||
style = Title1,
|
||||
color = colorResource(R.color.text_primary)
|
||||
)
|
||||
}
|
||||
Box(modifier = Modifier.align(Alignment.CenterEnd)) {
|
||||
Image(
|
||||
modifier = Modifier.padding(
|
||||
start = 16.dp,
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
end = 16.dp
|
||||
),
|
||||
painter = painterResource(id = R.drawable.ic_default_plus),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val lazyListState = rememberReorderableLazyListState(
|
||||
onMove = { from, to ->
|
||||
views.value = views.value.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
},
|
||||
onDragEnd = { from, to ->
|
||||
action(
|
||||
ViewersWidgetUi.Action.OnMove(
|
||||
currentViews = views.value,
|
||||
from = from,
|
||||
to = to
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
state = lazyListState.listState,
|
||||
modifier = Modifier
|
||||
.reorderable(lazyListState)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = views.value,
|
||||
key = { _, item -> item.id }) { index, view ->
|
||||
ReorderableItem(
|
||||
reorderableState = lazyListState,
|
||||
key = view.id
|
||||
) { isDragging ->
|
||||
val currentItem = LocalView.current
|
||||
if (isDragging) {
|
||||
currentItem.isHapticFeedbackEnabled = true
|
||||
currentItem.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
}
|
||||
val alpha =
|
||||
animateFloatAsState(if (isDragging) 0.8f else 1.0f, label = "")
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.height(52.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
.alpha(alpha.value)
|
||||
) {
|
||||
val (delete, text, edit, dnd, unsupported) = createRefs()
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(Delete(view.id))
|
||||
}
|
||||
.constrainAs(delete) {
|
||||
start.linkTo(parent.start)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing.value && !view.isActive) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_relation_delete),
|
||||
contentDescription = "Delete view"
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.detectReorder(lazyListState)
|
||||
.constrainAs(dnd) {
|
||||
end.linkTo(parent.end)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing.value) Visibility.Visible else Visibility.Gone
|
||||
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_dnd),
|
||||
contentDescription = "Dnd view"
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
action.invoke(Edit(view.id))
|
||||
}
|
||||
.constrainAs(edit) {
|
||||
end.linkTo(dnd.start, margin = 16.dp)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
visibility =
|
||||
if (isEditing.value) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_edit_24),
|
||||
contentDescription = "Edit view"
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.constrainAs(unsupported) {
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
end.linkTo(edit.start)
|
||||
visibility =
|
||||
if (!isEditing.value && view.isUnsupported) Visibility.Visible else Visibility.Gone
|
||||
},
|
||||
text = stringResource(id = R.string.unsupported),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Caption2Regular,
|
||||
textAlign = TextAlign.Left
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.noRippleThrottledClickable {
|
||||
if (!isEditing.value) {
|
||||
action.invoke(
|
||||
ViewersWidgetUi.Action.SetActive(
|
||||
view.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.constrainAs(text) {
|
||||
start.linkTo(
|
||||
delete.end,
|
||||
margin = 12.dp,
|
||||
goneMargin = 0.dp
|
||||
)
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(parent.bottom)
|
||||
end.linkTo(
|
||||
unsupported.start,
|
||||
margin = 8.dp,
|
||||
goneMargin = 38.dp
|
||||
)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
text = view.name,
|
||||
color = colorResource(id = if (view.isActive) R.color.text_primary else R.color.glyph_active),
|
||||
style = HeadlineSubheading,
|
||||
textAlign = TextAlign.Left,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
if (index != views.value.size - 1) {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionText(text: String, click: () -> Unit) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
top = 12.dp,
|
||||
bottom = 12.dp,
|
||||
end = 16.dp
|
||||
)
|
||||
.noRippleThrottledClickable { click() },
|
||||
text = text,
|
||||
style = BodyCalloutRegular,
|
||||
color = colorResource(id = R.color.glyph_active),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
9
core-ui/src/main/res/drawable/ic_edit_24.xml
Normal file
9
core-ui/src/main/res/drawable/ic_edit_24.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19.5,8L21.293,6.207C21.683,5.817 21.683,5.183 21.293,4.793L20.207,3.707C19.817,3.317 19.183,3.317 18.793,3.707L17,5.5L19.5,8ZM6.931,19.759L18,9.4L15.5,7L4.5,17L3,21L6.931,19.759Z"
|
||||
android:fillColor="@color/glyph_active"/>
|
||||
</vector>
|
10
core-ui/src/main/res/drawable/ic_view_drag_24.xml
Normal file
10
core-ui/src/main/res/drawable/ic_view_drag_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M1.5,6.5C1.224,6.5 1,6.724 1,7C1,7.276 1.224,7.5 1.5,7.5H22.5C22.776,7.5 23,7.276 23,7C23,6.724 22.776,6.5 22.5,6.5H1.5ZM1,12C1,11.724 1.224,11.5 1.5,11.5H22.5C22.776,11.5 23,11.724 23,12C23,12.276 22.776,12.5 22.5,12.5H1.5C1.224,12.5 1,12.276 1,12ZM1,17C1,16.724 1.224,16.5 1.5,16.5H22.5C22.776,16.5 23,16.724 23,17C23,17.276 22.776,17.5 22.5,17.5H1.5C1.224,17.5 1,17.276 1,17Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -244,6 +244,7 @@
|
|||
<string name="relation">Relation</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="view">View</string>
|
||||
<string name="views">Views</string>
|
||||
|
||||
<string name="choose_emoji">Choose emoji</string>
|
||||
<string name="logo_transition">logo_transition</string>
|
||||
|
@ -651,5 +652,6 @@
|
|||
<string name="templates_menu_edit">Edit template</string>
|
||||
<string name="templates_menu_duplicate">Duplicate</string>
|
||||
<string name="templates_menu_delete">Delete</string>
|
||||
<string name="unsupported">Unsupported</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
package com.anytypeio.anytype.domain.dataview.interactor
|
||||
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
|
||||
/**
|
||||
* Use-case for adding a new viewer to DV.
|
||||
*/
|
||||
class AddDataViewViewer(
|
||||
private val repo: BlockRepository
|
||||
) : BaseUseCase<Payload, AddDataViewViewer.Params>() {
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<AddDataViewViewer.Params, Payload>(dispatchers.io) {
|
||||
|
||||
override suspend fun run(params: Params) = safe {
|
||||
repo.addDataViewViewer(
|
||||
override suspend fun doWork(params: Params): Payload {
|
||||
return repo.addDataViewViewer(
|
||||
ctx = params.ctx,
|
||||
target = params.target,
|
||||
name = params.name,
|
||||
|
|
|
@ -2,7 +2,8 @@ package com.anytypeio.anytype.domain.dataview.interactor
|
|||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer.Params
|
||||
|
||||
|
@ -12,11 +13,12 @@ import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer.Par
|
|||
* @see [Params] for details.
|
||||
*/
|
||||
class DeleteDataViewViewer(
|
||||
private val repo: BlockRepository
|
||||
) : BaseUseCase<Payload, Params>() {
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<Params, Payload>(dispatchers.io) {
|
||||
|
||||
override suspend fun run(params: Params) = safe {
|
||||
repo.removeDataViewViewer(
|
||||
override suspend fun doWork(params: Params): Payload {
|
||||
return repo.removeDataViewViewer(
|
||||
ctx = params.ctx,
|
||||
dataview = params.dataview,
|
||||
viewer = params.viewer
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
package com.anytypeio.anytype.domain.dataview.interactor
|
||||
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.core_models.DVViewer
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DuplicateDataViewViewer.Params
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
|
||||
/**
|
||||
* Use-case for duplicating data view's view.
|
||||
* @see [Params] for details.
|
||||
*/
|
||||
class DuplicateDataViewViewer(
|
||||
private val repo: BlockRepository
|
||||
) : BaseUseCase<Payload, Params>() {
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<Params, Payload>(dispatchers.io) {
|
||||
|
||||
override suspend fun run(params: Params) = safe {
|
||||
repo.duplicateDataViewViewer(
|
||||
override suspend fun doWork(params: Params): Payload {
|
||||
return repo.duplicateDataViewViewer(
|
||||
context = params.context,
|
||||
target = params.target,
|
||||
viewer = params.viewer
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
package com.anytypeio.anytype.domain.dataview.interactor
|
||||
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.core_models.DVViewer
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RenameDataViewViewer.Params
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
|
||||
/**
|
||||
* Use-case for renaming data view's view.
|
||||
* @see [Params] for details.
|
||||
*/
|
||||
class RenameDataViewViewer(
|
||||
private val repo: BlockRepository
|
||||
) : BaseUseCase<Payload, Params>() {
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<Params, Payload>(dispatchers.io) {
|
||||
|
||||
override suspend fun run(params: Params) = safe {
|
||||
repo.updateDataViewViewer(
|
||||
override suspend fun doWork(params: Params): Payload {
|
||||
return repo.updateDataViewViewer(
|
||||
context = params.context,
|
||||
target = params.target,
|
||||
viewer = params.viewer
|
||||
|
|
|
@ -8,6 +8,7 @@ androidxComposeVersion = '1.4.3'
|
|||
composeKotlinCompilerVersion = '1.3.1'
|
||||
composeMaterial3Version = '1.1.1'
|
||||
composeMaterialVersion = '1.3.1'
|
||||
composeConstraintLayoutVersion = '1.0.1'
|
||||
|
||||
activityComposeVersion = '1.7.2'
|
||||
composeReorderableVersion = '0.9.6'
|
||||
|
@ -80,6 +81,7 @@ composeAccompanistPagerIndicators = { module = "com.google.accompanist:accompani
|
|||
composeAccompanistThemeAdapter = { module = "com.google.accompanist:accompanist-themeadapter-material", version.ref = "accompanistVersion" }
|
||||
composeAccompanistNavAnimation = { module = "com.google.accompanist:accompanist-navigation-animation", version.ref = "accompanistVersion" }
|
||||
composeReorderable = { module = "org.burnoutcrew.composereorderable:reorderable", version.ref = "composeReorderableVersion" }
|
||||
composeConstraintLayout = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "composeConstraintLayoutVersion" }
|
||||
kotlinxSerializationJson = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.4.1" }
|
||||
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompatVersion" }
|
||||
androidAnnotations = { module = "androidx.annotation:annotation", version.ref = "appcompatVersion" }
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewViewer
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.extension.ObjectStateAnalyticsEvent
|
||||
import com.anytypeio.anytype.presentation.extension.logEvent
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class CreateDataViewViewerViewModel(
|
||||
private val addDataViewViewer: AddDataViewViewer,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val analytics: Analytics,
|
||||
private val objectState: MutableStateFlow<ObjectState>
|
||||
) : BaseViewModel() {
|
||||
|
||||
val state = MutableStateFlow<ViewState>(ViewState.Init)
|
||||
private var dvType = DVViewerType.GRID
|
||||
|
||||
fun onAddViewer(
|
||||
name: String,
|
||||
ctx: String,
|
||||
target: String,
|
||||
) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
viewModelScope.launch {
|
||||
addDataViewViewer(
|
||||
AddDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
target = target,
|
||||
name = name,
|
||||
type = dvType
|
||||
)
|
||||
).process(
|
||||
failure = { error ->
|
||||
Timber.e(error, ERROR_ADD_NEW_VIEW).also {
|
||||
state.value = ViewState.Error(ERROR_ADD_NEW_VIEW)
|
||||
}
|
||||
},
|
||||
success = {
|
||||
dispatcher.send(it).also {
|
||||
logEvent(
|
||||
state = objectState.value,
|
||||
analytics = analytics,
|
||||
event = ObjectStateAnalyticsEvent.ADD_VIEW,
|
||||
startTime = startTime,
|
||||
type = dvType.formattedName
|
||||
)
|
||||
state.value = ViewState.Completed
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onGridClicked() {
|
||||
dvType = DVViewerType.GRID
|
||||
state.value = ViewState.Grid
|
||||
}
|
||||
|
||||
fun onListClicked() {
|
||||
dvType = DVViewerType.LIST
|
||||
state.value = ViewState.List
|
||||
}
|
||||
|
||||
fun onGalleryClicked() {
|
||||
dvType = DVViewerType.GALLERY
|
||||
state.value = ViewState.Gallery
|
||||
}
|
||||
|
||||
|
||||
class Factory(
|
||||
private val addDataViewViewer: AddDataViewViewer,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val analytics: Analytics,
|
||||
private val objectState: MutableStateFlow<ObjectState>
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return CreateDataViewViewerViewModel(
|
||||
addDataViewViewer = addDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
analytics = analytics,
|
||||
objectState = objectState
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ERROR_ADD_NEW_VIEW = "Error while creating a new data view view"
|
||||
}
|
||||
|
||||
sealed class ViewState {
|
||||
object Init : ViewState()
|
||||
object Completed : ViewState()
|
||||
object Grid : ViewState()
|
||||
object Gallery : ViewState()
|
||||
object List : ViewState()
|
||||
data class Error(val msg: String) : ViewState()
|
||||
}
|
||||
}
|
|
@ -1,286 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.*
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.extension.ObjectStateAnalyticsEvent
|
||||
import com.anytypeio.anytype.presentation.extension.logEvent
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class EditDataViewViewerViewModel(
|
||||
private val renameDataViewViewer: RenameDataViewViewer,
|
||||
private val deleteDataViewViewer: DeleteDataViewViewer,
|
||||
private val duplicateDataViewViewer: DuplicateDataViewViewer,
|
||||
private val updateDataViewViewer: UpdateDataViewViewer,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val objectState: StateFlow<ObjectState>,
|
||||
private val objectSetSession: ObjectSetSession,
|
||||
private val paginator: ObjectSetPaginator,
|
||||
private val analytics: Analytics
|
||||
) : BaseViewModel() {
|
||||
|
||||
val viewState = MutableStateFlow<ViewState>(ViewState.Init)
|
||||
val isDismissed = MutableSharedFlow<Boolean>(replay = 0)
|
||||
val isLoading = MutableStateFlow(false)
|
||||
val popupCommands = MutableSharedFlow<PopupMenuCommand>(replay = 0)
|
||||
|
||||
var initialName: String = ""
|
||||
var initialType: DVViewerType = DVViewerType.GRID
|
||||
|
||||
private var viewerType: DVViewerType = DVViewerType.GRID
|
||||
private var viewerName: String = ""
|
||||
|
||||
fun onStart(viewerId: Id) {
|
||||
val state = objectState.value.dataViewState() ?: return
|
||||
val viewer = state.viewers.firstOrNull { it.id == viewerId }
|
||||
if (viewer != null) {
|
||||
initialName = viewer.name
|
||||
initialType = viewer.type
|
||||
viewState.value = ViewState.Name(viewer.name)
|
||||
updateViewState(viewer.type)
|
||||
} else {
|
||||
Timber.e("Can't find viewer by id : $viewerId")
|
||||
}
|
||||
}
|
||||
|
||||
fun onViewerNameChanged(name: String) {
|
||||
viewerName = name
|
||||
}
|
||||
|
||||
fun onDuplicateClicked(ctx: Id, viewer: Id) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val state = objectState.value.dataViewState() ?: return
|
||||
viewModelScope.launch {
|
||||
duplicateDataViewViewer(
|
||||
DuplicateDataViewViewer.Params(
|
||||
context = ctx,
|
||||
target = state.dataViewBlock.id,
|
||||
viewer = state.viewers.first { it.id == viewer }
|
||||
)
|
||||
).process(
|
||||
failure = { e ->
|
||||
Timber.e(e, "Error while duplicating viewer: $viewer")
|
||||
_toasts.emit("Error while deleting viewer: ${e.localizedMessage}")
|
||||
},
|
||||
success = {
|
||||
dispatcher.send(it).also {
|
||||
logEvent(
|
||||
state = objectState.value,
|
||||
analytics = analytics,
|
||||
event = ObjectStateAnalyticsEvent.DUPLICATE_VIEW,
|
||||
startTime = startTime,
|
||||
type = viewerType.formattedName
|
||||
)
|
||||
isDismissed.emit(true)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteClicked(ctx: Id, viewer: Id) {
|
||||
val state = objectState.value.dataViewState() ?: return
|
||||
if (state.viewers.size > 1) {
|
||||
val targetIdx = state.viewers.indexOfFirst { it.id == viewer }
|
||||
val isActive = if (objectSetSession.currentViewerId.value != null) {
|
||||
objectSetSession.currentViewerId.value == viewer
|
||||
} else {
|
||||
targetIdx == 0
|
||||
}
|
||||
var nextViewerId: Id? = null
|
||||
if (isActive) {
|
||||
nextViewerId = if (targetIdx != state.viewers.lastIndex)
|
||||
state.viewers[targetIdx.inc()].id
|
||||
else
|
||||
state.viewers[targetIdx.dec()].id
|
||||
}
|
||||
proceedWithDeletion(
|
||||
ctx = ctx,
|
||||
dv = state.dataViewBlock.id,
|
||||
viewer = viewer,
|
||||
nextViewerId = nextViewerId
|
||||
)
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
_toasts.emit("Data view should have at least one view")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithDeletion(
|
||||
ctx: Id,
|
||||
dv: Id,
|
||||
viewer: Id,
|
||||
nextViewerId: Id?
|
||||
) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
viewModelScope.launch {
|
||||
deleteDataViewViewer(
|
||||
DeleteDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
viewer = viewer,
|
||||
dataview = dv
|
||||
)
|
||||
).process(
|
||||
failure = { e ->
|
||||
Timber.e(e, "Error while deleting viewer: $viewer")
|
||||
_toasts.emit("Error while deleting viewer: ${e.localizedMessage}")
|
||||
},
|
||||
success = { firstPayload ->
|
||||
dispatcher.send(firstPayload)
|
||||
logEvent(
|
||||
state = objectState.value,
|
||||
analytics = analytics,
|
||||
event = ObjectStateAnalyticsEvent.REMOVE_VIEW,
|
||||
startTime = startTime
|
||||
)
|
||||
if (nextViewerId != null) {
|
||||
objectSetSession.currentViewerId.value = nextViewerId
|
||||
paginator.offset.value = 0
|
||||
}
|
||||
isDismissed.emit(true)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onMenuClicked(viewer: Id) {
|
||||
val isDeletionAllowed = isDeletionAllowed(viewer)
|
||||
viewModelScope.launch {
|
||||
popupCommands.emit(PopupMenuCommand(isDeletionAllowed = isDeletionAllowed))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDeletionAllowed(viewerId: Id): Boolean {
|
||||
val activeViewerId = objectSetSession.currentViewerId.value
|
||||
?: (objectState.value.dataViewState()?.viewers?.firstOrNull()?.id ?: false)
|
||||
return viewerId != activeViewerId
|
||||
}
|
||||
|
||||
fun onDoneClicked(ctx: Id, viewerId: Id) {
|
||||
Timber.d("onDoneClicked, ctx:[$ctx], viewerId:[$viewerId], viewerType:[${viewerType.formattedName}], viewerName:[$viewerName]")
|
||||
if (initialName != viewerName || initialType != viewerType) {
|
||||
updateDVViewerType(ctx, viewerId, viewerType, viewerName)
|
||||
} else {
|
||||
viewModelScope.launch { isDismissed.emit(true) }
|
||||
}
|
||||
}
|
||||
|
||||
fun onGridClicked() {
|
||||
updateViewState(DVViewerType.GRID)
|
||||
}
|
||||
|
||||
fun onListClicked() {
|
||||
updateViewState(DVViewerType.LIST)
|
||||
}
|
||||
|
||||
fun onGalleryClicked() {
|
||||
updateViewState(DVViewerType.GALLERY)
|
||||
}
|
||||
|
||||
private fun updateDVViewerType(ctx: Id, viewerId: Id, type: DVViewerType, name: String) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val state = objectState.value.dataViewState() ?: return
|
||||
val viewer = state.viewers.find { it.id == viewerId }
|
||||
if (viewer != null) {
|
||||
viewModelScope.launch {
|
||||
isLoading.value = true
|
||||
updateDataViewViewer(
|
||||
UpdateDataViewViewer.Params.Fields(
|
||||
context = ctx,
|
||||
target = state.dataViewBlock.id,
|
||||
viewer = viewer.copy(type = type, name = name)
|
||||
)
|
||||
).process(
|
||||
success = { payload ->
|
||||
dispatcher.send(payload).also {
|
||||
logEvent(
|
||||
state = objectState.value,
|
||||
analytics = analytics,
|
||||
event = ObjectStateAnalyticsEvent.CHANGE_VIEW_TYPE,
|
||||
startTime = startTime,
|
||||
type = type.formattedName
|
||||
)
|
||||
isLoading.value = false
|
||||
isDismissed.emit(true)
|
||||
}
|
||||
},
|
||||
failure = {
|
||||
isLoading.value = false
|
||||
Timber.e(it, "Error while updating Viewer type")
|
||||
isDismissed.emit(true)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
sendToast("View not found. Please, try again later.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateViewState(type: DVViewerType) {
|
||||
viewerType = type
|
||||
viewState.value = when (type) {
|
||||
Block.Content.DataView.Viewer.Type.GRID -> ViewState.Grid
|
||||
Block.Content.DataView.Viewer.Type.LIST -> ViewState.List
|
||||
Block.Content.DataView.Viewer.Type.GALLERY -> ViewState.Gallery
|
||||
Block.Content.DataView.Viewer.Type.BOARD -> ViewState.Kanban
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val renameDataViewViewer: RenameDataViewViewer,
|
||||
private val deleteDataViewViewer: DeleteDataViewViewer,
|
||||
private val duplicateDataViewViewer: DuplicateDataViewViewer,
|
||||
private val updateDataViewViewer: UpdateDataViewViewer,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val objectState: StateFlow<ObjectState>,
|
||||
private val objectSetSession: ObjectSetSession,
|
||||
private val paginator: ObjectSetPaginator,
|
||||
private val analytics: Analytics
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return EditDataViewViewerViewModel(
|
||||
renameDataViewViewer = renameDataViewViewer,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
duplicateDataViewViewer = duplicateDataViewViewer,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
dispatcher = dispatcher,
|
||||
objectState = objectState,
|
||||
objectSetSession = objectSetSession,
|
||||
paginator = paginator,
|
||||
analytics = analytics
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
||||
private data class ViewerNameUpdate(
|
||||
val ctx: Id,
|
||||
val dataview: Id,
|
||||
val viewer: DVViewer,
|
||||
val name: String
|
||||
)
|
||||
|
||||
data class PopupMenuCommand(val isDeletionAllowed: Boolean = false)
|
||||
|
||||
sealed class ViewState {
|
||||
object Init : ViewState()
|
||||
data class Name(val name: String) : ViewState()
|
||||
object Completed : ViewState()
|
||||
object Grid : ViewState()
|
||||
object Gallery : ViewState()
|
||||
object List : ViewState()
|
||||
object Kanban : ViewState()
|
||||
data class Error(val msg: String) : ViewState()
|
||||
}
|
||||
}
|
|
@ -1,192 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetDataViewViewerPosition
|
||||
import com.anytypeio.anytype.presentation.common.BaseListViewModel
|
||||
import com.anytypeio.anytype.presentation.extension.ObjectStateAnalyticsEvent
|
||||
import com.anytypeio.anytype.presentation.extension.logEvent
|
||||
import com.anytypeio.anytype.presentation.sets.ManageViewerViewModel.ViewerView
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class ManageViewerViewModel(
|
||||
private val objectState: StateFlow<ObjectState>,
|
||||
private val session: ObjectSetSession,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val analytics: Analytics,
|
||||
private val deleteDataViewViewer: DeleteDataViewViewer,
|
||||
private val setDataViewViewerPosition: SetDataViewViewerPosition
|
||||
) : BaseListViewModel<ViewerView>() {
|
||||
|
||||
val isEditEnabled = MutableStateFlow(false)
|
||||
val isDismissed = MutableSharedFlow<Boolean>(replay = 0)
|
||||
val commands = MutableSharedFlow<Command>(replay = 0)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
objectState.filterIsInstance<ObjectState.DataView>().collect { s ->
|
||||
_views.value = s.viewers.mapIndexed { index, viewer ->
|
||||
ViewerView(
|
||||
id = viewer.id,
|
||||
name = viewer.name,
|
||||
type = viewer.type,
|
||||
isActive = if (session.currentViewerId.value != null)
|
||||
viewer.id == session.currentViewerId.value
|
||||
else
|
||||
index == 0,
|
||||
showActionMenu = isEditEnabled.value
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onOrderChanged(
|
||||
ctx: Id,
|
||||
dv: Id,
|
||||
newPosition: Int,
|
||||
newOrder: List<Id>,
|
||||
) {
|
||||
val currentOrder = views.value.map { it.id }
|
||||
if (newOrder == currentOrder) return
|
||||
val viewer = newOrder.getOrNull(newPosition)
|
||||
if (viewer != null) {
|
||||
viewModelScope.launch {
|
||||
// Workaround for preserving the previously first view as the active view
|
||||
val startTime = System.currentTimeMillis()
|
||||
if (newPosition == 0 && session.currentViewerId.value.isNullOrEmpty()) {
|
||||
session.currentViewerId.value = views.value.firstOrNull()?.id
|
||||
}
|
||||
setDataViewViewerPosition.stream(
|
||||
params = SetDataViewViewerPosition.Params(
|
||||
ctx = ctx,
|
||||
dv = dv,
|
||||
viewer = viewer,
|
||||
pos = newPosition
|
||||
)
|
||||
).collect { result ->
|
||||
logEvent(
|
||||
state = objectState.value,
|
||||
analytics = analytics,
|
||||
event = ObjectStateAnalyticsEvent.REPOSITION_VIEW,
|
||||
startTime = startTime,
|
||||
type = views.value.find { it.id == viewer }?.type?.formattedName
|
||||
)
|
||||
result.fold(
|
||||
onSuccess = { dispatcher.send(it) },
|
||||
onFailure = { Timber.e(it, "Error while changing view order") }
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendToast("Something went wrong. Please, try again later.")
|
||||
}
|
||||
}
|
||||
|
||||
fun onViewerActionClicked(view: ViewerView) {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.OpenEditScreen(view.id, view.name))
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteView(
|
||||
ctx: Id,
|
||||
dv: Id,
|
||||
view: ViewerView
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
deleteDataViewViewer(
|
||||
DeleteDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
dataview = dv,
|
||||
viewer = view.id
|
||||
)
|
||||
).process(
|
||||
failure = { Timber.e(it, "Error while deleting view") },
|
||||
success = { dispatcher.send(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onButtonEditClicked() {
|
||||
isEditEnabled.value = !isEditEnabled.value
|
||||
_views.value = views.value.map { view ->
|
||||
view.copy(showActionMenu = isEditEnabled.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun onButtonAddClicked() {
|
||||
viewModelScope.launch {
|
||||
commands.emit(Command.OpenCreateScreen)
|
||||
}
|
||||
}
|
||||
|
||||
fun onViewerClicked(
|
||||
ctx: Id,
|
||||
view: ViewerView
|
||||
) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
if (!isEditEnabled.value)
|
||||
viewModelScope.launch {
|
||||
session.currentViewerId.value = view.id
|
||||
logEvent(
|
||||
state = objectState.value,
|
||||
analytics = analytics,
|
||||
event = ObjectStateAnalyticsEvent.SWITCH_VIEW,
|
||||
startTime = startTime,
|
||||
type = view.type.formattedName
|
||||
)
|
||||
isDismissed.emit(true)
|
||||
}
|
||||
else
|
||||
Timber.d("Skipping click in edit mode")
|
||||
}
|
||||
|
||||
sealed class Command {
|
||||
data class OpenEditScreen(val id: Id, val name: String) : Command()
|
||||
object OpenCreateScreen : Command()
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val objectState: StateFlow<ObjectState>,
|
||||
private val session: ObjectSetSession,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val analytics: Analytics,
|
||||
private val deleteDataViewViewer: DeleteDataViewViewer,
|
||||
private val setDataViewViewerPosition: SetDataViewViewerPosition
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ManageViewerViewModel(
|
||||
objectState = objectState,
|
||||
session = session,
|
||||
dispatcher = dispatcher,
|
||||
analytics = analytics,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
setDataViewViewerPosition = setDataViewViewerPosition
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
||||
data class ViewerView(
|
||||
val id: Id,
|
||||
val name: String,
|
||||
val type: DVViewerType,
|
||||
val isActive: Boolean,
|
||||
val showActionMenu: Boolean = false,
|
||||
)
|
||||
}
|
|
@ -13,18 +13,6 @@ sealed class ObjectSetCommand {
|
|||
val isFavorite: Boolean
|
||||
) : Modal()
|
||||
|
||||
data class CreateViewer(
|
||||
val ctx: String,
|
||||
val target: Id
|
||||
) : Modal()
|
||||
|
||||
data class EditDataViewViewer(
|
||||
val ctx: Id,
|
||||
val viewer: Id
|
||||
) : Modal()
|
||||
|
||||
data class ManageViewer(val ctx: Id, val dataview: Id) : Modal()
|
||||
|
||||
data class OpenSettings(
|
||||
val ctx: Id,
|
||||
val dv: Id,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import android.util.Log
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.CoverType
|
||||
import com.anytypeio.anytype.core_models.DVFilter
|
||||
|
@ -8,6 +7,7 @@ import com.anytypeio.anytype.core_models.DVRecord
|
|||
import com.anytypeio.anytype.core_models.DVSort
|
||||
import com.anytypeio.anytype.core_models.DVViewer
|
||||
import com.anytypeio.anytype.core_models.DVViewerRelation
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVFilterUpdate
|
||||
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVSortUpdate
|
||||
import com.anytypeio.anytype.core_models.Event.Command.DataView.UpdateView.DVViewerFields
|
||||
|
@ -44,6 +44,7 @@ import com.anytypeio.anytype.presentation.sets.model.ObjectView
|
|||
import com.anytypeio.anytype.presentation.sets.model.SimpleRelationView
|
||||
import com.anytypeio.anytype.presentation.sets.model.Viewer
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerView
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
|
||||
fun ObjectState.DataView.featuredRelations(
|
||||
|
@ -479,4 +480,19 @@ fun ObjectWrapper.Type.toTemplateViewBlank(): TemplateView.Blank {
|
|||
typeId = id,
|
||||
layout = recommendedLayout?.code ?: ObjectType.Layout.BASIC.code
|
||||
)
|
||||
}
|
||||
|
||||
fun List<DVViewer>.toView(session: ObjectSetSession): List<ViewerView> {
|
||||
return mapIndexed { index, viewer ->
|
||||
ViewerView(
|
||||
id = viewer.id,
|
||||
name = viewer.name,
|
||||
type = viewer.type,
|
||||
isActive = if (session.currentViewerId.value != null)
|
||||
viewer.id == session.currentViewerId.value
|
||||
else
|
||||
index == 0,
|
||||
isUnsupported = viewer.type == DVViewerType.BOARD
|
||||
)
|
||||
}
|
||||
}
|
|
@ -68,6 +68,9 @@ import com.anytypeio.anytype.presentation.sets.model.Viewer
|
|||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectStateReducer
|
||||
import com.anytypeio.anytype.presentation.sets.subscription.DataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerEvent
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerView
|
||||
import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateMenuClick
|
||||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
|
@ -131,8 +134,9 @@ class ObjectSetViewModel(
|
|||
private val updateDataViewViewer: UpdateDataViewViewer,
|
||||
private val duplicateObjects: DuplicateObjects,
|
||||
private val templatesContainer: ObjectTypeTemplatesContainer,
|
||||
private val setObjectListIsArchived: SetObjectListIsArchived
|
||||
) : ViewModel(), SupportNavigation<EventWrapper<AppNavigation.Command>> {
|
||||
private val setObjectListIsArchived: SetObjectListIsArchived,
|
||||
private val viewerDelegate: ViewerDelegate
|
||||
) : ViewModel(), SupportNavigation<EventWrapper<AppNavigation.Command>>, ViewerDelegate by viewerDelegate {
|
||||
|
||||
val status = MutableStateFlow(SyncStatus.UNKNOWN)
|
||||
val error = MutableStateFlow<String?>(null)
|
||||
|
@ -160,6 +164,7 @@ class ObjectSetViewModel(
|
|||
val currentViewer = _currentViewer
|
||||
|
||||
private val _templateViews = MutableStateFlow<List<TemplateView>>(emptyList())
|
||||
private val _dvViews = MutableStateFlow<List<ViewerView>>(emptyList())
|
||||
|
||||
private val _header = MutableStateFlow<SetOrCollectionHeaderState>(
|
||||
SetOrCollectionHeaderState.None
|
||||
|
@ -168,6 +173,7 @@ class ObjectSetViewModel(
|
|||
|
||||
val isCustomizeViewPanelVisible = MutableStateFlow(false)
|
||||
val templatesWidgetState = MutableStateFlow(TemplatesWidgetUiState.init())
|
||||
val viewersWidgetState = MutableStateFlow(ViewersWidgetUi.init())
|
||||
|
||||
@Deprecated("could be deleted")
|
||||
val isLoading = MutableStateFlow(false)
|
||||
|
@ -266,6 +272,12 @@ class ObjectSetViewModel(
|
|||
templatesWidgetState.value = templatesWidgetState.value.copy(items = it)
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
_dvViews.collectLatest {
|
||||
viewersWidgetState.value = viewersWidgetState.value.copy(items = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun proceedWithSettingUnsplashImage(
|
||||
|
@ -458,7 +470,6 @@ class ObjectSetViewModel(
|
|||
dataViewState = dataViewState,
|
||||
objectState = objectState,
|
||||
currentViewId = currentViewId,
|
||||
templates = templates
|
||||
)
|
||||
ObjectState.Init -> DataViewViewState.Init
|
||||
ObjectState.ErrorLayout -> DataViewViewState.Error(msg = "Wrong layout, couldn't open object")
|
||||
|
@ -477,6 +488,7 @@ class ObjectSetViewModel(
|
|||
|
||||
return when (dataViewState) {
|
||||
DataViewState.Init -> {
|
||||
_dvViews.value = emptyList()
|
||||
if (dvViewer == null) {
|
||||
DataViewViewState.Collection.NoView
|
||||
} else {
|
||||
|
@ -484,6 +496,7 @@ class ObjectSetViewModel(
|
|||
}
|
||||
}
|
||||
is DataViewState.Loaded -> {
|
||||
_dvViews.value = objectState.viewers.toView(session)
|
||||
val relations = objectState.dataViewContent.relationLinks.mapNotNull {
|
||||
storeOfRelations.getByKey(it.key)
|
||||
}
|
||||
|
@ -520,7 +533,6 @@ class ObjectSetViewModel(
|
|||
dataViewState: DataViewState,
|
||||
objectState: ObjectState.DataView.Set,
|
||||
currentViewId: String?,
|
||||
templates: List<TemplateView>
|
||||
): DataViewViewState {
|
||||
if (!objectState.isInitialized) return DataViewViewState.Init
|
||||
|
||||
|
@ -530,6 +542,7 @@ class ObjectSetViewModel(
|
|||
|
||||
return when (dataViewState) {
|
||||
DataViewState.Init -> {
|
||||
_dvViews.value = emptyList()
|
||||
when {
|
||||
setOfValue.isEmpty() || query.isEmpty() -> DataViewViewState.Set.NoQuery
|
||||
viewer == null -> DataViewViewState.Set.NoView
|
||||
|
@ -537,6 +550,7 @@ class ObjectSetViewModel(
|
|||
}
|
||||
}
|
||||
is DataViewState.Loaded -> {
|
||||
_dvViews.value = objectState.viewers.toView(session)
|
||||
val relations = objectState.dataViewContent.relationLinks.mapNotNull {
|
||||
storeOfRelations.getByKey(it.key)
|
||||
}
|
||||
|
@ -1043,16 +1057,12 @@ class ObjectSetViewModel(
|
|||
|
||||
fun onExpandViewerMenuClicked() {
|
||||
Timber.d("onExpandViewerMenuClicked, ")
|
||||
val state = stateReducer.state.value.dataViewState() ?: return
|
||||
if (isRestrictionPresent(DataViewRestriction.VIEWS)
|
||||
) {
|
||||
toast(NOT_ALLOWED)
|
||||
} else {
|
||||
dispatch(
|
||||
ObjectSetCommand.Modal.ManageViewer(
|
||||
ctx = context,
|
||||
dataview = state.dataViewBlock.id
|
||||
)
|
||||
viewersWidgetState.value = viewersWidgetState.value.copy(
|
||||
showWidget = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1061,12 +1071,6 @@ class ObjectSetViewModel(
|
|||
Timber.d("onViewerEditClicked, ")
|
||||
val state = stateReducer.state.value.dataViewState() ?: return
|
||||
val viewer = state.viewerById(session.currentViewerId.value) ?: return
|
||||
dispatch(
|
||||
ObjectSetCommand.Modal.EditDataViewViewer(
|
||||
ctx = context,
|
||||
viewer = viewer.id
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun onMenuClicked() {
|
||||
|
@ -1748,6 +1752,66 @@ class ObjectSetViewModel(
|
|||
}
|
||||
//endregion
|
||||
|
||||
// region VIEWS
|
||||
fun onViewersWidgetAction(action: ViewersWidgetUi.Action) {
|
||||
when (action) {
|
||||
ViewersWidgetUi.Action.Dismiss -> {
|
||||
viewersWidgetState.value = viewersWidgetState.value.copy(
|
||||
showWidget = false,
|
||||
isEditing = false
|
||||
)
|
||||
}
|
||||
ViewersWidgetUi.Action.DoneMode -> {
|
||||
viewersWidgetState.value = viewersWidgetState.value.copy(isEditing = false)
|
||||
}
|
||||
ViewersWidgetUi.Action.EditMode -> {
|
||||
viewersWidgetState.value = viewersWidgetState.value.copy(isEditing = true)
|
||||
}
|
||||
is ViewersWidgetUi.Action.Delete -> {
|
||||
val state = stateReducer.state.value.dataViewState() ?: return
|
||||
viewModelScope.launch {
|
||||
onEvent(
|
||||
ViewerEvent.Delete(
|
||||
ctx = context,
|
||||
dv = state.dataViewBlock.id,
|
||||
viewer = action.viewer,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
is ViewersWidgetUi.Action.Edit -> TODO()
|
||||
is ViewersWidgetUi.Action.OnMove -> {
|
||||
Timber.d("onMove Viewer, from:[$action.from], to:[$action.to]")
|
||||
if (action.from == action.to) return
|
||||
val state = stateReducer.state.value.dataViewState() ?: return
|
||||
if (action.to == 0 && session.currentViewerId.value.isNullOrEmpty()) {
|
||||
session.currentViewerId.value = action.currentViews.firstOrNull()?.id
|
||||
}
|
||||
viewModelScope.launch {
|
||||
viewerDelegate.onEvent(
|
||||
ViewerEvent.UpdatePosition(
|
||||
ctx = context,
|
||||
dv = state.dataViewBlock.id,
|
||||
viewer = action.currentViews[action.to].id,
|
||||
position = action.to
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
is ViewersWidgetUi.Action.SetActive -> {
|
||||
viewModelScope.launch {
|
||||
onEvent(ViewerEvent.SetActive(viewer = action.id))
|
||||
}
|
||||
}
|
||||
|
||||
ViewersWidgetUi.Action.Plus -> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//endregion
|
||||
|
||||
companion object {
|
||||
const val NOT_ALLOWED = "Not allowed for this set"
|
||||
const val NOT_ALLOWED_CELL = "Not allowed for this cell"
|
||||
|
|
|
@ -33,6 +33,7 @@ import com.anytypeio.anytype.presentation.common.Delegator
|
|||
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectStateReducer
|
||||
import com.anytypeio.anytype.presentation.sets.subscription.DataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate
|
||||
import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
|
||||
|
@ -70,7 +71,8 @@ class ObjectSetViewModelFactory(
|
|||
private val updateDataViewViewer: UpdateDataViewViewer,
|
||||
private val duplicateObjects: DuplicateObjects,
|
||||
private val templatesContainer: ObjectTypeTemplatesContainer,
|
||||
private val setObjectListIsArchived: SetObjectListIsArchived
|
||||
private val setObjectListIsArchived: SetObjectListIsArchived,
|
||||
private val viewerDelegate: ViewerDelegate
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
|
@ -108,7 +110,8 @@ class ObjectSetViewModelFactory(
|
|||
updateDataViewViewer = updateDataViewViewer,
|
||||
duplicateObjects = duplicateObjects,
|
||||
templatesContainer = templatesContainer,
|
||||
setObjectListIsArchived = setObjectListIsArchived
|
||||
setObjectListIsArchived = setObjectListIsArchived,
|
||||
viewerDelegate = viewerDelegate
|
||||
) as T
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerView
|
||||
import com.anytypeio.anytype.presentation.widgets.FromIndex
|
||||
import com.anytypeio.anytype.presentation.widgets.ToIndex
|
||||
|
||||
data class ViewersWidgetUi(
|
||||
val showWidget: Boolean,
|
||||
val isEditing: Boolean,
|
||||
val items: List<ViewerView>
|
||||
) {
|
||||
|
||||
fun dismiss() = copy(
|
||||
showWidget = false,
|
||||
isEditing = false
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun init() = ViewersWidgetUi(
|
||||
showWidget = false,
|
||||
isEditing = false,
|
||||
items = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Action {
|
||||
object Dismiss : Action()
|
||||
object EditMode : Action()
|
||||
object DoneMode : Action()
|
||||
data class Delete(val viewer: Id) : Action()
|
||||
data class Edit(val id: Id) : Action()
|
||||
data class OnMove(
|
||||
val currentViews: List<ViewerView>,
|
||||
val from: FromIndex,
|
||||
val to: ToIndex
|
||||
) : Action()
|
||||
|
||||
data class SetActive(val id: Id) : Action()
|
||||
|
||||
object Plus : Action()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.anytypeio.anytype.presentation.sets.viewer
|
||||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.DVViewer
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.AddDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DeleteDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.DuplicateDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.RenameDataViewViewer
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.SetDataViewViewerPosition
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber
|
||||
|
||||
interface ViewerDelegate {
|
||||
suspend fun onEvent(event: ViewerEvent)
|
||||
}
|
||||
|
||||
sealed class ViewerEvent {
|
||||
data class Delete(val ctx: Id, val dv: Id, val viewer: Id) : ViewerEvent()
|
||||
data class Duplicate(val ctx: Id, val dv: Id, val viewer: DVViewer) : ViewerEvent()
|
||||
data class Rename(val ctx: Id, val dv: Id, val viewer: DVViewer) : ViewerEvent()
|
||||
data class AddNew(val ctx: Id, val dv: Id, val name: String, val type: DVViewerType) :
|
||||
ViewerEvent()
|
||||
|
||||
data class UpdatePosition(val ctx: Id, val dv: Id, val viewer: Id, val position: Int) :
|
||||
ViewerEvent()
|
||||
|
||||
data class SetActive(val viewer: Id) : ViewerEvent()
|
||||
}
|
||||
|
||||
class DefaultViewerDelegate @Inject constructor(
|
||||
private val session: ObjectSetSession,
|
||||
private val dispatcher: Dispatcher<Payload>,
|
||||
private val analytics: Analytics,
|
||||
private val deleteDataViewViewer: DeleteDataViewViewer,
|
||||
private val setDataViewViewerPosition: SetDataViewViewerPosition,
|
||||
private val duplicateDataViewViewer: DuplicateDataViewViewer,
|
||||
private val addDataViewViewer: AddDataViewViewer,
|
||||
private val renameDataViewViewer: RenameDataViewViewer
|
||||
) : ViewerDelegate {
|
||||
|
||||
override suspend fun onEvent(event: ViewerEvent) {}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.anytypeio.anytype.presentation.sets.viewer
|
||||
|
||||
import com.anytypeio.anytype.core_models.DVViewerType
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
|
||||
data class ViewerView(
|
||||
val id: Id,
|
||||
val name: String,
|
||||
val type: DVViewerType,
|
||||
val isActive: Boolean,
|
||||
val showActionMenu: Boolean = false,
|
||||
val isUnsupported: Boolean = false
|
||||
)
|
||||
|
||||
|
|
@ -60,6 +60,7 @@ import com.anytypeio.anytype.presentation.sets.state.DefaultObjectStateReducer
|
|||
import com.anytypeio.anytype.presentation.sets.subscription.DataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.subscription.DefaultDataViewSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.updateFormatForSubscription
|
||||
import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate
|
||||
import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer
|
||||
import com.anytypeio.anytype.presentation.util.DefaultCoroutineTestRule
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
|
@ -166,6 +167,9 @@ open class ObjectSetViewModelTestSetup {
|
|||
@Mock
|
||||
lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
|
||||
@Mock
|
||||
lateinit var viewerDelegate: ViewerDelegate
|
||||
|
||||
var stateReducer = DefaultObjectStateReducer()
|
||||
|
||||
lateinit var dataViewSubscriptionContainer: DataViewSubscriptionContainer
|
||||
|
@ -237,7 +241,8 @@ open class ObjectSetViewModelTestSetup {
|
|||
updateDataViewViewer = updateDataViewViewer,
|
||||
templatesContainer = templatesContainer,
|
||||
setObjectListIsArchived = setObjectListIsArchived,
|
||||
duplicateObjects = duplicateObjects
|
||||
duplicateObjects = duplicateObjects,
|
||||
viewerDelegate = viewerDelegate
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,330 +0,0 @@
|
|||
package com.anytypeio.anytype.presentation.sets.main
|
||||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.*
|
||||
import com.anytypeio.anytype.presentation.sets.EditDataViewViewerViewModel
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetPaginator
|
||||
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import com.anytypeio.anytype.presentation.util.CoroutinesTestRule
|
||||
import com.anytypeio.anytype.presentation.util.Dispatcher
|
||||
import com.anytypeio.anytype.test_utils.MockDataFactory
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.*
|
||||
|
||||
class ObjectSetViewerDeleteTest {
|
||||
|
||||
@get:Rule
|
||||
val coroutineTestRule = CoroutinesTestRule()
|
||||
|
||||
val title = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Text(
|
||||
style = Block.Content.Text.Style.TITLE,
|
||||
text = MockDataFactory.randomString(),
|
||||
marks = emptyList()
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val header = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = Block.Content.Layout(
|
||||
type = Block.Content.Layout.Type.HEADER
|
||||
),
|
||||
fields = Block.Fields.empty(),
|
||||
children = listOf(title.id)
|
||||
)
|
||||
|
||||
val paginator = ObjectSetPaginator()
|
||||
|
||||
@Mock
|
||||
lateinit var dispatcher: Dispatcher<Payload>
|
||||
|
||||
@Mock
|
||||
lateinit var renameDataViewViewer: RenameDataViewViewer
|
||||
|
||||
@Mock
|
||||
lateinit var deleteDataViewViewer: DeleteDataViewViewer
|
||||
|
||||
@Mock
|
||||
lateinit var duplicateDataViewViewer: DuplicateDataViewViewer
|
||||
|
||||
@Mock
|
||||
lateinit var updateDataViewViewer: UpdateDataViewViewer
|
||||
|
||||
@Mock
|
||||
lateinit var analytics: Analytics
|
||||
|
||||
private val ctx: Id = MockDataFactory.randomUuid()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not update active view after inactive view is deleted`() = runTest {
|
||||
// SETUP
|
||||
|
||||
val firstViewer = DVViewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
viewerRelations = emptyList(),
|
||||
type = DVViewerType.GRID,
|
||||
sorts = emptyList(),
|
||||
filters = emptyList()
|
||||
)
|
||||
|
||||
val secondViewer = firstViewer.copy(id = MockDataFactory.randomUuid())
|
||||
val thirdViewer = firstViewer.copy(id = MockDataFactory.randomUuid())
|
||||
|
||||
val activeViewerId = firstViewer.id
|
||||
|
||||
val objectSetSession = ObjectSetSession().apply {
|
||||
currentViewerId.value = activeViewerId
|
||||
}
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = DV(
|
||||
viewers = listOf(firstViewer, secondViewer, thirdViewer)
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val objectSetState = MutableStateFlow(
|
||||
ObjectState.DataView.Set(
|
||||
root = ctx,
|
||||
blocks = listOf(
|
||||
header,
|
||||
title,
|
||||
dv
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
stubRemoveDataViewViewer(
|
||||
dv = dv.id,
|
||||
viewer = secondViewer.id
|
||||
)
|
||||
|
||||
val vm = buildViewModel(
|
||||
objectSetState = objectSetState,
|
||||
objectSetSession = objectSetSession,
|
||||
updateDataViewViewer = updateDataViewViewer
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onDeleteClicked(
|
||||
ctx = ctx,
|
||||
viewer = secondViewer.id
|
||||
)
|
||||
|
||||
verifyBlocking(deleteDataViewViewer, times(1)) {
|
||||
invoke(
|
||||
DeleteDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
viewer = secondViewer.id,
|
||||
dataview = dv.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should set next view as active view if currently active view is being deleted`() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val firstViewer = DVViewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
viewerRelations = emptyList(),
|
||||
type = DVViewerType.GRID,
|
||||
sorts = emptyList(),
|
||||
filters = emptyList()
|
||||
)
|
||||
|
||||
val secondViewer = firstViewer.copy(id = MockDataFactory.randomUuid())
|
||||
val thirdViewer = firstViewer.copy(id = MockDataFactory.randomUuid())
|
||||
|
||||
val activeViewerId = firstViewer.id
|
||||
|
||||
val objectSetSession = ObjectSetSession().apply {
|
||||
currentViewerId.value = activeViewerId
|
||||
}
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = DV(
|
||||
viewers = listOf(firstViewer, secondViewer, thirdViewer)
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val objectSetState = MutableStateFlow(
|
||||
ObjectState.DataView.Set(
|
||||
root = ctx,
|
||||
blocks = listOf(
|
||||
header,
|
||||
title,
|
||||
dv
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
stubRemoveDataViewViewer(
|
||||
dv = dv.id,
|
||||
viewer = firstViewer.id
|
||||
)
|
||||
|
||||
val vm = buildViewModel(
|
||||
objectSetState = objectSetState,
|
||||
objectSetSession = objectSetSession,
|
||||
updateDataViewViewer = updateDataViewViewer
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onDeleteClicked(
|
||||
ctx = ctx,
|
||||
viewer = firstViewer.id
|
||||
)
|
||||
|
||||
verifyBlocking(deleteDataViewViewer, times(1)) {
|
||||
invoke(
|
||||
DeleteDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
viewer = firstViewer.id,
|
||||
dataview = dv.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should set prevous view as active view if currently active view is being deleted`() {
|
||||
|
||||
// SETUP
|
||||
|
||||
val firstViewer = DVViewer(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
name = MockDataFactory.randomString(),
|
||||
viewerRelations = emptyList(),
|
||||
type = DVViewerType.GRID,
|
||||
sorts = emptyList(),
|
||||
filters = emptyList()
|
||||
)
|
||||
|
||||
val secondViewer = firstViewer.copy(id = MockDataFactory.randomUuid())
|
||||
val thirdViewer = firstViewer.copy(id = MockDataFactory.randomUuid())
|
||||
|
||||
val activeViewerId = thirdViewer.id
|
||||
|
||||
val objectSetSession = ObjectSetSession().apply {
|
||||
currentViewerId.value = activeViewerId
|
||||
}
|
||||
|
||||
val dv = Block(
|
||||
id = MockDataFactory.randomUuid(),
|
||||
content = DV(
|
||||
viewers = listOf(firstViewer, secondViewer, thirdViewer)
|
||||
),
|
||||
children = emptyList(),
|
||||
fields = Block.Fields.empty()
|
||||
)
|
||||
|
||||
val objectSetState = MutableStateFlow(
|
||||
ObjectState.DataView.Set(
|
||||
root = ctx,
|
||||
blocks = listOf(
|
||||
header,
|
||||
title,
|
||||
dv
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
stubRemoveDataViewViewer(
|
||||
dv = dv.id,
|
||||
viewer = thirdViewer.id
|
||||
)
|
||||
|
||||
val vm = buildViewModel(
|
||||
objectSetState = objectSetState,
|
||||
objectSetSession = objectSetSession,
|
||||
updateDataViewViewer = updateDataViewViewer
|
||||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
vm.onDeleteClicked(
|
||||
ctx = ctx,
|
||||
viewer = thirdViewer.id
|
||||
)
|
||||
|
||||
verifyBlocking(deleteDataViewViewer, times(1)) {
|
||||
invoke(
|
||||
DeleteDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
viewer = thirdViewer.id,
|
||||
dataview = dv.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun buildViewModel(
|
||||
updateDataViewViewer: UpdateDataViewViewer,
|
||||
objectSetState: StateFlow<ObjectState>,
|
||||
objectSetSession: ObjectSetSession
|
||||
): EditDataViewViewerViewModel {
|
||||
return EditDataViewViewerViewModel(
|
||||
renameDataViewViewer = renameDataViewViewer,
|
||||
deleteDataViewViewer = deleteDataViewViewer,
|
||||
duplicateDataViewViewer = duplicateDataViewViewer,
|
||||
objectSetSession = objectSetSession,
|
||||
objectState = objectSetState,
|
||||
dispatcher = dispatcher,
|
||||
updateDataViewViewer = updateDataViewViewer,
|
||||
analytics = analytics,
|
||||
paginator = paginator
|
||||
)
|
||||
}
|
||||
|
||||
private fun stubRemoveDataViewViewer(
|
||||
viewer: Id,
|
||||
dv: Id
|
||||
) {
|
||||
deleteDataViewViewer.stub {
|
||||
onBlocking {
|
||||
invoke(
|
||||
DeleteDataViewViewer.Params(
|
||||
ctx = ctx,
|
||||
viewer = viewer,
|
||||
dataview = dv
|
||||
)
|
||||
)
|
||||
} doReturn Either.Right(
|
||||
Payload(
|
||||
context = ctx,
|
||||
events = emptyList()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue