1
Fork 0
mirror of https://github.com/Steffo99/twom.git synced 2024-11-21 23:54:26 +00:00

Complete basic login process

This commit is contained in:
Steffo 2023-11-22 18:45:35 +01:00
parent cdad623e96
commit c00039b008
Signed by: steffo
GPG key ID: 2A24051445686895
6 changed files with 222 additions and 34 deletions

View file

@ -0,0 +1,58 @@
package eu.steffo.twom.login
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.TextUnit
@Composable
@Preview(showBackground = true)
fun ErrorText(
modifier: Modifier = Modifier,
text: String = "",
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
minLines: Int = 1,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
) {
Text(
modifier = modifier,
text = text,
color = MaterialTheme.colorScheme.error,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
overflow = overflow,
softWrap = softWrap,
maxLines = maxLines,
minLines = minLines,
onTextLayout = onTextLayout,
style = style,
)
}

View file

@ -9,7 +9,16 @@ class LoginActivity : ComponentActivity() {
super.onStart()
setContent {
LoginActivityScaffold()
LoginActivityScaffold(
onBack = {
setResult(RESULT_CANCELED)
finish()
},
onLogin = {
setResult(RESULT_OK)
finish()
},
)
}
}
}

View file

@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Button
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
@ -21,9 +23,15 @@ import eu.steffo.twom.R
import eu.steffo.twom.matrix.TwoMMatrix
import eu.steffo.twom.theme.TwoMPadding
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.data.LoginFlowResult
import org.matrix.android.sdk.api.auth.login.LoginWizard
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
import org.matrix.android.sdk.api.failure.MatrixIdFailure
import org.matrix.android.sdk.api.session.Session
// TODO: Localize error messages
@Composable
@Preview(showBackground = true)
fun LoginActivityControl(
@ -35,19 +43,15 @@ fun LoginActivityControl(
var username by rememberSaveable { mutableStateOf("") }
var password by rememberSaveable { mutableStateOf("") }
var loggingIn by rememberSaveable { mutableStateOf(false) }
var loginStep by rememberSaveable { mutableStateOf(LoginStep.NONE) }
var errorMessage by rememberSaveable { mutableStateOf<String?>(null) }
Column(modifier) {
if (loggingIn) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
)
} else {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
progress = 0.0f,
)
}
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(),
progress = loginStep.step.toFloat() / LoginStep.DONE.step.toFloat(),
color = if (errorMessage != null) MaterialTheme.colorScheme.error else ProgressIndicatorDefaults.linearColor
)
Row(TwoMPadding.base) {
Text(LocalContext.current.getString(R.string.login_text))
}
@ -88,44 +92,120 @@ fun LoginActivityControl(
modifier = Modifier.fillMaxWidth(),
onClick = {
scope.launch Login@{
Log.d(this::class.qualifiedName, "Launching login wizard...")
val wizard = TwoMMatrix.matrix.authenticationService().getLoginWizard()
errorMessage = null
// TODO: Which exceptions can this spawn?
Log.d(this::class.qualifiedName, "Trying to login as: $username")
loggingIn = true
Log.d("Login", "Getting authentication service...")
loginStep = LoginStep.SERVICE
val auth = TwoMMatrix.matrix.authenticationService()
Log.d("Login", "Retrieving .well-known data for: $username")
loginStep = LoginStep.WELLKNOWN
lateinit var wellKnown: WellknownResult
try {
wellKnown = auth.getWellKnownData(username, null)
} catch (e: MatrixIdFailure.InvalidMatrixId) {
Log.d(
"Login",
"User seems to have input an invalid Matrix ID: $username",
e
)
errorMessage = "The input Matrix ID is invalid."
return@Login
} catch (e: Throwable) {
// TODO: It sure would be nice to know which exceptions can be thrown here.
Log.e(
"Login",
"Something went wrong while retrieving .well-known data for: $username",
e
)
errorMessage = e.message
return@Login
}
if (wellKnown !is WellknownResult.Prompt) {
Log.w(
"Login",
"Data is not .well-known for: $username"
)
errorMessage =
"Non .well-known Matrix servers are not currently supported by TwoM."
return@Login
}
Log.d("Login", "Retrieving login flows for: ${wellKnown.homeServerUrl}")
loginStep = LoginStep.FLOWS
lateinit var flows: LoginFlowResult
try {
flows = auth.getLoginFlow(
HomeServerConnectionConfig
.Builder()
.withHomeServerUri(wellKnown.homeServerUrl)
.build()
)
} catch (e: Throwable) {
// TODO: It sure would be nice to know which exceptions can be thrown here.
Log.e(
"Login",
"Something went wrong while retrieving login flows for: ${wellKnown.homeServerUrl}",
e
)
errorMessage = e.message
return@Login
}
Log.d("Login", "Creating login wizard...")
loginStep = LoginStep.WIZARD
lateinit var wizard: LoginWizard
try {
wizard = auth.getLoginWizard() // Why is this stateful? Aargh.
} catch (e: Throwable) {
// TODO: It sure would be nice to know which exceptions can be thrown here.
Log.e(
"Login",
"Something went wrong while creating the login wizard.",
e
)
errorMessage = e.message
return@Login
}
Log.d("Login", "Logging in as: $username")
loginStep = LoginStep.LOGIN
lateinit var session: Session
// TODO: Why does this not catch the exception?
try {
session = wizard.login(
login = username,
password = password,
initialDeviceName = "Garasauto", // TODO
deviceId = "Garasauto", // TODO
initialDeviceName = "Garasauto", // TODO: Set a proper device name
deviceId = "Garasauto", // TODO: Set a proper device id
)
} catch (e: RuntimeException) {
} catch (e: Throwable) {
Log.e(
this::class.qualifiedName,
"Login",
"Something went wrong while logging in as: $username",
e
)
errorMessage = e.message
return@Login
} finally {
loggingIn = false
}
Log.d(
this::class.qualifiedName,
"Logged in with session id: ${session.sessionId}"
"Login",
"Logged in successfully with session id: ${session.sessionId}"
)
loginStep = LoginStep.DONE
onLogin(session)
}
},
enabled = (username != ""),
enabled = (username != "" && (loginStep == LoginStep.NONE || errorMessage != null)),
) {
Text(LocalContext.current.getString(R.string.login_complete_text))
}
}
if (errorMessage != null) {
Row(TwoMPadding.base) {
ErrorText(text = errorMessage ?: "Unknown error")
}
}
}
}

View file

@ -23,8 +23,6 @@ import org.matrix.android.sdk.api.session.Session
@Preview
fun LoginActivityScaffold(
onBack: () -> Unit = {},
selectedHomeserver: String? = null,
onSelectHomeserver: () -> Unit = {},
onLogin: (session: Session) -> Unit = {},
) {
TwoMTheme {
@ -43,7 +41,10 @@ fun LoginActivityScaffold(
)
}
) {
LoginActivityControl(Modifier.padding(it))
LoginActivityControl(
modifier = Modifier.padding(it),
onLogin = onLogin
)
}
}
}

View file

@ -0,0 +1,11 @@
package eu.steffo.twom.login
enum class LoginStep(val step: Int) {
NONE(0),
SERVICE(1),
WELLKNOWN(2),
FLOWS(3),
WIZARD(4),
LOGIN(5),
DONE(6),
}

View file

@ -20,12 +20,15 @@ import androidx.compose.ui.platform.LocalContext
import eu.steffo.twom.R
import eu.steffo.twom.login.LoginActivity
import eu.steffo.twom.theme.TwoMTheme
import org.matrix.android.sdk.api.session.Session
@OptIn(ExperimentalMaterial3Api::class)
class MatrixActivity : ComponentActivity() {
private lateinit var loginLauncher: ActivityResultLauncher<Intent>
private var session: Session? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
actionBar?.hide()
@ -33,9 +36,35 @@ class MatrixActivity : ComponentActivity() {
TwoMMatrix.ensureMatrix(applicationContext)
loginLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
Log.d(this::class.qualifiedName, "LoginActivity has returned a result.")
}
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) HandleResult@{
Log.d(this::class.qualifiedName, "LoginActivity has returned a result!")
when (it.resultCode) {
RESULT_OK -> {
session =
TwoMMatrix.matrix.authenticationService().getLastAuthenticatedSession()
setContent {
TwoMTheme {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(LocalContext.current.getString(R.string.app_name))
}
)
}
) {
Text(session?.myUserId ?: "No session", Modifier.padding(it))
}
}
}
}
}
if (it.resultCode == RESULT_CANCELED) {
return@HandleResult
}
}
}
override fun onStart() {
@ -59,7 +88,7 @@ class MatrixActivity : ComponentActivity() {
loginLauncher.launch(Intent(applicationContext, LoginActivity::class.java))
}
) {
Text("")
Text("plis login with matrics no scam 100%")
}
}
}