diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index c5a267ece..ad4deb4f5 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -18,6 +18,7 @@ import org.openedx.app.data.storage.PreferencesManager import org.openedx.app.room.AppDatabase import org.openedx.app.room.DATABASE_NAME import org.openedx.app.system.notifier.AppNotifier +import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.AuthRouter import org.openedx.auth.presentation.sso.FacebookAuthHelper @@ -155,6 +156,7 @@ val appModule = module { single { get() } single { get() } + factory { AgreementProvider(get(), get()) } factory { FacebookAuthHelper() } factory { GoogleAuthHelper(get()) } factory { MicrosoftAuthHelper() } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 2f86dbb5a..cadfc2800 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -74,13 +74,14 @@ val screenModule = module { get(), get(), get(), + get(), courseId, infoType, ) } viewModel { (courseId: String?, infoType: String?) -> - SignUpViewModel(get(), get(), get(), get(), get(), get(), get(), courseId, infoType) + SignUpViewModel(get(), get(), get(), get(), get(), get(), get(), get(), courseId, infoType) } viewModel { RestorePasswordViewModel(get(), get(), get(), get()) } diff --git a/auth/src/main/java/org/openedx/auth/presentation/AgreementProvider.kt b/auth/src/main/java/org/openedx/auth/presentation/AgreementProvider.kt new file mode 100644 index 000000000..2b8f021e2 --- /dev/null +++ b/auth/src/main/java/org/openedx/auth/presentation/AgreementProvider.kt @@ -0,0 +1,58 @@ +package org.openedx.auth.presentation + +import androidx.compose.ui.text.intl.Locale +import org.openedx.auth.R +import org.openedx.core.ApiConstants +import org.openedx.core.config.Config +import org.openedx.core.domain.model.RegistrationField +import org.openedx.core.domain.model.RegistrationFieldType +import org.openedx.core.system.ResourceManager + +class AgreementProvider( + private val config: Config, + private val resourceManager: ResourceManager, +) { + internal fun getAgreement(isSignIn: Boolean): RegistrationField? { + val agreementConfig = config.getAgreement(Locale.current.language) + if (agreementConfig.eulaUrl.isBlank()) return null + val agreementRes = if (isSignIn) { + R.string.auth_agreement_signin_in + } else { + R.string.auth_agreement_creating_account + } + val eula = resourceManager.getString( + R.string.auth_cdata_template, + agreementConfig.eulaUrl, + resourceManager.getString(R.string.auth_agreement_eula) + ) + val tos = resourceManager.getString( + R.string.auth_cdata_template, + agreementConfig.tosUrl, + resourceManager.getString(R.string.auth_agreement_tos) + ) + val privacy = resourceManager.getString( + R.string.auth_cdata_template, + agreementConfig.privacyPolicyUrl, + resourceManager.getString(R.string.auth_agreement_privacy) + ) + val text = resourceManager.getString( + agreementRes, + eula, + tos, + config.getPlatformName(), + privacy, + ) + return RegistrationField( + name = ApiConstants.RegistrationFields.HONOR_CODE, + label = text, + type = RegistrationFieldType.PLAINTEXT, + placeholder = "", + instructions = "", + exposed = false, + required = false, + restrictions = RegistrationField.Restrictions(), + options = emptyList(), + errorInstructions = "" + ) + } +} 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 829d376f1..9ce5cfc98 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,7 @@ package org.openedx.auth.presentation.signin +import org.openedx.core.domain.model.RegistrationField + /** * Data class to store UI state of the SignIn screen * @@ -18,4 +20,5 @@ internal data class SignInUIState( val isLogistrationEnabled: Boolean = false, 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 d47950341..5ce30a4ac 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 @@ -14,6 +14,7 @@ import org.openedx.auth.R import org.openedx.auth.data.model.AuthType import org.openedx.auth.domain.interactor.AuthInteractor import org.openedx.auth.domain.model.SocialAuthResponse +import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.sso.OAuthHelper import org.openedx.core.BaseViewModel @@ -38,6 +39,7 @@ class SignInViewModel( private val appUpgradeNotifier: AppUpgradeNotifier, private val analytics: AuthAnalytics, private val oAuthHelper: OAuthHelper, + agreementProvider: AgreementProvider, config: Config, val courseId: String?, val infoType: String?, @@ -52,6 +54,7 @@ class SignInViewModel( isMicrosoftAuthEnabled = config.getMicrosoftConfig().isEnabled(), isSocialAuthEnabled = config.isSocialAuthEnabled(), isLogistrationEnabled = config.isPreLoginExperienceEnabled(), + agreement = agreementProvider.getAgreement(isSignIn = true), ) ) internal val uiState: StateFlow = _uiState 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 0abcf0bf9..c536b77a6 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 @@ -59,8 +59,10 @@ import org.openedx.auth.presentation.signin.SignInUIState import org.openedx.auth.presentation.ui.LoginTextField import org.openedx.auth.presentation.ui.SocialAuthView import org.openedx.core.UIMessage +import org.openedx.core.extension.TextConverter import org.openedx.core.ui.BackBtn import org.openedx.core.ui.HandleUIMessage +import org.openedx.core.ui.HyperlinkText import org.openedx.core.ui.OpenEdXButton import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType @@ -185,6 +187,17 @@ internal fun LoginScreen( state, onEvent, ) + state.agreement?.let { + Spacer(modifier = Modifier.height(24.dp)) + val linkedText = + TextConverter.htmlTextToLinkedText(state.agreement.label) + HyperlinkText( + modifier = Modifier.testTag("txt_${state.agreement.name}"), + fullText = linkedText.text, + hyperLinks = linkedText.links, + linkTextColor = MaterialTheme.appColors.primary + ) + } } } } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt index 23e0458d9..0f7873b78 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpUIState.kt @@ -6,6 +6,9 @@ import org.openedx.core.system.notifier.AppUpgradeEvent data class SignUpUIState( val allFields: List = emptyList(), + val requiredFields: List = emptyList(), + val optionalFields: List = emptyList(), + val agreementFields: List = emptyList(), val isFacebookAuthEnabled: Boolean = false, val isGoogleAuthEnabled: Boolean = false, val isMicrosoftAuthEnabled: Boolean = false, diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt index e8ca67e93..563884718 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt @@ -1,5 +1,6 @@ package org.openedx.auth.presentation.signup +import androidx.compose.ui.text.intl.Locale import androidx.fragment.app.Fragment import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers @@ -14,11 +15,11 @@ import kotlinx.coroutines.withContext import org.openedx.auth.data.model.AuthType import org.openedx.auth.domain.interactor.AuthInteractor import org.openedx.auth.domain.model.SocialAuthResponse +import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.sso.OAuthHelper import org.openedx.core.ApiConstants import org.openedx.core.BaseViewModel -import org.openedx.core.R import org.openedx.core.UIMessage import org.openedx.core.config.Config import org.openedx.core.data.storage.CorePreferences @@ -28,6 +29,7 @@ import org.openedx.core.extension.isInternetError import org.openedx.core.system.ResourceManager import org.openedx.core.system.notifier.AppUpgradeNotifier import org.openedx.core.utils.Logger +import org.openedx.core.R as coreR class SignUpViewModel( private val interactor: AuthInteractor, @@ -35,6 +37,7 @@ class SignUpViewModel( private val analytics: AuthAnalytics, private val preferencesManager: CorePreferences, private val appUpgradeNotifier: AppUpgradeNotifier, + private val agreementProvider: AgreementProvider, private val oAuthHelper: OAuthHelper, private val config: Config, val courseId: String?, @@ -69,24 +72,21 @@ class SignUpViewModel( _uiState.update { it.copy(isLoading = true) } viewModelScope.launch { try { - val allFields = interactor.getRegistrationFields() + updateFields(interactor.getRegistrationFields()) _uiState.update { state -> - state.copy( - allFields = allFields, - isLoading = false, - ) + state.copy(isLoading = false) } } catch (e: Exception) { if (e.isInternetError()) { _uiMessage.emit( UIMessage.SnackBarMessage( - resourceManager.getString(R.string.core_error_no_connection) + resourceManager.getString(coreR.string.core_error_no_connection) ) ) } else { _uiMessage.emit( UIMessage.SnackBarMessage( - resourceManager.getString(R.string.core_error_unknown_error) + resourceManager.getString(coreR.string.core_error_unknown_error) ) ) } @@ -94,10 +94,40 @@ class SignUpViewModel( } } + private fun updateFields(allFields: List) { + val mutableAllFields = allFields.toMutableList() + val requiredFields = mutableListOf() + val optionalFields = mutableListOf() + val agreementFields = mutableListOf() + val agreement = agreementProvider.getAgreement(isSignIn = false) + if (agreement != null) { + val honourCode = allFields.find { it.name == ApiConstants.RegistrationFields.HONOR_CODE } + val marketingEmails = allFields.find { it.name == ApiConstants.RegistrationFields.MARKETING_EMAILS } + mutableAllFields.remove(honourCode) + requiredFields.addAll(mutableAllFields.filter { it.required }) + optionalFields.addAll(mutableAllFields.filter { !it.required }) + requiredFields.remove(marketingEmails) + optionalFields.remove(marketingEmails) + marketingEmails?.let { agreementFields.add(it) } + agreementFields.add(agreement) + } else { + requiredFields.addAll(mutableAllFields.filter { it.required }) + optionalFields.addAll(mutableAllFields.filter { !it.required }) + } + _uiState.update { state -> + state.copy( + allFields = mutableAllFields, + requiredFields = requiredFields, + optionalFields = optionalFields, + agreementFields = agreementFields, + ) + } + } + fun register() { analytics.createAccountClickedEvent("") val mapFields = uiState.value.allFields.associate { it.name to it.placeholder } + - mapOf(ApiConstants.HONOR_CODE to true.toString()) + mapOf(ApiConstants.RegistrationFields.HONOR_CODE to true.toString()) val resultMap = mapFields.toMutableMap() uiState.value.allFields.filter { !it.required }.forEach { (k, _) -> if (mapFields[k].isNullOrEmpty()) { @@ -137,13 +167,13 @@ class SignUpViewModel( if (e.isInternetError()) { _uiMessage.emit( UIMessage.SnackBarMessage( - resourceManager.getString(R.string.core_error_no_connection) + resourceManager.getString(coreR.string.core_error_no_connection) ) ) } else { _uiMessage.emit( UIMessage.SnackBarMessage( - resourceManager.getString(R.string.core_error_unknown_error) + resourceManager.getString(coreR.string.core_error_unknown_error) ) ) } @@ -178,18 +208,18 @@ class SignUpViewModel( runCatching { interactor.loginSocial(socialAuth.accessToken, socialAuth.authType) }.onFailure { + val fields = uiState.value.allFields.toMutableList() + .filter { field -> field.type != RegistrationFieldType.PASSWORD } + updateField(ApiConstants.NAME, socialAuth.name) + updateField(ApiConstants.EMAIL, socialAuth.email) + setErrorInstructions(emptyMap()) _uiState.update { - val fields = it.allFields.toMutableList() - .filter { field -> field.type != RegistrationFieldType.PASSWORD } - updateField(ApiConstants.NAME, socialAuth.name) - updateField(ApiConstants.EMAIL, socialAuth.email) - setErrorInstructions(emptyMap()) it.copy( isLoading = false, socialAuth = socialAuth, - allFields = fields ) } + updateFields(fields) }.onSuccess { setUserId() analytics.userLoginEvent(socialAuth.authType.methodName) @@ -208,12 +238,8 @@ class SignUpViewModel( updatedFields.add(it.copy(errorInstructions = "")) } } - _uiState.update { state -> - state.copy( - allFields = updatedFields, - isLoading = false, - ) - } + updateFields(updatedFields) + _uiState.update { it.copy(isLoading = false) } } private fun collectAppUpgradeEvent() { @@ -231,15 +257,13 @@ class SignUpViewModel( } fun updateField(key: String, value: String) { - _uiState.update { - val updatedFields = uiState.value.allFields.toMutableList().map { field -> - if (field.name == key) { - field.copy(placeholder = value) - } else { - field - } + val updatedFields = uiState.value.allFields.toMutableList().map { field -> + if (field.name == key) { + field.copy(placeholder = value) + } else { + field } - it.copy(allFields = updatedFields) } + updateFields(updatedFields) } } 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 0658396e2..9706f8adb 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 @@ -137,9 +137,6 @@ internal fun SignUpView( val isImeVisible by isImeVisibleState() - val fields = uiState.allFields.filter { it.required } - val optionalFields = uiState.allFields.filter { !it.required } - LaunchedEffect(uiState.validationError) { if (uiState.validationError) { coroutine.launch { @@ -294,7 +291,6 @@ internal fun SignUpView( modifier = Modifier .fillMaxHeight() .background(MaterialTheme.appColors.background), - verticalArrangement = Arrangement.spacedBy(24.dp), horizontalAlignment = Alignment.CenterHorizontally ) { if (uiState.isLoading) { @@ -350,7 +346,7 @@ internal fun SignUpView( } } RequiredFields( - fields = fields, + fields = uiState.requiredFields, showErrorMap = showErrorMap, selectableNamesMap = selectableNamesMap, onSelectClick = { serverName, field, list -> @@ -369,7 +365,7 @@ internal fun SignUpView( }, onFieldUpdated = onFieldUpdated ) - if (optionalFields.isNotEmpty()) { + if (uiState.optionalFields.isNotEmpty()) { ExpandableText( modifier = Modifier.testTag("txt_optional_field"), isExpanded = showOptionalFields, @@ -377,32 +373,52 @@ internal fun SignUpView( showOptionalFields = !showOptionalFields } ) - Surface(color = MaterialTheme.appColors.background) { - AnimatedVisibility(visible = showOptionalFields) { - OptionalFields( - fields = optionalFields, - showErrorMap = showErrorMap, - selectableNamesMap = selectableNamesMap, - onSelectClick = { serverName, field, list -> - keyboardController?.hide() - serverFieldName.value = - serverName - expandedList = list - coroutine.launch { - if (bottomSheetScaffoldState.isVisible) { - bottomSheetScaffoldState.hide() - } else { - bottomDialogTitle = field.label - showErrorMap[field.name] = false - bottomSheetScaffoldState.show() - } + AnimatedVisibility(visible = showOptionalFields) { + OptionalFields( + fields = uiState.optionalFields, + showErrorMap = showErrorMap, + selectableNamesMap = selectableNamesMap, + onSelectClick = { serverName, field, list -> + keyboardController?.hide() + serverFieldName.value = + serverName + expandedList = list + coroutine.launch { + if (bottomSheetScaffoldState.isVisible) { + bottomSheetScaffoldState.hide() + } else { + bottomDialogTitle = field.label + showErrorMap[field.name] = false + bottomSheetScaffoldState.show() } - }, - onFieldUpdated = onFieldUpdated, - ) - } + } + }, + onFieldUpdated = onFieldUpdated, + ) } } + if (uiState.agreementFields.isNotEmpty()) { + OptionalFields( + fields = uiState.agreementFields, + showErrorMap = showErrorMap, + selectableNamesMap = selectableNamesMap, + onSelectClick = { serverName, field, list -> + keyboardController?.hide() + serverFieldName.value = serverName + expandedList = list + coroutine.launch { + if (bottomSheetScaffoldState.isVisible) { + bottomSheetScaffoldState.hide() + } else { + bottomDialogTitle = field.label + showErrorMap[field.name] = false + bottomSheetScaffoldState.show() + } + } + }, + onFieldUpdated = onFieldUpdated + ) + } if (uiState.isButtonLoading) { Box( @@ -472,7 +488,10 @@ private fun RegistrationScreenTabletPreview() { SignUpView( windowSize = WindowSize(WindowType.Medium, WindowType.Medium), uiState = SignUpUIState( - allFields = listOf(field, field, field.copy(required = false)), + allFields = listOf(field), + requiredFields = listOf(field, field), + optionalFields = listOf(field, field), + agreementFields = listOf(field), ), uiMessage = null, onBackClick = {}, diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt index a16e77505..e97959549 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt @@ -95,7 +95,9 @@ fun RequiredFields( } RegistrationFieldType.CHECKBOX -> { - //Text("checkbox") + CheckboxField(text = field.label, defaultValue = field.defaultValue) { + onFieldUpdated(field.name, it.toString()) + } } RegistrationFieldType.SELECT -> { @@ -172,7 +174,9 @@ fun OptionalFields( } RegistrationFieldType.CHECKBOX -> { - //Text("checkbox") + CheckboxField(text = field.label, defaultValue = field.defaultValue) { + onFieldUpdated(field.name, it.toString()) + } } RegistrationFieldType.SELECT -> { diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/CheckboxField.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/CheckboxField.kt new file mode 100644 index 000000000..031b69562 --- /dev/null +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/CheckboxField.kt @@ -0,0 +1,61 @@ +package org.openedx.auth.presentation.ui + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Row +import androidx.compose.material.Checkbox +import androidx.compose.material.CheckboxDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +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 androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import org.openedx.core.ui.noRippleClickable +import org.openedx.core.ui.theme.appColors +import org.openedx.core.ui.theme.appTypography + +@Composable +internal fun CheckboxField( + text: String, + defaultValue: Boolean, + onValueChanged: (Boolean) -> Unit +) { + var checkedState by remember { mutableStateOf(defaultValue) } + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = checkedState, + colors = CheckboxDefaults.colors( + checkedColor = MaterialTheme.appColors.primary, + uncheckedColor = MaterialTheme.appColors.textFieldText + ), + onCheckedChange = { + checkedState = it + onValueChanged(it) + } + ) + Text( + modifier = Modifier.noRippleClickable { + checkedState = !checkedState + onValueChanged(checkedState) + }, + text = text, + style = MaterialTheme.appTypography.bodySmall, + ) + } +} + +@Preview(widthDp = 375, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(widthDp = 375, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun CheckboxFieldPreview() { + MaterialTheme { + CheckboxField( + text = "Test", + defaultValue = true, + ) {} + } +} diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 85eb3a47f..4f8ce12d8 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -33,4 +33,10 @@ Continue with Microsoft You\'ve successfully signed in with %s. We just need a little more information before you start learning with %s. + End User Licence Agreement + Terms of Service and Honor Code + Privacy Policy + By creating an account, you agree to the %1$s and %2$s and you acknowledge that %3$s and each Member process your personal data in accordance with the %4$s. + By signing in to this app, you agree to the %1$s and %2$s and you acknowledge that %3$s and each Member process your personal data in accordance with the %4$s. + %2$s]]> 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 6b04b596b..7fa93886e 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 @@ -23,6 +23,7 @@ import org.junit.Test import org.junit.rules.TestRule import org.openedx.auth.R import org.openedx.auth.domain.interactor.AuthInteractor +import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.sso.OAuthHelper import org.openedx.core.UIMessage @@ -54,6 +55,7 @@ class SignInViewModelTest { private val interactor = mockk() private val analytics = mockk() private val appUpgradeNotifier = mockk() + private val agreementProvider = mockk() private val oAuthHelper = mockk() private val invalidCredential = "Invalid credentials" @@ -73,6 +75,7 @@ class SignInViewModelTest { every { resourceManager.getString(R.string.auth_invalid_email_username) } returns invalidEmailOrUsername every { resourceManager.getString(R.string.auth_invalid_password) } returns invalidPassword every { appUpgradeNotifier.notifier } returns emptyFlow() + every { agreementProvider.getAgreement(true) } returns null every { config.isPreLoginExperienceEnabled() } returns false every { config.isSocialAuthEnabled() } returns false every { config.getFacebookConfig() } returns FacebookConfig() @@ -98,6 +101,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -126,6 +130,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -156,6 +161,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -185,6 +191,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -216,6 +223,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -248,6 +256,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -281,6 +290,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -314,6 +324,7 @@ class SignInViewModelTest { analytics = analytics, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", diff --git a/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt index f93447bb8..326a3b36c 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signup/SignUpViewModelTest.kt @@ -1,6 +1,7 @@ package org.openedx.auth.presentation.signup import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.compose.ui.text.intl.Locale import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every @@ -26,6 +27,7 @@ import org.junit.Test import org.junit.rules.TestRule import org.openedx.auth.data.model.ValidationFields import org.openedx.auth.domain.interactor.AuthInteractor +import org.openedx.auth.presentation.AgreementProvider import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.sso.OAuthHelper import org.openedx.core.ApiConstants @@ -37,6 +39,7 @@ import org.openedx.core.config.GoogleConfig import org.openedx.core.config.MicrosoftConfig import org.openedx.core.data.model.User import org.openedx.core.data.storage.CorePreferences +import org.openedx.core.domain.model.AgreementUrls import org.openedx.core.domain.model.RegistrationField import org.openedx.core.domain.model.RegistrationFieldType import org.openedx.core.system.ResourceManager @@ -57,6 +60,7 @@ class SignUpViewModelTest { private val interactor = mockk() private val analytics = mockk() private val appUpgradeNotifier = mockk() + private val agreementProvider = mockk() private val oAuthHelper = mockk() //region parameters @@ -107,7 +111,9 @@ class SignUpViewModelTest { every { resourceManager.getString(R.string.core_error_no_connection) } returns noInternet every { resourceManager.getString(R.string.core_error_unknown_error) } returns somethingWrong every { appUpgradeNotifier.notifier } returns emptyFlow() + every { agreementProvider.getAgreement(false) } returns null every { config.isSocialAuthEnabled() } returns false + every { config.getAgreement(Locale.current.language) } returns AgreementUrls() every { config.getFacebookConfig() } returns FacebookConfig() every { config.getGoogleConfig() } returns GoogleConfig() every { config.getMicrosoftConfig() } returns MicrosoftConfig() @@ -127,6 +133,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -168,6 +175,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -215,6 +223,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -252,6 +261,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -300,6 +310,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -325,6 +336,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", @@ -350,6 +362,7 @@ class SignUpViewModelTest { preferencesManager = preferencesManager, appUpgradeNotifier = appUpgradeNotifier, oAuthHelper = oAuthHelper, + agreementProvider = agreementProvider, config = config, courseId = "", infoType = "", diff --git a/core/src/main/java/org/openedx/core/ApiConstants.kt b/core/src/main/java/org/openedx/core/ApiConstants.kt index 558df5434..786d63cc4 100644 --- a/core/src/main/java/org/openedx/core/ApiConstants.kt +++ b/core/src/main/java/org/openedx/core/ApiConstants.kt @@ -20,7 +20,6 @@ object ApiConstants { const val ACCESS_TOKEN = "access_token" const val CLIENT_ID = "client_id" const val EMAIL = "email" - const val HONOR_CODE = "honor_code" const val NAME = "name" const val PASSWORD = "password" const val PROVIDER = "provider" @@ -30,4 +29,9 @@ object ApiConstants { const val AUTH_TYPE_MICROSOFT = "azuread-oauth2" const val COURSE_KEY = "course_key" + + object RegistrationFields { + const val HONOR_CODE = "honor_code" + const val MARKETING_EMAILS = "marketing_emails_opt_in" + } } diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index cc1f37269..c6fb8f6e2 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -47,6 +47,10 @@ class Config(context: Context) { return getString(FEEDBACK_EMAIL_ADDRESS, "") } + fun getPlatformName(): String { + return getString(PLATFORM_NAME, "") + } + fun getAgreement(locale: String): AgreementUrls { val agreement = getObjectOrNewInstance(AGREEMENT_URLS, AgreementUrlsConfig::class.java).mapToDomain() @@ -168,6 +172,7 @@ class Config(context: Context) { private const val COURSE_BANNER_ENABLED = "COURSE_BANNER_ENABLED" private const val COURSE_TOP_TAB_BAR_ENABLED = "COURSE_TOP_TAB_BAR_ENABLED" private const val COURSE_UNIT_PROGRESS_ENABLED = "COURSE_UNIT_PROGRESS_ENABLED" + private const val PLATFORM_NAME = "PLATFORM_NAME" } enum class ViewType { diff --git a/core/src/main/java/org/openedx/core/domain/model/RegistrationField.kt b/core/src/main/java/org/openedx/core/domain/model/RegistrationField.kt index 20b1af6eb..94bbdee8c 100644 --- a/core/src/main/java/org/openedx/core/domain/model/RegistrationField.kt +++ b/core/src/main/java/org/openedx/core/domain/model/RegistrationField.kt @@ -13,7 +13,8 @@ data class RegistrationField( val required: Boolean, val restrictions: Restrictions, val options: List