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:
parent
46ccd1a003
commit
9bf83e87a2
10 changed files with 200 additions and 72 deletions
|
@ -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
|
||||
}
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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>>
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue