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

Feature | Sync-status without GUI (#1193)

This commit is contained in:
Evgenii Kozlov 2020-12-17 21:23:30 +03:00 committed by GitHub
parent 812df6d7ca
commit ce0d55e58e
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 187 additions and 0 deletions

View file

@ -19,6 +19,8 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.page.navigation.GetListPages
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
import com.anytypeio.anytype.domain.status.ThreadStatusChannel
import com.anytypeio.anytype.presentation.page.DocumentExternalEventReducer
import com.anytypeio.anytype.presentation.page.Editor
import com.anytypeio.anytype.presentation.page.PageViewModelFactory
@ -81,6 +83,7 @@ object EditorSessionModule {
openPage: OpenPage,
closePage: ClosePage,
interceptEvents: InterceptEvents,
interceptThreadStatus: InterceptThreadStatus,
updateLinkMarks: UpdateLinkMarks,
removeLinkMark: RemoveLinkMark,
createPage: CreatePage,
@ -101,6 +104,7 @@ object EditorSessionModule {
createDocument = createDocument,
createNewDocument = createNewDocument,
interceptEvents = interceptEvents,
interceptThreadStatus = interceptThreadStatus,
updateLinkMarks = updateLinkMarks,
removeLinkMark = removeLinkMark,
documentEventReducer = documentExternalEventReducer,
@ -275,6 +279,16 @@ object EditorUseCaseModule {
context = Dispatchers.IO
)
@JvmStatic
@Provides
@PerScreen
fun providesInterceptThreadStatusUseCase(
channel: ThreadStatusChannel
): InterceptThreadStatus = InterceptThreadStatus(
channel = channel,
context = Dispatchers.IO
)
@JvmStatic
@Provides
@PerScreen

View file

@ -2,10 +2,14 @@ package com.anytypeio.anytype.di.main
import com.anytypeio.anytype.data.auth.event.EventDataChannel
import com.anytypeio.anytype.data.auth.event.EventRemoteChannel
import com.anytypeio.anytype.data.auth.status.ThreadStatusDataChannel
import com.anytypeio.anytype.data.auth.status.ThreadStatusRemoteChannel
import com.anytypeio.anytype.domain.event.interactor.EventChannel
import com.anytypeio.anytype.domain.status.ThreadStatusChannel
import com.anytypeio.anytype.middleware.EventProxy
import com.anytypeio.anytype.middleware.interactor.EventHandler
import com.anytypeio.anytype.middleware.interactor.MiddlewareEventChannel
import com.anytypeio.anytype.middleware.interactor.ThreadStatusMiddlewareChannel
import dagger.Module
import dagger.Provides
import javax.inject.Singleton
@ -34,6 +38,27 @@ object EventModule {
proxy: EventProxy
): EventRemoteChannel = MiddlewareEventChannel(events = proxy)
@JvmStatic
@Provides
@Singleton
fun provideThreadStatusChannel(
channel: ThreadStatusDataChannel
): ThreadStatusChannel = channel
@JvmStatic
@Provides
@Singleton
fun provideThreadStatusDataChannel(
remote: ThreadStatusRemoteChannel
): ThreadStatusDataChannel = ThreadStatusDataChannel(remote)
@JvmStatic
@Provides
@Singleton
fun provideThreadStatusRemoteChannel(
proxy: EventProxy
): ThreadStatusRemoteChannel = ThreadStatusMiddlewareChannel(events = proxy)
@JvmStatic
@Provides
@Singleton

View file

@ -0,0 +1,9 @@
package com.anytypeio.anytype.data.auth.model
enum class SyncStatusEntity {
UNKNOWN,
OFFLINE,
SYNCING,
SYNCED,
FAILED
}

View file

@ -0,0 +1,17 @@
package com.anytypeio.anytype.data.auth.status
import com.anytypeio.anytype.domain.status.SyncStatus
import com.anytypeio.anytype.domain.status.ThreadStatusChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
class ThreadStatusDataChannel(
private val remote: ThreadStatusRemoteChannel,
) : ThreadStatusChannel {
override fun observe(ctx: String): Flow<SyncStatus> {
return remote
.observe(ctx)
.map { status -> SyncStatus.valueOf(status.name) }
}
}

View file

@ -0,0 +1,9 @@
package com.anytypeio.anytype.data.auth.status
import com.anytypeio.anytype.data.auth.model.SyncStatusEntity
import com.anytypeio.anytype.domain.common.Id
import kotlinx.coroutines.flow.Flow
interface ThreadStatusRemoteChannel {
fun observe(ctx: Id): Flow<SyncStatusEntity>
}

View file

@ -0,0 +1,20 @@
package com.anytypeio.anytype.domain.status
import com.anytypeio.anytype.domain.base.FlowUseCase
import com.anytypeio.anytype.domain.common.Id
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlin.coroutines.CoroutineContext
class InterceptThreadStatus(
private val context: CoroutineContext,
private val channel: ThreadStatusChannel,
) : FlowUseCase<SyncStatus, InterceptThreadStatus.Params>() {
override fun build(params: Params?): Flow<SyncStatus> {
checkNotNull(params) { "Params are required for this use-case." }
return channel.observe(params.ctx).flowOn(context)
}
class Params(val ctx: Id)
}

View file

@ -0,0 +1,21 @@
package com.anytypeio.anytype.domain.status
import com.anytypeio.anytype.domain.common.Hash
import com.anytypeio.anytype.domain.common.Id
data class SyncAccount(
val id: Id,
val name: String,
val image: Hash,
val isOnline: Boolean,
val lastPulled: Int,
val lastEdited: Int,
val devices: List<Device>,
) {
data class Device(
val name: String,
val isOnline: Boolean,
val lastPulled: Int,
val lastEdited: Int,
)
}

View file

@ -0,0 +1,9 @@
package com.anytypeio.anytype.domain.status
enum class SyncStatus {
UNKNOWN,
OFFLINE,
SYNCING,
SYNCED,
FAILED
}

View file

@ -0,0 +1,7 @@
package com.anytypeio.anytype.domain.status
import kotlinx.coroutines.flow.Flow
interface ThreadStatusChannel {
fun observe(ctx: String): Flow<SyncStatus>
}

View file

@ -0,0 +1,35 @@
package com.anytypeio.anytype.middleware.interactor
import anytype.Event.Status.Thread.SyncStatus
import com.anytypeio.anytype.data.auth.model.SyncStatusEntity
import com.anytypeio.anytype.data.auth.status.ThreadStatusRemoteChannel
import com.anytypeio.anytype.middleware.EventProxy
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
class ThreadStatusMiddlewareChannel(
private val events: EventProxy,
) : ThreadStatusRemoteChannel {
override fun observe(ctx: String): Flow<SyncStatusEntity> = events.flow()
.filter { it.contextId == ctx }
.mapNotNull { emission ->
emission
.messages
.lastOrNull { it.threadStatus != null }
?.threadStatus
?.summary
?.status
}
.mapLatest { status ->
when (status) {
SyncStatus.Unknown -> SyncStatusEntity.UNKNOWN
SyncStatus.Offline -> SyncStatusEntity.OFFLINE
SyncStatus.Syncing -> SyncStatusEntity.SYNCING
SyncStatus.Synced -> SyncStatusEntity.SYNCED
SyncStatus.Failed -> SyncStatusEntity.FAILED
}
}
}

View file

@ -45,6 +45,7 @@ import com.anytypeio.anytype.domain.ext.*
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.navigation.GetListPages
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
import com.anytypeio.anytype.presentation.BuildConfig
import com.anytypeio.anytype.presentation.common.StateReducer
import com.anytypeio.anytype.presentation.common.SupportCommand
@ -99,6 +100,7 @@ class PageViewModel(
private val createNewDocument: CreateNewDocument,
private val archiveDocument: ArchiveDocument,
private val interceptEvents: InterceptEvents,
private val interceptThreadStatus: InterceptThreadStatus,
private val updateLinkMarks: UpdateLinkMarks,
private val removeLinkMark: RemoveLinkMark,
private val reducer: StateReducer<List<Block>, Event>,
@ -503,6 +505,12 @@ class PageViewModel(
.collect { refresh() }
}
jobs += viewModelScope.launch {
interceptThreadStatus
.build(InterceptThreadStatus.Params(context))
.collect { _toasts.send(it.toString()) }
}
jobs += viewModelScope.launch {
bridge
.flow()

View file

@ -12,6 +12,7 @@ import com.anytypeio.anytype.domain.event.model.Payload
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.navigation.GetListPages
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
import com.anytypeio.anytype.presentation.common.StateReducer
import com.anytypeio.anytype.presentation.page.editor.Orchestrator
import com.anytypeio.anytype.presentation.page.render.DefaultBlockViewRenderer
@ -25,6 +26,7 @@ open class PageViewModelFactory(
private val createNewDocument: CreateNewDocument,
private val archiveDocument: ArchiveDocument,
private val interceptEvents: InterceptEvents,
private val interceptThreadStatus: InterceptThreadStatus,
private val updateLinkMarks: UpdateLinkMarks,
private val removeLinkMark: RemoveLinkMark,
private val documentEventReducer: StateReducer<List<Block>, Event>,
@ -43,6 +45,7 @@ open class PageViewModelFactory(
closePage = closePage,
archiveDocument = archiveDocument,
interceptEvents = interceptEvents,
interceptThreadStatus = interceptThreadStatus,
updateLinkMarks = updateLinkMarks,
removeLinkMark = removeLinkMark,
createPage = createPage,

View file

@ -23,6 +23,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.page.navigation.GetListPages
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
import com.anytypeio.anytype.presentation.MockBlockFactory
import com.anytypeio.anytype.presentation.navigation.AppNavigation
import com.anytypeio.anytype.presentation.page.editor.*
@ -78,6 +79,9 @@ open class PageViewModelTest {
@Mock
lateinit var interceptEvents: InterceptEvents
@Mock
lateinit var interceptThreadStatus: InterceptThreadStatus
@Mock
lateinit var createBlock: CreateBlock
@ -3810,6 +3814,7 @@ open class PageViewModelTest {
closePage = closePage,
createPage = createPage,
interceptEvents = interceptEvents,
interceptThreadStatus = interceptThreadStatus,
updateLinkMarks = updateLinkMark,
removeLinkMark = removeLinkMark,
reducer = DocumentExternalEventReducer(),

View file

@ -20,6 +20,7 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.*
import com.anytypeio.anytype.domain.page.bookmark.SetupBookmark
import com.anytypeio.anytype.domain.page.navigation.GetListPages
import com.anytypeio.anytype.domain.status.InterceptThreadStatus
import com.anytypeio.anytype.presentation.page.DocumentExternalEventReducer
import com.anytypeio.anytype.presentation.page.Editor
import com.anytypeio.anytype.presentation.page.PageViewModel
@ -48,6 +49,9 @@ open class EditorPresentationTestSetup {
@Mock
lateinit var interceptEvents: InterceptEvents
@Mock
lateinit var interceptThreadStatus: InterceptThreadStatus
@Mock
lateinit var createBlock: CreateBlock
@ -163,6 +167,7 @@ open class EditorPresentationTestSetup {
closePage = closePage,
createPage = createPage,
interceptEvents = interceptEvents,
interceptThreadStatus = interceptThreadStatus,
updateLinkMarks = updateLinkMark,
removeLinkMark = removeLinkMark,
reducer = DocumentExternalEventReducer(),