diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt index f61361e43e..fb8c09049d 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt @@ -3,14 +3,18 @@ package com.anytypeio.anytype.di.feature.gallery import androidx.lifecycle.ViewModelProvider import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_utils.di.scope.PerScreen +import com.anytypeio.anytype.data.auth.event.EventProcessImportDateChannel +import com.anytypeio.anytype.data.auth.event.EventProcessImportRemoteChannel import com.anytypeio.anytype.di.common.ComponentDependencies import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers import com.anytypeio.anytype.domain.block.repo.BlockRepository import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider -import com.anytypeio.anytype.domain.workspace.EventProcessChannel +import com.anytypeio.anytype.domain.workspace.EventProcessImportChannel import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationViewModel import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationViewModelFactory +import com.anytypeio.anytype.middleware.EventProxy +import com.anytypeio.anytype.middleware.interactor.EventProcessImportMiddlewareChannel import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment import dagger.Binds @@ -44,6 +48,18 @@ interface GalleryInstallationComponent { @Module object GalleryInstallationModule { + @Provides + @PerScreen + fun provideEventProcessRemoteChannel( + proxy: EventProxy + ): EventProcessImportRemoteChannel = EventProcessImportMiddlewareChannel(events = proxy) + + @Provides + @PerScreen + fun provideEventProcessDateChannel( + channel: EventProcessImportRemoteChannel + ): EventProcessImportChannel = EventProcessImportDateChannel(channel = channel) + @Provides @PerScreen fun provideGradientProvider(): SpaceGradientProvider { @@ -68,5 +84,5 @@ interface GalleryInstallationComponentDependencies : ComponentDependencies { fun analytics(): Analytics fun urlBuilder(): UrlBuilder fun userPermissionProvider(): UserPermissionProvider - fun eventProcessChannel(): EventProcessChannel + fun eventProxy(): EventProxy } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt index 1478b4ba42..4267a072ef 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt @@ -4,8 +4,6 @@ import com.anytypeio.anytype.core_utils.tools.FeatureToggles import com.anytypeio.anytype.data.auth.account.AccountStatusDataChannel import com.anytypeio.anytype.data.auth.account.AccountStatusRemoteChannel import com.anytypeio.anytype.data.auth.event.EventDataChannel -import com.anytypeio.anytype.data.auth.event.EventProcessDateChannel -import com.anytypeio.anytype.data.auth.event.EventProcessRemoteChannel import com.anytypeio.anytype.data.auth.event.EventRemoteChannel import com.anytypeio.anytype.data.auth.event.FileLimitsDataChannel import com.anytypeio.anytype.data.auth.event.SubscriptionDataChannel @@ -17,7 +15,6 @@ import com.anytypeio.anytype.domain.event.interactor.EventChannel import com.anytypeio.anytype.domain.search.SubscriptionEventChannel import com.anytypeio.anytype.domain.status.ThreadStatusChannel import com.anytypeio.anytype.data.auth.event.FileLimitsRemoteChannel -import com.anytypeio.anytype.domain.workspace.EventProcessChannel import com.anytypeio.anytype.domain.workspace.FileLimitsEventChannel import com.anytypeio.anytype.middleware.EventProxy import com.anytypeio.anytype.middleware.interactor.* @@ -132,20 +129,6 @@ object EventModule { channel: FileLimitsRemoteChannel ): FileLimitsEventChannel = FileLimitsDataChannel(channel = channel) - @JvmStatic - @Provides - @Singleton - fun provideEventProcessRemoteChannel( - proxy: EventProxy - ): EventProcessRemoteChannel = EventProcessMiddlewareChannel(events = proxy) - - @JvmStatic - @Provides - @Singleton - fun provideProcessDataChannel( - channel: EventProcessRemoteChannel - ): EventProcessChannel = EventProcessDateChannel(channel = channel) - @Module interface Bindings { diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Process.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Process.kt index 696c054a50..47b021aa0b 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Process.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Process.kt @@ -30,16 +30,33 @@ data class Process( ) sealed class Event { - data class New( - val process: Process? - ) : Event() - data class Update( - val process: Process? - ) : Event() + sealed class DropFiles : Event() { + data class New( + val process: Process + ) : DropFiles() - data class Done( - val process: Process? - ) : Event() + data class Update( + val process: Process + ) : DropFiles() + + data class Done( + val process: Process + ) : DropFiles() + } + + sealed class Import : Event() { + data class New( + val process: Process + ) : Import() + + data class Update( + val process: Process + ) : Import() + + data class Done( + val process: Process + ) : Import() + } } } diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/event/EventProcessRemoteChannel.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/event/EventProcessRemoteChannel.kt index 19be035e6a..2854f296ab 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/event/EventProcessRemoteChannel.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/event/EventProcessRemoteChannel.kt @@ -1,18 +1,32 @@ package com.anytypeio.anytype.data.auth.event import com.anytypeio.anytype.core_models.Process -import com.anytypeio.anytype.domain.workspace.EventProcessChannel +import com.anytypeio.anytype.domain.workspace.EventProcessDropFilesChannel +import com.anytypeio.anytype.domain.workspace.EventProcessImportChannel import kotlinx.coroutines.flow.Flow -interface EventProcessRemoteChannel { - fun observe(): Flow> +interface EventProcessImportRemoteChannel { + fun observe(): Flow> } -class EventProcessDateChannel( - private val channel: EventProcessRemoteChannel -) : EventProcessChannel { +class EventProcessImportDateChannel( + private val channel: EventProcessImportRemoteChannel +) : EventProcessImportChannel { - override fun observe(): Flow> { + override fun observe(): Flow> { + return channel.observe() + } +} + +interface EventProcessDropFilesRemoteChannel { + fun observe(): Flow> +} + +class EventProcessDropFilesDateChannel( + private val channel: EventProcessDropFilesRemoteChannel +) : EventProcessDropFilesChannel { + + override fun observe(): Flow> { return channel.observe() } } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/workspace/EventProcessChannel.kt b/domain/src/main/java/com/anytypeio/anytype/domain/workspace/EventProcessChannel.kt index c6fb4b2e5e..ff337b8dc1 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/workspace/EventProcessChannel.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/workspace/EventProcessChannel.kt @@ -3,6 +3,10 @@ package com.anytypeio.anytype.domain.workspace import com.anytypeio.anytype.core_models.Process import kotlinx.coroutines.flow.Flow -interface EventProcessChannel { - fun observe(): Flow> +interface EventProcessImportChannel { + fun observe(): Flow> +} + +interface EventProcessDropFilesChannel { + fun observe(): Flow> } \ No newline at end of file diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt index bb13ecce22..20254c11a4 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt @@ -13,7 +13,6 @@ import com.anytypeio.anytype.analytics.base.sendEvent import com.anytypeio.anytype.analytics.props.Props import com.anytypeio.anytype.core_models.ManifestInfo import com.anytypeio.anytype.core_models.ObjectWrapper -import com.anytypeio.anytype.core_models.Process import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.domain.base.fold @@ -23,12 +22,11 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.spaces.CreateSpace import com.anytypeio.anytype.domain.spaces.GetSpaceViews -import com.anytypeio.anytype.domain.workspace.EventProcessChannel +import com.anytypeio.anytype.domain.workspace.EventProcessImportChannel import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationNavigation import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationSpacesState import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationState import com.anytypeio.anytype.gallery_experience.models.GallerySpaceView -import com.anytypeio.anytype.presentation.extension.getTypePropName import com.anytypeio.anytype.presentation.spaces.SelectSpaceViewModel.Companion.MAX_SPACE_COUNT import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import com.anytypeio.anytype.presentation.spaces.spaceIcon @@ -47,7 +45,7 @@ class GalleryInstallationViewModel( private val urlBuilder: UrlBuilder, private val spaceGradientProvider: SpaceGradientProvider, private val userPermissionProvider: UserPermissionProvider, - private val eventProcessChannel: EventProcessChannel + private val eventProcessChannel: EventProcessImportChannel ) : ViewModel() { val mainState = MutableStateFlow(GalleryInstallationState.Loading) @@ -225,9 +223,6 @@ class GalleryInstallationViewModel( viewModelScope.launch { eventProcessChannel.observe().collect { events -> Timber.d("EventProcessChannel events: $events") - if (events.any { it is Process.Event.Done && it.process?.type == Process.Type.IMPORT }) { - command.emit(GalleryInstallationNavigation.Dismiss) - } } } } diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt index c24b8d2c25..f6f87eddc2 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt @@ -9,7 +9,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.spaces.CreateSpace import com.anytypeio.anytype.domain.spaces.GetSpaceViews -import com.anytypeio.anytype.domain.workspace.EventProcessChannel +import com.anytypeio.anytype.domain.workspace.EventProcessImportChannel import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import javax.inject.Inject @@ -23,7 +23,7 @@ class GalleryInstallationViewModelFactory @Inject constructor( private val urlBuilder: UrlBuilder, private val spaceGradientProvider: SpaceGradientProvider, private val userPermissionProvider: UserPermissionProvider, - private val eventProcessChannel: EventProcessChannel + private val eventProcessChannel: EventProcessImportChannel ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventProcessMiddlewareChannel.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventProcessMiddlewareChannel.kt index dc0ebe2a85..cb696fca90 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventProcessMiddlewareChannel.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventProcessMiddlewareChannel.kt @@ -1,42 +1,119 @@ package com.anytypeio.anytype.middleware.interactor +import anytype.Model import com.anytypeio.anytype.core_models.Process -import com.anytypeio.anytype.data.auth.event.EventProcessRemoteChannel +import com.anytypeio.anytype.data.auth.event.EventProcessDropFilesRemoteChannel +import com.anytypeio.anytype.data.auth.event.EventProcessImportRemoteChannel import com.anytypeio.anytype.middleware.EventProxy import com.anytypeio.anytype.middleware.mappers.toCoreModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapNotNull -class EventProcessMiddlewareChannel( +class EventProcessDropFilesMiddlewareChannel( private val events: EventProxy -) : EventProcessRemoteChannel { +) : EventProcessDropFilesRemoteChannel { - override fun observe(): Flow> { + override fun observe(): Flow> { return events.flow() .mapNotNull { emission -> emission.messages.mapNotNull { message -> + val eventProcessNew = message.processNew + val eventProcessUpdate = message.processUpdate + val eventProcessDone = message.processDone + when { - message.processNew != null -> { - val event = message.processNew - checkNotNull(event) - Process.Event.New( - process = event.process?.toCoreModel() - ) + eventProcessNew != null -> { + val process = eventProcessNew.process + val processType = process?.type + if (processType == Model.Process.Type.DropFiles) { + Process.Event.DropFiles.New( + process = process.toCoreModel() + ) + } else { + null + } } - message.processUpdate != null -> { - val event = message.processUpdate - checkNotNull(event) - Process.Event.Update( - process = event.process?.toCoreModel() - ) + + eventProcessUpdate != null -> { + val process = eventProcessUpdate.process + val processType = process?.type + if (processType == Model.Process.Type.DropFiles) { + Process.Event.DropFiles.Update( + process = process.toCoreModel() + ) + } else { + null + } } - message.processDone != null -> { - val event = message.processDone - checkNotNull(event) - Process.Event.Done( - process = event.process?.toCoreModel() - ) + + eventProcessDone != null -> { + val process = eventProcessDone.process + val processType = process?.type + if (processType == Model.Process.Type.DropFiles) { + Process.Event.DropFiles.Done( + process = process.toCoreModel() + ) + } else { + null + } } + + else -> null + } + } + } + } +} + +class EventProcessImportMiddlewareChannel( + private val events: EventProxy +) : EventProcessImportRemoteChannel { + + override fun observe(): Flow> { + return events.flow() + .mapNotNull { emission -> + emission.messages.mapNotNull { message -> + val eventProcessNew = message.processNew + val eventProcessUpdate = message.processUpdate + val eventProcessDone = message.processDone + + when { + eventProcessNew != null -> { + val process = eventProcessNew.process + val processType = process?.type + if (processType == Model.Process.Type.Import) { + Process.Event.Import.New( + process = process.toCoreModel() + ) + } else { + null + } + } + + eventProcessUpdate != null -> { + val process = eventProcessUpdate.process + val processType = process?.type + if (processType == Model.Process.Type.Import) { + Process.Event.Import.Update( + process = process.toCoreModel() + ) + } else { + null + } + } + + eventProcessDone != null -> { + val process = eventProcessDone.process + val processType = process?.type + if (processType == Model.Process.Type.Import) { + Process.Event.Import.Done( + process = process.toCoreModel() + ) + } else { + null + } + } + else -> null } } diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt index 18fad9ed19..4e0a51fda5 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt @@ -21,7 +21,6 @@ import com.anytypeio.anytype.presentation.sets.subscription.DefaultDataViewSubsc import com.anytypeio.anytype.test_utils.MockDataFactory import kotlin.test.assertIs import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import net.lachlanmckee.timberjunit.TimberTestRule @@ -147,6 +146,7 @@ class CollectionCreateAndAddObjectTest: ObjectSetViewModelTestSetup() { stubSpaceManager(mockObjectCollection.spaceId) stubInterceptEvents() + stubProfileIcon() stubInterceptThreadStatus() stubOpenObject( doc = listOf( @@ -176,10 +176,9 @@ class CollectionCreateAndAddObjectTest: ObjectSetViewModelTestSetup() { val first = awaitItem() assertIs(first) - advanceUntilIdle() + cancelAndIgnoreRemainingEvents() - val second = awaitItem() - assertIs(second) + advanceUntilIdle() val newObjectTypeKey = MockDataFactory.randomString() val newObjectTemplate = MockDataFactory.randomString() diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt index 12143bf501..4ac035c6ac 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt @@ -12,8 +12,10 @@ 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.RelationLink +import com.anytypeio.anytype.core_models.Relations import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.StubConfig +import com.anytypeio.anytype.core_models.StubObject import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeId @@ -34,6 +36,7 @@ import com.anytypeio.anytype.domain.dataview.interactor.CreateDataViewObject import com.anytypeio.anytype.domain.dataview.interactor.UpdateDataViewViewer import com.anytypeio.anytype.domain.event.interactor.InterceptEvents import com.anytypeio.anytype.domain.launch.GetDefaultObjectType +import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider @@ -65,6 +68,8 @@ import com.anytypeio.anytype.presentation.collections.MockSet import com.anytypeio.anytype.presentation.common.Action import com.anytypeio.anytype.presentation.common.Delegator import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider +import com.anytypeio.anytype.presentation.home.HomeScreenViewModel +import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Companion.HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION import com.anytypeio.anytype.presentation.home.UserPermissionProviderStub import com.anytypeio.anytype.presentation.relations.ObjectSetConfig import com.anytypeio.anytype.presentation.search.ObjectSearchConstants @@ -371,6 +376,24 @@ open class ObjectSetViewModelTestSetup { } } + fun stubProfileIcon() { + val searchParams = StoreSearchByIdsParams( + subscription = HOME_SCREEN_PROFILE_OBJECT_SUBSCRIPTION, + targets = listOf(spaceConfig.profile), + keys = listOf( + Relations.ID, + Relations.SPACE_ID, + Relations.NAME, + Relations.ICON_EMOJI, + Relations.ICON_IMAGE, + Relations.ICON_OPTION + ) + ) + storelessSubscriptionContainer.stub { + onBlocking { subscribe(searchParams) } doReturn flowOf(listOf(StubObject())) + } + } + suspend fun stubSubscriptionResults( subscription: Id = MockDataFactory.randomString(), spaceId: Id,