Login: change server screen WIP
This commit is contained in:
@@ -5,11 +5,9 @@ import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.navigation.popUpTo
|
||||
import io.element.android.x.destinations.LoginScreenNavigationDestination
|
||||
import io.element.android.x.destinations.MessagesScreenNavigationDestination
|
||||
import io.element.android.x.destinations.RoomListScreenNavigationDestination
|
||||
import io.element.android.x.destinations.OnBoardingScreenNavigationDestination
|
||||
import io.element.android.x.destinations.*
|
||||
import io.element.android.x.features.login.LoginScreen
|
||||
import io.element.android.x.features.login.changeserver.ChangeServerScreen
|
||||
import io.element.android.x.features.messages.MessagesScreen
|
||||
import io.element.android.x.features.onboarding.OnBoardingScreen
|
||||
import io.element.android.x.features.roomlist.RoomListScreen
|
||||
@@ -32,6 +30,10 @@ fun OnBoardingScreenNavigation(navigator: DestinationsNavigator) {
|
||||
@Composable
|
||||
fun LoginScreenNavigation(navigator: DestinationsNavigator) {
|
||||
LoginScreen(
|
||||
homeserver = "matrix.org",
|
||||
onChangeServer = {
|
||||
navigator.navigate(ChangeServerScreenNavigationDestination)
|
||||
},
|
||||
onLoginWithSuccess = {
|
||||
navigator.navigate(RoomListScreenNavigationDestination) {
|
||||
popUpTo(OnBoardingScreenNavigationDestination) {
|
||||
@@ -42,6 +44,17 @@ fun LoginScreenNavigation(navigator: DestinationsNavigator) {
|
||||
)
|
||||
}
|
||||
|
||||
// TODO Create a subgraph in Login module
|
||||
@Destination
|
||||
@Composable
|
||||
fun ChangeServerScreenNavigation(navigator: DestinationsNavigator) {
|
||||
ChangeServerScreen(
|
||||
onChangeServerSuccess = {
|
||||
navigator.popBackStack()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@RootNavGraph(start = true)
|
||||
@Destination
|
||||
@Composable
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package io.element.android.x.features.login
|
||||
|
||||
sealed interface LoginActions {
|
||||
data class SetHomeserver(val homeserver: String) : LoginActions
|
||||
data class SetLogin(val login: String) : LoginActions
|
||||
data class SetPassword(val password: String) : LoginActions
|
||||
object Submit : LoginActions
|
||||
}
|
||||
@@ -2,132 +2,184 @@
|
||||
|
||||
package io.element.android.x.features.login
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.compose.collectAsState
|
||||
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||
import io.element.android.x.designsystem.components.VectorButton
|
||||
import io.element.android.x.designsystem.ElementXTheme
|
||||
|
||||
@Composable
|
||||
fun LoginScreen(
|
||||
viewModel: LoginViewModel = mavericksViewModel(),
|
||||
onLoginWithSuccess: () -> Unit = { }
|
||||
homeserver: String,
|
||||
onChangeServer: () -> Unit = { },
|
||||
onLoginWithSuccess: () -> Unit = { },
|
||||
) {
|
||||
val state: LoginViewState by viewModel.collectAsState()
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
viewModel.homeserver = homeserver
|
||||
}
|
||||
LoginContent(
|
||||
state = state,
|
||||
onHomeserverChanged = { viewModel.handle(LoginActions.SetHomeserver(it)) },
|
||||
onLoginChanged = { viewModel.handle(LoginActions.SetLogin(it)) },
|
||||
onPasswordChanged = { viewModel.handle(LoginActions.SetPassword(it)) },
|
||||
onSubmitClicked = { viewModel.handle(LoginActions.Submit) },
|
||||
homeserver = homeserver,
|
||||
onChangeServer = onChangeServer,
|
||||
onLoginChanged = viewModel::onSetName,
|
||||
onPasswordChanged = viewModel::onSetPassword,
|
||||
onSubmitClicked = viewModel::onSubmit,
|
||||
onLoginWithSuccess = onLoginWithSuccess
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LoginContent(
|
||||
state: LoginViewState,
|
||||
onHomeserverChanged: (String) -> Unit,
|
||||
onLoginChanged: (String) -> Unit,
|
||||
onPasswordChanged: (String) -> Unit,
|
||||
onSubmitClicked: () -> Unit,
|
||||
onLoginWithSuccess: () -> Unit
|
||||
homeserver: String = "",
|
||||
onChangeServer: () -> Unit = {},
|
||||
onLoginChanged: (String) -> Unit = {},
|
||||
onPasswordChanged: (String) -> Unit = {},
|
||||
onSubmitClicked: () -> Unit = {},
|
||||
onLoginWithSuccess: () -> Unit = {},
|
||||
) {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.verticalScroll(
|
||||
state = scrollState,
|
||||
)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
val isError = state.isLoggedIn is Fail
|
||||
Image(
|
||||
painterResource(id = R.drawable.element_logo_green),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.padding(40.dp)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = state.homeserver,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onValueChange = {
|
||||
onHomeserverChanged(it)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Uri,
|
||||
),
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = state.login,
|
||||
// Title
|
||||
Text(
|
||||
text = "Welcome back",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp),
|
||||
onValueChange = {
|
||||
onLoginChanged(it)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Text,
|
||||
),
|
||||
.padding(horizontal = 16.dp, vertical = 48.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 24.sp,
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = state.password,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp),
|
||||
onValueChange = {
|
||||
onPasswordChanged(it)
|
||||
},
|
||||
isError = isError,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Send,
|
||||
),
|
||||
)
|
||||
if (isError) {
|
||||
Text(
|
||||
text = (state.isLoggedIn as? Fail)?.toString().orEmpty(),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
// Form
|
||||
Column(
|
||||
//modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = homeserver,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onValueChange = { /* no op */ },
|
||||
enabled = false,
|
||||
label = {
|
||||
Text(text = "Server")
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Uri,
|
||||
),
|
||||
)
|
||||
Button(
|
||||
onClick = onChangeServer,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(top = 8.dp, end = 8.dp),
|
||||
content = {
|
||||
Text(text = "Change")
|
||||
}
|
||||
)
|
||||
}
|
||||
OutlinedTextField(
|
||||
value = state.login,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 60.dp),
|
||||
label = {
|
||||
Text(text = "Email or username")
|
||||
},
|
||||
onValueChange = onLoginChanged,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Text,
|
||||
),
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = state.password,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 24.dp),
|
||||
onValueChange = onPasswordChanged,
|
||||
label = {
|
||||
Text(text = "Password")
|
||||
},
|
||||
isError = isError,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Send,
|
||||
),
|
||||
)
|
||||
if (isError) {
|
||||
Text(
|
||||
text = (state.isLoggedIn as? Fail)?.toString().orEmpty(),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
VectorButton(
|
||||
text = "Submit",
|
||||
onClick = {
|
||||
onSubmitClicked()
|
||||
},
|
||||
// Submit
|
||||
Button(
|
||||
onClick = onSubmitClicked,
|
||||
enabled = state.submitEnabled,
|
||||
modifier = Modifier
|
||||
.align(Alignment.End)
|
||||
.padding(top = 16.dp)
|
||||
)
|
||||
if (state.isLoggedIn is Loading) {
|
||||
// FIXME This does not work, we never enter this if block
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 32.dp)
|
||||
) {
|
||||
Text(text = "Continue")
|
||||
}
|
||||
if (state.isLoggedIn is Success) {
|
||||
onLoginWithSuccess()
|
||||
}
|
||||
}
|
||||
if (state.isLoggedIn is Loading) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun LoginContentPreview() {
|
||||
ElementXTheme(darkTheme = false) {
|
||||
LoginContent(
|
||||
state = LoginViewState(),
|
||||
homeserver = "matrix.org",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
package io.element.android.x.features.login
|
||||
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MavericksViewModel
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import io.element.android.x.matrix.MatrixInstance
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LoginViewModel(initialState: LoginViewState) :
|
||||
MavericksViewModel<LoginViewState>(initialState) {
|
||||
|
||||
lateinit var homeserver: String
|
||||
|
||||
private val matrix = MatrixInstance.getInstance()
|
||||
|
||||
fun handle(action: LoginActions) {
|
||||
when (action) {
|
||||
is LoginActions.SetHomeserver -> handleSetHomeserver(action)
|
||||
is LoginActions.SetLogin -> handleSetName(action)
|
||||
is LoginActions.SetPassword -> handleSetPassword(action)
|
||||
LoginActions.Submit -> handleSubmit()
|
||||
fun onSubmit() = withState { state ->
|
||||
setState {
|
||||
copy(isLoggedIn = Loading())
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSubmit() = withState { state ->
|
||||
viewModelScope.launch {
|
||||
suspend {
|
||||
matrix.login(state.homeserver, state.login, state.password)
|
||||
// Ensure the server is passed to the Rust SDK
|
||||
matrix.setHomeserver(homeserver)
|
||||
matrix.login(state.login, state.password)
|
||||
matrix.activeClient().startSync()
|
||||
}.execute {
|
||||
copy(isLoggedIn = it)
|
||||
@@ -29,15 +30,21 @@ class LoginViewModel(initialState: LoginViewState) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSetHomeserver(action: LoginActions.SetHomeserver) {
|
||||
setState { copy(homeserver = action.homeserver) }
|
||||
fun onSetPassword(password: String) {
|
||||
setState {
|
||||
copy(
|
||||
password = password,
|
||||
isLoggedIn = Uninitialized,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSetPassword(action: LoginActions.SetPassword) {
|
||||
setState { copy(password = action.password) }
|
||||
}
|
||||
|
||||
private fun handleSetName(action: LoginActions.SetLogin) {
|
||||
setState { copy(login = action.login) }
|
||||
fun onSetName(name: String) {
|
||||
setState {
|
||||
copy(
|
||||
login = name,
|
||||
isLoggedIn = Uninitialized,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
package io.element.android.x.features.login
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
|
||||
data class LoginViewState(
|
||||
val homeserver: String = "matrix.org",
|
||||
val login: String = "",
|
||||
val password: String = "",
|
||||
val isLoggedIn: Async<Unit> = Uninitialized,
|
||||
) : MavericksState {
|
||||
|
||||
val submitEnabled = homeserver.isNotEmpty() && login.isNotEmpty() && password.isNotEmpty()
|
||||
|
||||
|
||||
val submitEnabled = login.isNotEmpty() && password.isNotEmpty() && isLoggedIn !is Loading
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
package io.element.android.x.features.login.changeserver
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.compose.collectAsState
|
||||
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||
|
||||
@Composable
|
||||
fun ChangeServerScreen(
|
||||
viewModel: ChangeServerViewModel = mavericksViewModel(),
|
||||
onChangeServerSuccess: () -> Unit = { }
|
||||
) {
|
||||
val state: ChangeServerViewState by viewModel.collectAsState()
|
||||
ChangeServerContent(
|
||||
state = state,
|
||||
onChangeServer = viewModel::setServer,
|
||||
onChangeServerSubmit = viewModel::setServerSubmit,
|
||||
onChangeServerSuccess = onChangeServerSuccess
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ChangeServerContent(
|
||||
state: ChangeServerViewState,
|
||||
onChangeServer: (String) -> Unit = {},
|
||||
onChangeServerSubmit: () -> Unit = {},
|
||||
onChangeServerSuccess: () -> Unit = {},
|
||||
) {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(
|
||||
state = scrollState,
|
||||
)
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
{
|
||||
val isError = state.changeServerAction is Fail
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = 99.dp)
|
||||
.size(width = 81.dp, height = 73.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
shape = RoundedCornerShape(32.dp)
|
||||
),
|
||||
text = "\uDBC2\uDEAC",
|
||||
fontSize = 34.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = "Your server",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.defaultMinSize(minHeight = 56.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.padding(top = 38.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 24.sp,
|
||||
)
|
||||
Text(
|
||||
text = "A server is a home for all your data.\n" +
|
||||
"You choose your server and it’s easy to make one.", // TODO "Learn more.",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.padding(top = 16.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
fontSize = 16.sp,
|
||||
color = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = state.homeserver,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 200.dp),
|
||||
onValueChange = onChangeServer,
|
||||
label = {
|
||||
Text(text = "Server")
|
||||
},
|
||||
isError = isError,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Send,
|
||||
),
|
||||
)
|
||||
if (isError) {
|
||||
Text(
|
||||
text = (state.changeServerAction as? Fail)?.toString().orEmpty(),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
Button(
|
||||
onClick = onChangeServerSubmit,
|
||||
enabled = state.submitEnabled,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 44.dp)
|
||||
) {
|
||||
Text(text = "Continue")
|
||||
}
|
||||
if (state.changeServerAction is Success) {
|
||||
onChangeServerSuccess()
|
||||
}
|
||||
}
|
||||
if (state.changeServerAction is Loading) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun ChangeServerContentPreview() {
|
||||
ChangeServerContent(
|
||||
state = ChangeServerViewState(homeserver = "matrix.org"),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.element.android.x.features.login.changeserver
|
||||
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MavericksViewModel
|
||||
import io.element.android.x.matrix.MatrixInstance
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ChangeServerViewModel(initialState: ChangeServerViewState) :
|
||||
MavericksViewModel<ChangeServerViewState>(initialState) {
|
||||
|
||||
private val matrix = MatrixInstance.getInstance()
|
||||
|
||||
fun setServer(server: String) {
|
||||
setState {
|
||||
copy(homeserver = server)
|
||||
}
|
||||
}
|
||||
|
||||
fun setServerSubmit() = withState { state ->
|
||||
setState {
|
||||
copy(changeServerAction = Loading())
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
suspend {
|
||||
matrix.setHomeserver(state.homeserver)
|
||||
}.execute { it ->
|
||||
copy(changeServerAction = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.element.android.x.features.login.changeserver
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
|
||||
data class ChangeServerViewState(
|
||||
val homeserver: String = "matrix.org",
|
||||
val changeServerAction: Async<Unit> = Uninitialized,
|
||||
) : MavericksState {
|
||||
val submitEnabled = homeserver.isNotEmpty() && changeServerAction !is Loading
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package io.element.android.x.features.onboarding
|
||||
|
||||
sealed interface OnBoardingActions {
|
||||
data class GoToPage(val page: Int) : OnBoardingActions
|
||||
}
|
||||
@@ -48,4 +48,5 @@ dependencies {
|
||||
implementation 'androidx.fragment:fragment-ktx:1.5.3'
|
||||
|
||||
implementation 'com.airbnb.android:mavericks-compose:3.0.1'
|
||||
implementation 'androidx.compose.foundation:foundation-layout:1.3.1'
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package io.element.android.x.core.compose
|
||||
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.isImeVisible
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
||||
/**
|
||||
* Inspired from https://stackoverflow.com/questions/68847559/how-can-i-detect-keyboard-opening-and-closing-in-jetpack-compose
|
||||
*/
|
||||
enum class Keyboard {
|
||||
Opened, Closed
|
||||
}
|
||||
|
||||
// Note: it does not work as expected...
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun keyboardAsState(): State<Keyboard> {
|
||||
val lifecycle = LocalLifecycleOwner.current.lifecycle
|
||||
val isResumed = lifecycle.currentState == Lifecycle.State.RESUMED
|
||||
return rememberUpdatedState(if (WindowInsets.isImeVisible && isResumed) Keyboard.Opened else Keyboard.Closed)
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import io.element.android.x.matrix.util.logError
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.AuthenticationService
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
@@ -27,6 +26,7 @@ class Matrix(
|
||||
private val baseFolder = File(context.filesDir, "matrix")
|
||||
private val sessionStore = SessionStore(context)
|
||||
private val matrixClient = MutableStateFlow<Optional<MatrixClient>>(Optional.empty())
|
||||
private val authService = AuthenticationService(baseFolder.absolutePath)
|
||||
|
||||
init {
|
||||
sessionStore.isLoggedIn()
|
||||
@@ -70,10 +70,14 @@ class Matrix(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun login(homeserver: String, username: String, password: String): MatrixClient =
|
||||
suspend fun setHomeserver(homeserver: String) {
|
||||
withContext(coroutineDispatchers.io) {
|
||||
val authService = AuthenticationService(baseFolder.absolutePath)
|
||||
authService.configureHomeserver(homeserver)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun login(username: String, password: String): MatrixClient =
|
||||
withContext(coroutineDispatchers.io) {
|
||||
val client = authService.login(username, password, "MatrixRustSDKSample", null)
|
||||
sessionStore.storeData(client.session())
|
||||
createMatrixClient(client)
|
||||
|
||||
Reference in New Issue
Block a user