diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt index 09b54a9aff..aabe1e16a5 100644 --- a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt +++ b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt @@ -19,6 +19,7 @@ import com.anytypeio.anytype.domain.block.interactor.UpdateText import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.Gateway import com.anytypeio.anytype.domain.cover.SetDocCoverImage +import com.anytypeio.anytype.domain.dataview.SetDataViewSource import com.anytypeio.anytype.domain.dataview.interactor.AddNewRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewRecord import com.anytypeio.anytype.domain.dataview.interactor.SetActiveViewer @@ -64,6 +65,7 @@ abstract class TestObjectSetSetup { private lateinit var interceptThreadStatus: InterceptThreadStatus private lateinit var setDocCoverImage: SetDocCoverImage private lateinit var downloadUnsplashImage: DownloadUnsplashImage + private lateinit var setDataViewSource: SetDataViewSource lateinit var urlBuilder: UrlBuilder @@ -123,6 +125,7 @@ abstract class TestObjectSetSetup { open fun setup() { MockitoAnnotations.openMocks(this) + setDataViewSource = SetDataViewSource(repo) addDataViewRelation = AddNewRelationToDataView(repo) updateText = UpdateText(repo) openObjectSet = OpenObjectSet(repo, auth) @@ -144,6 +147,7 @@ abstract class TestObjectSetSetup { ) ) + TestObjectSetFragment.testVmFactory = ObjectSetViewModelFactory( openObjectSet = openObjectSet, closeBlock = closeBlock, @@ -165,7 +169,8 @@ abstract class TestObjectSetSetup { setDocCoverImage = setDocCoverImage, delegator = delegator, getTemplates = getTemplates, - createNewObject = createNewObject + createNewObject = createNewObject, + setDataViewSource = setDataViewSource ) } diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt index 96692e628c..fbc7fba496 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt @@ -21,6 +21,7 @@ import com.anytypeio.anytype.domain.block.interactor.UpdateText import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.config.UserSettingsRepository import com.anytypeio.anytype.domain.cover.SetDocCoverImage +import com.anytypeio.anytype.domain.dataview.SetDataViewSource import com.anytypeio.anytype.domain.dataview.interactor.AddNewRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewRecord import com.anytypeio.anytype.domain.search.SearchObjects @@ -89,8 +90,8 @@ interface ObjectSetSubComponent { fun objectSetSettingsComponent(): ObjectSetSettingsSubComponent.Builder fun viewerCardSizeSelectComponent(): ViewerCardSizeSelectSubcomponent.Builder fun viewerImagePreviewSelectComponent(): ViewerImagePreviewSelectSubcomponent.Builder - fun relationAddToDataViewComponent() : RelationAddToDataViewSubComponent.Builder - fun relationCreateFromScratchForDataViewComponent() : RelationCreateFromScratchForDataViewSubComponent.Builder + fun relationAddToDataViewComponent(): RelationAddToDataViewSubComponent.Builder + fun relationCreateFromScratchForDataViewComponent(): RelationCreateFromScratchForDataViewSubComponent.Builder fun dataviewViewerActionComponent(): DataViewViewerActionSubComponent.Builder fun selectSortRelationComponent(): SelectSortRelationSubComponent.Builder fun selectFilterRelationComponent(): SelectFilterRelationSubComponent.Builder @@ -101,10 +102,10 @@ interface ObjectSetSubComponent { fun relationTextValueComponent(): RelationTextValueSubComponent.Builder fun relationDateValueComponent(): RelationDataValueSubComponent.Builder - fun objectSetMenuComponent() : ObjectSetMenuComponent.Builder - fun objectSetIconPickerComponent() : ObjectSetIconPickerComponent.Builder - fun objectSetCoverComponent() : SelectCoverObjectSetSubComponent.Builder - fun objectUnsplashComponent() : UnsplashSubComponent.Builder + fun objectSetMenuComponent(): ObjectSetMenuComponent.Builder + fun objectSetIconPickerComponent(): ObjectSetIconPickerComponent.Builder + fun objectSetCoverComponent(): SelectCoverObjectSetSubComponent.Builder + fun objectUnsplashComponent(): UnsplashSubComponent.Builder } @Module @@ -141,7 +142,8 @@ object ObjectSetModule { downloadUnsplashImage: DownloadUnsplashImage, setDocCoverImage: SetDocCoverImage, getTemplates: GetTemplates, - createNewObject: CreateNewObject + createNewObject: CreateNewObject, + setDataViewSource: SetDataViewSource ): ObjectSetViewModelFactory = ObjectSetViewModelFactory( openObjectSet = openObjectSet, closeBlock = closeBlock, @@ -163,7 +165,8 @@ object ObjectSetModule { downloadUnsplashImage = downloadUnsplashImage, setDocCoverImage = setDocCoverImage, getTemplates = getTemplates, - createNewObject = createNewObject + createNewObject = createNewObject, + setDataViewSource = setDataViewSource ) @JvmStatic @@ -173,12 +176,19 @@ object ObjectSetModule { getDefaultEditorType: GetDefaultEditorType, getTemplates: GetTemplates, createPage: CreatePage, - ) : CreateNewObject = CreateNewObject( + ): CreateNewObject = CreateNewObject( getDefaultEditorType, getTemplates, createPage ) + @JvmStatic + @Provides + @PerScreen + fun provideSetDataViewSource( + repo: BlockRepository + ): SetDataViewSource = SetDataViewSource(repo) + @JvmStatic @Provides @PerScreen @@ -259,7 +269,7 @@ object ObjectSetModule { @PerScreen fun provideInterceptThreadStatus( channel: ThreadStatusChannel - ) : InterceptThreadStatus = InterceptThreadStatus( + ): InterceptThreadStatus = InterceptThreadStatus( channel = channel ) @@ -295,7 +305,7 @@ object ObjectSetModule { @JvmStatic @Provides @PerScreen - fun provideDelegator() : Delegator = Delegator.Default() + fun provideDelegator(): Delegator = Delegator.Default() @JvmStatic @Provides @@ -307,7 +317,7 @@ object ObjectSetModule { @PerScreen fun provideDataViewObjectRelationProvider( state: StateFlow - ) : ObjectRelationProvider = DataViewObjectRelationProvider(state) + ): ObjectRelationProvider = DataViewObjectRelationProvider(state) @JvmStatic @Provides @@ -315,14 +325,14 @@ object ObjectSetModule { fun provideDataViewObjectValueProvider( state: StateFlow, session: ObjectSetSession - ) : ObjectValueProvider = DataViewObjectValueProvider(state, session) + ): ObjectValueProvider = DataViewObjectValueProvider(state, session) @JvmStatic @Provides @PerScreen fun provideObjectTypeProvider( state: StateFlow, - ) : ObjectTypeProvider = object : ObjectTypeProvider { + ): ObjectTypeProvider = object : ObjectTypeProvider { override fun provide(): List = state.value.objectTypes } @@ -331,7 +341,7 @@ object ObjectSetModule { @PerScreen fun provideObjectDetailProvider( state: StateFlow, - ) : ObjectDetailProvider = object : ObjectDetailProvider { + ): ObjectDetailProvider = object : ObjectDetailProvider { override fun provide(): Map = state.value.details } @@ -340,7 +350,7 @@ object ObjectSetModule { @PerScreen fun provideUpdateDetailUseCase( repository: BlockRepository - ) : UpdateDetail = UpdateDetail(repository) + ): UpdateDetail = UpdateDetail(repository) @JvmStatic @Provides diff --git a/app/src/main/java/com/anytypeio/anytype/ui/objects/ObjectTypeChangeFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/objects/ObjectTypeChangeFragment.kt index 581fd2a8fe..57f11b039e 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/objects/ObjectTypeChangeFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/objects/ObjectTypeChangeFragment.kt @@ -10,6 +10,7 @@ import androidx.fragment.app.setFragmentResult import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager +import com.anytypeio.anytype.R import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.SmartBlockType import com.anytypeio.anytype.core_ui.features.objects.ObjectTypeVerticalAdapter @@ -37,6 +38,11 @@ class ObjectTypeChangeFragment : private val isDraft: Boolean get() = argOrNull(OBJECT_IS_DRAFT_KEY) ?: false + private val isSetSource: Boolean get() = argOrNull(ARG_IS_SET_SOURCE) ?: false + + private val selectedSources : List + get() = argOrNull>(ARG_SOURCES) ?: emptyList() + @Inject lateinit var factory: ObjectTypeChangeViewModelFactory @@ -51,6 +57,9 @@ class ObjectTypeChangeFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + if (isSetSource) { + binding.tvTitle.text = getString(R.string.select_source) + } binding.recycler.apply { adapter = objectTypeAdapter layoutManager = LinearLayoutManager(context) @@ -83,7 +92,8 @@ class ObjectTypeChangeFragment : vm.onStart( smartBlockType = smartBlockType, excludedTypes = excludedTypes, - isDraft = isDraft + isDraft = isDraft, + selectedSources = selectedSources ) } @@ -105,6 +115,8 @@ class ObjectTypeChangeFragment : companion object { const val ARG_SMART_BLOCK_TYPE = "arg.object-type.smart-block-type" const val ARG_EXCLUDED_TYPES = "arg.object-type.excluded-types" + const val ARG_IS_SET_SOURCE = "arg.object-type.is-set-source" + const val ARG_SOURCES = "arg.object-type.sources" const val OBJECT_TYPE_URL_KEY = "object-type-url.key" const val OBJECT_TYPE_NAME_KEY = "object-type-name.key" const val OBJECT_TYPE_REQUEST_KEY = "object-type.request" diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt index c0941bf912..6147cefd20 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt @@ -23,6 +23,7 @@ import androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STO import androidx.core.view.children import androidx.core.view.marginBottom import androidx.core.view.updatePadding +import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController @@ -49,6 +50,7 @@ import com.anytypeio.anytype.core_utils.ext.drawable import com.anytypeio.anytype.core_utils.ext.gone import com.anytypeio.anytype.core_utils.ext.hideKeyboard import com.anytypeio.anytype.core_utils.ext.hideSoftInput +import com.anytypeio.anytype.core_utils.ext.invisible import com.anytypeio.anytype.core_utils.ext.subscribe import com.anytypeio.anytype.core_utils.ext.syncFocusWithImeVisibility import com.anytypeio.anytype.core_utils.ext.syncTranslationWithImeVisibility @@ -69,6 +71,7 @@ import com.anytypeio.anytype.ui.base.NavigationFragment import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectSetFragment import com.anytypeio.anytype.ui.editor.modals.IconPickerFragmentBase import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuBaseFragment +import com.anytypeio.anytype.ui.objects.ObjectTypeChangeFragment import com.anytypeio.anytype.ui.relations.RelationDateValueFragment import com.anytypeio.anytype.ui.relations.RelationDateValueFragment.DateValueEditReceiver import com.anytypeio.anytype.ui.relations.RelationTextValueFragment @@ -111,7 +114,7 @@ open class ObjectSetFragment : private val topToolbarStatusText: TextView get() = binding.topToolbar.root.findViewById(R.id.tvStatus) - private val addNewButton: ImageView + private val addNewButton: TextView get() = binding.dataViewHeader.root.findViewById(R.id.addNewButton) private val customizeViewButton: ImageView @@ -242,6 +245,14 @@ open class ObjectSetFragment : binding.listView.onTaskCheckboxClicked = { id -> vm.onTaskCheckboxClicked(id) } + setFragmentResultListener(ObjectTypeChangeFragment.OBJECT_TYPE_REQUEST_KEY) { _, bundle -> + val source = bundle.getString(ObjectTypeChangeFragment.OBJECT_TYPE_URL_KEY) + if (source != null) { + vm.onDataViewSourcePicked(source = source) + } else { + toast("Error while setting Set source. Source is empty") + } + } } private fun setupWindowInsetAnimation() { @@ -313,19 +324,6 @@ open class ObjectSetFragment : vm.navigation.observe(viewLifecycleOwner, navObserver) lifecycleScope.subscribe(vm.toasts.stream()) { toast(it) } lifecycleScope.subscribe(vm.status) { setStatus(it) } - lifecycleScope.subscribe(vm.featured) { featured -> - if (featured != null) { - featuredRelations.visible() - featuredRelations.set( - item = featured, - click = {}, - isObjectSet = true - ) - } else { - featuredRelations.clear() - featuredRelations.gone() - } - } lifecycleScope.subscribe(vm.isCustomizeViewPanelVisible) { isCustomizeViewPanelVisible -> if (isCustomizeViewPanelVisible) showBottomPanel() else hideBottomPanel() } @@ -348,6 +346,7 @@ open class ObjectSetFragment : when (viewer) { is Viewer.GridView -> { with(binding) { + dataViewHeader.root.visible() unsupportedViewError.gone() unsupportedViewError.text = null galleryView.clear() @@ -362,6 +361,7 @@ open class ObjectSetFragment : viewerGridHeaderAdapter.submitList(emptyList()) viewerGridAdapter.submitList(emptyList()) with(binding) { + dataViewHeader.root.visible() unsupportedViewError.gone() unsupportedViewError.text = null listView.gone() @@ -377,6 +377,7 @@ open class ObjectSetFragment : viewerGridHeaderAdapter.submitList(emptyList()) viewerGridAdapter.submitList(emptyList()) with(binding) { + dataViewHeader.root.visible() unsupportedViewError.gone() unsupportedViewError.text = null galleryView.gone() @@ -389,6 +390,7 @@ open class ObjectSetFragment : viewerGridHeaderAdapter.submitList(emptyList()) viewerGridAdapter.submitList(emptyList()) with(binding) { + dataViewHeader.root.visible() galleryView.gone() galleryView.clear() listView.gone() @@ -401,6 +403,7 @@ open class ObjectSetFragment : viewerGridHeaderAdapter.submitList(emptyList()) viewerGridAdapter.submitList(emptyList()) with(binding) { + dataViewHeader.root.invisible() galleryView.gone() galleryView.clear() listView.gone() @@ -612,8 +615,8 @@ open class ObjectSetFragment : } is ObjectSetCommand.Modal.SetNameForCreatedRecord -> { findNavController().navigate( - R.id.setNameForNewRecordScreen, - bundleOf(SetObjectSetRecordNameFragment.CONTEXT_KEY to command.ctx) + R.id.setNameForNewRecordScreen, + bundleOf(SetObjectSetRecordNameFragment.CONTEXT_KEY to command.ctx) ) } is ObjectSetCommand.Intent.MailTo -> { @@ -681,6 +684,17 @@ open class ObjectSetFragment : ) ) } + is ObjectSetCommand.Modal.OpenSelectSourceScreen -> { + findNavController() + .navigate( + R.id.objectTypeChangeScreen, + bundleOf( + ObjectTypeChangeFragment.ARG_SMART_BLOCK_TYPE to command.smartBlockType, + ObjectTypeChangeFragment.ARG_IS_SET_SOURCE to true, + ObjectTypeChangeFragment.ARG_SOURCES to command.sources + ) + ) + } } } @@ -756,6 +770,19 @@ open class ObjectSetFragment : binding.dvProgressBar.hide() } } + jobs += lifecycleScope.subscribe(vm.featured) { featured -> + if (featured != null) { + featuredRelations.visible() + featuredRelations.set( + item = featured, + click = vm::onClickListener, + isObjectSet = true + ) + } else { + featuredRelations.clear() + featuredRelations.gone() + } + } vm.onStart(ctx) } diff --git a/app/src/main/res/drawable/ic_plus_white_12.xml b/app/src/main/res/drawable/ic_plus_white_12.xml new file mode 100644 index 0000000000..64692847c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_plus_white_12.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_object_set.xml b/app/src/main/res/layout/fragment_object_set.xml index ae12d997f8..0ad1a6e8fb 100644 --- a/app/src/main/res/layout/fragment_object_set.xml +++ b/app/src/main/res/layout/fragment_object_set.xml @@ -43,11 +43,11 @@ android:layout_width="0dp" android:layout_height="@dimen/data_view_divider_height" android:background="@color/shape_primary" + android:visibility="invisible" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/dataViewHeader" /> - + android:layout_height="56dp" + android:orientation="horizontal"> + android:layout_height="match_parent" + android:layout_weight="1"> - + android:layout_gravity="center_vertical" + android:layout_marginEnd="20dp" + android:background="@drawable/bg_set_new_button" + android:drawableStart="@drawable/ic_plus_white_12" + android:drawablePadding="4dp" + android:fontFamily="@font/inter_medium" + android:paddingStart="8dp" + android:paddingTop="5dp" + android:paddingEnd="8dp" + android:paddingBottom="5dp" + android:text="New" + android:textColor="@color/white" + android:textSize="12sp" /> \ No newline at end of file diff --git a/app/src/main/res/xml/fragment_object_set_scene.xml b/app/src/main/res/xml/fragment_object_set_scene.xml index 25bc3113d3..da30b9981a 100644 --- a/app/src/main/res/xml/fragment_object_set_scene.xml +++ b/app/src/main/res/xml/fragment_object_set_scene.xml @@ -29,7 +29,16 @@ android:layout_height="@dimen/default_toolbar_height" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" - motion:layout_constraintTop_toBottomOf="@+id/objectHeader" /> + motion:layout_constraintTop_toBottomOf="@+id/objectHeader" + motion:visibilityMode="ignore" /> + + motion:layout_constraintTop_toBottomOf="@+id/topToolbar" + motion:visibilityMode="ignore"/> + = emptyList() -): RecyclerView.Adapter() { - - override fun onCreateViewHolder( - parent: ViewGroup, viewType: Int - ): FeaturedRelationViewHolder { - val inflater = LayoutInflater.from(parent.context) - return when(viewType) { - R.layout.item_featured_relation_default -> { - FeaturedRelationViewHolder.Default( - binding = ItemFeaturedRelationDefaultBinding.inflate( - inflater, parent, false - ) - ) - } - R.layout.item_featured_relation_tags -> { - FeaturedRelationViewHolder.Tags( - binding = ItemFeaturedRelationTagsBinding.inflate( - inflater, parent, false - ) - ) - } - R.layout.item_featured_relation_status -> { - FeaturedRelationViewHolder.Status( - binding = ItemFeaturedRelationStatusBinding.inflate( - inflater, parent, false - ) - ) - } - else -> throw IllegalStateException("Unexpected view type: $viewType") - } - } - - override fun onBindViewHolder(holder: FeaturedRelationViewHolder, position: Int) { - when(holder) { - is FeaturedRelationViewHolder.Default -> { - holder.bind(items[position]) - } - is FeaturedRelationViewHolder.Tags -> { - holder.bind(items[position] as DocumentRelationView.Tags) - } - is FeaturedRelationViewHolder.Status -> { - holder.bind(items[position] as DocumentRelationView.Status) - } - } - } - - override fun getItemCount(): Int = items.size - - override fun getItemViewType(position: Int): Int = when(items[position]) { - is DocumentRelationView.Default -> R.layout.item_featured_relation_default - is DocumentRelationView.Tags -> R.layout.item_featured_relation_tags - is DocumentRelationView.Status -> R.layout.item_featured_relation_status - is DocumentRelationView.Checkbox -> TODO() - is DocumentRelationView.File -> TODO() - is DocumentRelationView.Object -> TODO() - is DocumentRelationView.ObjectType -> R.layout.item_featured_relation_default - } - - fun update(items: List) { - this.items = items - notifyDataSetChanged() - } -} \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/holders/FeaturedRelationViewHolder.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/holders/FeaturedRelationViewHolder.kt deleted file mode 100644 index 78588a2ac6..0000000000 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/holders/FeaturedRelationViewHolder.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.anytypeio.anytype.core_ui.features.relations.holders - -import android.view.View -import android.widget.TextView -import androidx.recyclerview.widget.RecyclerView -import com.anytypeio.anytype.core_ui.R -import com.anytypeio.anytype.core_ui.databinding.ItemFeaturedRelationDefaultBinding -import com.anytypeio.anytype.core_ui.databinding.ItemFeaturedRelationStatusBinding -import com.anytypeio.anytype.core_ui.databinding.ItemFeaturedRelationTagsBinding -import com.anytypeio.anytype.core_ui.extensions.color -import com.anytypeio.anytype.core_ui.extensions.dark -import com.anytypeio.anytype.core_ui.extensions.veryLight -import com.anytypeio.anytype.core_utils.ext.setDrawableColor -import com.anytypeio.anytype.core_models.ThemeColor -import com.anytypeio.anytype.presentation.relations.DocumentRelationView -import com.anytypeio.anytype.presentation.sets.model.StatusView -import com.anytypeio.anytype.presentation.sets.model.TagView - - -sealed class FeaturedRelationViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - class Default( - val binding: ItemFeaturedRelationDefaultBinding - ) : FeaturedRelationViewHolder(binding.root) { - fun bind(item: DocumentRelationView) { - binding.tvFeaturedRelationValue.text = item.value - } - } - - class Tags( - val binding: ItemFeaturedRelationTagsBinding - ) : FeaturedRelationViewHolder(binding.root) { - - private val container = binding.featuredRelationTagContainer - - fun bind(item: DocumentRelationView.Tags) { - // TODO optimize create and delete only diff between views - container.removeAllViews() - item.tags.forEach { tag -> - container.addView(createTagView(tag)) - } - } - - private fun createTagView(tag: TagView): View { - val context = itemView.context - val resources = context.resources - val defaultTextColor = context.color(R.color.default_filter_tag_text_color) - val defaultBackgroundColor = context.color(R.color.default_filter_tag_background_color) - val themeColor = ThemeColor.values().find { it.code == tag.color } ?: ThemeColor.DEFAULT - return TextView(context).apply { - text = tag.tag - setBackgroundResource(R.drawable.rect_dv_cell_tag_item) - background.setDrawableColor(resources.veryLight(themeColor, defaultBackgroundColor)) - setTextColor(resources.dark(themeColor, defaultTextColor)) - } - } - } - - class Status( - val binding: ItemFeaturedRelationStatusBinding - ) : FeaturedRelationViewHolder(binding.root) { - - private val container = binding.featuredRelationStatusContainer - - fun bind(item: DocumentRelationView.Status) { - // TODO optimize create and delete only diff between views - container.removeAllViews() - item.status.forEach { status -> - container.addView(createStatusView(status)) - } - } - - private fun createStatusView(status: StatusView): View { - val resources = itemView.context.resources - val color = ThemeColor.values().find { it.code == status.color } ?: ThemeColor.DEFAULT - val defaultTextColor = itemView.context.color(R.color.default_filter_tag_text_color) - return TextView(itemView.context).apply { - text = status.status - setTextColor(resources.dark(color, defaultTextColor)) - } - } - } -} \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt index 1eae5eb220..ce5c83b6b7 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/FeaturedRelationGroupWidget.kt @@ -16,8 +16,10 @@ import com.anytypeio.anytype.core_ui.menu.ObjectTypePopupMenu import com.anytypeio.anytype.core_utils.ext.dimen import com.anytypeio.anytype.core_utils.ext.setDrawableColor import com.anytypeio.anytype.core_models.ThemeColor +import com.anytypeio.anytype.core_ui.extensions.color import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView +import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.relations.DocumentRelationView import com.anytypeio.anytype.presentation.sets.model.ObjectView @@ -249,6 +251,50 @@ class FeaturedRelationGroupWidget : ConstraintLayout { addView(view) ids.add(view.id) } + is DocumentRelationView.Source -> { + relation.sources.forEach { obj -> + val view = ObjectIconTextWidget(context).apply { + id = generateViewId() + when (obj) { + is ObjectView.Default -> { + setTextColor(context.color(R.color.text_secondary)) + setTextSize(context.dimen(R.dimen.featured_relations_text_size)) + setup( + name = obj.name, + icon = obj.icon + ) + } + is ObjectView.Deleted -> { + setTextColor(context.color(R.color.glyph_active)) + setTextSize(context.dimen(R.dimen.featured_relations_text_size)) + setup( + name = context.getString(R.string.deleted), + icon = ObjectIcon.None + ) + } + } + } + view.setOnClickListener { + click( + ListenerType.Relation.SetSource(sources = relation.sources) + ) + } + addView(view) + ids.add(view.id) + } + if (relation.sources.isEmpty()) { + val placeholder = + buildPlaceholderView(resources.getString(R.string.source)).apply { + setOnClickListener { + click( + ListenerType.Relation.SetSource(sources = emptyList()) + ) + } + } + addView(placeholder) + ids.add(placeholder.id) + } + } } if (index != item.relations.lastIndex) { diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt index 2630a86b43..ec2df1bdeb 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/ObjectIconTextWidget.kt @@ -4,14 +4,15 @@ import android.content.Context import android.util.AttributeSet import android.util.TypedValue import android.view.LayoutInflater -import android.widget.FrameLayout +import androidx.constraintlayout.widget.ConstraintLayout import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.databinding.WidgetObjectIconTextBinding +import com.anytypeio.anytype.core_utils.ext.gone import com.anytypeio.anytype.presentation.objects.ObjectIcon class ObjectIconTextWidget @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr) { +) : ConstraintLayout(context, attrs, defStyleAttr) { val binding = WidgetObjectIconTextBinding.inflate( LayoutInflater.from(context), this, true @@ -22,23 +23,33 @@ class ObjectIconTextWidget @JvmOverloads constructor( } private fun setupAttributeValues(set: AttributeSet?) { - if (set == null) return val attrs = context.obtainStyledAttributes(set, R.styleable.ObjectIconTextWidget, 0, 0) val nameTextSize = attrs.getDimensionPixelSize(R.styleable.ObjectIconTextWidget_nameTextSize, 0) if (nameTextSize > 0) { - binding.objectName.setTextSize(TypedValue.COMPLEX_UNIT_PX, nameTextSize.toFloat()) + setTextSize(nameTextSize.toFloat()) } val nameTextColor = attrs.getColor(R.styleable.ObjectIconTextWidget_nameTextColor, 0) - binding.objectName.setTextColor(nameTextColor) + setTextColor(nameTextColor) attrs.recycle() } + fun setTextSize(textSize: Float) { + binding.objectName.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + } + + fun setTextColor(textColor: Int) { + binding.objectName.setTextColor(textColor) + } + fun setup(name: String?, icon: ObjectIcon) { binding.objectName.text = name binding.objectIcon.setIcon(icon) + if (icon is ObjectIcon.None) { + binding.objectIcon.gone() + } } } \ No newline at end of file diff --git a/core-ui/src/main/res/drawable/bg_set_new_button.xml b/core-ui/src/main/res/drawable/bg_set_new_button.xml new file mode 100644 index 0000000000..8a8c238dfd --- /dev/null +++ b/core-ui/src/main/res/drawable/bg_set_new_button.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/core-ui/src/main/res/drawable/ic_check_black_14.xml b/core-ui/src/main/res/drawable/ic_check_black_14.xml new file mode 100644 index 0000000000..30ef8a77f0 --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_check_black_14.xml @@ -0,0 +1,10 @@ + + + diff --git a/core-ui/src/main/res/drawable/ic_dv_customize_view.xml b/core-ui/src/main/res/drawable/ic_dv_customize_view.xml index 5cddb1d8fe..7a7a9eb0bb 100644 --- a/core-ui/src/main/res/drawable/ic_dv_customize_view.xml +++ b/core-ui/src/main/res/drawable/ic_dv_customize_view.xml @@ -4,19 +4,7 @@ android:viewportWidth="24" android:viewportHeight="24"> - - - + android:fillColor="@color/glyph_active" + android:fillType="evenOdd" + android:pathData="M16.5,7C16.5,7.828 15.828,8.5 15,8.5C14.172,8.5 13.5,7.828 13.5,7C13.5,6.172 14.172,5.5 15,5.5C15.828,5.5 16.5,6.172 16.5,7ZM20.25,6.25H17.906C17.573,4.956 16.398,4 15,4C13.602,4 12.427,4.956 12.094,6.25H3.75C3.336,6.25 3,6.586 3,7C3,7.414 3.336,7.75 3.75,7.75H12.094C12.427,9.044 13.602,10 15,10C16.398,10 17.573,9.044 17.906,7.75H20.25C20.664,7.75 21,7.414 21,7C21,6.586 20.664,6.25 20.25,6.25ZM7.5,17C7.5,17.828 8.172,18.5 9,18.5C9.828,18.5 10.5,17.828 10.5,17C10.5,16.172 9.828,15.5 9,15.5C8.172,15.5 7.5,16.172 7.5,17ZM6.095,17.75C6.428,19.044 7.602,20 9,20C10.398,20 11.573,19.044 11.906,17.75H20.25C20.664,17.75 21,17.414 21,17C21,16.586 20.664,16.25 20.25,16.25H11.906C11.573,14.956 10.398,14 9,14C7.602,14 6.428,14.956 6.095,16.25H3.75C3.336,16.25 3,16.586 3,17C3,17.414 3.336,17.75 3.75,17.75H6.095Z" /> diff --git a/core-ui/src/main/res/drawable/ic_plus_white.xml b/core-ui/src/main/res/drawable/ic_plus_white.xml deleted file mode 100644 index a96d2f0541..0000000000 --- a/core-ui/src/main/res/drawable/ic_plus_white.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/core-ui/src/main/res/layout/item_featured_relation_default.xml b/core-ui/src/main/res/layout/item_featured_relation_default.xml deleted file mode 100644 index 3b46402e45..0000000000 --- a/core-ui/src/main/res/layout/item_featured_relation_default.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/core-ui/src/main/res/layout/item_featured_relation_status.xml b/core-ui/src/main/res/layout/item_featured_relation_status.xml deleted file mode 100644 index 5f04641de8..0000000000 --- a/core-ui/src/main/res/layout/item_featured_relation_status.xml +++ /dev/null @@ -1,7 +0,0 @@ - - \ No newline at end of file diff --git a/core-ui/src/main/res/layout/item_featured_relation_tags.xml b/core-ui/src/main/res/layout/item_featured_relation_tags.xml deleted file mode 100644 index c3d03571be..0000000000 --- a/core-ui/src/main/res/layout/item_featured_relation_tags.xml +++ /dev/null @@ -1,7 +0,0 @@ - - \ No newline at end of file diff --git a/core-ui/src/main/res/layout/item_object_type_item.xml b/core-ui/src/main/res/layout/item_object_type_item.xml index 37004e1528..54fe6bbd30 100644 --- a/core-ui/src/main/res/layout/item_object_type_item.xml +++ b/core-ui/src/main/res/layout/item_object_type_item.xml @@ -1,9 +1,9 @@ + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + \ No newline at end of file diff --git a/core-ui/src/main/res/layout/widget_object_icon_text.xml b/core-ui/src/main/res/layout/widget_object_icon_text.xml index 344dbdb701..7ede2b15e6 100644 --- a/core-ui/src/main/res/layout/widget_object_icon_text.xml +++ b/core-ui/src/main/res/layout/widget_object_icon_text.xml @@ -1,5 +1,5 @@ - + android:layout_gravity="center_vertical" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:visibility="visible" /> - + diff --git a/core-ui/src/main/res/values/colors.xml b/core-ui/src/main/res/values/colors.xml index f60d9c54ce..3ee84031db 100644 --- a/core-ui/src/main/res/values/colors.xml +++ b/core-ui/src/main/res/values/colors.xml @@ -180,6 +180,7 @@ #CC0066C3 #FFC532 + #FFB522 #1A50491C @color/shape_tertiary #F1F0ED diff --git a/core-ui/src/main/res/values/dimens.xml b/core-ui/src/main/res/values/dimens.xml index 63b64872c8..32042c5486 100644 --- a/core-ui/src/main/res/values/dimens.xml +++ b/core-ui/src/main/res/values/dimens.xml @@ -301,4 +301,6 @@ 0.5dp + 13sp + \ No newline at end of file diff --git a/core-ui/src/main/res/values/strings.xml b/core-ui/src/main/res/values/strings.xml index 42422eb2d9..42a7917d27 100644 --- a/core-ui/src/main/res/values/strings.xml +++ b/core-ui/src/main/res/values/strings.xml @@ -443,6 +443,8 @@ Select tags Select status Select objects + Source + Select source Objects Web pages Select files diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt index 5c8c8b9b7c..ed49adb0cd 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataRepository.kt @@ -629,4 +629,12 @@ class BlockDataRepository( override suspend fun objectToSet(ctx: Id, source: List): Id { return remote.objectToSet(ctx, source) } + + override suspend fun blockDataViewSetSource( + ctx: Id, + block: Id, + sources: List + ): Payload { + return remote.blockDataViewSetSource(ctx, block, sources) + } } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt index f82fba5bf3..5cd7a560a6 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockDataStore.kt @@ -255,4 +255,6 @@ interface BlockDataStore { suspend fun fillTableRow(ctx: String, targetIds: List): Payload suspend fun objectToSet(ctx: Id, source: List): Id + + suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List): Payload } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt index 302f550eac..105a7880f6 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemote.kt @@ -254,4 +254,6 @@ interface BlockRemote { suspend fun fillTableRow(ctx: String, targetIds: List): Payload suspend fun objectToSet(ctx: Id, source: List): Id + + suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List): Payload } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt index 6f042ba93f..86c3fe92d7 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/block/BlockRemoteDataStore.kt @@ -545,4 +545,12 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore { override suspend fun objectToSet(ctx: Id, source: List): Id { return remote.objectToSet(ctx, source) } + + override suspend fun blockDataViewSetSource( + ctx: Id, + block: Id, + sources: List + ): Payload { + return remote.blockDataViewSetSource(ctx, block, sources) + } } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt index 8f4452da6a..5aae2ab7c1 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/block/repo/BlockRepository.kt @@ -318,4 +318,6 @@ interface BlockRepository { suspend fun fillTableRow(ctx: String, targetIds: List): Payload suspend fun objectToSet(ctx: Id, source: List): Id + + suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List): Payload } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/dataview/SetDataViewSource.kt b/domain/src/main/java/com/anytypeio/anytype/domain/dataview/SetDataViewSource.kt new file mode 100644 index 0000000000..9f0e128167 --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/dataview/SetDataViewSource.kt @@ -0,0 +1,28 @@ +package com.anytypeio.anytype.domain.dataview + +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.Either +import com.anytypeio.anytype.domain.block.repo.BlockRepository + +class SetDataViewSource(private val repo: BlockRepository) : + BaseUseCase() { + + override suspend fun run(params: Params): Either = safe { + repo.blockDataViewSetSource( + ctx = params.ctx, + block = DEFAULT_DATA_VIEW_BLOCK_ID, + sources = params.sources + ) + } + + companion object { + const val DEFAULT_DATA_VIEW_BLOCK_ID = "dataview" + } + + data class Params( + val ctx: Id, + val sources: List + ) +} \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt index 177210a48c..336931b6b6 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/block/BlockMiddleware.kt @@ -584,4 +584,12 @@ class BlockMiddleware( override suspend fun objectToSet(ctx: Id, source: List): Id { return middleware.objectToSet(ctx, source) } + + override suspend fun blockDataViewSetSource( + ctx: Id, + block: Id, + sources: List + ): Payload { + return middleware.blockDataViewSetSource(ctx, block, sources) + } } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index 3198f1053b..3fc93224de 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -1595,7 +1595,8 @@ class Middleware( if (BuildConfig.DEBUG) logRequest(request) val response = service.objectShow(request) if (BuildConfig.DEBUG) logResponse(response) - return response.objectView?.toPayload() ?: throw IllegalStateException("Object view was null") + return response.objectView?.toPayload() + ?: throw IllegalStateException("Object view was null") } @Throws(Exception::class) @@ -1722,17 +1723,34 @@ class Middleware( } @Throws(Exception::class) - fun objectToSet(ctx: String, source: List) : String { + fun objectToSet(ctx: String, source: List): String { val request = Rpc.Object.ToSet.Request( contextId = ctx, source = source ) if (BuildConfig.DEBUG) logRequest(request) val response = service.objectToSet(request) - if(BuildConfig.DEBUG) logResponse(response) + if (BuildConfig.DEBUG) logResponse(response) return response.setId } + @Throws(Exception::class) + fun blockDataViewSetSource( + ctx: Id, + blockId: Id, + sources: List + ): Payload { + val request = Rpc.BlockDataview.SetSource.Request( + contextId = ctx, + blockId = blockId, + source = sources + ) + if (BuildConfig.DEBUG) logRequest(request) + val response = service.blockDataViewSetSource(request) + if (BuildConfig.DEBUG) logResponse(response) + return response.event.toPayload() + } + private fun logRequest(any: Any) { val message = "===> " + any::class.java.canonicalName + ":" + "\n" + any.toString() Timber.d(message) diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt index 205b9659a5..5aedf1b9d6 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt @@ -277,6 +277,9 @@ interface MiddlewareService { @Throws(Exception::class) fun blockDataViewRelationDelete(request: Rpc.BlockDataview.Relation.Delete.Request): Rpc.BlockDataview.Relation.Delete.Response + @Throws(Exception::class) + fun blockDataViewSetSource(request: Rpc.BlockDataview.SetSource.Request): Rpc.BlockDataview.SetSource.Response + //endregion //region TEXT BLOCK commands diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt index b0aafb071b..265400f4ed 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt @@ -1103,4 +1103,16 @@ class MiddlewareServiceImplementation : MiddlewareService { return response } } + + override fun blockDataViewSetSource(request: Rpc.BlockDataview.SetSource.Request): Rpc.BlockDataview.SetSource.Response { + val encoded = + Service.blockDataviewSetSource(Rpc.BlockDataview.SetSource.Request.ADAPTER.encode(request)) + val response = Rpc.BlockDataview.SetSource.Response.ADAPTER.decode(encoded) + val error = response.error + if (error != null && error.code != Rpc.BlockDataview.SetSource.Response.Error.Code.NULL) { + throw Exception(error.description) + } else { + return response + } + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt index 40b4aae979..14245274b9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/listener/ListenerType.kt @@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.presentation.editor.editor.BlockDimensions import com.anytypeio.anytype.presentation.editor.editor.model.BlockView import com.anytypeio.anytype.presentation.relations.DocumentRelationView +import com.anytypeio.anytype.presentation.sets.model.ObjectView sealed interface ListenerType { @@ -65,6 +66,7 @@ sealed interface ListenerType { data class ChangeObjectType(val type: String) : Relation() data class ObjectTypeOpenSet(val type: String) : Relation() data class Featured(val relation: DocumentRelationView) : Relation() + data class SetSource(val sources: List) : Relation() } data class TableOfContentsItem(val target: Id, val item: Id) : ListenerType diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt index 5cdd8493e7..f53b6efff6 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/BlockView.kt @@ -47,6 +47,7 @@ import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_RELATION_FILE import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_RELATION_OBJECT import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_RELATION_PLACEHOLDER +import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_RELATION_SOURCE import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_RELATION_STATUS import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_RELATION_TAGS import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_TABLE @@ -1196,6 +1197,7 @@ sealed class BlockView : ViewType { is DocumentRelationView.Object -> HOLDER_RELATION_OBJECT is DocumentRelationView.File -> HOLDER_RELATION_FILE is DocumentRelationView.ObjectType -> HOLDER_OBJECT_TYPE + is DocumentRelationView.Source -> HOLDER_RELATION_SOURCE } } } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt index b5a61e657f..d0555b7cc3 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/model/types/Types.kt @@ -53,6 +53,7 @@ object Types { const val HOLDER_RELATION_OBJECT = 43 const val HOLDER_RELATION_FILE = 44 const val HOLDER_RELATION_CHECKBOX = 45 + const val HOLDER_RELATION_SOURCE = 58 const val HOLDER_DESCRIPTION = 46 const val HOLDER_FEATURED_RELATION = 47 diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt index c096bcfbe4..53bff3048c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/mapper/MapperExtension.kt @@ -760,14 +760,16 @@ fun Relation.Format.toView() = when (this) { Relation.Format.RELATIONS -> ColumnView.Format.RELATIONS } -fun List.toObjectTypeView(): List = map { oType -> - ObjectTypeView.Item( - id = oType.url, - name = oType.name, - emoji = oType.emoji, - description = oType.description - ) -} +fun List.toObjectTypeView(selectedSources: List = emptyList()): List = + map { oType -> + ObjectTypeView.Item( + id = oType.url, + name = oType.name, + emoji = oType.emoji, + description = oType.description, + isSelected = selectedSources.contains(oType.url) + ) + } fun List.toView(): List = map { layout -> when (layout) { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt index d25e8f1b1f..800f6c80ae 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeChangeViewModel.kt @@ -32,7 +32,8 @@ class ObjectTypeChangeViewModel( fun onStart( smartBlockType: SmartBlockType, excludedTypes: List = emptyList(), - isDraft: Boolean + isDraft: Boolean, + selectedSources: List ) { viewModelScope.launch { getCompatibleObjectTypes.invoke( @@ -44,17 +45,25 @@ class ObjectTypeChangeViewModel( failure = { Timber.e(it, "Error while getting object types") }, success = { types -> if (excludedTypes.isEmpty()) { - setViews(objectTypes = types) + setViews( + objectTypes = types, + selectedSources = selectedSources + ) } else { - setViews(objectTypes = types.filter { t -> !excludedTypes.contains(t.url) }) + setViews( + objectTypes = types.filter { !excludedTypes.contains(it.url) }, + selectedSources = selectedSources + ) } } ) } } - private fun setViews(objectTypes: List) { - views.value = objectTypes.toObjectTypeView() + private fun setViews(objectTypes: List, selectedSources: List) { + views.value = objectTypes + .toObjectTypeView(selectedSources = selectedSources) + .sortedBy { !selectedSources.contains(it.id) } } fun onQueryChanged(input: String) { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeView.kt index 46183d5222..795b71bd4f 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectTypeView.kt @@ -9,7 +9,8 @@ sealed class ObjectTypeView { val id: String, val name: String, val description: String?, - val emoji: String? + val emoji: String?, + val isSelected: Boolean = false ) : ObjectTypeView() object Search : ObjectTypeView() diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt index 336ffc79cf..bd76a37778 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/objects/ObjectWrapperExtensions.kt @@ -15,6 +15,7 @@ import com.anytypeio.anytype.presentation.sets.model.FileView import com.anytypeio.anytype.presentation.sets.model.ObjectView import com.anytypeio.anytype.presentation.sets.model.StatusView import com.anytypeio.anytype.presentation.sets.model.TagView +import com.anytypeio.anytype.presentation.sets.toObjectView import timber.log.Timber fun ObjectWrapper.Basic.values( @@ -261,22 +262,7 @@ fun ObjectWrapper.Basic.objects( ids.forEach { id -> val wrapper = ObjectWrapper.Basic(details[id]?.map ?: return@forEach) - if (wrapper.isDeleted == true) { - result.add(ObjectView.Deleted(id = id)) - } else { - result.add( - ObjectView.Default( - id = id, - name = wrapper.getProperName(), - icon = ObjectIcon.from( - obj = wrapper, - layout = wrapper.layout, - builder = urlBuilder - ), - types = wrapper.type - ) - ) - } + result.add(wrapper.toObjectView(urlBuilder)) } return result } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/DocumentRelationView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/DocumentRelationView.kt index eb9aec6a02..af6e416094 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/DocumentRelationView.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/DocumentRelationView.kt @@ -58,6 +58,14 @@ sealed class DocumentRelationView : DefaultObjectDiffIdentifier { val objects: List ) : DocumentRelationView() + data class Source( + override val relationId: Id, + override val name: String, + override val value: String? = null, + override val isFeatured: Boolean = false, + val sources: List + ) : DocumentRelationView() + data class File( override val relationId: Id, override val name: String, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt index b0a9648045..651e24d39e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/ObjectSetRenderMapper.kt @@ -59,6 +59,7 @@ import com.anytypeio.anytype.presentation.sets.model.StatusView import com.anytypeio.anytype.presentation.sets.model.TagView import com.anytypeio.anytype.presentation.sets.model.Viewer import com.anytypeio.anytype.presentation.sets.model.ViewerTabView +import com.anytypeio.anytype.presentation.sets.toObjectView import timber.log.Timber @@ -517,21 +518,8 @@ fun Relation.toObjects( val list = arrayListOf() ids.forEach { id -> val wrapper = ObjectWrapper.Basic(details[id]?.map ?: emptyMap()) - if (wrapper.isDeleted == true) { - list.add(ObjectView.Deleted(id = id)) - } else { - list.add( - ObjectView.Default( - id = id, - name = wrapper.getProperName(), - icon = ObjectIcon.from( - obj = wrapper, - layout = wrapper.layout, - builder = urlBuilder - ), - types = wrapper.type - ) - ) + if (!wrapper.isEmpty()) { + list.add(wrapper.toObjectView(urlBuilder)) } } list diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt index 30df8e3b3d..9b3637993b 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt @@ -1,6 +1,7 @@ package com.anytypeio.anytype.presentation.sets import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.SmartBlockType sealed class ObjectSetCommand { @@ -77,6 +78,11 @@ sealed class ObjectSetCommand { data class OpenCoverActionMenu( val ctx: Id ) : Modal() + + data class OpenSelectSourceScreen( + val smartBlockType: SmartBlockType, + val sources: List + ) : Modal() } sealed class Intent : ObjectSetCommand() { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt index f6ab14716e..0aca2404ad 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetExtension.kt @@ -3,9 +3,12 @@ package com.anytypeio.anytype.presentation.sets import com.anytypeio.anytype.core_models.* import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.presentation.editor.editor.model.BlockView +import com.anytypeio.anytype.presentation.objects.ObjectIcon +import com.anytypeio.anytype.presentation.objects.getProperName import com.anytypeio.anytype.presentation.relations.DocumentRelationView import com.anytypeio.anytype.presentation.relations.ObjectSetConfig.ID_KEY import com.anytypeio.anytype.presentation.relations.view +import com.anytypeio.anytype.presentation.sets.model.ObjectView import com.anytypeio.anytype.presentation.sets.model.SimpleRelationView fun ObjectSet.updateRecord( @@ -27,7 +30,7 @@ fun ObjectSet.updateRecord( fun ObjectSet.featuredRelations( ctx: Id, urlBuilder: UrlBuilder -) : BlockView.FeaturedRelation? { +): BlockView.FeaturedRelation? { val block = blocks.find { it.content is Block.Content.FeaturedRelations } if (block != null) { val views = mutableListOf() @@ -72,6 +75,22 @@ private fun mapFeaturedRelations( null } } + Relations.SET_OF -> { + val objectSet = ObjectWrapper.Basic(details.details[ctx]?.map.orEmpty()) + val sources = mutableListOf() + objectSet.setOf.forEach { objectTypeId -> + val wrapper = ObjectWrapper.Basic(details.details[objectTypeId]?.map.orEmpty()) + if (!wrapper.isEmpty()) { + sources.add(wrapper.toObjectView(urlBuilder = urlBuilder)) + } + } + DocumentRelationView.Source( + relationId = id, + name = Relations.RELATION_NAME_EMPTY, + isFeatured = true, + sources = sources + ) + } else -> { val relation = relations.firstOrNull { it.key == id } relation?.view( @@ -121,4 +140,18 @@ fun DV.getRelation(relationKey: Id): Relation? = relations.firstOrNull { it.key fun DV.isRelationReadOnly(relationKey: Id): Boolean { val relation = getRelation(relationKey) return relation != null && relation.isReadOnly +} + +fun ObjectWrapper.Basic.toObjectView(urlBuilder: UrlBuilder): ObjectView = when (isDeleted) { + true -> ObjectView.Deleted(id) + else -> ObjectView.Default( + id = id, + name = getProperName(), + icon = ObjectIcon.from( + obj = this, + layout = layout, + builder = urlBuilder + ), + types = type + ) } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetReducer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetReducer.kt index 7ad9d0e717..b3240081fb 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetReducer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetReducer.kt @@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.Event import com.anytypeio.anytype.core_models.Event.Command import com.anytypeio.anytype.core_models.ext.amend import com.anytypeio.anytype.core_models.ext.unset +import com.anytypeio.anytype.core_utils.ext.replace import com.anytypeio.anytype.presentation.extension.updateFields import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableSharedFlow @@ -176,6 +177,19 @@ class ObjectSetReducer { ) ) } + is Command.UpdateStructure -> { + state.copy( + blocks = state.blocks.replace( + replacement = { target -> target.copy(children = event.children) }, + target = { block -> block.id == event.id } + ) + ) + } + is Command.AddBlock -> { + state.copy( + blocks = state.blocks + event.blocks + ) + } else -> { Timber.d("Ignoring event: $event") state.copy() diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt index a3014200b7..b487c0a83f 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt @@ -19,6 +19,7 @@ import com.anytypeio.anytype.core_models.ObjectWrapper import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.SmartBlockType import com.anytypeio.anytype.core_models.SyncStatus import com.anytypeio.anytype.core_models.ext.content import com.anytypeio.anytype.core_models.ext.title @@ -27,6 +28,7 @@ import com.anytypeio.anytype.core_utils.common.EventWrapper import com.anytypeio.anytype.domain.base.Result import com.anytypeio.anytype.domain.block.interactor.UpdateText import com.anytypeio.anytype.domain.cover.SetDocCoverImage +import com.anytypeio.anytype.domain.dataview.SetDataViewSource import com.anytypeio.anytype.domain.dataview.interactor.AddNewRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewRecord import com.anytypeio.anytype.domain.dataview.interactor.SetActiveViewer @@ -44,6 +46,7 @@ import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage import com.anytypeio.anytype.presentation.common.Action import com.anytypeio.anytype.presentation.common.Delegator import com.anytypeio.anytype.presentation.editor.editor.Proxy +import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType import com.anytypeio.anytype.presentation.editor.editor.model.BlockView import com.anytypeio.anytype.presentation.editor.model.TextUpdate import com.anytypeio.anytype.presentation.extension.sendAnalyticsObjectCreateEvent @@ -100,7 +103,8 @@ class ObjectSetViewModel( private val session: ObjectSetSession, private val analytics: Analytics, private val getTemplates: GetTemplates, - private val createNewObject: CreateNewObject + private val createNewObject: CreateNewObject, + private val setDataViewSource: SetDataViewSource ) : ViewModel(), SupportNavigation> { val status = MutableStateFlow(SyncStatus.UNKNOWN) @@ -1028,7 +1032,12 @@ class ObjectSetViewModel( error.value = DATA_VIEW_NOT_FOUND_ERROR } } else { - error.value = OBJECT_SET_HAS_EMPTY_SOURCE_ERROR + dispatch( + ObjectSetCommand.Modal.OpenSelectSourceScreen( + sources = emptyList(), + smartBlockType = SmartBlockType.PAGE + ) + ) } } @@ -1195,11 +1204,39 @@ class ObjectSetViewModel( } } + fun onClickListener(clicked: ListenerType) { + Timber.d("onClickListener, clicked:[$clicked]") + when (clicked) { + is ListenerType.Relation.SetSource -> { + val sources = clicked.sources.map { it.id } + dispatch( + ObjectSetCommand.Modal.OpenSelectSourceScreen( + sources = sources, + smartBlockType = SmartBlockType.PAGE + ) + ) + } + else -> {} + } + } + + fun onDataViewSourcePicked(source: Id) { + viewModelScope.launch { + val params = SetDataViewSource.Params( + ctx = context, + sources = listOf(source) + ) + setDataViewSource(params).proceed( + failure = { e -> Timber.e(e, "Error while setting Set source") }, + success = { payload -> defaultPayloadConsumer(payload) } + ) + } + } + companion object { const val TITLE_CHANNEL_DISPATCH_DELAY = 300L const val NOT_ALLOWED = "Not allowed for this set" const val NOT_ALLOWED_CELL = "Not allowed for this cell" - const val OBJECT_TYPE_UNKNOWN = "Can't open object, object type unknown" const val DATA_VIEW_HAS_NO_VIEW_MSG = "Data view has no view." const val DATA_VIEW_NOT_FOUND_ERROR = "Content missing for this set. Please, try again later." diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt index 4282813c5e..ddaefe0bf0 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModelFactory.kt @@ -6,6 +6,7 @@ import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.domain.block.interactor.UpdateText import com.anytypeio.anytype.domain.cover.SetDocCoverImage +import com.anytypeio.anytype.domain.dataview.SetDataViewSource import com.anytypeio.anytype.domain.dataview.interactor.AddNewRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewRecord import com.anytypeio.anytype.domain.dataview.interactor.SetActiveViewer @@ -44,7 +45,8 @@ class ObjectSetViewModelFactory( private val session: ObjectSetSession, private val analytics: Analytics, private val getTemplates: GetTemplates, - private val createNewObject: CreateNewObject + private val createNewObject: CreateNewObject, + private val setDataViewSource: SetDataViewSource ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { @@ -69,7 +71,8 @@ class ObjectSetViewModelFactory( session = session, analytics = analytics, getTemplates = getTemplates, - createNewObject = createNewObject + createNewObject = createNewObject, + setDataViewSource = setDataViewSource ) as T } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt index d235c7a39c..fcb87fbd22 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/SetsExtension.kt @@ -223,40 +223,14 @@ fun Map.buildObjectViews( val value = this.getOrDefault(columnKey, null) if (value is Id) { val wrapper = ObjectWrapper.Basic(details[value]?.map ?: emptyMap()) - if (wrapper.isDeleted == true) { - objects.add(ObjectView.Deleted(id = value)) - } else { - objects.add( - ObjectView.Default( - id = value, - name = wrapper.getProperName(), - icon = ObjectIcon.from( - obj = wrapper, - layout = wrapper.layout, - builder = builder - ), - types = wrapper.type - ) - ) + if (!wrapper.isEmpty()) { + objects.add(wrapper.toObjectView(urlBuilder = builder)) } } else if (value is List<*>) { value.typeOf().forEach { id -> val wrapper = ObjectWrapper.Basic(details[id]?.map ?: emptyMap()) - if (wrapper.isDeleted == true) { - objects.add(ObjectView.Deleted(id = id)) - } else { - objects.add( - ObjectView.Default( - id = id, - name = wrapper.getProperName(), - icon = ObjectIcon.from( - obj = wrapper, - layout = wrapper.layout, - builder = builder - ), - types = wrapper.type - ) - ) + if (!wrapper.isEmpty()) { + objects.add(wrapper.toObjectView(urlBuilder = builder)) } } } diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt index 69ca08288d..76041d8719 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt @@ -15,6 +15,7 @@ import com.anytypeio.anytype.domain.base.Result import com.anytypeio.anytype.domain.block.interactor.UpdateText import com.anytypeio.anytype.domain.config.Gateway import com.anytypeio.anytype.domain.cover.SetDocCoverImage +import com.anytypeio.anytype.domain.dataview.SetDataViewSource import com.anytypeio.anytype.domain.dataview.interactor.AddNewRelationToDataView import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewRecord import com.anytypeio.anytype.domain.dataview.interactor.SetActiveViewer @@ -96,6 +97,9 @@ open class ObjectSetViewModelTestSetup { @Mock lateinit var createNewObject: CreateNewObject + @Mock + lateinit var setDataViewSource: SetDataViewSource + val dispatcher = Dispatcher.Default() val delegator = Delegator.Default() val reducer = ObjectSetReducer() @@ -126,7 +130,8 @@ open class ObjectSetViewModelTestSetup { downloadUnsplashImage = downloadUnsplashImage, setDocCoverImage = setDocCoverImage, getTemplates = getTemplates, - createNewObject = createNewObject + createNewObject = createNewObject, + setDataViewSource = setDataViewSource ) fun stubInterceptEvents( diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetZeroDataViewTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetZeroDataViewTest.kt index 2b71e246a0..751bcf5362 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetZeroDataViewTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetZeroDataViewTest.kt @@ -45,36 +45,6 @@ class ObjectSetZeroDataViewTest : ObjectSetViewModelTestSetup() { MockitoAnnotations.openMocks(this) } - @Test - fun `should show empty-source error`() { - - // SETUP - - stubInterceptEvents() - stubOpenObjectSet( - doc = listOf( - header, - title - ) - ) - - val vm = givenViewModel() - - // TESTING - - assertEquals( - expected = null, - actual = vm.error.value - ) - - vm.onStart(root) - - assertEquals( - expected = ObjectSetViewModel.OBJECT_SET_HAS_EMPTY_SOURCE_ERROR, - actual = vm.error.value - ) - } - @Test fun `should show no-content error because of missing dv`() {