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:
parent
812df6d7ca
commit
ce0d55e58e
14 changed files with 187 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.anytypeio.anytype.data.auth.model
|
||||
|
||||
enum class SyncStatusEntity {
|
||||
UNKNOWN,
|
||||
OFFLINE,
|
||||
SYNCING,
|
||||
SYNCED,
|
||||
FAILED
|
||||
}
|
|
@ -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) }
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.anytypeio.anytype.domain.status
|
||||
|
||||
enum class SyncStatus {
|
||||
UNKNOWN,
|
||||
OFFLINE,
|
||||
SYNCING,
|
||||
SYNCED,
|
||||
FAILED
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.anytypeio.anytype.domain.status
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface ThreadStatusChannel {
|
||||
fun observe(ctx: String): Flow<SyncStatus>
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue