-
Notifications
You must be signed in to change notification settings - Fork 784
#5307 Adds ForceLoginFallback feature flag to Login and Registration #5325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
507ddc2
7132488
f18808b
137d804
64e0748
c89f28f
4ebaa34
2917d4e
092761c
981393f
92c6d59
3d57d72
8d0410d
9f0cef7
65242df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Adds forceLoginFallback feature flag and usages to FTUE login and registration |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,8 @@ class FtueAuthVariant( | |
private val popEnterAnim = R.anim.no_anim | ||
private val popExitAnim = R.anim.exit_fade_out | ||
|
||
private var isForceLoginFallbackEnabled = false | ||
|
||
private val topFragment: Fragment? | ||
get() = supportFragmentManager.findFragmentById(views.loginFragmentContainer.id) | ||
|
||
|
@@ -109,10 +111,6 @@ class FtueAuthVariant( | |
} | ||
} | ||
|
||
override fun setIsLoading(isLoading: Boolean) { | ||
// do nothing | ||
} | ||
|
||
private fun addFirstFragment() { | ||
val splashFragment = when (vectorFeatures.isOnboardingSplashCarouselEnabled()) { | ||
true -> FtueAuthSplashCarouselFragment::class.java | ||
|
@@ -121,11 +119,25 @@ class FtueAuthVariant( | |
activity.addFragment(views.loginFragmentContainer, splashFragment) | ||
} | ||
|
||
private fun updateWithState(viewState: OnboardingViewState) { | ||
isForceLoginFallbackEnabled = viewState.isForceLoginFallbackEnabled | ||
views.loginLoading.isVisible = shouldShowLoading(viewState) | ||
} | ||
|
||
private fun shouldShowLoading(viewState: OnboardingViewState) = | ||
if (vectorFeatures.isOnboardingPersonalizeEnabled()) { | ||
viewState.isLoading() | ||
} else { | ||
// Keep loading when during success because of the delay when switching to the next Activity | ||
viewState.isLoading() || viewState.isAuthTaskCompleted() | ||
} | ||
|
||
override fun setIsLoading(isLoading: Boolean) = Unit | ||
|
||
private fun handleOnboardingViewEvents(viewEvents: OnboardingViewEvents) { | ||
when (viewEvents) { | ||
is OnboardingViewEvents.RegistrationFlowResult -> { | ||
// Check that all flows are supported by the application | ||
if (viewEvents.flowResult.missingStages.any { !it.isSupported() }) { | ||
if (registrationShouldFallback(viewEvents)) { | ||
// Display a popup to propose use web fallback | ||
onRegistrationStageNotSupported() | ||
} else { | ||
|
@@ -136,11 +148,7 @@ class FtueAuthVariant( | |
// First ask for login and password | ||
// I add a tag to indicate that this fragment is a registration stage. | ||
// This way it will be automatically popped in when starting the next registration stage | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthLoginFragment::class.java, | ||
tag = FRAGMENT_REGISTRATION_STAGE_TAG, | ||
option = commonOption | ||
) | ||
openAuthLoginFragmentWithTag(FRAGMENT_REGISTRATION_STAGE_TAG) | ||
} | ||
} | ||
} | ||
|
@@ -228,13 +236,23 @@ class FtueAuthVariant( | |
}.exhaustive | ||
} | ||
|
||
private fun updateWithState(viewState: OnboardingViewState) { | ||
views.loginLoading.isVisible = if (vectorFeatures.isOnboardingPersonalizeEnabled()) { | ||
viewState.isLoading() | ||
} else { | ||
// Keep loading when during success because of the delay when switching to the next Activity | ||
viewState.isLoading() || viewState.isAuthTaskCompleted() | ||
} | ||
private fun registrationShouldFallback(registrationFlowResult: OnboardingViewEvents.RegistrationFlowResult) = | ||
isForceLoginFallbackEnabled || registrationFlowResult.containsUnsupportedRegistrationFlow() | ||
|
||
private fun OnboardingViewEvents.RegistrationFlowResult.containsUnsupportedRegistrationFlow() = | ||
flowResult.missingStages.any { !it.isSupported() } | ||
|
||
private fun onRegistrationStageNotSupported() { | ||
MaterialAlertDialogBuilder(activity) | ||
.setTitle(R.string.app_name) | ||
.setMessage(activity.getString(R.string.login_registration_not_supported)) | ||
.setPositiveButton(R.string.yes) { _, _ -> | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthWebFragment::class.java, | ||
option = commonOption) | ||
} | ||
.setNegativeButton(R.string.no, null) | ||
.show() | ||
} | ||
|
||
private fun onWebLoginError(onWebLoginError: OnboardingViewEvents.OnWebLoginError) { | ||
|
@@ -264,64 +282,67 @@ class FtueAuthVariant( | |
// state.signMode could not be ready yet. So use value from the ViewEvent | ||
when (OnboardingViewEvents.signMode) { | ||
SignMode.Unknown -> error("Sign mode has to be set before calling this method") | ||
SignMode.SignUp -> { | ||
// This is managed by the OnboardingViewEvents | ||
} | ||
SignMode.SignIn -> { | ||
// It depends on the LoginMode | ||
when (state.loginMode) { | ||
LoginMode.Unknown, | ||
is LoginMode.Sso -> error("Developer error") | ||
is LoginMode.SsoAndPassword, | ||
LoginMode.Password -> activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthLoginFragment::class.java, | ||
tag = FRAGMENT_LOGIN_TAG, | ||
option = commonOption) | ||
LoginMode.Unsupported -> onLoginModeNotSupported(state.loginModeSupportedTypes) | ||
}.exhaustive | ||
} | ||
SignMode.SignInWithMatrixId -> activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthLoginFragment::class.java, | ||
tag = FRAGMENT_LOGIN_TAG, | ||
option = commonOption) | ||
SignMode.SignUp -> Unit // This case is processed in handleOnboardingViewEvents | ||
SignMode.SignIn -> handleSignInSelected(state) | ||
SignMode.SignInWithMatrixId -> handleSignInWithMatrixId(state) | ||
}.exhaustive | ||
} | ||
|
||
/** | ||
* Handle the SSO redirection here | ||
*/ | ||
override fun onNewIntent(intent: Intent?) { | ||
intent?.data | ||
?.let { tryOrNull { it.getQueryParameter("loginToken") } } | ||
?.let { onboardingViewModel.handle(OnboardingAction.LoginWithToken(it)) } | ||
private fun handleSignInSelected(state: OnboardingViewState) { | ||
if (isForceLoginFallbackEnabled) { | ||
onLoginModeNotSupported(state.loginModeSupportedTypes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Real change no. 2 |
||
} else { | ||
disambiguateLoginMode(state) | ||
} | ||
} | ||
|
||
private fun onRegistrationStageNotSupported() { | ||
MaterialAlertDialogBuilder(activity) | ||
.setTitle(R.string.app_name) | ||
.setMessage(activity.getString(R.string.login_registration_not_supported)) | ||
.setPositiveButton(R.string.yes) { _, _ -> | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthWebFragment::class.java, | ||
option = commonOption) | ||
} | ||
.setNegativeButton(R.string.no, null) | ||
.show() | ||
private fun disambiguateLoginMode(state: OnboardingViewState) = when (state.loginMode) { | ||
LoginMode.Unknown, | ||
is LoginMode.Sso -> error("Developer error") | ||
is LoginMode.SsoAndPassword, | ||
LoginMode.Password -> openAuthLoginFragmentWithTag(FRAGMENT_LOGIN_TAG) | ||
LoginMode.Unsupported -> onLoginModeNotSupported(state.loginModeSupportedTypes) | ||
} | ||
|
||
private fun openAuthLoginFragmentWithTag(tag: String) { | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthLoginFragment::class.java, | ||
tag = tag, | ||
option = commonOption) | ||
} | ||
|
||
private fun onLoginModeNotSupported(supportedTypes: List<String>) { | ||
MaterialAlertDialogBuilder(activity) | ||
.setTitle(R.string.app_name) | ||
.setMessage(activity.getString(R.string.login_mode_not_supported, supportedTypes.joinToString { "'$it'" })) | ||
.setPositiveButton(R.string.yes) { _, _ -> | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthWebFragment::class.java, | ||
option = commonOption) | ||
} | ||
.setPositiveButton(R.string.yes) { _, _ -> openAuthWebFragment() } | ||
.setNegativeButton(R.string.no, null) | ||
.show() | ||
} | ||
|
||
private fun handleSignInWithMatrixId(state: OnboardingViewState) { | ||
if (isForceLoginFallbackEnabled) { | ||
onLoginModeNotSupported(state.loginModeSupportedTypes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Real change no. 3 |
||
} else { | ||
openAuthLoginFragmentWithTag(FRAGMENT_LOGIN_TAG) | ||
} | ||
} | ||
|
||
private fun openAuthWebFragment() { | ||
activity.addFragmentToBackstack(views.loginFragmentContainer, | ||
FtueAuthWebFragment::class.java, | ||
option = commonOption) | ||
} | ||
|
||
/** | ||
* Handle the SSO redirection here | ||
*/ | ||
override fun onNewIntent(intent: Intent?) { | ||
intent?.data | ||
?.let { tryOrNull { it.getQueryParameter("loginToken") } } | ||
?.let { onboardingViewModel.handle(OnboardingAction.LoginWithToken(it)) } | ||
} | ||
|
||
private fun handleRegistrationNavigation(flowResult: FlowResult) { | ||
// Complete all mandatory stages first | ||
val mandatoryStage = flowResult.missingStages.firstOrNull { it.mandatory } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,4 +59,16 @@ class VectorDataStore @Inject constructor( | |
settings[forceDialPadDisplay] = force | ||
} | ||
} | ||
|
||
private val forceLoginFallback = booleanPreferencesKey("force_login_fallback") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would have expected this to be beside the dial pad option within the I have an upcoming PR to move the override options out of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Soz for the conflict 😅 For visibility sake, because they're pretty minor, we decided that you'd resolve them on your pr |
||
|
||
val forceLoginFallbackFlow: Flow<Boolean> = context.dataStore.data.map { preferences -> | ||
preferences[forceLoginFallback].orFalse() | ||
} | ||
|
||
suspend fun setForceLoginFallbackFlow(force: Boolean) { | ||
context.dataStore.edit { settings -> | ||
settings[forceLoginFallback] = force | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok for this private var, as a cache, because the boolean is also in the state.