Skip to content

Commit

Permalink
Merge pull request #5158 from vector-im/feature/adm/ftue-post-account…
Browse files Browse the repository at this point in the history
…-creation

FTUE - Account created screen
  • Loading branch information
bmarty authored Feb 23, 2022
2 parents 924a4f8 + 4975406 commit 276c526
Show file tree
Hide file tree
Showing 12 changed files with 264 additions and 27 deletions.
1 change: 1 addition & 0 deletions changelog.d/5158.wip
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Starts the FTUE account personalisation flow by adding an account created screen behind a feature flag
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ class DebugFeaturesStateFactory @Inject constructor(
label = "FTUE Use Case",
key = DebugFeatureKeys.onboardingUseCase,
factory = VectorFeatures::isOnboardingUseCaseEnabled
),
createBooleanFeature(
label = "FTUE Personalize profile",
key = DebugFeatureKeys.onboardingPersonalize,
factory = VectorFeatures::isOnboardingPersonalizeEnabled
)
))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class DebugVectorFeatures(

override fun isOnboardingUseCaseEnabled(): Boolean = read(DebugFeatureKeys.onboardingUseCase) ?: vectorFeatures.isOnboardingUseCaseEnabled()

override fun isOnboardingPersonalizeEnabled(): Boolean = read(DebugFeatureKeys.onboardingPersonalize)
?: vectorFeatures.isOnboardingPersonalizeEnabled()

fun <T> override(value: T?, key: Preferences.Key<T>) = updatePreferences {
if (value == null) {
it.remove(key)
Expand Down Expand Up @@ -102,4 +105,5 @@ object DebugFeatureKeys {
val onboardingAlreadyHaveAnAccount = booleanPreferencesKey("onboarding-already-have-an-account")
val onboardingSplashCarousel = booleanPreferencesKey("onboarding-splash-carousel")
val onboardingUseCase = booleanPreferencesKey("onbboarding-splash-carousel")
val onboardingPersonalize = booleanPreferencesKey("onbboarding-personalize")
}
6 changes: 6 additions & 0 deletions vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import im.vector.app.features.login2.created.AccountCreatedFragment
import im.vector.app.features.login2.terms.LoginTermsFragment2
import im.vector.app.features.matrixto.MatrixToRoomSpaceFragment
import im.vector.app.features.matrixto.MatrixToUserFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthAccountCreatedFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthCaptchaFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthGenericTextInputFormFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthLoginFragment
Expand Down Expand Up @@ -473,6 +474,11 @@ interface FragmentModule {
@FragmentKey(FtueAuthTermsFragment::class)
fun bindFtueAuthTermsFragment(fragment: FtueAuthTermsFragment): Fragment

@Binds
@IntoMap
@FragmentKey(FtueAuthAccountCreatedFragment::class)
fun bindFtueAuthAccountCreatedFragment(fragment: FtueAuthAccountCreatedFragment): Fragment

@Binds
@IntoMap
@FragmentKey(UserListFragment::class)
Expand Down
2 changes: 2 additions & 0 deletions vector/src/main/java/im/vector/app/features/VectorFeatures.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface VectorFeatures {
fun isOnboardingAlreadyHaveAccountSplashEnabled(): Boolean
fun isOnboardingSplashCarouselEnabled(): Boolean
fun isOnboardingUseCaseEnabled(): Boolean
fun isOnboardingPersonalizeEnabled(): Boolean

enum class OnboardingVariant {
LEGACY,
Expand All @@ -37,4 +38,5 @@ class DefaultVectorFeatures : VectorFeatures {
override fun isOnboardingAlreadyHaveAccountSplashEnabled() = true
override fun isOnboardingSplashCarouselEnabled() = true
override fun isOnboardingUseCaseEnabled() = true
override fun isOnboardingPersonalizeEnabled() = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ sealed class OnboardingViewEvents : VectorViewEvents {
data class OnSendMsisdnSuccess(val msisdn: String) : OnboardingViewEvents()

data class OnWebLoginError(val errorCode: Int, val description: String, val failingUrl: String) : OnboardingViewEvents()
object OnAccountCreated : OnboardingViewEvents()
object OnAccountSignedIn : OnboardingViewEvents()
object OnTakeMeHome : OnboardingViewEvents()
object OnPersonalizeProfile : OnboardingViewEvents()
}
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class OnboardingViewModel @AssistedInject constructor(
}
null
}
?.let { onSessionCreated(it) }
?.let { onSessionCreated(it, isAccountCreated = false) }
}
}
}
Expand Down Expand Up @@ -301,7 +301,7 @@ class OnboardingViewModel @AssistedInject constructor(
}
?.let { data ->
when (data) {
is RegistrationResult.Success -> onSessionCreated(data.session)
is RegistrationResult.Success -> onSessionCreated(data.session, isAccountCreated = true)
is RegistrationResult.FlowResponse -> onFlowResponse(data.flowResult)
}
}
Expand Down Expand Up @@ -600,11 +600,11 @@ class OnboardingViewModel @AssistedInject constructor(
}
when (data) {
is WellknownResult.Prompt ->
onWellknownSuccess(action, data, homeServerConnectionConfig)
directLoginOnWellknownSuccess(action, data, homeServerConnectionConfig)
is WellknownResult.FailPrompt ->
// Relax on IS discovery if homeserver is valid
if (data.homeServerUrl != null && data.wellKnown != null) {
onWellknownSuccess(action, WellknownResult.Prompt(data.homeServerUrl!!, null, data.wellKnown!!), homeServerConnectionConfig)
directLoginOnWellknownSuccess(action, WellknownResult.Prompt(data.homeServerUrl!!, null, data.wellKnown!!), homeServerConnectionConfig)
} else {
onWellKnownError()
}
Expand All @@ -624,9 +624,9 @@ class OnboardingViewModel @AssistedInject constructor(
_viewEvents.post(OnboardingViewEvents.Failure(Exception(stringProvider.getString(R.string.autodiscover_well_known_error))))
}

private suspend fun onWellknownSuccess(action: OnboardingAction.LoginOrRegister,
wellKnownPrompt: WellknownResult.Prompt,
homeServerConnectionConfig: HomeServerConnectionConfig?) {
private suspend fun directLoginOnWellknownSuccess(action: OnboardingAction.LoginOrRegister,
wellKnownPrompt: WellknownResult.Prompt,
homeServerConnectionConfig: HomeServerConnectionConfig?) {
val alteredHomeServerConnectionConfig = homeServerConnectionConfig
?.copy(
homeServerUriBase = Uri.parse(wellKnownPrompt.homeServerUrl),
Expand All @@ -648,7 +648,7 @@ class OnboardingViewModel @AssistedInject constructor(
onDirectLoginError(failure)
return
}
onSessionCreated(data)
onSessionCreated(data, isAccountCreated = true)
}

private fun onDirectLoginError(failure: Throwable) {
Expand Down Expand Up @@ -706,7 +706,7 @@ class OnboardingViewModel @AssistedInject constructor(
}
?.let {
reAuthHelper.data = action.password
onSessionCreated(it)
onSessionCreated(it, isAccountCreated = false)
}
}
}
Expand Down Expand Up @@ -736,8 +736,9 @@ class OnboardingViewModel @AssistedInject constructor(
}
}

private suspend fun onSessionCreated(session: Session) {
awaitState().useCase?.let { useCase ->
private suspend fun onSessionCreated(session: Session, isAccountCreated: Boolean) {
val state = awaitState()
state.useCase?.let { useCase ->
session.vectorStore(applicationContext).setUseCase(useCase)
analyticsTracker.updateUserProperties(UserProperties(ftueUseCaseSelection = useCase.toTrackingValue()))
}
Expand All @@ -750,6 +751,11 @@ class OnboardingViewModel @AssistedInject constructor(
asyncLoginAction = Success(Unit)
)
}

when (isAccountCreated) {
true -> _viewEvents.post(OnboardingViewEvents.OnAccountCreated)
false -> _viewEvents.post(OnboardingViewEvents.OnAccountSignedIn)
}
}

private fun handleWebLoginSuccess(action: OnboardingAction.WebLoginSuccess) = withState { state ->
Expand All @@ -768,7 +774,7 @@ class OnboardingViewModel @AssistedInject constructor(
}
null
}
?.let { onSessionCreated(it) }
?.let { onSessionCreated(it, isAccountCreated = false) }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,10 @@ data class OnboardingViewState(
asyncHomeServerLoginFlowRequest is Loading ||
asyncResetPassword is Loading ||
asyncResetMailConfirmed is Loading ||
asyncRegistration is Loading ||
// Keep loading when it is success because of the delay to switch to the next Activity
asyncLoginAction is Success
asyncRegistration is Loading
}

fun isUserLogged(): Boolean {
fun isAuthTaskCompleted(): Boolean {
return asyncLoginAction is Success
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.app.features.onboarding.ftueauth

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.databinding.FragmentFtueAccountCreatedBinding
import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewEvents
import javax.inject.Inject

class FtueAuthAccountCreatedFragment @Inject constructor(
private val activeSessionHolder: ActiveSessionHolder
) : AbstractFtueAuthFragment<FragmentFtueAccountCreatedBinding>() {

override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueAccountCreatedBinding {
return FragmentFtueAccountCreatedBinding.inflate(inflater, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupViews()
}

private fun setupViews() {
views.accountCreatedSubtitle.text = getString(R.string.ftue_account_created_subtitle, activeSessionHolder.getActiveSession().myUserId)
views.accountCreatedPersonalize.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnPersonalizeProfile)) }
views.accountCreatedTakeMeHome.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnTakeMeHome)) }
}

override fun resetViewModel() {
// Nothing to do
}

override fun onBackPressed(toolbarButton: Boolean): Boolean {
viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnTakeMeHome))
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import im.vector.app.core.extensions.POP_BACK_STACK_EXCLUSIVE
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.ScreenOrientationLocker
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivityLoginBinding
Expand Down Expand Up @@ -220,22 +221,20 @@ class FtueAuthVariant(
FtueAuthUseCaseFragment::class.java,
option = commonOption)
}
OnboardingViewEvents.OnAccountCreated -> onAccountCreated()
OnboardingViewEvents.OnAccountSignedIn -> onAccountSignedIn()
OnboardingViewEvents.OnPersonalizeProfile -> TODO()
OnboardingViewEvents.OnTakeMeHome -> navigateToHome(createdAccount = true)
}.exhaustive
}

private fun updateWithState(viewState: OnboardingViewState) {
if (viewState.isUserLogged()) {
val intent = HomeActivity.newIntent(
activity,
accountCreation = viewState.signMode == SignMode.SignUp
)
activity.startActivity(intent)
activity.finish()
return
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()
}

// Loading
views.loginLoading.isVisible = viewState.isLoading()
}

private fun onWebLoginError(onWebLoginError: OnboardingViewEvents.OnWebLoginError) {
Expand Down Expand Up @@ -368,4 +367,26 @@ class FtueAuthVariant(
else -> Unit // Should not happen
}
}

private fun onAccountSignedIn() {
navigateToHome(createdAccount = false)
}

private fun onAccountCreated() {
if (vectorFeatures.isOnboardingPersonalizeEnabled()) {
activity.supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
activity.replaceFragment(
views.loginFragmentContainer,
FtueAuthAccountCreatedFragment::class.java,
)
} else {
navigateToHome(createdAccount = true)
}
}

private fun navigateToHome(createdAccount: Boolean) {
val intent = HomeActivity.newIntent(activity, accountCreation = createdAccount)
activity.startActivity(intent)
activity.finish()
}
}
Loading

0 comments on commit 276c526

Please sign in to comment.