anytype-kotlin-wild/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationAddBaseFragment.kt
Evgenii Kozlov 36fe52e5ad
DROID-607 Relations & types and options | Refactoring | Everything-is-an-object refactoring (#2720)
* DROID-439 App | Relations refactoring, use SearchObjects for object types (#2592)
* DROID-446 Objects | Enhancement | Store relation links and process its updates (#2597)
* DROID-456 Tech | Remove deprecated API for creating object types (#2601)
* DROID-455 Object types | Enhancement Get object type list from ObjectSearch on Global search screen (#2602)
* DROID-459 Sets | Refactoring | Use relations links instead of relations for building search params to get data view data (#2603)
* DROID-458 Objects | Refactoring | Integrate new api for creating objets (#2604)
* DROID-464 Relations | Refactoring | New API for creating a relation from scratch - for data view or for an object (#2605)
* DROID-467 Relations | Refactoring | New API for creating options - for tags and statuses (#2607)
* DROID-470 Relations | Refactoring | New API for removing any relation from an object or from a data view (#2608)
* DROID-460 Tech | Object relations list (#2610)
* DROID-486 Sets | Refactoring | Displaying and controlling visibility of data view relations (#2611)
* DROID-500 Relations | Refactoring | Extend API of ObjectStore to be able to get a relation by its id (#2619)
* DROID-459 Sets | Fix | Get relations from store by id and not by key (#2618)
* DROID-489 Tech | Relations as object, add relationKey to relation connected screens (#2622)
* DROID-490 Sets | Refactoring | Displaying relation values for current object in bottom sheet cells (#2629)
* DROID-505 Relations | Refactoring | New interface for relations store (#2633)
* DROID-509 Relations | Refactoring | Bind new relations store with subscription container (#2635)
* DROID-507 Tech | MW , migration + relation links (#2636)
* DROID-507 Tech | MW , migration + relation links, fixes (#2637)
* DROID-517 Sets | Fix | Provide correct keys for data view search-and-subscribe query (#2641)
* DROID-409 Relations | Refactoring | Use relation key instead of id when creating new relation (#2642)
* DROID-521 Sets & Objects | Refactoring | Add relation to a data view or to an object from existing relations (#2644)
* DROID-522 Relations | Refactoring | Add objects to relations with object format (#2645)
* DROID-523 Object types | Refactoring | Implement global store for object types (#2646)
* DROID-527 Object types | Refactoring | Integrate global store for object types (#2647)
* DROID-531 Relations | Refactoring | Parse tag and status relations values (#2649)
* DROID-535 Tech | Integrate new MW lib with migration fixes (#2653)
* DROID-535 Tech | MW integration fixes (#2660)
* DROID-559 Relations | Refactoring | Parse tag and status values in editor (#2662)
* DROID-560 Relations | Refactoring | Integrate new lib with fixes (#2663)
* DROID-561 Relations | Refactoring | Parsing tag and status values in dv (#2665)
* DROID-562 Dashboard | Refactoring | Use store of object types as object type provider for favorites tab on dashboard (#2667)
* DROID-567 Relations | Refactoring | Suggest available options to populate a relation (#2671)
* DROID-604 Relations | Refactoring | Use details from Object.CreateRelation.Response to populate relation store (#2705)
* DROID-603 Relations | Refactoring | Creating relation options + Deleting relation from object (#2706)
* DROID-619 Relations | Refactoring | Migrate data view sorts and filters to the new relation-as-object paradigm (#2711)
* DROID-622 Relations | Tech | Update MW to 0.24.0-rc1 (#2714)
* DROID-598 Sets | Refactoring | Provide relation format for date filters (#2715)
* DROID-625 Protocol | Enhancement | Integrate v0.24.0-rc2 (#2718)
2022-11-24 18:11:19 +03:00

283 lines
10 KiB
Kotlin

package com.anytypeio.anytype.ui.relations
import android.content.res.Resources
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.FrameLayout
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.anytypeio.anytype.R
import com.anytypeio.anytype.analytics.base.EventsDictionary
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_ui.features.relations.RelationAddAdapter
import com.anytypeio.anytype.core_ui.features.relations.RelationAddHeaderAdapter
import com.anytypeio.anytype.core_ui.reactive.focusChanges
import com.anytypeio.anytype.core_ui.reactive.textChanges
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.drawable
import com.anytypeio.anytype.core_utils.ext.invisible
import com.anytypeio.anytype.core_utils.ext.statusBarHeight
import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetTextInputFragment
import com.anytypeio.anytype.databinding.FragmentRelationAddBinding
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.relations.RelationAddToDataViewViewModel
import com.anytypeio.anytype.presentation.relations.RelationAddToObjectViewModel
import com.anytypeio.anytype.presentation.relations.RelationAddViewModelBase
import com.anytypeio.anytype.presentation.relations.model.RelationView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import java.io.Serializable
import javax.inject.Inject
abstract class RelationAddBaseFragment : BaseBottomSheetTextInputFragment<FragmentRelationAddBinding>() {
abstract val vm: RelationAddViewModelBase
override val textInput: EditText get() = binding.searchBar.root.findViewById(R.id.filterInputField)
abstract val ctx: String
private lateinit var searchRelationInput: EditText
lateinit var clearSearchText: View
protected val createFromScratchAdapter = RelationAddHeaderAdapter {
onCreateFromScratchClicked()
}
private val relationAdapter = RelationAddAdapter { relation ->
onRelationSelected(ctx = ctx, relation = relation)
}
private val concatAdapter = ConcatAdapter(createFromScratchAdapter, relationAdapter)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
searchRelationInput = binding.searchBar.root.findViewById(R.id.filterInputField)
searchRelationInput.apply {
hint = getString(R.string.find_a_relation)
}
clearSearchText = binding.searchBar.root.findViewById(R.id.clearSearchText)
clearSearchText.setOnClickListener {
searchRelationInput.setText("")
clearSearchText.invisible()
}
setupFullHeight()
binding.relationAddRecycler.apply {
layoutManager = LinearLayoutManager(context)
adapter = concatAdapter
addItemDecoration(
DividerItemDecoration(context, DividerItemDecoration.VERTICAL).apply {
setDrawable(drawable(R.drawable.divider_relations_with_padding))
}
)
}
with(lifecycleScope) {
subscribe(searchRelationInput.focusChanges()) { hasFocus -> if (hasFocus) expand(view) }
subscribe(searchRelationInput.textChanges()) {
createFromScratchAdapter.query = it.toString()
vm.onQueryChanged(it.toString())
}
subscribe(vm.results) { relationAdapter.submitList(it) }
subscribe(vm.isDismissed) { isDismissed -> if (isDismissed) dismiss() }
subscribe(vm.toasts) { toast(it) }
subscribe(searchRelationInput.textChanges()) {
if (it.isEmpty()) clearSearchText.invisible() else clearSearchText.visible()
}
}
}
private fun setupFullHeight() {
val lp = (binding.root.layoutParams as FrameLayout.LayoutParams)
lp.height =
Resources.getSystem().displayMetrics.heightPixels - requireActivity().statusBarHeight
binding.root.layoutParams = lp
}
private fun expand(root: View) {
BottomSheetBehavior.from(root.parent as View).state = BottomSheetBehavior.STATE_EXPANDED
}
override fun onStart() {
super.onStart()
vm.onStart()
}
abstract fun onRelationSelected(ctx: Id, relation: RelationView.Existing)
abstract fun onCreateFromScratchClicked()
override fun inflateBinding(
inflater: LayoutInflater,
container: ViewGroup?
): FragmentRelationAddBinding = FragmentRelationAddBinding.inflate(
inflater, container, false
)
companion object {
const val CTX_KEY = "arg.relation-add.ctx"
}
}
class RelationAddToObjectFragment : RelationAddBaseFragment() {
override val ctx get() = arg<Id>(CTX_KEY)
@Inject
lateinit var factory: RelationAddToObjectViewModel.Factory
override val vm: RelationAddToObjectViewModel by viewModels { factory }
override fun onRelationSelected(ctx: Id, relation: RelationView.Existing) {
vm.onRelationSelected(
ctx = ctx,
relation = relation,
screenType = EventsDictionary.Type.menu
)
}
override fun onCreateFromScratchClicked() {
RelationCreateFromScratchForObjectFragment
.new(
ctx = ctx,
query = createFromScratchAdapter.query
)
.show(childFragmentManager, null)
}
override fun injectDependencies() {
componentManager().relationAddToObjectComponent.get(ctx).inject(this)
}
override fun releaseDependencies() {
componentManager().relationAddToObjectComponent.release(ctx)
}
companion object {
fun new(ctx: Id) = RelationAddToObjectFragment().apply {
arguments = bundleOf(CTX_KEY to ctx)
}
}
}
class RelationAddToDataViewFragment : RelationAddBaseFragment() {
private val dv get() = arg<Id>(DV_KEY)
override val ctx get() = arg<Id>(CTX_KEY)
@Inject
lateinit var factory: RelationAddToDataViewViewModel.Factory
override val vm: RelationAddToDataViewViewModel by viewModels { factory }
override fun onRelationSelected(ctx: Id, relation: RelationView.Existing) {
vm.onRelationSelected(
ctx = ctx,
relation = relation,
dv = dv,
screenType = EventsDictionary.Type.dataView
)
}
override fun onCreateFromScratchClicked() {
RelationCreateFromScratchForDataViewFragment
.new(
ctx = ctx,
dv = dv,
query = createFromScratchAdapter.query
)
.show(childFragmentManager, null)
}
override fun injectDependencies() {
componentManager().relationAddToDataViewComponent.get(ctx).inject(this)
}
override fun releaseDependencies() {
componentManager().relationAddToDataViewComponent.release(ctx)
}
companion object {
fun new(ctx: Id, dv: Id, viewer: Id): RelationAddToDataViewFragment =
RelationAddToDataViewFragment().apply {
arguments = bundleOf(
CTX_KEY to ctx,
DV_KEY to dv,
VIEWER_KEY to viewer
)
}
private const val DV_KEY = "arg.relation-add-to-data-view.dv"
private const val VIEWER_KEY = "arg.relation-add-to-data-view.viewer"
}
}
class RelationAddToObjectBlockFragment : RelationAddBaseFragment() {
override val ctx get() = arg<Id>(CTX_KEY)
private val target get() = arg<Id>(TARGET_KEY)
@Inject
lateinit var factory: RelationAddToObjectViewModel.Factory
override val vm: RelationAddToObjectViewModel by viewModels { factory }
override fun onStart() {
with(lifecycleScope) {
jobs += subscribe(vm.commands) { execute(it) }
}
super.onStart()
}
override fun onRelationSelected(ctx: Id, relation: RelationView.Existing) {
vm.onRelationSelected(
ctx = ctx,
relation = relation,
screenType = EventsDictionary.Type.block
)
}
private fun execute(command: RelationAddToObjectViewModel.Command) {
when (command) {
is RelationAddToObjectViewModel.Command.OnRelationAdd -> {
findNavController().run {
val result = RelationAddResult(target = target, relation = command.relation)
previousBackStackEntry?.savedStateHandle?.set(RELATION_ADD_RESULT_KEY, result)
popBackStack()
}
}
}
}
override fun onCreateFromScratchClicked() {
findNavController().navigate(
R.id.action_relationAddToObjectBlockFragment_to_relationCreateFromScratchForObjectBlockFragment,
bundleOf(
RelationCreateFromScratchBaseFragment.CTX_KEY to ctx,
RelationCreateFromScratchBaseFragment.QUERY_KEY to createFromScratchAdapter.query,
RelationCreateFromScratchForObjectBlockFragment.TARGET_KEY to target
)
)
}
override fun injectDependencies() {
componentManager().relationAddToObjectComponent.get(ctx).inject(this)
}
override fun releaseDependencies() {
componentManager().relationAddToObjectComponent.release(ctx)
}
companion object {
const val TARGET_KEY = "arg.relation-add-to-object-block.target"
const val RELATION_ADD_RESULT_KEY = "arg.relation-add-to-object-block.result"
}
}
data class RelationAddResult(val target: String, val relation: String) : Serializable