Move some package on core + try some stuff around sync/roomlist
This commit is contained in:
parent
8e3f600bd1
commit
2bf898582c
18 changed files with 106 additions and 43 deletions
|
|
@ -66,6 +66,7 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":libraries:designsystem")
|
implementation project(":libraries:designsystem")
|
||||||
implementation project(":libraries:matrix")
|
implementation project(":libraries:matrix")
|
||||||
|
implementation project(":libraries:core")
|
||||||
implementation project(":features:onboarding")
|
implementation project(":features:onboarding")
|
||||||
implementation project(":features:login")
|
implementation project(":features:login")
|
||||||
implementation project(":features:roomlist")
|
implementation project(":features:roomlist")
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,14 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||||
import com.ramcosta.composedestinations.rememberNavHostEngine
|
import com.ramcosta.composedestinations.rememberNavHostEngine
|
||||||
|
import io.element.android.x.core.compose.OnLifecycleEvent
|
||||||
import io.element.android.x.designsystem.ElementXTheme
|
import io.element.android.x.designsystem.ElementXTheme
|
||||||
import io.element.android.x.destinations.LoginScreenNavigationDestination
|
|
||||||
import io.element.android.x.destinations.OnBoardingScreenNavigationDestination
|
import io.element.android.x.destinations.OnBoardingScreenNavigationDestination
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
|
@ -52,4 +54,8 @@ private fun MainScreen(viewModel: MainViewModel) {
|
||||||
navGraph = NavGraphs.root,
|
navGraph = NavGraphs.root,
|
||||||
startRoute = startRoute
|
startRoute = startRoute
|
||||||
)
|
)
|
||||||
|
|
||||||
|
OnLifecycleEvent { _, event ->
|
||||||
|
Timber.v("OnLifecycleEvent: $event")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package io.element.android.x
|
package io.element.android.x
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import io.element.android.x.matrix.MatrixInstance
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainViewModel : ViewModel() {
|
class MainViewModel : ViewModel() {
|
||||||
private val matrix = MatrixInstance.getInstance()
|
private val matrix = MatrixInstance.getInstance()
|
||||||
|
|
@ -11,7 +13,22 @@ class MainViewModel : ViewModel() {
|
||||||
return matrix.isLoggedIn().first()
|
return matrix.isLoggedIn().first()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startSyncIfLogged(){
|
||||||
|
viewModelScope.launch {
|
||||||
|
if(!isLoggedIn()) return@launch
|
||||||
|
matrix.activeClient().startSync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopSyncIfLogged(){
|
||||||
|
viewModelScope.launch {
|
||||||
|
if (!isLoggedIn()) return@launch
|
||||||
|
matrix.activeClient().stopSync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun restoreSession() {
|
suspend fun restoreSession() {
|
||||||
matrix.restoreSession()
|
matrix.restoreSession()
|
||||||
|
matrix.activeClient().startSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ class LoginViewModel(initialState: LoginViewState) :
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
suspend {
|
suspend {
|
||||||
matrix.login(state.homeserver, state.login, state.password)
|
matrix.login(state.homeserver, state.login, state.password)
|
||||||
Unit
|
matrix.activeClient().startSync()
|
||||||
}.execute {
|
}.execute {
|
||||||
copy(isLoggedIn = it)
|
copy(isLoggedIn = it)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import com.airbnb.mvrx.compose.collectAsState
|
import com.airbnb.mvrx.compose.collectAsState
|
||||||
import com.airbnb.mvrx.compose.mavericksViewModel
|
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||||
import io.element.android.x.core.data.LogCompositions
|
import io.element.android.x.core.compose.LogCompositions
|
||||||
import io.element.android.x.core.data.StableCharSequence
|
import io.element.android.x.core.data.StableCharSequence
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.x.features.messages.components.*
|
import io.element.android.x.features.messages.components.*
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.compose.collectAsState
|
import com.airbnb.mvrx.compose.collectAsState
|
||||||
import com.airbnb.mvrx.compose.mavericksViewModel
|
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||||
import io.element.android.x.core.data.LogCompositions
|
import io.element.android.x.core.compose.LogCompositions
|
||||||
import io.element.android.x.designsystem.ElementXTheme
|
import io.element.android.x.designsystem.ElementXTheme
|
||||||
import io.element.android.x.designsystem.components.ProgressDialog
|
import io.element.android.x.designsystem.components.ProgressDialog
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ class RoomListViewModel(initialState: RoomListViewState) :
|
||||||
private fun handleInit() {
|
private fun handleInit() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val client = getClient()
|
val client = getClient()
|
||||||
client.startSync()
|
|
||||||
suspend {
|
suspend {
|
||||||
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
||||||
val userDisplayName = client.loadUserDisplayName().getOrNull()
|
val userDisplayName = client.loadUserDisplayName().getOrNull()
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import io.element.android.x.core.data.LogCompositions
|
import io.element.android.x.core.compose.LogCompositions
|
||||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
import io.element.android.x.features.roomlist.model.MatrixUser
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package io.element.android.x.core.data
|
package io.element.android.x.core.compose
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package io.element.android.x.core.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) {
|
||||||
|
val eventHandler = rememberUpdatedState(onEvent)
|
||||||
|
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
|
||||||
|
|
||||||
|
DisposableEffect(lifecycleOwner.value) {
|
||||||
|
val lifecycle = lifecycleOwner.value.lifecycle
|
||||||
|
val observer = LifecycleEventObserver { owner, event ->
|
||||||
|
eventHandler.value(owner, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle.addObserver(observer)
|
||||||
|
onDispose {
|
||||||
|
lifecycle.removeObserver(observer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package io.element.android.x.core.data
|
package io.element.android.x.core.coroutine
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package io.element.android.x.matrix
|
package io.element.android.x.matrix
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.element.android.x.core.data.CoroutineDispatchers
|
import io.element.android.x.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.x.matrix.session.SessionStore
|
import io.element.android.x.matrix.session.SessionStore
|
||||||
import io.element.android.x.matrix.util.logError
|
import io.element.android.x.matrix.util.logError
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package io.element.android.x.matrix
|
package io.element.android.x.matrix
|
||||||
|
|
||||||
import io.element.android.x.core.data.CoroutineDispatchers
|
import io.element.android.x.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.x.matrix.core.UserId
|
import io.element.android.x.matrix.core.UserId
|
||||||
import io.element.android.x.matrix.media.MediaResolver
|
import io.element.android.x.matrix.media.MediaResolver
|
||||||
import io.element.android.x.matrix.media.RustMediaResolver
|
import io.element.android.x.matrix.media.RustMediaResolver
|
||||||
|
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.*
|
import org.matrix.rustcomponents.sdk.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
class MatrixClient internal constructor(
|
class MatrixClient internal constructor(
|
||||||
private val client: Client,
|
private val client: Client,
|
||||||
|
|
@ -67,6 +68,7 @@ class MatrixClient internal constructor(
|
||||||
private var slidingSyncObserverToken: StoppableSpawn? = null
|
private var slidingSyncObserverToken: StoppableSpawn? = null
|
||||||
|
|
||||||
private val mediaResolver = RustMediaResolver(this)
|
private val mediaResolver = RustMediaResolver(this)
|
||||||
|
private val isSyncing = AtomicBoolean(false)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
client.setDelegate(clientDelegate)
|
client.setDelegate(clientDelegate)
|
||||||
|
|
@ -84,15 +86,19 @@ class MatrixClient internal constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startSync() {
|
fun startSync() {
|
||||||
roomSummaryDataSource.startSync()
|
if (isSyncing.compareAndSet(false, true)) {
|
||||||
slidingSync.setObserver(slidingSyncObserverProxy)
|
roomSummaryDataSource.startSync()
|
||||||
slidingSyncObserverToken = slidingSync.sync()
|
slidingSync.setObserver(slidingSyncObserverProxy)
|
||||||
|
slidingSyncObserverToken = slidingSync.sync()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopSync() {
|
fun stopSync() {
|
||||||
roomSummaryDataSource.stopSync()
|
if (isSyncing.compareAndSet(true, false)) {
|
||||||
slidingSync.setObserver(null)
|
roomSummaryDataSource.stopSync()
|
||||||
slidingSyncObserverToken?.cancel()
|
slidingSync.setObserver(null)
|
||||||
|
slidingSyncObserverToken?.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun roomSummaryDataSource(): RoomSummaryDataSource = roomSummaryDataSource
|
fun roomSummaryDataSource(): RoomSummaryDataSource = roomSummaryDataSource
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package io.element.android.x.matrix.room
|
package io.element.android.x.matrix.room
|
||||||
|
|
||||||
import io.element.android.x.core.data.CoroutineDispatchers
|
import io.element.android.x.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.x.matrix.core.RoomId
|
import io.element.android.x.matrix.core.RoomId
|
||||||
import io.element.android.x.matrix.core.UserId
|
import io.element.android.x.matrix.core.UserId
|
||||||
import io.element.android.x.matrix.timeline.MatrixTimeline
|
import io.element.android.x.matrix.timeline.MatrixTimeline
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
package io.element.android.x.matrix.room
|
package io.element.android.x.matrix.room
|
||||||
|
|
||||||
import io.element.android.x.core.data.CoroutineDispatchers
|
import io.element.android.x.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.x.core.data.flow.chunk
|
import io.element.android.x.core.data.flow.chunk
|
||||||
import io.element.android.x.matrix.room.message.RoomMessageFactory
|
|
||||||
import io.element.android.x.matrix.sync.roomListDiff
|
import io.element.android.x.matrix.sync.roomListDiff
|
||||||
import io.element.android.x.matrix.sync.state
|
import io.element.android.x.matrix.sync.state
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.cancelChildren
|
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import org.matrix.rustcomponents.sdk.*
|
import org.matrix.rustcomponents.sdk.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
interface RoomSummaryDataSource {
|
interface RoomSummaryDataSource {
|
||||||
fun roomSummaries(): Flow<List<RoomSummary>>
|
fun roomSummaries(): Flow<List<RoomSummary>>
|
||||||
|
|
@ -27,33 +24,43 @@ internal class RustRoomSummaryDataSource(
|
||||||
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory()
|
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory()
|
||||||
) : RoomSummaryDataSource, Closeable {
|
) : RoomSummaryDataSource, Closeable {
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.io)
|
private val singleDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||||
|
|
||||||
|
private val coroutineScope = CoroutineScope(SupervisorJob() + singleDispatcher)
|
||||||
|
|
||||||
private val roomSummaries = MutableStateFlow<List<RoomSummary>>(emptyList())
|
private val roomSummaries = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||||
private val state = MutableStateFlow(SlidingSyncState.COLD)
|
private val state = MutableStateFlow(SlidingSyncState.COLD)
|
||||||
|
|
||||||
|
fun startSync() {
|
||||||
|
coroutineScope.launch {
|
||||||
|
updateRoomSummaries {
|
||||||
|
clear()
|
||||||
|
addAll(
|
||||||
|
slidingSyncView.currentRoomsList().map(::buildSummaryForRoomListEntry)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun startSync(){
|
slidingSyncView.roomListDiff()
|
||||||
slidingSyncView.roomListDiff()
|
.chunk(30)
|
||||||
.chunk(100)
|
.onEach { diffs ->
|
||||||
.onEach { diffs ->
|
updateRoomSummaries {
|
||||||
updateRoomSummaries {
|
diffs.forEach {
|
||||||
diffs.forEach {
|
applyDiff(it)
|
||||||
applyDiff(it)
|
}
|
||||||
}
|
}
|
||||||
}
|
}.collect()
|
||||||
}.launchIn(coroutineScope)
|
|
||||||
|
|
||||||
slidingSyncView.state()
|
slidingSyncView.state()
|
||||||
.onEach { slidingSyncState ->
|
.onEach { slidingSyncState ->
|
||||||
Timber.v("New sliding sync state: $slidingSyncState")
|
Timber.v("New sliding sync state: $slidingSyncState")
|
||||||
state.value = slidingSyncState
|
state.value = slidingSyncState
|
||||||
}.launchIn(coroutineScope)
|
}.collect()
|
||||||
|
|
||||||
slidingSyncUpdateFlow
|
slidingSyncUpdateFlow
|
||||||
.onEach {
|
.onEach {
|
||||||
didReceiveSyncUpdate(it)
|
didReceiveSyncUpdate(it)
|
||||||
}.launchIn(coroutineScope)
|
}.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopSync() {
|
fun stopSync() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package io.element.android.x.matrix.timeline
|
package io.element.android.x.matrix.timeline
|
||||||
|
|
||||||
import io.element.android.x.core.data.CoroutineDispatchers
|
import io.element.android.x.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.x.core.data.flow.chunk
|
import io.element.android.x.core.data.flow.chunk
|
||||||
import io.element.android.x.matrix.core.EventId
|
import io.element.android.x.matrix.core.EventId
|
||||||
import io.element.android.x.matrix.room.MatrixRoom
|
import io.element.android.x.matrix.room.MatrixRoom
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue