1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-2550 App | Tech | Process event channel refactoring (#1357)

This commit is contained in:
Konstantin Ivanov 2024-07-04 14:54:47 +02:00 committed by GitHub
parent 46ccd1a003
commit 9bf83e87a2
Signed by: github
GPG key ID: B5690EEEBB952194
10 changed files with 200 additions and 72 deletions

View file

@ -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
}

View file

@ -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 {

View file

@ -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()
}
}
}

View file

@ -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<List<Process.Event>>
interface EventProcessImportRemoteChannel {
fun observe(): Flow<List<Process.Event.Import>>
}
class EventProcessDateChannel(
private val channel: EventProcessRemoteChannel
) : EventProcessChannel {
class EventProcessImportDateChannel(
private val channel: EventProcessImportRemoteChannel
) : EventProcessImportChannel {
override fun observe(): Flow<List<Process.Event>> {
override fun observe(): Flow<List<Process.Event.Import>> {
return channel.observe()
}
}
interface EventProcessDropFilesRemoteChannel {
fun observe(): Flow<List<Process.Event.DropFiles>>
}
class EventProcessDropFilesDateChannel(
private val channel: EventProcessDropFilesRemoteChannel
) : EventProcessDropFilesChannel {
override fun observe(): Flow<List<Process.Event.DropFiles>> {
return channel.observe()
}
}

View file

@ -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<List<Process.Event>>
interface EventProcessImportChannel {
fun observe(): Flow<List<Process.Event.Import>>
}
interface EventProcessDropFilesChannel {
fun observe(): Flow<List<Process.Event.DropFiles>>
}

View file

@ -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>(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)
}
}
}
}

View file

@ -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 <T : ViewModel> create(modelClass: Class<T>): T {

View file

@ -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<List<Process.Event>> {
override fun observe(): Flow<List<Process.Event.DropFiles>> {
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<List<Process.Event.Import>> {
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
}
}

View file

@ -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<DataViewViewState.Init>(first)
advanceUntilIdle()
cancelAndIgnoreRemainingEvents()
val second = awaitItem()
assertIs<DataViewViewState.Collection.Default>(second)
advanceUntilIdle()
val newObjectTypeKey = MockDataFactory.randomString()
val newObjectTemplate = MockDataFactory.randomString()

View file

@ -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,