diff --git a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt index 8c41bd4479..fd725797b5 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt @@ -59,7 +59,6 @@ import com.anytypeio.anytype.di.feature.TextBlockIconPickerModule import com.anytypeio.anytype.di.feature.ViewerFilterModule import com.anytypeio.anytype.di.feature.ViewerSortModule import com.anytypeio.anytype.di.feature.auth.DaggerDeletedAccountComponent -import com.anytypeio.anytype.di.feature.auth.DeletedAccountModule import com.anytypeio.anytype.di.feature.cover.UnsplashModule import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent import com.anytypeio.anytype.di.feature.library.DaggerLibraryComponent @@ -675,6 +674,14 @@ class ComponentManager( .build() } + val relationAddToObjectSetComponent = DependentComponentMap { ctx -> + objectSetComponent + .get(ctx) + .relationAddToObjectComponent() + .module(RelationAddToObjectModule) + .build() + } + val relationAddToDataViewComponent = DependentComponentMap { ctx -> objectSetComponent .get(ctx) @@ -691,6 +698,14 @@ class ComponentManager( .build() } + val relationCreateFromScratchForObjectSetComponent = DependentComponentMap { ctx -> + objectSetComponent + .get(ctx) + .relationCreateFromScratchForObjectComponent() + .module(RelationCreateFromScratchForObjectModule) + .build() + } + val relationFormatPickerObjectComponent = DependentComponentMap { ctx -> relationCreateFromScratchForObjectComponent .get(ctx) 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 30f762661c..8e0969d9cb 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 @@ -7,7 +7,9 @@ import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.core_utils.di.scope.PerScreen import com.anytypeio.anytype.di.feature.cover.UnsplashSubComponent import com.anytypeio.anytype.di.feature.relations.RelationAddToDataViewSubComponent +import com.anytypeio.anytype.di.feature.relations.RelationAddToObjectSubComponent import com.anytypeio.anytype.di.feature.relations.RelationCreateFromScratchForDataViewSubComponent +import com.anytypeio.anytype.di.feature.relations.RelationCreateFromScratchForObjectSubComponent import com.anytypeio.anytype.di.feature.sets.CreateFilterSubComponent import com.anytypeio.anytype.di.feature.sets.ModifyFilterSubComponent import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationSubComponent @@ -38,6 +40,7 @@ import com.anytypeio.anytype.domain.objects.options.GetOptions import com.anytypeio.anytype.domain.page.CloseBlock import com.anytypeio.anytype.domain.page.CreateObject import com.anytypeio.anytype.domain.relations.AddFileToObject +import com.anytypeio.anytype.domain.relations.AddRelationToObject import com.anytypeio.anytype.domain.relations.DeleteRelationFromDataView import com.anytypeio.anytype.domain.search.CancelSearchSubscription import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer @@ -120,6 +123,8 @@ interface ObjectSetSubComponent { fun objectUnsplashComponent(): UnsplashSubComponent.Builder fun objectRelationListComponent(): ObjectRelationListComponent.Builder + fun relationAddToObjectComponent(): RelationAddToObjectSubComponent.Builder + fun relationCreateFromScratchForObjectComponent(): RelationCreateFromScratchForObjectSubComponent.Builder } @Module( @@ -525,10 +530,15 @@ object ObjectSetModule { @PerScreen fun dataViewRelationListProvider( objectStateFlow: MutableStateFlow - ) : RelationListProvider = RelationListProvider.DataViewRelationListProvider( + ) : RelationListProvider = RelationListProvider.ObjectSetRelationListProvider( objectStates = objectStateFlow ) + @JvmStatic + @Provides + @PerScreen + fun provideAddRelationToObject(repo: BlockRepository) = AddRelationToObject(repo) + @Module interface Bindings { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt index 65c4c2525a..fd40486361 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt @@ -102,7 +102,10 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment(CTX_KEY) + private val isSetOrCollection get() = arg(IS_SET_OR_COLLECTION_KEY) @Inject lateinit var factory: RelationAddToObjectViewModel.Factory @@ -160,22 +161,40 @@ class RelationAddToObjectFragment : RelationAddBaseFragment() { override fun onCreateFromScratchClicked() { val fr = RelationCreateFromScratchForObjectFragment.new( ctx = ctx, - query = createFromScratchAdapter.query + query = createFromScratchAdapter.query, + isSetOrCollection = isSetOrCollection ) fr.showChildFragment() } override fun injectDependencies() { - componentManager().relationAddToObjectComponent.get(ctx).inject(this) + if (isSetOrCollection) { + componentManager().relationAddToObjectSetComponent.get(ctx).inject(this) + } else { + componentManager().relationAddToObjectComponent.get(ctx).inject(this) + } } override fun releaseDependencies() { - componentManager().relationAddToObjectComponent.release(ctx) + if (isSetOrCollection) { + componentManager().relationAddToObjectSetComponent.release(ctx) + } else { + componentManager().relationAddToObjectComponent.release(ctx) + } } companion object { - fun new(ctx: Id) = RelationAddToObjectFragment().apply { - arguments = bundleOf(CTX_KEY to ctx) + + private const val IS_SET_OR_COLLECTION_KEY = "arg.relation-add-to-object.is-set-or-collection" + + fun new( + ctx: Id, + isSetOrCollection: Boolean = true + ) = RelationAddToObjectFragment().apply { + arguments = bundleOf( + CTX_KEY to ctx, + IS_SET_OR_COLLECTION_KEY to isSetOrCollection + ) } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationCreateFromScratchBaseFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationCreateFromScratchBaseFragment.kt index 14e91e40cb..34155c3365 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationCreateFromScratchBaseFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/relations/RelationCreateFromScratchBaseFragment.kt @@ -146,6 +146,8 @@ abstract class RelationCreateFromScratchBaseFragment : class RelationCreateFromScratchForObjectFragment : RelationCreateFromScratchBaseFragment() { + private val isSetOrCollection : Boolean get() = arg(IS_SET_OR_COLLECTION_KEY) + @Inject lateinit var factory: RelationCreateFromScratchForObjectViewModel.Factory override val vm: RelationCreateFromScratchForObjectViewModel by viewModels { factory } @@ -175,16 +177,35 @@ class RelationCreateFromScratchForObjectFragment : RelationCreateFromScratchBase } override fun injectDependencies() { - componentManager().relationCreateFromScratchForObjectComponent.get(ctx).inject(this) + if (isSetOrCollection) { + componentManager().relationCreateFromScratchForObjectSetComponent.get(ctx).inject(this) + } else { + componentManager().relationCreateFromScratchForObjectComponent.get(ctx).inject(this) + } } override fun releaseDependencies() { - componentManager().relationCreateFromScratchForObjectComponent.release(ctx) + if (isSetOrCollection) { + componentManager().relationCreateFromScratchForObjectSetComponent.release(ctx) + } else { + componentManager().relationCreateFromScratchForObjectComponent.release(ctx) + } } companion object { - fun new(ctx: Id, query: String) = RelationCreateFromScratchForObjectFragment().apply { - arguments = bundleOf(CTX_KEY to ctx, QUERY_KEY to query) + + private const val IS_SET_OR_COLLECTION_KEY = "arg.relation-create-from-scratch.is-set-or-collection" + + fun new( + ctx: Id, + query: String, + isSetOrCollection: Boolean = false + ) = RelationCreateFromScratchForObjectFragment().apply { + arguments = bundleOf( + CTX_KEY to ctx, + QUERY_KEY to query, + IS_SET_OR_COLLECTION_KEY to isSetOrCollection + ) } fun args(ctx: Id, query: String) = bundleOf(CTX_KEY to ctx, QUERY_KEY to query) diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/DocumentRelationAdapter.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/DocumentRelationAdapter.kt index 882aa812f7..b82fc7e162 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/DocumentRelationAdapter.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/relations/DocumentRelationAdapter.kt @@ -173,7 +173,7 @@ class DocumentRelationAdapter( if (payload.isModeChanged) { val item = items[position] check(item is RelationListViewModel.Model.Item) - holder.setIsRemovable(item.isRemoveable) + holder.setIsRemovable(item.isRemovable) } else { super.onBindViewHolder(holder, position, payloads) } @@ -235,7 +235,7 @@ class DocumentRelationAdapter( if (holder is ListRelationViewHolder) { check(item is RelationListViewModel.Model.Item) holder.setIsFeatured(item.view.featured) - holder.setIsRemovable(item.isRemoveable) + holder.setIsRemovable(item.isRemovable) } } @@ -289,7 +289,7 @@ class DocumentRelationAdapter( val oldItem = old[oldItemPosition] val newItem = new[newItemPosition] return if (oldItem is RelationListViewModel.Model.Item && newItem is RelationListViewModel.Model.Item) { - if (newItem.isRemoveable != oldItem.isRemoveable) + if (newItem.isRemovable != oldItem.isRemovable) GranularChange(isModeChanged = true) else null diff --git a/docs/screens.md b/docs/screens.md index 0f2dd16b0d..7e3974f042 100644 --- a/docs/screens.md +++ b/docs/screens.md @@ -6,7 +6,11 @@ [Main] - [ObjectSetMenuFragment] showing menu for a Set or Collection - - [ObjectRelationListFragment] displaying list of given object's relations - - [RelationTextValueFragment] + - [ObjectRelationListFragment] displaying list of Relations for this Set or this Collection + - [RelationTextValueFragment] editing Relation from this Data View or from this Set or this Collection + - [RelationAddToObjectFragment] adding a Relation to given Set or Collection + - [RelationAddToDataViewFragment] adding a Relation to the Data View contained in this Set or this Collection + - [RelationCreateFromScratchForObjectFragment] creating a Relation for this Set or this Collection + - [RelationCreateFromScratchForDataViewFragment] creating a Relation for the Data View contained in this Set or this Collection // TODO diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationListViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationListViewModel.kt index 15a6b394fa..e7a7221e52 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationListViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/RelationListViewModel.kt @@ -80,7 +80,7 @@ class RelationListViewModel( ).map { view -> Model.Item( view = view, - isRemoveable = isPossibleToRemoveRelation(relationKey = view.key) + isRemovable = isPossibleToRemoveRelation(relationKey = view.key) ) } }.map { views -> @@ -199,7 +199,7 @@ class RelationListViewModel( isEditMode.value = !isEditMode.value views.value = views.value.map { view -> if (view is Model.Item) { - view.copy(isRemoveable = isPossibleToRemoveRelation(relationKey = view.view.key)) + view.copy(isRemovable = isPossibleToRemoveRelation(relationKey = view.view.key)) } else { view } @@ -377,7 +377,7 @@ class RelationListViewModel( data class Item( val view: ObjectRelationView, - val isRemoveable: Boolean = false + val isRemovable: Boolean = false ) : Model() { override val identifier: String get() = view.identifier } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/providers/RelationListProvider.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/providers/RelationListProvider.kt index 50474824da..e718dc1a4e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/providers/RelationListProvider.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/relations/providers/RelationListProvider.kt @@ -2,7 +2,6 @@ package com.anytypeio.anytype.presentation.relations.providers import com.anytypeio.anytype.core_models.Block import com.anytypeio.anytype.core_models.RelationLink -import com.anytypeio.anytype.core_models.ext.content import com.anytypeio.anytype.presentation.editor.Editor import com.anytypeio.anytype.presentation.sets.state.ObjectState import kotlinx.coroutines.flow.Flow @@ -29,7 +28,7 @@ interface RelationListProvider { override fun getDetails() = storage.details.current() } - class DataViewRelationListProvider( + class ObjectSetRelationListProvider( private val objectStates: StateFlow ) : RelationListProvider { @@ -51,10 +50,10 @@ interface RelationListProvider { private fun mapLinks(state: ObjectState) = when (state) { is ObjectState.DataView.Collection -> { - state.dataViewBlock.content().relationLinks + state.objectRelationLinks } is ObjectState.DataView.Set -> { - state.dataViewBlock.content().relationLinks + state.objectRelationLinks } else -> emptyList() } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/DefaultObjectStateReducer.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/DefaultObjectStateReducer.kt index ee1712a88b..59e7ef3dac 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/DefaultObjectStateReducer.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/DefaultObjectStateReducer.kt @@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Event.Command import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.ObjectType import com.anytypeio.anytype.core_models.ext.amend +import com.anytypeio.anytype.core_models.ext.remove import com.anytypeio.anytype.core_models.ext.unset import com.anytypeio.anytype.core_utils.ext.replace import com.anytypeio.anytype.presentation.sets.updateFields @@ -56,10 +57,16 @@ class DefaultObjectStateReducer : ObjectStateReducer { private fun reduce(state: ObjectState, event: Event): Transformation { val effects = mutableListOf() - val newState = when (event) { + val newState : ObjectState = when (event) { is Command.ShowObject -> { handleShowObject(event) } + is Command.ObjectRelationLinks.Amend -> { + amendObjectRelationLinks(state, event) + } + is Command.ObjectRelationLinks.Remove -> { + removeObjectRelationLinks(state, event) + } is Command.DataView.SetView -> { handleSetView(state, event) } @@ -96,6 +103,7 @@ class DefaultObjectStateReducer : ObjectStateReducer { is Command.AddBlock -> { handleAddBlock(state, event) } + else -> { Timber.d("Ignoring event: $event") state @@ -107,6 +115,48 @@ class DefaultObjectStateReducer : ObjectStateReducer { ) } + private fun removeObjectRelationLinks( + state: ObjectState, + event: Command.ObjectRelationLinks.Remove + ) = when (state) { + is ObjectState.DataView.Collection -> { + state.copy( + objectRelationLinks = state.objectRelationLinks.remove( + event.keys + ) + ) + } + is ObjectState.DataView.Set -> { + state.copy( + objectRelationLinks = state.objectRelationLinks.remove( + event.keys + ) + ) + } + else -> state + } + + private fun amendObjectRelationLinks( + state: ObjectState, + event: Command.ObjectRelationLinks.Amend + ) = when (state) { + is ObjectState.DataView.Collection -> { + state.copy( + objectRelationLinks = state.objectRelationLinks.amend( + event.relationLinks + ) + ) + } + is ObjectState.DataView.Set -> { + state.copy( + objectRelationLinks = state.objectRelationLinks.amend( + event.relationLinks + ) + ) + } + else -> state + } + //region EVENTS /** @@ -119,14 +169,16 @@ class DefaultObjectStateReducer : ObjectStateReducer { blocks = event.blocks, details = event.details.details, objectRestrictions = event.objectRestrictions, - dataViewRestrictions = event.dataViewRestrictions + dataViewRestrictions = event.dataViewRestrictions, + objectRelationLinks = event.relationLinks ) ObjectType.Layout.SET.code -> ObjectState.DataView.Set( root = event.root, blocks = event.blocks, details = event.details.details, objectRestrictions = event.objectRestrictions, - dataViewRestrictions = event.dataViewRestrictions + dataViewRestrictions = event.dataViewRestrictions, + objectRelationLinks = event.relationLinks ) else -> { Timber.e("Wrong layout type: $layout") diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/ObjectState.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/ObjectState.kt index ee0c6799bf..cd4cd8ad81 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/ObjectState.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/state/ObjectState.kt @@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.Block import com.anytypeio.anytype.core_models.DV import com.anytypeio.anytype.core_models.DVViewer import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.RelationLink import com.anytypeio.anytype.core_models.restrictions.DataViewRestrictions import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction @@ -12,12 +13,15 @@ sealed class ObjectState { abstract val isInitialized: Boolean sealed class DataView : ObjectState() { + abstract val root: Id abstract val blocks: List abstract val details: Map abstract val objectRestrictions: List abstract val dataViewRestrictions: List + abstract val objectRelationLinks: List + abstract val dataViewContent: DV abstract val dataViewBlock: Block abstract val viewers: List @@ -27,7 +31,8 @@ sealed class ObjectState { override val blocks: List = emptyList(), override val details: Map = emptyMap(), override val objectRestrictions: List = emptyList(), - override val dataViewRestrictions: List = emptyList() + override val dataViewRestrictions: List = emptyList(), + override val objectRelationLinks: List = emptyList() ) : DataView() { override val isInitialized get() = blocks.any { it.content is DV } @@ -41,7 +46,8 @@ sealed class ObjectState { override val blocks: List = emptyList(), override val details: Map = emptyMap(), override val objectRestrictions: List = emptyList(), - override val dataViewRestrictions: List = emptyList() + override val dataViewRestrictions: List = emptyList(), + override val objectRelationLinks: List = emptyList() ) : DataView() { override val isInitialized get() = blocks.any { it.content is DV }