mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-417 Set | Empty source state (#2583)
* DROID-417 legacy * DROID-417 icon text widget refactoring * DROID-417 update icon widget * DROID-417 relation holder source * DROID-417 render source as featured relation * DROID-417 blockDataViewSetSource command * DROID-417 blockDataViewSetSource command, data + middle layer * DROID-417 use case + di * DROID-417 source set + render no source state * DROID-417 type change screen, update title * DROID-417 clicks + command * DROID-417 add event updateStructure and addBlock to set events reducer * DROID-417 add clicks on set source relations * DROID-417 start select source screen * DROID-417 header + divider visibility * DROID-417 icon replace * DROID-417 button new update * DROID-417 move featured relation subscription to onStart * DROID-417 fix tests * DROID-417 design + clicks * DROID-417 code style * DROID-417 holder source * DROID-417 add extension mapping to object view * DROID-417 add is selected state for object type view * DROID-417 sort types by selected * DROID-417 pr fix * DROID-417 rename view * DROID-417 pr fix * DROID-417 do not map empty objects * DROID-417 ci * DROID-417 ci * DROID-417 ci off Co-authored-by: konstantiniiv <ki@anytype.io>
This commit is contained in:
parent
e4363820b0
commit
a2a979a5ce
53 changed files with 517 additions and 401 deletions
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Action> = Delegator.Default()
|
||||
fun provideDelegator(): Delegator<Action> = Delegator.Default()
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
|
@ -307,7 +317,7 @@ object ObjectSetModule {
|
|||
@PerScreen
|
||||
fun provideDataViewObjectRelationProvider(
|
||||
state: StateFlow<ObjectSet>
|
||||
) : ObjectRelationProvider = DataViewObjectRelationProvider(state)
|
||||
): ObjectRelationProvider = DataViewObjectRelationProvider(state)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
|
@ -315,14 +325,14 @@ object ObjectSetModule {
|
|||
fun provideDataViewObjectValueProvider(
|
||||
state: StateFlow<ObjectSet>,
|
||||
session: ObjectSetSession
|
||||
) : ObjectValueProvider = DataViewObjectValueProvider(state, session)
|
||||
): ObjectValueProvider = DataViewObjectValueProvider(state, session)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideObjectTypeProvider(
|
||||
state: StateFlow<ObjectSet>,
|
||||
) : ObjectTypeProvider = object : ObjectTypeProvider {
|
||||
): ObjectTypeProvider = object : ObjectTypeProvider {
|
||||
override fun provide(): List<ObjectType> = state.value.objectTypes
|
||||
}
|
||||
|
||||
|
@ -331,7 +341,7 @@ object ObjectSetModule {
|
|||
@PerScreen
|
||||
fun provideObjectDetailProvider(
|
||||
state: StateFlow<ObjectSet>,
|
||||
) : ObjectDetailProvider = object : ObjectDetailProvider {
|
||||
): ObjectDetailProvider = object : ObjectDetailProvider {
|
||||
override fun provide(): Map<Id, Block.Fields> = state.value.details
|
||||
}
|
||||
|
||||
|
@ -340,7 +350,7 @@ object ObjectSetModule {
|
|||
@PerScreen
|
||||
fun provideUpdateDetailUseCase(
|
||||
repository: BlockRepository
|
||||
) : UpdateDetail = UpdateDetail(repository)
|
||||
): UpdateDetail = UpdateDetail(repository)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
|
|
|
@ -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<Boolean>(OBJECT_IS_DRAFT_KEY) ?: false
|
||||
|
||||
private val isSetSource: Boolean get() = argOrNull<Boolean>(ARG_IS_SET_SOURCE) ?: false
|
||||
|
||||
private val selectedSources : List<Id>
|
||||
get() = argOrNull<List<Id>>(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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
10
app/src/main/res/drawable/ic_plus_white_12.xml
Normal file
10
app/src/main/res/drawable/ic_plus_white_12.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12dp"
|
||||
android:height="12dp"
|
||||
android:viewportWidth="12"
|
||||
android:viewportHeight="12">
|
||||
<path
|
||||
android:pathData="M5.999,0C5.644,0 5.356,0.288 5.356,0.643V5.356H0.643C0.288,5.356 0,5.644 0,5.999C0,6.354 0.288,6.642 0.643,6.642H5.356V11.357C5.356,11.712 5.644,12 5.999,12C6.354,12 6.642,11.712 6.642,11.357V6.642H11.357C11.712,6.642 12,6.354 12,5.999C12,5.644 11.712,5.356 11.357,5.356H6.642V0.643C6.642,0.288 6.354,0 5.999,0Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -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" />
|
||||
|
||||
|
||||
<include
|
||||
android:id="@+id/gridContainer"
|
||||
layout="@layout/item_viewer_container"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
android:background="@drawable/dragger" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTitle"
|
||||
style="@style/ModalTitleStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -3,53 +3,62 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/dataViewToolbar"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp">
|
||||
android:layout_height="56dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/switchViewContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCurrentViewerName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_weight="01"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_weight="01"
|
||||
android:drawablePadding="2dp"
|
||||
android:fontFamily="@font/inter_semibold"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="17sp"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
app:drawableEndCompat="@drawable/ic_arrow_expand_dv_viewer"
|
||||
tools:text="All Pages" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:id="@+id/customizeViewButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/content_description_customize_view_button"
|
||||
android:src="@drawable/ic_dv_customize_view" />
|
||||
|
||||
<ImageView
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
<TextView
|
||||
android:id="@+id/addNewButton"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_add_new_object_to_set" />
|
||||
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" />
|
||||
|
||||
</LinearLayout>
|
|
@ -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" />
|
||||
<Constraint
|
||||
android:id="@+id/controlDivider2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/data_view_divider_height"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/dataViewHeader"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/paginatorToolbar"
|
||||
android:layout_width="0dp"
|
||||
|
@ -85,7 +94,16 @@
|
|||
android:layout_height="@dimen/default_toolbar_height"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/topToolbar" />
|
||||
motion:layout_constraintTop_toBottomOf="@+id/topToolbar"
|
||||
motion:visibilityMode="ignore"/>
|
||||
<Constraint
|
||||
android:id="@+id/controlDivider2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/data_view_divider_height"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/dataViewHeader"
|
||||
motion:visibilityMode="ignore"/>
|
||||
<Constraint
|
||||
android:id="@+id/paginatorToolbar"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -15,6 +15,11 @@ class ObjectTypeHolder(
|
|||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: ObjectTypeView.Item) = with(binding) {
|
||||
if (item.isSelected) {
|
||||
icSelected.visible()
|
||||
} else {
|
||||
icSelected.gone()
|
||||
}
|
||||
ivIcon.setIcon(
|
||||
emoji = item.emoji,
|
||||
image = null,
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
package com.anytypeio.anytype.core_ui.features.relations
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
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.features.relations.holders.FeaturedRelationViewHolder
|
||||
import com.anytypeio.anytype.presentation.relations.DocumentRelationView
|
||||
|
||||
class FeaturedRelationAdapter(
|
||||
private var items: List<DocumentRelationView> = emptyList()
|
||||
): RecyclerView.Adapter<FeaturedRelationViewHolder>() {
|
||||
|
||||
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<DocumentRelationView>) {
|
||||
this.items = items
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
8
core-ui/src/main/res/drawable/bg_set_new_button.xml
Normal file
8
core-ui/src/main/res/drawable/bg_set_new_button.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/amber_100" />
|
||||
<corners android:radius="@dimen/dp_6" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
10
core-ui/src/main/res/drawable/ic_check_black_14.xml
Normal file
10
core-ui/src/main/res/drawable/ic_check_black_14.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:pathData="M13.633,1.403L6.131,13.191L0.47,7.53L1.53,6.47L5.869,10.809L12.367,0.597L13.633,1.403Z"
|
||||
android:fillColor="@color/glyph_selected"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -4,19 +4,7 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,6L20,6A1,1 0,0 1,21 7L21,7A1,1 0,0 1,20 8L4,8A1,1 0,0 1,3 7L3,7A1,1 0,0 1,4 6z"
|
||||
android:fillColor="@color/glyph_active" />
|
||||
<path
|
||||
android:pathData="M17.25,7C17.25,8.1046 16.3546,9 15.25,9C14.1454,9 13.25,8.1046 13.25,7C13.25,5.8954 14.1454,5 15.25,5C16.3546,5 17.25,5.8954 17.25,7Z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="@color/background_primary"
|
||||
android:strokeColor="@color/glyph_active" />
|
||||
<path
|
||||
android:pathData="M4,16L20,16A1,1 0,0 1,21 17L21,17A1,1 0,0 1,20 18L4,18A1,1 0,0 1,3 17L3,17A1,1 0,0 1,4 16z"
|
||||
android:fillColor="@color/glyph_active" />
|
||||
<path
|
||||
android:pathData="M9.25,17m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="@color/background_primary"
|
||||
android:strokeColor="@color/glyph_active" />
|
||||
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" />
|
||||
</vector>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="17dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="17">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M7,0.75h2v16h-2z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M16,7.75l-0,2l-16,0l-0,-2z" />
|
||||
</vector>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
tools:text="Anytype"
|
||||
android:id="@+id/tvFeaturedRelationValue"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/featuredRelationStatusContainer"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"/>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/featuredRelationTagContainer"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"/>
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.ObjectIconWidget
|
||||
android:id="@+id/ivIcon"
|
||||
|
@ -26,13 +26,15 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:hint="@string/untitled"
|
||||
android:textColorHint="@color/text_tertiary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/tvSubtitle"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ic_selected"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ivIcon"
|
||||
app:layout_constraintTop_toTopOf="@+id/ivIcon"
|
||||
app:layout_goneMarginEnd="0dp"
|
||||
tools:text="File" />
|
||||
|
||||
<TextView
|
||||
|
@ -41,14 +43,16 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ivIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ic_selected"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ivIcon"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
|
||||
app:layout_goneMarginEnd="0dp"
|
||||
tools:text="Just start writing with a plain text" />
|
||||
|
||||
<View
|
||||
|
@ -61,4 +65,14 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ic_selected"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_check_black_14"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -7,19 +7,26 @@
|
|||
|
||||
<com.anytypeio.anytype.core_ui.widgets.ObjectIconWidget
|
||||
android:id="@+id/objectIcon"
|
||||
style="@style/ObjectIcon15Style"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
style="@style/ObjectIcon15Style"
|
||||
android:layout_gravity="center_vertical" />
|
||||
android:layout_gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/objectName"
|
||||
style="@style/GridCellDateTextStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="@color/black"
|
||||
app:layout_goneMarginStart="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/objectIcon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Feature" />
|
||||
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -180,6 +180,7 @@
|
|||
|
||||
<color name="dashboard_tab_color">#CC0066C3</color>
|
||||
<color name="amber_80">#FFC532</color>
|
||||
<color name="amber_100">#FFB522</color>
|
||||
<color name="table_row_header_background">#1A50491C</color>
|
||||
<color name="object_loading_state_gradient_start_color">@color/shape_tertiary</color>
|
||||
<color name="object_loading_state_gradient_end_color">#F1F0ED</color>
|
||||
|
|
|
@ -301,4 +301,6 @@
|
|||
|
||||
<dimen name="block_text_markup_underline_height">0.5dp</dimen>
|
||||
|
||||
<dimen name="featured_relations_text_size">13sp</dimen>
|
||||
|
||||
</resources>
|
|
@ -443,6 +443,8 @@
|
|||
<string name="select_tags">Select tags</string>
|
||||
<string name="select_status">Select status</string>
|
||||
<string name="select_objects">Select objects</string>
|
||||
<string name="source">Source</string>
|
||||
<string name="select_source">Select source</string>
|
||||
<string name="objects">Objects</string>
|
||||
<string name="web_pages">Web pages</string>
|
||||
<string name="select_files">Select files</string>
|
||||
|
|
|
@ -629,4 +629,12 @@ class BlockDataRepository(
|
|||
override suspend fun objectToSet(ctx: Id, source: List<String>): Id {
|
||||
return remote.objectToSet(ctx, source)
|
||||
}
|
||||
|
||||
override suspend fun blockDataViewSetSource(
|
||||
ctx: Id,
|
||||
block: Id,
|
||||
sources: List<Id>
|
||||
): Payload {
|
||||
return remote.blockDataViewSetSource(ctx, block, sources)
|
||||
}
|
||||
}
|
|
@ -255,4 +255,6 @@ interface BlockDataStore {
|
|||
suspend fun fillTableRow(ctx: String, targetIds: List<String>): Payload
|
||||
|
||||
suspend fun objectToSet(ctx: Id, source: List<String>): Id
|
||||
|
||||
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
|
||||
}
|
|
@ -254,4 +254,6 @@ interface BlockRemote {
|
|||
suspend fun fillTableRow(ctx: String, targetIds: List<String>): Payload
|
||||
|
||||
suspend fun objectToSet(ctx: Id, source: List<String>): Id
|
||||
|
||||
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
|
||||
}
|
|
@ -545,4 +545,12 @@ class BlockRemoteDataStore(private val remote: BlockRemote) : BlockDataStore {
|
|||
override suspend fun objectToSet(ctx: Id, source: List<String>): Id {
|
||||
return remote.objectToSet(ctx, source)
|
||||
}
|
||||
|
||||
override suspend fun blockDataViewSetSource(
|
||||
ctx: Id,
|
||||
block: Id,
|
||||
sources: List<Id>
|
||||
): Payload {
|
||||
return remote.blockDataViewSetSource(ctx, block, sources)
|
||||
}
|
||||
}
|
|
@ -318,4 +318,6 @@ interface BlockRepository {
|
|||
suspend fun fillTableRow(ctx: String, targetIds: List<String>): Payload
|
||||
|
||||
suspend fun objectToSet(ctx: Id, source: List<String>): Id
|
||||
|
||||
suspend fun blockDataViewSetSource(ctx: Id, block: Id, sources: List<String>): Payload
|
||||
}
|
|
@ -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<Payload, SetDataViewSource.Params>() {
|
||||
|
||||
override suspend fun run(params: Params): Either<Throwable, Payload> = 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<Id>
|
||||
)
|
||||
}
|
|
@ -584,4 +584,12 @@ class BlockMiddleware(
|
|||
override suspend fun objectToSet(ctx: Id, source: List<String>): Id {
|
||||
return middleware.objectToSet(ctx, source)
|
||||
}
|
||||
|
||||
override suspend fun blockDataViewSetSource(
|
||||
ctx: Id,
|
||||
block: Id,
|
||||
sources: List<Id>
|
||||
): Payload {
|
||||
return middleware.blockDataViewSetSource(ctx, block, sources)
|
||||
}
|
||||
}
|
|
@ -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>) : String {
|
||||
fun objectToSet(ctx: String, source: List<String>): 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<Id>
|
||||
): 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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<ObjectView>) : Relation()
|
||||
}
|
||||
|
||||
data class TableOfContentsItem(val target: Id, val item: Id) : ListenerType
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -760,14 +760,16 @@ fun Relation.Format.toView() = when (this) {
|
|||
Relation.Format.RELATIONS -> ColumnView.Format.RELATIONS
|
||||
}
|
||||
|
||||
fun List<ObjectType>.toObjectTypeView(): List<ObjectTypeView.Item> = map { oType ->
|
||||
ObjectTypeView.Item(
|
||||
id = oType.url,
|
||||
name = oType.name,
|
||||
emoji = oType.emoji,
|
||||
description = oType.description
|
||||
)
|
||||
}
|
||||
fun List<ObjectType>.toObjectTypeView(selectedSources: List<Id> = emptyList()): List<ObjectTypeView.Item> =
|
||||
map { oType ->
|
||||
ObjectTypeView.Item(
|
||||
id = oType.url,
|
||||
name = oType.name,
|
||||
emoji = oType.emoji,
|
||||
description = oType.description,
|
||||
isSelected = selectedSources.contains(oType.url)
|
||||
)
|
||||
}
|
||||
|
||||
fun List<ObjectType.Layout>.toView(): List<ObjectLayoutView> = map { layout ->
|
||||
when (layout) {
|
||||
|
|
|
@ -32,7 +32,8 @@ class ObjectTypeChangeViewModel(
|
|||
fun onStart(
|
||||
smartBlockType: SmartBlockType,
|
||||
excludedTypes: List<Id> = emptyList(),
|
||||
isDraft: Boolean
|
||||
isDraft: Boolean,
|
||||
selectedSources: List<Id>
|
||||
) {
|
||||
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<ObjectType>) {
|
||||
views.value = objectTypes.toObjectTypeView()
|
||||
private fun setViews(objectTypes: List<ObjectType>, selectedSources: List<Id>) {
|
||||
views.value = objectTypes
|
||||
.toObjectTypeView(selectedSources = selectedSources)
|
||||
.sortedBy { !selectedSources.contains(it.id) }
|
||||
}
|
||||
|
||||
fun onQueryChanged(input: String) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -58,6 +58,14 @@ sealed class DocumentRelationView : DefaultObjectDiffIdentifier {
|
|||
val objects: List<ObjectView>
|
||||
) : 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<ObjectView>
|
||||
) : DocumentRelationView()
|
||||
|
||||
data class File(
|
||||
override val relationId: Id,
|
||||
override val name: String,
|
||||
|
|
|
@ -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<ObjectView>()
|
||||
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
|
||||
|
|
|
@ -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<Id>
|
||||
) : Modal()
|
||||
}
|
||||
|
||||
sealed class Intent : ObjectSetCommand() {
|
||||
|
|
|
@ -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<DocumentRelationView>()
|
||||
|
@ -72,6 +75,22 @@ private fun mapFeaturedRelations(
|
|||
null
|
||||
}
|
||||
}
|
||||
Relations.SET_OF -> {
|
||||
val objectSet = ObjectWrapper.Basic(details.details[ctx]?.map.orEmpty())
|
||||
val sources = mutableListOf<ObjectView>()
|
||||
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
|
||||
)
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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<EventWrapper<AppNavigation.Command>> {
|
||||
|
||||
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."
|
||||
|
|
|
@ -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 <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
|
@ -69,7 +71,8 @@ class ObjectSetViewModelFactory(
|
|||
session = session,
|
||||
analytics = analytics,
|
||||
getTemplates = getTemplates,
|
||||
createNewObject = createNewObject
|
||||
createNewObject = createNewObject,
|
||||
setDataViewSource = setDataViewSource
|
||||
) as T
|
||||
}
|
||||
}
|
|
@ -223,40 +223,14 @@ fun Map<String, Any?>.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<Id>().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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Payload>()
|
||||
val delegator = Delegator.Default<Action>()
|
||||
val reducer = ObjectSetReducer()
|
||||
|
@ -126,7 +130,8 @@ open class ObjectSetViewModelTestSetup {
|
|||
downloadUnsplashImage = downloadUnsplashImage,
|
||||
setDocCoverImage = setDocCoverImage,
|
||||
getTemplates = getTemplates,
|
||||
createNewObject = createNewObject
|
||||
createNewObject = createNewObject,
|
||||
setDataViewSource = setDataViewSource
|
||||
)
|
||||
|
||||
fun stubInterceptEvents(
|
||||
|
|
|
@ -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`() {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue