mirror of
https://github.com/Steffo99/twom.git
synced 2024-11-24 09:04:24 +00:00
Refactor out manageLogin
This commit is contained in:
parent
63ef1a4edd
commit
529d821db1
7 changed files with 239 additions and 234 deletions
|
@ -5,7 +5,7 @@ import android.content.Intent
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContract
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
import eu.steffo.twom.composables.login.LoginScaffold
|
import eu.steffo.twom.composables.login.components.LoginScaffold
|
||||||
|
|
||||||
|
|
||||||
class LoginActivity : ComponentActivity() {
|
class LoginActivity : ComponentActivity() {
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package eu.steffo.twom.composables.errorhandling
|
package eu.steffo.twom.composables.errorhandling
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
|
||||||
|
private const val TAG = "LocalizableError"
|
||||||
|
|
||||||
data class LocalizableError(
|
data class LocalizableError(
|
||||||
@StringRes val stringResourceId: Int,
|
@StringRes val stringResourceId: Int,
|
||||||
|
@ -25,3 +30,20 @@ fun LocalizableError?.Display(contents: @Composable (rendered: String) -> Unit)
|
||||||
val rendered = this.render() ?: return
|
val rendered = this.render() ?: return
|
||||||
contents(rendered)
|
contents(rendered)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun MutableState<LocalizableError?>.capture(
|
||||||
|
@StringRes error: Int,
|
||||||
|
coroutine: suspend () -> Unit,
|
||||||
|
): Unit? {
|
||||||
|
try {
|
||||||
|
coroutine()
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
Log.v(TAG, "Cancelled coroutine execution", e)
|
||||||
|
return null
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e(TAG, "Captured error during coroutine execution", e)
|
||||||
|
this.value = LocalizableError(error, e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return Unit
|
||||||
|
}
|
|
@ -1,231 +0,0 @@
|
||||||
package eu.steffo.twom.composables.login
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
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
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import eu.steffo.twom.R
|
|
||||||
import eu.steffo.twom.composables.errorhandling.Display
|
|
||||||
import eu.steffo.twom.composables.errorhandling.ErrorText
|
|
||||||
import eu.steffo.twom.composables.errorhandling.LocalizableError
|
|
||||||
import eu.steffo.twom.composables.fields.PasswordField
|
|
||||||
import eu.steffo.twom.composables.theme.basePadding
|
|
||||||
import eu.steffo.twom.utils.TwoMGlobals
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
enum class LoginStep(val step: Int) {
|
|
||||||
NONE(0),
|
|
||||||
SERVICE(1),
|
|
||||||
WELLKNOWN(2),
|
|
||||||
FLOWS(3),
|
|
||||||
WIZARD(4),
|
|
||||||
LOGIN(5),
|
|
||||||
DONE(6),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
fun LoginForm(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onLogin: (session: Session) -> Unit = {},
|
|
||||||
) {
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
var username by rememberSaveable { mutableStateOf("") }
|
|
||||||
var password by rememberSaveable { mutableStateOf("") }
|
|
||||||
|
|
||||||
var loginStep by rememberSaveable { mutableStateOf(LoginStep.NONE) }
|
|
||||||
var error by remember { mutableStateOf<LocalizableError?>(null) }
|
|
||||||
|
|
||||||
suspend fun doLogin() {
|
|
||||||
error = null
|
|
||||||
|
|
||||||
Log.d("Login", "Getting authentication service...")
|
|
||||||
loginStep = LoginStep.SERVICE
|
|
||||||
val auth = TwoMGlobals.matrix.authenticationService()
|
|
||||||
|
|
||||||
Log.d("Login", "Resetting authentication service...")
|
|
||||||
auth.reset()
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
error = LocalizableError(R.string.login_error_username_invalid)
|
|
||||||
return
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Log.e(
|
|
||||||
"Login",
|
|
||||||
"Something went wrong while retrieving .well-known data for: $username",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
error = LocalizableError(R.string.login_error_wellknown_generic, e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (wellKnown !is WellknownResult.Prompt) {
|
|
||||||
Log.w(
|
|
||||||
"Login",
|
|
||||||
"Data is not .well-known for: $username"
|
|
||||||
)
|
|
||||||
error = LocalizableError(R.string.login_error_wellknown_missing)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d("Login", "Retrieving login flows for: ${wellKnown.homeServerUrl}")
|
|
||||||
loginStep = LoginStep.FLOWS
|
|
||||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
|
||||||
lateinit var flows: LoginFlowResult
|
|
||||||
try {
|
|
||||||
@Suppress("UNUSED_VALUE")
|
|
||||||
flows = auth.getLoginFlow(
|
|
||||||
HomeServerConnectionConfig
|
|
||||||
.Builder()
|
|
||||||
.withHomeServerUri(wellKnown.homeServerUrl)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Log.e(
|
|
||||||
"Login",
|
|
||||||
"Something went wrong while retrieving login flows for: ${wellKnown.homeServerUrl}",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
error = LocalizableError(R.string.login_error_flows_generic, e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
Log.e(
|
|
||||||
"Login",
|
|
||||||
"Something went wrong while setting up the login wizard.",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
error = LocalizableError(R.string.login_error_wizard_generic, e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d("Login", "Logging in as: $username")
|
|
||||||
loginStep = LoginStep.LOGIN
|
|
||||||
lateinit var session: Session
|
|
||||||
try {
|
|
||||||
session = wizard.login(
|
|
||||||
login = username,
|
|
||||||
password = password,
|
|
||||||
initialDeviceName = "TwoM (Android)",
|
|
||||||
)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Log.e(
|
|
||||||
"Login",
|
|
||||||
"Something went wrong while logging in as: $username",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
error = LocalizableError(R.string.login_error_login_generic, e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(
|
|
||||||
"Login",
|
|
||||||
"Logged in successfully with session id: ${session.sessionId}"
|
|
||||||
)
|
|
||||||
loginStep = LoginStep.DONE
|
|
||||||
|
|
||||||
onLogin(session)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(modifier) {
|
|
||||||
LinearProgressIndicator(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
progress = loginStep.step.toFloat() / LoginStep.DONE.step.toFloat(),
|
|
||||||
color = if (error != null) MaterialTheme.colorScheme.error else ProgressIndicatorDefaults.linearColor
|
|
||||||
)
|
|
||||||
Row(Modifier.basePadding()) {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_text))
|
|
||||||
}
|
|
||||||
Row(Modifier.basePadding()) {
|
|
||||||
TextField(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
singleLine = true,
|
|
||||||
value = username,
|
|
||||||
onValueChange = { username = it },
|
|
||||||
label = {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_username_label))
|
|
||||||
},
|
|
||||||
placeholder = {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_username_placeholder))
|
|
||||||
},
|
|
||||||
supportingText = {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_username_supporting))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(Modifier.basePadding()) {
|
|
||||||
PasswordField(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
value = password,
|
|
||||||
onValueChange = { password = it },
|
|
||||||
label = {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_password_label))
|
|
||||||
},
|
|
||||||
placeholder = {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_password_placeholder))
|
|
||||||
},
|
|
||||||
supportingText = {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_password_supporting))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row(Modifier.basePadding()) {
|
|
||||||
Button(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
enabled = (username != "" && (loginStep == LoginStep.NONE || error != null)),
|
|
||||||
onClick = {
|
|
||||||
scope.launch { doLogin() }
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Text(LocalContext.current.getString(R.string.login_complete_text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
error.Display {
|
|
||||||
Row(Modifier.basePadding()) {
|
|
||||||
ErrorText(
|
|
||||||
text = it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
package eu.steffo.twom.composables.login.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
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
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import eu.steffo.twom.R
|
||||||
|
import eu.steffo.twom.composables.errorhandling.Display
|
||||||
|
import eu.steffo.twom.composables.errorhandling.ErrorText
|
||||||
|
import eu.steffo.twom.composables.fields.PasswordField
|
||||||
|
import eu.steffo.twom.composables.login.effects.LoginStep
|
||||||
|
import eu.steffo.twom.composables.login.effects.manageLogin
|
||||||
|
import eu.steffo.twom.composables.theme.basePadding
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
fun LoginForm(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onLogin: (session: Session) -> Unit = {},
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
var username by rememberSaveable { mutableStateOf("") }
|
||||||
|
var password by rememberSaveable { mutableStateOf("") }
|
||||||
|
|
||||||
|
val manager = manageLogin()
|
||||||
|
|
||||||
|
Column(modifier) {
|
||||||
|
LinearProgressIndicator(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
progress = manager.step.ord.toFloat() / LoginStep.DONE.ord.toFloat(),
|
||||||
|
color = if (manager.error != null) {
|
||||||
|
MaterialTheme.colorScheme.error
|
||||||
|
} else {
|
||||||
|
ProgressIndicatorDefaults.linearColor
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Row(Modifier.basePadding()) {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_text))
|
||||||
|
}
|
||||||
|
Row(Modifier.basePadding()) {
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
singleLine = true,
|
||||||
|
value = username,
|
||||||
|
onValueChange = { username = it },
|
||||||
|
label = {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_username_label))
|
||||||
|
},
|
||||||
|
placeholder = {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_username_placeholder))
|
||||||
|
},
|
||||||
|
supportingText = {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_username_supporting))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(Modifier.basePadding()) {
|
||||||
|
PasswordField(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
value = password,
|
||||||
|
onValueChange = { password = it },
|
||||||
|
label = {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_password_label))
|
||||||
|
},
|
||||||
|
placeholder = {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_password_placeholder))
|
||||||
|
},
|
||||||
|
supportingText = {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_password_supporting))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(Modifier.basePadding()) {
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = (username != "" && (manager.step == LoginStep.NONE || manager.error != null)),
|
||||||
|
onClick = {
|
||||||
|
scope.launch DoLogin@{
|
||||||
|
val session = manager.login(username, password) ?: return@DoLogin
|
||||||
|
onLogin(session)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Text(LocalContext.current.getString(R.string.login_complete_text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
manager.error.Display {
|
||||||
|
Row(Modifier.basePadding()) {
|
||||||
|
ErrorText(
|
||||||
|
text = it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.steffo.twom.composables.login
|
package eu.steffo.twom.composables.login.components
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.steffo.twom.composables.login
|
package eu.steffo.twom.composables.login.components
|
||||||
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
|
@ -0,0 +1,101 @@
|
||||||
|
package eu.steffo.twom.composables.login.effects
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import eu.steffo.twom.R
|
||||||
|
import eu.steffo.twom.composables.errorhandling.LocalizableError
|
||||||
|
import eu.steffo.twom.composables.errorhandling.capture
|
||||||
|
import eu.steffo.twom.utils.TwoMGlobals
|
||||||
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
|
||||||
|
private const val TAG = "manageLogin"
|
||||||
|
|
||||||
|
enum class LoginStep(val ord: Int) {
|
||||||
|
NONE(0),
|
||||||
|
RESET(1),
|
||||||
|
WELLKNOWN(2),
|
||||||
|
FLOWS(3),
|
||||||
|
WIZARD(4),
|
||||||
|
LOGIN(5),
|
||||||
|
DONE(6),
|
||||||
|
}
|
||||||
|
|
||||||
|
data class LoginManager(
|
||||||
|
val step: LoginStep,
|
||||||
|
val error: LocalizableError?,
|
||||||
|
val login: suspend (username: String, password: String) -> Session?,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun manageLogin(): LoginManager {
|
||||||
|
var step by remember { mutableStateOf(LoginStep.NONE) }
|
||||||
|
val error = remember { mutableStateOf<LocalizableError?>(null) }
|
||||||
|
|
||||||
|
suspend fun login(username: String, password: String): Session? {
|
||||||
|
Log.i(TAG, "Starting login process for: $username")
|
||||||
|
step = LoginStep.NONE
|
||||||
|
|
||||||
|
Log.d(TAG, "Resetting authentication service...")
|
||||||
|
step = LoginStep.RESET
|
||||||
|
val auth = TwoMGlobals.matrix.authenticationService()
|
||||||
|
error.capture(R.string.login_error_wellknown_generic) {
|
||||||
|
auth.reset()
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
Log.d(TAG, "Retrieving .well-known data for: $username")
|
||||||
|
step = LoginStep.WELLKNOWN
|
||||||
|
lateinit var wellKnown: WellknownResult
|
||||||
|
error.capture(R.string.login_error_wellknown_generic) {
|
||||||
|
wellKnown = auth.getWellKnownData(
|
||||||
|
matrixId = username,
|
||||||
|
homeServerConnectionConfig = null,
|
||||||
|
)
|
||||||
|
} ?: return null
|
||||||
|
if (wellKnown !is WellknownResult.Prompt) {
|
||||||
|
error.value = LocalizableError(R.string.login_error_wellknown_missing)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Retrieving login flows for: $username")
|
||||||
|
step = LoginStep.FLOWS
|
||||||
|
error.capture(R.string.login_error_flows_generic) {
|
||||||
|
auth.getLoginFlow(
|
||||||
|
HomeServerConnectionConfig
|
||||||
|
.Builder()
|
||||||
|
.withHomeServerUri((wellKnown as WellknownResult.Prompt).homeServerUrl)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
Log.d(TAG, "Getting login wizard...")
|
||||||
|
step = LoginStep.WIZARD
|
||||||
|
val wizard = auth.getLoginWizard()
|
||||||
|
|
||||||
|
Log.d(TAG, "Logging in as: $username")
|
||||||
|
step = LoginStep.LOGIN
|
||||||
|
lateinit var session: Session
|
||||||
|
error.capture(R.string.login_error_login_generic) {
|
||||||
|
session = wizard.login(
|
||||||
|
login = username,
|
||||||
|
password = password,
|
||||||
|
initialDeviceName = "TwoM (Android)"
|
||||||
|
)
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
Log.i(TAG, "Logged in as: $session")
|
||||||
|
step = LoginStep.DONE
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoginManager(
|
||||||
|
step = step,
|
||||||
|
error = error.value,
|
||||||
|
login = ::login,
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue