Skip to content

Commit

Permalink
feat: eula on registration and sign in (openedx#236)
Browse files Browse the repository at this point in the history
  • Loading branch information
k1rill authored Feb 27, 2024
1 parent b543768 commit 77fc6cb
Show file tree
Hide file tree
Showing 22 changed files with 427 additions and 113 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -168,6 +169,7 @@ val appModule = module {
single<CourseAnalytics> { get<AnalyticsManager>() }
single<DiscussionAnalytics> { get<AnalyticsManager>() }

factory { AgreementProvider(get(), get()) }
factory { FacebookAuthHelper() }
factory { GoogleAuthHelper(get()) }
factory { MicrosoftAuthHelper() }
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,16 @@ val screenModule = module {
get(),
get(),
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(), get(), courseId, infoType)
}
viewModel { RestorePasswordViewModel(get(), get(), get(), get()) }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.openedx.auth.presentation

import androidx.compose.ui.text.intl.Locale
import org.openedx.auth.R
import org.openedx.core.config.Config
import org.openedx.core.system.ResourceManager

class AgreementProvider(
private val config: Config,
private val resourceManager: ResourceManager,
) {
internal fun getAgreement(isSignIn: Boolean): String? {
val agreementConfig = config.getAgreement(Locale.current.language)
if (agreementConfig.eulaUrl.isBlank()) return null
val platformName = config.getPlatformName()
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,
"$platformName ${resourceManager.getString(R.string.auth_agreement_eula)}"
)
val tos = resourceManager.getString(
R.string.auth_cdata_template,
agreementConfig.tosUrl,
"$platformName ${resourceManager.getString(R.string.auth_agreement_tos)}"
)
val privacy = resourceManager.getString(
R.string.auth_cdata_template,
agreementConfig.privacyPolicyUrl,
"$platformName ${resourceManager.getString(R.string.auth_agreement_privacy)}"
)
return resourceManager.getString(
agreementRes,
eula,
tos,
config.getPlatformName(),
privacy,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ interface AuthRouter {

fun navigateToNativeDiscoverCourses(fm: FragmentManager, querySearch: String)

fun navigateToWebContent(fm: FragmentManager, title: String, url: String)

fun clearBackStack(fm: FragmentManager)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import org.openedx.auth.data.model.AuthType
import org.openedx.auth.presentation.AuthRouter
import org.openedx.auth.presentation.signin.compose.LoginScreen
import org.openedx.core.AppUpdateState
import org.openedx.core.presentation.global.WhatsNewGlobalManager
import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRequiredScreen
import org.openedx.core.ui.rememberWindowSize
import org.openedx.core.ui.theme.OpenEdXTheme
Expand All @@ -31,8 +28,6 @@ class SignInFragment : Fragment() {
requireArguments().getString(ARG_INFO_TYPE, "")
)
}
private val router: AuthRouter by inject()
private val whatsNewGlobalManager by inject<WhatsNewGlobalManager>()

override fun onCreateView(
inflater: LayoutInflater,
Expand Down Expand Up @@ -61,41 +56,27 @@ class SignInFragment : Fragment() {
)

AuthEvent.ForgotPasswordClick -> {
viewModel.forgotPasswordClickedEvent()
router.navigateToRestorePassword(parentFragmentManager)
viewModel.navigateToForgotPassword(parentFragmentManager)
}

AuthEvent.RegisterClick -> {
viewModel.signUpClickedEvent()
router.navigateToSignUp(parentFragmentManager, null, null)
viewModel.navigateToSignUp(parentFragmentManager)
}

AuthEvent.BackClick -> {
requireActivity().supportFragmentManager.popBackStackImmediate()
}

is AuthEvent.OpenLink -> viewModel.openLink(
parentFragmentManager,
event.links,
event.link
)
}
},
)
LaunchedEffect(state.loginSuccess) {
val isNeedToShowWhatsNew =
whatsNewGlobalManager.shouldShowWhatsNew()
if (state.loginSuccess) {
router.clearBackStack(parentFragmentManager)
if (isNeedToShowWhatsNew) {
router.navigateToWhatsNew(
parentFragmentManager,
viewModel.courseId,
viewModel.infoType
)
} else {
router.navigateToMain(
parentFragmentManager,
viewModel.courseId,
viewModel.infoType
)
}
}

viewModel.proceedWhatsNew(parentFragmentManager)
}
} else {
AppUpgradeRequiredScreen(
Expand Down Expand Up @@ -125,6 +106,7 @@ class SignInFragment : Fragment() {
internal sealed interface AuthEvent {
data class SignIn(val login: String, val password: String) : AuthEvent
data class SocialSignIn(val authType: AuthType) : AuthEvent
data class OpenLink(val links: Map<String, String>, val link: String) : AuthEvent
object RegisterClick : AuthEvent
object ForgotPasswordClick : AuthEvent
object BackClick : AuthEvent
Expand Down
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -18,4 +20,5 @@ internal data class SignInUIState(
val isLogistrationEnabled: Boolean = false,
val showProgress: Boolean = false,
val loginSuccess: Boolean = false,
val agreement: RegistrationField? = null,
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.openedx.auth.presentation.signin

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
Expand All @@ -14,15 +15,19 @@ 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.AuthRouter
import org.openedx.auth.presentation.sso.OAuthHelper
import org.openedx.core.BaseViewModel
import org.openedx.core.SingleEventLiveData
import org.openedx.core.UIMessage
import org.openedx.core.Validator
import org.openedx.core.config.Config
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.domain.model.createHonorCodeField
import org.openedx.core.extension.isInternetError
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.AppUpgradeEvent
Expand All @@ -38,6 +43,9 @@ class SignInViewModel(
private val appUpgradeNotifier: AppUpgradeNotifier,
private val analytics: AuthAnalytics,
private val oAuthHelper: OAuthHelper,
private val router: AuthRouter,
private val whatsNewGlobalManager: WhatsNewGlobalManager,
agreementProvider: AgreementProvider,
config: Config,
val courseId: String?,
val infoType: String?,
Expand All @@ -52,6 +60,7 @@ class SignInViewModel(
isMicrosoftAuthEnabled = config.getMicrosoftConfig().isEnabled(),
isSocialAuthEnabled = config.isSocialAuthEnabled(),
isLogistrationEnabled = config.isPreLoginExperienceEnabled(),
agreement = agreementProvider.getAgreement(isSignIn = true)?.createHonorCodeField(),
)
)
internal val uiState: StateFlow<SignInUIState> = _uiState
Expand Down Expand Up @@ -124,11 +133,13 @@ class SignInViewModel(
}
}

fun signUpClickedEvent() {
fun navigateToSignUp(parentFragmentManager: FragmentManager) {
router.navigateToSignUp(parentFragmentManager, null, null)
analytics.signUpClickedEvent()
}

fun forgotPasswordClickedEvent() {
fun navigateToForgotPassword(parentFragmentManager: FragmentManager) {
router.navigateToRestorePassword(parentFragmentManager)
analytics.forgotPasswordClickedEvent()
}

Expand Down Expand Up @@ -177,4 +188,33 @@ class SignInViewModel(
}
} ?: onUnknownError()
}

fun openLink(fragmentManager: FragmentManager, links: Map<String, String>, link: String) {
links.forEach { (key, value) ->
if (value == link) {
router.navigateToWebContent(fragmentManager, key, value)
return
}
}
}

fun proceedWhatsNew(parentFragmentManager: FragmentManager) {
val isNeedToShowWhatsNew = whatsNewGlobalManager.shouldShowWhatsNew()
if (uiState.value.loginSuccess) {
router.clearBackStack(parentFragmentManager)
if (isNeedToShowWhatsNew) {
router.navigateToWhatsNew(
parentFragmentManager,
courseId,
infoType
)
} else {
router.navigateToMain(
parentFragmentManager,
courseId,
infoType
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -185,6 +187,20 @@ 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,
action = { link ->
onEvent(AuthEvent.OpenLink(linkedText.links, link))
},
)
}
}
}
}
Expand Down Expand Up @@ -349,7 +365,6 @@ private fun SignInScreenPreview() {
}
}


@Preview(name = "NEXUS_9_Light", device = Devices.NEXUS_9, uiMode = UI_MODE_NIGHT_NO)
@Preview(name = "NEXUS_9_Night", device = Devices.NEXUS_9, uiMode = UI_MODE_NIGHT_YES)
@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class SignUpFragment : Fragment() {
},
onFieldUpdated = { key, value ->
viewModel.updateField(key, value)
},
onHyperLinkClick = { links, link ->
viewModel.openLink(parentFragmentManager, links, link)
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import org.openedx.core.system.notifier.AppUpgradeEvent

data class SignUpUIState(
val allFields: List<RegistrationField> = emptyList(),
val requiredFields: List<RegistrationField> = emptyList(),
val optionalFields: List<RegistrationField> = emptyList(),
val agreementFields: List<RegistrationField> = emptyList(),
val isFacebookAuthEnabled: Boolean = false,
val isGoogleAuthEnabled: Boolean = false,
val isMicrosoftAuthEnabled: Boolean = false,
Expand Down
Loading

0 comments on commit 77fc6cb

Please sign in to comment.