Fix bunch of issues around login/logout and introduces messages feature

This commit is contained in:
ganfra 2022-11-04 14:50:30 +01:00
parent b5e4ef9637
commit d04d847521
19 changed files with 314 additions and 89 deletions

View file

@ -1,16 +1,12 @@
package io.element.android.x.designsystem
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import com.google.accompanist.systemuicontroller.rememberSystemUiController
private val DarkColorScheme = darkColorScheme(

View file

@ -0,0 +1,39 @@
package io.element.android.x.designsystem.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
@Composable
fun ProgressDialog(text: String? = null, onDismiss: () -> Unit = {}) {
Dialog(
onDismissRequest = onDismiss,
DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxWidth()
.background(
MaterialTheme.colorScheme.onBackground,
shape = RoundedCornerShape(8.dp)
)
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
CircularProgressIndicator(modifier = Modifier.padding(16.dp), color = MaterialTheme.colorScheme.background)
if (!text.isNullOrBlank()) {
Text(text = text, Modifier.padding(16.dp))
}
}
}
}
}

View file

@ -4,15 +4,20 @@ import android.content.Context
import io.element.android.x.core.data.CoroutineDispatchers
import io.element.android.x.matrix.session.SessionStore
import io.element.android.x.matrix.util.logError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.AuthenticationService
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientBuilder
import java.io.File
import java.util.Optional
class Matrix(
coroutineScope: CoroutineScope,
context: Context,
) {
private val coroutineDispatchers = CoroutineDispatchers(
io = Dispatchers.IO,
computation = Dispatchers.Default,
@ -20,9 +25,31 @@ class Matrix(
)
private val baseFolder = File(context.filesDir, "matrix")
private val sessionStore = SessionStore(context)
private val matrixClient = MutableStateFlow<Optional<MatrixClient>>(Optional.empty())
private val isLoggedIn = MutableStateFlow(false)
suspend fun restoreSession(): MatrixClient? {
return sessionStore.getStoredData()
init {
sessionStore.isLoggedIn()
.distinctUntilChanged()
.onEach { isLoggedIn ->
this.isLoggedIn.value = isLoggedIn
if (!isLoggedIn) {
matrixClient.value = Optional.empty()
}
}
.launchIn(coroutineScope)
}
fun isLoggedIn(): Flow<Boolean> {
return isLoggedIn
}
fun matrixClient(): Flow<Optional<MatrixClient>> {
return matrixClient
}
suspend fun restoreSession() = withContext(coroutineDispatchers.io) {
sessionStore.getStoredData()
?.let { sessionData ->
try {
ClientBuilder()
@ -36,15 +63,26 @@ class Matrix(
null
}
}?.let {
MatrixClient(it, sessionStore, coroutineDispatchers)
createMatrixClient(it)
}
}
suspend fun login(homeserver: String, username: String, password: String): MatrixClient {
val authService = AuthenticationService(baseFolder.absolutePath)
authService.configureHomeserver(homeserver)
val client = authService.login(username, password, "MatrixRustSDKSample", null)
sessionStore.storeData(SessionStore.SessionData(client.userId(), client.restoreToken()))
return MatrixClient(client, sessionStore, coroutineDispatchers)
suspend fun login(homeserver: String, username: String, password: String): MatrixClient =
withContext(coroutineDispatchers.io) {
val authService = AuthenticationService(baseFolder.absolutePath)
authService.configureHomeserver(homeserver)
val client = authService.login(username, password, "MatrixRustSDKSample", null)
sessionStore.storeData(SessionStore.SessionData(client.userId(), client.restoreToken()))
createMatrixClient(client)
}
private fun createMatrixClient(client: Client): MatrixClient {
return MatrixClient(
client = client,
sessionStore = sessionStore,
dispatchers = coroutineDispatchers
).also {
matrixClient.value = Optional.of(it)
}
}
}

View file

@ -61,7 +61,6 @@ class MatrixClient internal constructor(
init {
client.setDelegate(clientDelegate)
}
fun startSync() {
slidingSync.setObserver(slidingSyncObserver)
slidingSyncObserverToken = slidingSync.sync()

View file

@ -2,6 +2,7 @@ package io.element.android.x.matrix
import android.annotation.SuppressLint
import android.content.Context
import kotlinx.coroutines.GlobalScope
object MatrixInstance {
@ -9,7 +10,7 @@ object MatrixInstance {
private lateinit var instance: Matrix
fun init(context: Context) {
instance = Matrix(context)
instance = Matrix(GlobalScope, context)
}
fun getInstance(): Matrix {

View file

@ -6,10 +6,13 @@ import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_sessions")
private val userIdPreference = stringPreferencesKey("userId")
// TODO It contains the access token, so it has to be stored in a more secured storage.
// I would expect the Rust SDK to provide a more obscure token.
private val restoreTokenPreference = stringPreferencesKey("restoreToken")
@ -25,6 +28,11 @@ internal class SessionStore(
private val store = context.dataStore
fun isLoggedIn(): Flow<Boolean> {
return store.data.map { prefs ->
prefs[userIdPreference] != null && prefs[restoreTokenPreference] != null
}
}
suspend fun storeData(sessionData: SessionData) {
store.edit { prefs ->