From eca22e157c67491b59407aab59a484d87624b843 Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Tue, 19 Nov 2024 00:20:29 +0500 Subject: [PATCH 1/6] feat: Update resource files Fixes: LEARNER-10256 --- .../main/res/drawable/ic_auth_facebook.xml | 17 ++++---- auth/src/main/res/drawable/ic_auth_google.xml | 39 +++++++++---------- .../main/res/drawable/ic_auth_microsoft.xml | 27 +++++++------ auth/src/main/res/values/strings.xml | 4 ++ .../edx/org/openedx/core/ui/theme/Colors.kt | 2 + .../org/openedx/core/ui/theme/LocalShapes.kt | 4 +- .../org/openedx/core/ui/theme/AppColors.kt | 1 + .../java/org/openedx/core/ui/theme/Shape.kt | 1 + .../java/org/openedx/core/ui/theme/Theme.kt | 2 + .../org/openedx/core/ui/theme/LocalShapes.kt | 3 +- 10 files changed, 59 insertions(+), 41 deletions(-) diff --git a/auth/src/main/res/drawable/ic_auth_facebook.xml b/auth/src/main/res/drawable/ic_auth_facebook.xml index b8e7aa393..ac7e6e8d6 100644 --- a/auth/src/main/res/drawable/ic_auth_facebook.xml +++ b/auth/src/main/res/drawable/ic_auth_facebook.xml @@ -1,9 +1,12 @@ - - + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + + + diff --git a/auth/src/main/res/drawable/ic_auth_google.xml b/auth/src/main/res/drawable/ic_auth_google.xml index 95bbcc563..8b42a58c1 100644 --- a/auth/src/main/res/drawable/ic_auth_google.xml +++ b/auth/src/main/res/drawable/ic_auth_google.xml @@ -1,22 +1,21 @@ - - - - - + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + + + + + + diff --git a/auth/src/main/res/drawable/ic_auth_microsoft.xml b/auth/src/main/res/drawable/ic_auth_microsoft.xml index ce31faab7..654451c9f 100644 --- a/auth/src/main/res/drawable/ic_auth_microsoft.xml +++ b/auth/src/main/res/drawable/ic_auth_microsoft.xml @@ -3,16 +3,19 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - - - - + + + + + + + diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 49a8fb68e..b2a95a49b 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -44,4 +44,8 @@ %2$s]]> Show password Hide password + Continue with: + Last sign in + Or sign in with email: + Or register below: diff --git a/core/src/edx/org/openedx/core/ui/theme/Colors.kt b/core/src/edx/org/openedx/core/ui/theme/Colors.kt index 031b15b83..2fe1c9541 100644 --- a/core/src/edx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/edx/org/openedx/core/ui/theme/Colors.kt @@ -59,6 +59,7 @@ val light_card_view_border = light_text_field_border val light_divider = light_primary val light_certificate_foreground = light_surface val light_bottom_sheet_toggle = light_text_accent +val light_social_auth_divider = Color(0xFFADADAD) val light_rate_stars = light_warning val light_inactive_button_background = Color(0xFFFCFCFC) @@ -143,6 +144,7 @@ val dark_secondary_button_bordered_text = Color(0xFFD23228) // Brand 500 val dark_card_view_background = dark_surface val dark_card_view_border = dark_text_field_border val dark_divider = dark_primary +val dark_social_auth_divider = dark_onSurface val dark_certificate_foreground = Color(0xD92EB865) val dark_bottom_sheet_toggle = Color(0xFF03C7E8) // Accent A Isotope Blue diff --git a/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt b/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt index ec533e525..7fa0839e0 100644 --- a/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt +++ b/core/src/edx/org/openedx/core/ui/theme/LocalShapes.kt @@ -1,5 +1,6 @@ package org.openedx.core.ui.theme +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Shapes @@ -20,6 +21,7 @@ internal val LocalShapes = staticCompositionLocalOf { cardShape = RoundedCornerShape(12.dp), screenBackgroundShapeFull = RoundedCornerShape(24.dp), courseImageShape = RoundedCornerShape(8.dp), - dialogShape = RoundedCornerShape(24.dp) + dialogShape = RoundedCornerShape(24.dp), + socialAuthButtonShape = CircleShape, ) } diff --git a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt index 7baebb255..66ab1ff02 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt @@ -37,6 +37,7 @@ data class AppColors( val cardViewBackground: Color, val cardViewBorder: Color, val divider: Color, + val socialAuthDivider: Color, val certificateForeground: Color, val bottomSheetToggle: Color, diff --git a/core/src/main/java/org/openedx/core/ui/theme/Shape.kt b/core/src/main/java/org/openedx/core/ui/theme/Shape.kt index eed4d481d..142a962fb 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Shape.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Shape.kt @@ -16,6 +16,7 @@ data class AppShapes( val screenBackgroundShapeFull: CornerBasedShape, val courseImageShape: CornerBasedShape, val dialogShape: CornerBasedShape, + val socialAuthButtonShape: CornerBasedShape, ) val MaterialTheme.appShapes: AppShapes diff --git a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt index 47a69fac1..2c5c63b61 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt @@ -54,6 +54,7 @@ private val DarkColorPalette = AppColors( cardViewBackground = dark_card_view_background, cardViewBorder = dark_card_view_border, divider = dark_divider, + socialAuthDivider = dark_social_auth_divider, certificateForeground = dark_certificate_foreground, bottomSheetToggle = dark_bottom_sheet_toggle, @@ -146,6 +147,7 @@ private val LightColorPalette = AppColors( cardViewBackground = light_card_view_background, cardViewBorder = light_card_view_border, divider = light_divider, + socialAuthDivider = light_social_auth_divider, certificateForeground = light_certificate_foreground, bottomSheetToggle = light_bottom_sheet_toggle, diff --git a/core/src/openedx/org/openedx/core/ui/theme/LocalShapes.kt b/core/src/openedx/org/openedx/core/ui/theme/LocalShapes.kt index b5415bc5e..4f1f193fe 100644 --- a/core/src/openedx/org/openedx/core/ui/theme/LocalShapes.kt +++ b/core/src/openedx/org/openedx/core/ui/theme/LocalShapes.kt @@ -20,6 +20,7 @@ internal val LocalShapes = staticCompositionLocalOf { cardShape = RoundedCornerShape(12.dp), screenBackgroundShapeFull = RoundedCornerShape(24.dp), courseImageShape = RoundedCornerShape(8.dp), - dialogShape = RoundedCornerShape(24.dp) + dialogShape = RoundedCornerShape(24.dp), + socialAuthButtonShape = RoundedCornerShape(8.dp), ) } From a3a5de9c5e9b607b9a940beee8fdc5842bb10da4 Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Tue, 19 Nov 2024 00:22:38 +0500 Subject: [PATCH 2/6] feat: Store last sign in type in preferences Fixes: LEARNER-10256 --- .../org/openedx/app/data/storage/PreferencesManager.kt | 8 ++++++++ .../org/openedx/auth/presentation/signin/SignInUIState.kt | 2 ++ .../openedx/auth/presentation/signin/SignInViewModel.kt | 8 +++++--- .../java/org/openedx/core/data/storage/CorePreferences.kt | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt b/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt index 0d9a05e94..1ecd9f40c 100644 --- a/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt +++ b/app/src/main/java/org/openedx/app/data/storage/PreferencesManager.kt @@ -3,6 +3,7 @@ package org.openedx.app.data.storage import android.content.Context import com.google.gson.Gson import org.openedx.app.BuildConfig +import org.openedx.auth.data.model.AuthType import org.openedx.core.data.model.User import org.openedx.core.data.storage.CorePreferences import org.openedx.core.data.storage.InAppReviewPreferences @@ -167,6 +168,12 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences } get() = getBoolean(RESET_APP_DIRECTORY, true) + override var lastSignInType: String + set(value) { + saveString(LAST_SIGN_IN_TYPE, AuthType.valueOf(value).name) + } + get() = getString(LAST_SIGN_IN_TYPE, AuthType.PASSWORD.name) + override fun setCalendarSyncEventsDialogShown(courseName: String) { saveBoolean(courseName.replaceSpace("_"), true) } @@ -189,5 +196,6 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences private const val VIDEO_SETTINGS_DOWNLOAD_QUALITY = "video_settings_download_quality" private const val APP_CONFIG = "app_config" private const val RESET_APP_DIRECTORY = "reset_app_directory" + private const val LAST_SIGN_IN_TYPE = "last_sign_in_type" } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt index 9ce5cfc98..751c6da3d 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt @@ -1,5 +1,6 @@ package org.openedx.auth.presentation.signin +import org.openedx.auth.data.model.AuthType import org.openedx.core.domain.model.RegistrationField /** @@ -18,6 +19,7 @@ internal data class SignInUIState( val isMicrosoftAuthEnabled: Boolean = false, val isSocialAuthEnabled: Boolean = false, val isLogistrationEnabled: Boolean = false, + val lastSignIn: AuthType = AuthType.PASSWORD, val showProgress: Boolean = false, val loginSuccess: Boolean = false, val agreement: RegistrationField? = null, diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt index dd03bdaae..dc780bd15 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt @@ -63,6 +63,7 @@ class SignInViewModel( isMicrosoftAuthEnabled = config.getMicrosoftConfig().isEnabled(), isSocialAuthEnabled = config.isSocialAuthEnabled(), isLogistrationEnabled = config.isPreLoginExperienceEnabled(), + lastSignIn = AuthType.valueOf(preferencesManager.lastSignInType), agreement = agreementProvider.getAgreement(isSignIn = true)?.createHonorCodeField(), ) ) @@ -99,7 +100,7 @@ class SignInViewModel( try { interactor.login(username, password) _uiState.update { it.copy(loginSuccess = true) } - setUserId() + setMetadata(AuthType.PASSWORD) logEvent( AuthAnalyticsEvent.SIGN_IN_SUCCESS, buildMap { @@ -173,7 +174,7 @@ class SignInViewModel( }.onSuccess { logger.d { "Social login (${authType.methodName}) success" } _uiState.update { it.copy(loginSuccess = true) } - setUserId() + setMetadata(authType) _uiState.update { it.copy(showProgress = false) } appNotifier.send(SignInEvent()) } @@ -189,10 +190,11 @@ class SignInViewModel( _uiState.update { it.copy(showProgress = false) } } - private fun setUserId() { + private fun setMetadata(authType: AuthType) { preferencesManager.user?.let { analytics.setUserIdForSession(it.id) } + preferencesManager.lastSignInType = authType.name } private suspend fun SocialAuthResponse?.checkToken() { diff --git a/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt b/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt index 29495bae8..8891de9d9 100644 --- a/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt +++ b/core/src/main/java/org/openedx/core/data/storage/CorePreferences.kt @@ -13,6 +13,7 @@ interface CorePreferences { var videoSettings: VideoSettings var appConfig: AppConfig var canResetAppDirectory: Boolean + var lastSignInType: String fun clear() } From c2f560d2e81e084abddd77b665797a069fadc89a Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Tue, 19 Nov 2024 00:26:57 +0500 Subject: [PATCH 3/6] fix: Sign In Success Analytics Fixes: LEARNER-10256 --- .../presentation/signin/SignInViewModel.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt index dc780bd15..cd513387f 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt @@ -101,15 +101,7 @@ class SignInViewModel( interactor.login(username, password) _uiState.update { it.copy(loginSuccess = true) } setMetadata(AuthType.PASSWORD) - logEvent( - AuthAnalyticsEvent.SIGN_IN_SUCCESS, - buildMap { - put( - AuthAnalyticsKey.METHOD.key, - AuthType.PASSWORD.methodName.lowercase() - ) - } - ) + logSignInSuccessEvent(AuthType.PASSWORD) appNotifier.send(SignInEvent()) } catch (e: Exception) { if (e is EdxError.InvalidGrantException) { @@ -176,6 +168,7 @@ class SignInViewModel( _uiState.update { it.copy(loginSuccess = true) } setMetadata(authType) _uiState.update { it.copy(showProgress = false) } + logSignInSuccessEvent(authType) appNotifier.send(SignInEvent()) } } @@ -249,6 +242,17 @@ class SignInViewModel( ) } + private fun logSignInSuccessEvent(authType: AuthType) { + val event = AuthAnalyticsEvent.SIGN_IN_SUCCESS + analytics.logEvent( + event = event.eventName, + params = buildMap { + put(AuthAnalyticsKey.NAME.key, event.biValue) + put(AuthAnalyticsKey.METHOD.key, authType.methodName.lowercase()) + } + ) + } + private fun logSignInScreenEvent() { val event = AuthAnalyticsEvent.SIGN_IN analytics.logScreenEvent( From c0c0d9ca4e4f875875b4445a1fe8851a05a9e309 Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Tue, 19 Nov 2024 00:31:04 +0500 Subject: [PATCH 4/6] refactor: Improve the social auth view Fixes: LEARNER-10256 --- .../presentation/signin/compose/SignInView.kt | 43 ++-- .../presentation/signup/compose/SignUpView.kt | 38 +++- .../auth/presentation/ui/SocialAuthView.kt | 206 +++++++++++------- 3 files changed, 186 insertions(+), 101 deletions(-) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index eec450070..2ee267a49 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -226,6 +226,30 @@ private fun AuthForm( var isPasswordError by rememberSaveable { mutableStateOf(false) } Column(horizontalAlignment = Alignment.CenterHorizontally) { + if (state.isSocialAuthEnabled) { + SocialAuthView( + modifier = buttonWidth, + isGoogleAuthEnabled = state.isGoogleAuthEnabled, + isFacebookAuthEnabled = state.isFacebookAuthEnabled, + isMicrosoftAuthEnabled = state.isMicrosoftAuthEnabled, + lastSignIn = state.lastSignIn, + isSignIn = true, + ) { + keyboardController?.hide() + onEvent(AuthEvent.SocialSignIn(it)) + } + Text( + modifier = Modifier + .testTag("txt_sign_in_with_email") + .fillMaxWidth() + .padding(vertical = 16.dp), + text = stringResource( + id = R.string.auth_sign_in_with_email + ), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleSmall + ) + } LoginTextField( modifier = Modifier .fillMaxWidth(), @@ -306,18 +330,6 @@ private fun AuthForm( } ) } - if (state.isSocialAuthEnabled) { - SocialAuthView( - modifier = buttonWidth, - isGoogleAuthEnabled = state.isGoogleAuthEnabled, - isFacebookAuthEnabled = state.isFacebookAuthEnabled, - isMicrosoftAuthEnabled = state.isMicrosoftAuthEnabled, - isSignIn = true, - ) { - keyboardController?.hide() - onEvent(AuthEvent.SocialSignIn(it)) - } - } } } @@ -409,7 +421,12 @@ private fun SignInScreenPreview() { OpenEdXTheme { LoginScreen( windowSize = WindowSize(WindowType.Compact, WindowType.Compact), - state = SignInUIState(), + state = SignInUIState().copy( + isSocialAuthEnabled = true, + isFacebookAuthEnabled = true, + isGoogleAuthEnabled = true, + isMicrosoftAuthEnabled = true, + ), uiMessage = null, onEvent = {}, ) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt index 0623d3432..11e6f9594 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn @@ -346,6 +347,31 @@ internal fun SignUpView( color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.titleSmall ) + if (uiState.isSocialAuthEnabled) { + Spacer(modifier = Modifier.height(24.dp)) + SocialAuthView( + modifier = buttonWidth, + isGoogleAuthEnabled = uiState.isGoogleAuthEnabled, + isFacebookAuthEnabled = uiState.isFacebookAuthEnabled, + isMicrosoftAuthEnabled = uiState.isMicrosoftAuthEnabled, + isSignIn = false, + ) { + keyboardController?.hide() + onRegisterClick(it) + } + Text( + modifier = Modifier + .testTag("txt_register_below") + .padding(top = 8.dp) + .offset(y = 8.dp) + .fillMaxWidth(), + text = stringResource( + id = R.string.auth_register_below + ), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleSmall + ) + } } } RequiredFields( @@ -446,18 +472,6 @@ internal fun SignUpView( } ) } - if (uiState.isSocialAuthEnabled && uiState.socialAuth == null) { - SocialAuthView( - modifier = buttonWidth, - isGoogleAuthEnabled = uiState.isGoogleAuthEnabled, - isFacebookAuthEnabled = uiState.isFacebookAuthEnabled, - isMicrosoftAuthEnabled = uiState.isMicrosoftAuthEnabled, - isSignIn = false, - ) { - keyboardController?.hide() - onRegisterClick(it) - } - } Spacer(Modifier.height(70.dp)) } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt index 2d69a131b..a99bf391e 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/SocialAuthView.kt @@ -1,11 +1,17 @@ package org.openedx.auth.presentation.ui import android.content.res.Configuration +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.Divider import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -15,13 +21,15 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.openedx.auth.R import org.openedx.auth.data.model.AuthType -import org.openedx.core.ui.OpenEdXBrandButton import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appShapes +import org.openedx.core.ui.theme.appTypography @Composable internal fun SocialAuthView( @@ -29,90 +37,129 @@ internal fun SocialAuthView( isGoogleAuthEnabled: Boolean = true, isFacebookAuthEnabled: Boolean = true, isMicrosoftAuthEnabled: Boolean = true, + lastSignIn: AuthType = AuthType.PASSWORD, isSignIn: Boolean = false, onEvent: (AuthType) -> Unit, ) { Column( modifier = modifier - .padding(top = 24.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) + .padding(top = 8.dp, bottom = 16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) ) { - if (isGoogleAuthEnabled) { - val stringRes = if (isSignIn) { - R.string.auth_google - } else { - R.string.auth_continue_google - } - OpenEdXBrandButton( - backgroundColor = MaterialTheme.appColors.authGoogleButtonBackground, - onClick = { onEvent(AuthType.GOOGLE) } - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = painterResource(id = R.drawable.ic_auth_google), - contentDescription = null, - tint = Color.Unspecified, - ) - Text( - modifier = Modifier.padding(start = 10.dp), - text = stringResource(id = stringRes), - color = MaterialTheme.appColors.textPrimaryLight, - ) - } - } + Text( + modifier = Modifier + .testTag("txt_social_continue_with"), + text = stringResource(id = R.string.auth_continue_with), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.titleSmall + ) + + SocialAuthButtons( + lastSignIn = lastSignIn, + isGoogleAuthEnabled = isGoogleAuthEnabled, + isFacebookAuthEnabled = isFacebookAuthEnabled, + isMicrosoftAuthEnabled = isMicrosoftAuthEnabled, + isSignIn = isSignIn, + onEvent = onEvent, + ) + } +} + +@Composable +private fun SocialAuthButtons( + lastSignIn: AuthType, + isGoogleAuthEnabled: Boolean, + isFacebookAuthEnabled: Boolean, + isMicrosoftAuthEnabled: Boolean, + isSignIn: Boolean, + onEvent: (AuthType) -> Unit, +) { + val enabledAuthTypes = mutableListOf().apply { + if (isGoogleAuthEnabled && (!isSignIn || lastSignIn != AuthType.GOOGLE)) { + add(AuthType.GOOGLE) } - if (isFacebookAuthEnabled) { - val stringRes = if (isSignIn) { - R.string.auth_facebook - } else { - R.string.auth_continue_facebook - } - OpenEdXBrandButton( - backgroundColor = MaterialTheme.appColors.authFacebookButtonBackground, - onClick = { onEvent(AuthType.FACEBOOK) } - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = painterResource(id = R.drawable.ic_auth_facebook), - contentDescription = null, - tint = MaterialTheme.appColors.primaryButtonText, - ) - Text( - modifier = Modifier - .testTag("txt_facebook_auth") - .padding(start = 10.dp), - color = MaterialTheme.appColors.primaryButtonText, - text = stringResource(id = stringRes) - ) - } - } + if (isMicrosoftAuthEnabled && (!isSignIn || lastSignIn != AuthType.MICROSOFT)) { + add(AuthType.MICROSOFT) } - if (isMicrosoftAuthEnabled) { - val stringRes = if (isSignIn) { - R.string.auth_microsoft - } else { - R.string.auth_continue_microsoft - } - OpenEdXBrandButton( - backgroundColor = MaterialTheme.appColors.authMicrosoftButtonBackground, - onClick = { onEvent(AuthType.MICROSOFT) } - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = painterResource(id = R.drawable.ic_auth_microsoft), - contentDescription = null, - tint = Color.Unspecified, - ) - Text( - modifier = Modifier - .testTag("txt_microsoft_auth") - .padding(start = 10.dp), - color = MaterialTheme.appColors.primaryButtonText, - text = stringResource(id = stringRes) - ) - } + if (isFacebookAuthEnabled && (!isSignIn || lastSignIn != AuthType.FACEBOOK)) { + add(AuthType.FACEBOOK) + } + } + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + if (isSignIn && lastSignIn != AuthType.PASSWORD) { + Text( + modifier = Modifier + .testTag("txt_last_sign_in_with") + .padding(end = 12.dp), + text = stringResource(id = R.string.auth_last_sign_in), + color = MaterialTheme.appColors.textPrimary, + style = MaterialTheme.appTypography.bodySmall, + textAlign = TextAlign.Center + ) + SocialAuthButton(isSignIn = true, authType = lastSignIn, onEvent = onEvent) + if (enabledAuthTypes.size > 1) { + Divider( + modifier = Modifier + .padding(start = 4.dp, end = 20.dp) + .width(1.dp) + .height(42.dp), + color = MaterialTheme.appColors.socialAuthDivider + ) } } + + enabledAuthTypes.forEach { authType -> + SocialAuthButton(isSignIn = isSignIn, authType = authType, onEvent = onEvent) + } + } +} + + +@Composable +private fun SocialAuthButton( + isSignIn: Boolean, + authType: AuthType, + onEvent: (AuthType) -> Unit, +) { + val (iconRes, descriptionRes) = when (authType) { + AuthType.GOOGLE -> Pair( + R.drawable.ic_auth_google, + if (isSignIn) R.string.auth_google else R.string.auth_continue_google + ) + + AuthType.FACEBOOK -> Pair( + R.drawable.ic_auth_facebook, + if (isSignIn) R.string.auth_facebook else R.string.auth_continue_facebook + ) + + AuthType.MICROSOFT -> Pair( + R.drawable.ic_auth_microsoft, + if (isSignIn) R.string.auth_microsoft else R.string.auth_continue_microsoft + ) + + AuthType.PASSWORD -> return + } + + IconButton( + modifier = Modifier + .padding(end = 16.dp) + .border( + width = 1.dp, + color = MaterialTheme.appColors.textFieldHint, + shape = MaterialTheme.appShapes.socialAuthButtonShape + ) + .size(42.dp), + onClick = { onEvent(authType) } + ) { + Icon( + modifier = Modifier.size(24.dp), + painter = painterResource(id = iconRes), + contentDescription = stringResource(id = descriptionRes), + tint = Color.Unspecified + ) } } @@ -121,6 +168,13 @@ internal fun SocialAuthView( @Composable private fun SocialAuthViewPreview() { OpenEdXTheme { - SocialAuthView() {} + SocialAuthView( + isGoogleAuthEnabled = true, + isFacebookAuthEnabled = true, + isMicrosoftAuthEnabled = true, + lastSignIn = AuthType.GOOGLE, + isSignIn = true, + onEvent = {} + ) } } From cef280cfc4bb10e704a2b7a0c69e31aec253674c Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Tue, 19 Nov 2024 01:13:26 +0500 Subject: [PATCH 5/6] feat: Fix Auth Test Cases Fixes: LEARNER-10256 --- .../openedx/auth/presentation/signin/SignInViewModelTest.kt | 4 +++- core/src/openedx/org/openedx/core/ui/theme/Colors.kt | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt index a46b371c8..782130692 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt @@ -22,6 +22,7 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TestRule import org.openedx.auth.R +import org.openedx.auth.data.model.AuthType import org.openedx.auth.domain.interactor.AuthInteractor import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics @@ -38,7 +39,6 @@ import org.openedx.core.data.storage.CorePreferences import org.openedx.core.presentation.global.WhatsNewGlobalManager import org.openedx.core.system.EdxError import org.openedx.core.system.ResourceManager -import org.openedx.core.system.notifier.app.AppEvent import org.openedx.core.system.notifier.app.AppNotifier import org.openedx.core.system.notifier.app.SignInEvent import java.net.UnknownHostException @@ -88,6 +88,7 @@ class SignInViewModelTest { every { config.getGoogleConfig() } returns GoogleConfig() every { config.getMicrosoftConfig() } returns MicrosoftConfig() every { analytics.logScreenEvent(any(), any()) } returns Unit + every { preferencesManager.lastSignInType } returns AuthType.PASSWORD.name } @After @@ -237,6 +238,7 @@ class SignInViewModelTest { every { validator.isPasswordValid(any()) } returns true every { preferencesManager.user } returns user every { analytics.setUserIdForSession(any()) } returns Unit + every { preferencesManager.lastSignInType = AuthType.PASSWORD.name } returns Unit every { analytics.logEvent(any(), any()) } returns Unit coEvery { appNotifier.send(any()) } returns Unit val viewModel = SignInViewModel( diff --git a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt index e85ab2fbc..089ebe2a3 100644 --- a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt @@ -76,6 +76,7 @@ val light_progress_bar_color = light_primary val light_progress_bar_background_color = Color(0xFF97A5BB) val light_primary_card_caution_background = Color(0xFFF3F1ED) val light_primary_card_info_background = Color(0xFFE7E4DB) +val light_social_auth_divider = light_divider val dark_primary = Color(0xFF3F68F8) @@ -152,3 +153,4 @@ val dark_progress_bar_color = light_primary val dark_progress_bar_background_color = Color(0xFF8E9BAE) val dark_primary_card_caution_background = Color(0xFF2D494E) val dark_primary_card_info_background = Color(0xFF0E3639) +val dark_social_auth_divider = dark_divider From fe6e270c34064e98d0a0e138001afeaae1e8d1b9 Mon Sep 17 00:00:00 2001 From: Hamza Israr Date: Tue, 26 Nov 2024 08:35:27 +0500 Subject: [PATCH 6/6] chore: Update doc string Fixes: LEARNER-10256 --- .../org/openedx/auth/presentation/signin/SignInUIState.kt | 7 +++++-- .../openedx/auth/presentation/signin/compose/SignInView.kt | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt index 751c6da3d..6803f7d78 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt @@ -9,9 +9,12 @@ import org.openedx.core.domain.model.RegistrationField * @param isFacebookAuthEnabled is Facebook auth enabled * @param isGoogleAuthEnabled is Google auth enabled * @param isMicrosoftAuthEnabled is Microsoft auth enabled - * @param isSocialAuthEnabled is OAuth buttons visible + * @param isSocialAuthEnabled are OAuth buttons visible + * @param isLogistrationEnabled indicates if the pre-login experience is available + * @param lastSignIn the last authentication type used * @param showProgress is progress visible - * @param loginSuccess is login succeed + * @param loginSuccess indicates if the login was successful + * @param agreement contains the honor code with multiple hyperlinks to agreement URLs */ internal data class SignInUIState( val isFacebookAuthEnabled: Boolean = false, diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index 2ee267a49..2e46aec35 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -228,7 +228,7 @@ private fun AuthForm( Column(horizontalAlignment = Alignment.CenterHorizontally) { if (state.isSocialAuthEnabled) { SocialAuthView( - modifier = buttonWidth, + modifier = buttonWidth.fillMaxWidth(), isGoogleAuthEnabled = state.isGoogleAuthEnabled, isFacebookAuthEnabled = state.isFacebookAuthEnabled, isMicrosoftAuthEnabled = state.isMicrosoftAuthEnabled,