Loading app/src/main/kotlin/foundation/e/accountmanager/network/OAuthMurena.kt +2 −2 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ object OAuthMurena { } } fun signIn(email: String?, locale: String?, config: AuthorizationServiceConfiguration): AuthorizationRequest { fun signIn(userId: String?, locale: String?, config: AuthorizationServiceConfiguration): AuthorizationRequest { val builder = AuthorizationRequest.Builder( config, CLIENT_ID, Loading @@ -70,7 +70,7 @@ object OAuthMurena { ) return builder .setScopes(*SCOPES) .setLoginHint(email) .setLoginHint(userId) .setUiLocales(locale) .build() } Loading app/src/main/kotlin/foundation/e/accountmanager/ui/setup/MurenaLogin.kt +11 −56 Original line number Diff line number Diff line Loading @@ -17,26 +17,19 @@ */ package foundation.e.accountmanager.ui.setup import android.accounts.AccountManager import android.content.Context import android.net.Uri import androidx.activity.compose.LocalActivity import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width 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.material.icons.Icons Loading @@ -47,7 +40,6 @@ import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text Loading Loading @@ -154,10 +146,10 @@ object MurenaLogin : LoginType { } MurenaLoginScreen( email = uiState.email, userId = uiState.userId, serverUri = uiState.baseUri, discoveryEndPoint = uiState.discoveryEndPoint, onSetEmail = model::setEmail, onSetUserId = model::setUserId, onSetServerUrl = model::setCustomBareUri, onSetDiscoveryEndPoint = model::setDiscoveryEndPoint, canContinue = uiState.canContinue, Loading Loading @@ -201,10 +193,10 @@ fun MultipleECloudAccountNotAcceptedDialog(onDismiss: () -> Unit) { @Composable fun MurenaLoginScreen( email: String, userId: String, serverUri: String, discoveryEndPoint: String, onSetEmail: (String) -> Unit = {}, onSetUserId: (String) -> Unit = {}, onSetServerUrl: (String) -> Unit = {}, onSetDiscoveryEndPoint: (String) -> Unit = {}, canContinue: Boolean, Loading Loading @@ -240,13 +232,12 @@ fun MurenaLoginScreen( val focusRequester = remember { FocusRequester() } OutlinedTextField( value = email, onValueChange = onSetEmail, value = userId, onValueChange = onSetUserId, singleLine = true, label = { Text(stringResource(R.string.login_user_id)) }, placeholder = { Text("example@murena.io") }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Email, keyboardType = KeyboardType.Text, imeAction = ImeAction.Done ), modifier = Modifier Loading @@ -254,42 +245,6 @@ fun MurenaLoginScreen( .focusRequester(focusRequester) ) // Suggestion buttons to add domain suffixes if (!email.contains("@")) { Row( horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier .fillMaxWidth() .padding(top = 8.dp) ) { OutlinedButton( onClick = { onSetEmail("$email@murena.io") }, contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), shape = RoundedCornerShape(12.dp), modifier = Modifier .defaultMinSize(minHeight = 32.dp) ) { Text( text = "@murena.io", style = MaterialTheme.typography.bodySmall ) } OutlinedButton( onClick = { onSetEmail("$email@e.email") }, contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), shape = RoundedCornerShape(12.dp), modifier = Modifier .defaultMinSize(minHeight = 32.dp) ) { Text( text = "@e.email", style = MaterialTheme.typography.bodySmall ) } } } if (showServerField) { OutlinedTextField( value = serverUri, Loading Loading @@ -324,7 +279,7 @@ fun MurenaLoginScreen( } LaunchedEffect(Unit) { if (email.isEmpty()) focusRequester.requestFocus() if (userId.isEmpty()) focusRequester.requestFocus() } Spacer(modifier = Modifier.height(14.dp)) Loading Loading @@ -368,7 +323,7 @@ fun MurenaLoginScreen( @Preview(showBackground = true) fun MurenaLoginScreen_Preview_Empty() { MurenaLoginScreen( email = "", userId = "", serverUri = "", discoveryEndPoint = "", canContinue = false, Loading @@ -377,9 +332,9 @@ fun MurenaLoginScreen_Preview_Empty() { @Composable @Preview(showBackground = true) fun MurenaLoginScreen_Preview_WithDefaultEmail() { fun MurenaLoginScreen_Preview_WithDefaultUserId() { MurenaLoginScreen( email = "example@murena.io", userId = "example", serverUri = OAuthMurena.baseUri, discoveryEndPoint = OAuthMurena.discoveryUri.toString(), canContinue = true, Loading app/src/main/kotlin/foundation/e/accountmanager/ui/setup/MurenaLoginModel.kt +7 −9 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ class MurenaLoginModel @AssistedInject constructor( } data class UiState( val email: String = "", val userId: String = "", val baseUri: String = OAuthMurena.baseUri, val discoveryEndPoint: String = OAuthMurena.discoveryUri.toString(), val error: String? = null, Loading @@ -74,9 +74,7 @@ class MurenaLoginModel @AssistedInject constructor( /** login info (set after successful login) */ val result: LoginInfo? = null ) { val canContinue = email.isNotEmpty() && baseUri.startsWith("https", ignoreCase = true) && (email.endsWith("@murena.io", ignoreCase = true) || email.endsWith("@e.email", ignoreCase = true)) val emailWithDomain = if (email.contains("@")) email else "$email@murena.io" val canContinue = userId.isNotEmpty() && baseUri.startsWith("https", ignoreCase = true) } var uiState by mutableStateOf(UiState()) Loading @@ -84,14 +82,14 @@ class MurenaLoginModel @AssistedInject constructor( init { uiState = uiState.copy( email = initialLoginInfo.credentials?.username ?: "", userId = initialLoginInfo.credentials?.username ?: "", error = null, result = null ) } fun setEmail(email: String) { uiState = uiState.copy(email = email) fun setUserId(userId: String) { uiState = uiState.copy(userId = userId) } fun setCustomBareUri(uri: String) { Loading @@ -117,7 +115,7 @@ class MurenaLoginModel @AssistedInject constructor( try { val config = OAuthMurena.fetchOAuthConfigSuspend(uiState.discoveryEndPoint.toUri()) return OAuthMurena.signIn( email = uiState.emailWithDomain, userId = uiState.userId, locale = Locale.getDefault().toLanguageTag(), config = config ) Loading @@ -140,7 +138,7 @@ class MurenaLoginModel @AssistedInject constructor( result = LoginInfo( baseUri = URI(uiState.baseUri), credentials = credentials, suggestedAccountName = uiState.emailWithDomain suggestedAccountName = uiState.userId ) ) } catch (e: Exception) { Loading Loading
app/src/main/kotlin/foundation/e/accountmanager/network/OAuthMurena.kt +2 −2 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ object OAuthMurena { } } fun signIn(email: String?, locale: String?, config: AuthorizationServiceConfiguration): AuthorizationRequest { fun signIn(userId: String?, locale: String?, config: AuthorizationServiceConfiguration): AuthorizationRequest { val builder = AuthorizationRequest.Builder( config, CLIENT_ID, Loading @@ -70,7 +70,7 @@ object OAuthMurena { ) return builder .setScopes(*SCOPES) .setLoginHint(email) .setLoginHint(userId) .setUiLocales(locale) .build() } Loading
app/src/main/kotlin/foundation/e/accountmanager/ui/setup/MurenaLogin.kt +11 −56 Original line number Diff line number Diff line Loading @@ -17,26 +17,19 @@ */ package foundation.e.accountmanager.ui.setup import android.accounts.AccountManager import android.content.Context import android.net.Uri import androidx.activity.compose.LocalActivity import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width 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.material.icons.Icons Loading @@ -47,7 +40,6 @@ import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text Loading Loading @@ -154,10 +146,10 @@ object MurenaLogin : LoginType { } MurenaLoginScreen( email = uiState.email, userId = uiState.userId, serverUri = uiState.baseUri, discoveryEndPoint = uiState.discoveryEndPoint, onSetEmail = model::setEmail, onSetUserId = model::setUserId, onSetServerUrl = model::setCustomBareUri, onSetDiscoveryEndPoint = model::setDiscoveryEndPoint, canContinue = uiState.canContinue, Loading Loading @@ -201,10 +193,10 @@ fun MultipleECloudAccountNotAcceptedDialog(onDismiss: () -> Unit) { @Composable fun MurenaLoginScreen( email: String, userId: String, serverUri: String, discoveryEndPoint: String, onSetEmail: (String) -> Unit = {}, onSetUserId: (String) -> Unit = {}, onSetServerUrl: (String) -> Unit = {}, onSetDiscoveryEndPoint: (String) -> Unit = {}, canContinue: Boolean, Loading Loading @@ -240,13 +232,12 @@ fun MurenaLoginScreen( val focusRequester = remember { FocusRequester() } OutlinedTextField( value = email, onValueChange = onSetEmail, value = userId, onValueChange = onSetUserId, singleLine = true, label = { Text(stringResource(R.string.login_user_id)) }, placeholder = { Text("example@murena.io") }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Email, keyboardType = KeyboardType.Text, imeAction = ImeAction.Done ), modifier = Modifier Loading @@ -254,42 +245,6 @@ fun MurenaLoginScreen( .focusRequester(focusRequester) ) // Suggestion buttons to add domain suffixes if (!email.contains("@")) { Row( horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier .fillMaxWidth() .padding(top = 8.dp) ) { OutlinedButton( onClick = { onSetEmail("$email@murena.io") }, contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), shape = RoundedCornerShape(12.dp), modifier = Modifier .defaultMinSize(minHeight = 32.dp) ) { Text( text = "@murena.io", style = MaterialTheme.typography.bodySmall ) } OutlinedButton( onClick = { onSetEmail("$email@e.email") }, contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), shape = RoundedCornerShape(12.dp), modifier = Modifier .defaultMinSize(minHeight = 32.dp) ) { Text( text = "@e.email", style = MaterialTheme.typography.bodySmall ) } } } if (showServerField) { OutlinedTextField( value = serverUri, Loading Loading @@ -324,7 +279,7 @@ fun MurenaLoginScreen( } LaunchedEffect(Unit) { if (email.isEmpty()) focusRequester.requestFocus() if (userId.isEmpty()) focusRequester.requestFocus() } Spacer(modifier = Modifier.height(14.dp)) Loading Loading @@ -368,7 +323,7 @@ fun MurenaLoginScreen( @Preview(showBackground = true) fun MurenaLoginScreen_Preview_Empty() { MurenaLoginScreen( email = "", userId = "", serverUri = "", discoveryEndPoint = "", canContinue = false, Loading @@ -377,9 +332,9 @@ fun MurenaLoginScreen_Preview_Empty() { @Composable @Preview(showBackground = true) fun MurenaLoginScreen_Preview_WithDefaultEmail() { fun MurenaLoginScreen_Preview_WithDefaultUserId() { MurenaLoginScreen( email = "example@murena.io", userId = "example", serverUri = OAuthMurena.baseUri, discoveryEndPoint = OAuthMurena.discoveryUri.toString(), canContinue = true, Loading
app/src/main/kotlin/foundation/e/accountmanager/ui/setup/MurenaLoginModel.kt +7 −9 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ class MurenaLoginModel @AssistedInject constructor( } data class UiState( val email: String = "", val userId: String = "", val baseUri: String = OAuthMurena.baseUri, val discoveryEndPoint: String = OAuthMurena.discoveryUri.toString(), val error: String? = null, Loading @@ -74,9 +74,7 @@ class MurenaLoginModel @AssistedInject constructor( /** login info (set after successful login) */ val result: LoginInfo? = null ) { val canContinue = email.isNotEmpty() && baseUri.startsWith("https", ignoreCase = true) && (email.endsWith("@murena.io", ignoreCase = true) || email.endsWith("@e.email", ignoreCase = true)) val emailWithDomain = if (email.contains("@")) email else "$email@murena.io" val canContinue = userId.isNotEmpty() && baseUri.startsWith("https", ignoreCase = true) } var uiState by mutableStateOf(UiState()) Loading @@ -84,14 +82,14 @@ class MurenaLoginModel @AssistedInject constructor( init { uiState = uiState.copy( email = initialLoginInfo.credentials?.username ?: "", userId = initialLoginInfo.credentials?.username ?: "", error = null, result = null ) } fun setEmail(email: String) { uiState = uiState.copy(email = email) fun setUserId(userId: String) { uiState = uiState.copy(userId = userId) } fun setCustomBareUri(uri: String) { Loading @@ -117,7 +115,7 @@ class MurenaLoginModel @AssistedInject constructor( try { val config = OAuthMurena.fetchOAuthConfigSuspend(uiState.discoveryEndPoint.toUri()) return OAuthMurena.signIn( email = uiState.emailWithDomain, userId = uiState.userId, locale = Locale.getDefault().toLanguageTag(), config = config ) Loading @@ -140,7 +138,7 @@ class MurenaLoginModel @AssistedInject constructor( result = LoginInfo( baseUri = URI(uiState.baseUri), credentials = credentials, suggestedAccountName = uiState.emailWithDomain suggestedAccountName = uiState.userId ) ) } catch (e: Exception) { Loading