diff --git a/changelog.d/5158.wip b/changelog.d/5158.wip new file mode 100644 index 0000000000..67a3d83a7a --- /dev/null +++ b/changelog.d/5158.wip @@ -0,0 +1 @@ +Starts the FTUE account personalisation flow by adding an account created screen behind a feature flag \ No newline at end of file diff --git a/changelog.d/5312.misc b/changelog.d/5312.misc new file mode 100644 index 0000000000..d724f1ba3f --- /dev/null +++ b/changelog.d/5312.misc @@ -0,0 +1 @@ +Log the `since` token used and `next_batch` token returned when doing an incremental sync. diff --git a/changelog.d/5313.misc b/changelog.d/5313.misc new file mode 100644 index 0000000000..efc225a0a4 --- /dev/null +++ b/changelog.d/5313.misc @@ -0,0 +1 @@ +Update reaction button layout. \ No newline at end of file diff --git a/changelog.d/5318.misc b/changelog.d/5318.misc new file mode 100644 index 0000000000..d724f1ba3f --- /dev/null +++ b/changelog.d/5318.misc @@ -0,0 +1 @@ +Log the `since` token used and `next_batch` token returned when doing an incremental sync. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index 1ee62ad774..b4da1a02cd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -147,7 +147,7 @@ internal class DefaultSyncTask @Inject constructor( } defaultSyncStatusService.endAll() } else { - Timber.tag(loggerTag.value).d("Start incremental sync request") + Timber.tag(loggerTag.value).d("Start incremental sync request with since token $token") defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncIdle) val syncResponse = try { executeRequest(globalErrorReceiver) { @@ -163,7 +163,10 @@ internal class DefaultSyncTask @Inject constructor( } val nbRooms = syncResponse.rooms?.invite.orEmpty().size + syncResponse.rooms?.join.orEmpty().size + syncResponse.rooms?.leave.orEmpty().size val nbToDevice = syncResponse.toDevice?.events.orEmpty().size - Timber.tag(loggerTag.value).d("Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s)") + val nextBatch = syncResponse.nextBatch + Timber.tag(loggerTag.value).d( + "Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s). Got nextBatch: $nextBatch" + ) defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncParsing( rooms = nbRooms, toDevice = nbToDevice diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt index 46f46ad964..3fbe80fd98 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt @@ -49,6 +49,11 @@ class DebugFeaturesStateFactory @Inject constructor( key = DebugFeatureKeys.onboardingUseCase, factory = VectorFeatures::isOnboardingUseCaseEnabled ), + createBooleanFeature( + label = "FTUE Personalize profile", + key = DebugFeatureKeys.onboardingPersonalize, + factory = VectorFeatures::isOnboardingPersonalizeEnabled + ), createBooleanFeature( label = "Force login fallback", key = DebugFeatureKeys.forceLoginFallback, diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt index 396dd02a37..85d3a501f6 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt @@ -51,6 +51,9 @@ class DebugVectorFeatures( override fun isOnboardingUseCaseEnabled(): Boolean = read(DebugFeatureKeys.onboardingUseCase) ?: vectorFeatures.isOnboardingUseCaseEnabled() + override fun isOnboardingPersonalizeEnabled(): Boolean = read(DebugFeatureKeys.onboardingPersonalize) + ?: vectorFeatures.isOnboardingPersonalizeEnabled() + override fun isForceLoginFallbackEnabled(): Boolean = read(DebugFeatureKeys.forceLoginFallback) ?: vectorFeatures.isForceLoginFallbackEnabled() fun override(value: T?, key: Preferences.Key) = updatePreferences { @@ -104,5 +107,6 @@ 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") val forceLoginFallback = booleanPreferencesKey("force-login-fallback") } diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index e7aa83ae75..5eb735d22e 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -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 @@ -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) diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index 451ecc4722..7d8d14b3af 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -24,6 +24,7 @@ interface VectorFeatures { fun isOnboardingAlreadyHaveAccountSplashEnabled(): Boolean fun isOnboardingSplashCarouselEnabled(): Boolean fun isOnboardingUseCaseEnabled(): Boolean + fun isOnboardingPersonalizeEnabled(): Boolean fun isForceLoginFallbackEnabled(): Boolean enum class OnboardingVariant { @@ -38,5 +39,6 @@ class DefaultVectorFeatures : VectorFeatures { override fun isOnboardingAlreadyHaveAccountSplashEnabled() = true override fun isOnboardingSplashCarouselEnabled() = true override fun isOnboardingUseCaseEnabled() = true + override fun isOnboardingPersonalizeEnabled() = false override fun isForceLoginFallbackEnabled() = false } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt index d6105cda13..536c1d1875 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt @@ -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() } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt index d279c5bbe9..ca3c3644bd 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt @@ -243,7 +243,7 @@ class OnboardingViewModel @AssistedInject constructor( } null } - ?.let { onSessionCreated(it) } + ?.let { onSessionCreated(it, isAccountCreated = false) } } } } @@ -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) } } @@ -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() } @@ -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), @@ -648,7 +648,7 @@ class OnboardingViewModel @AssistedInject constructor( onDirectLoginError(failure) return } - onSessionCreated(data) + onSessionCreated(data, isAccountCreated = true) } private fun onDirectLoginError(failure: Throwable) { @@ -706,7 +706,7 @@ class OnboardingViewModel @AssistedInject constructor( } ?.let { reAuthHelper.data = action.password - onSessionCreated(it) + onSessionCreated(it, isAccountCreated = false) } } } @@ -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())) } @@ -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 -> @@ -768,7 +774,7 @@ class OnboardingViewModel @AssistedInject constructor( } null } - ?.let { onSessionCreated(it) } + ?.let { onSessionCreated(it, isAccountCreated = false) } } } } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt index d05a8294f6..7bad2682a9 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewState.kt @@ -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 } } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt new file mode 100644 index 0000000000..d021fd2813 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt @@ -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() { + + 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 + } +} diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt index d08136eb70..962b40df66 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt @@ -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 @@ -216,6 +217,10 @@ class FtueAuthVariant( FtueAuthUseCaseFragment::class.java, option = commonOption) } + OnboardingViewEvents.OnAccountCreated -> onAccountCreated() + OnboardingViewEvents.OnAccountSignedIn -> onAccountSignedIn() + OnboardingViewEvents.OnPersonalizeProfile -> TODO() + OnboardingViewEvents.OnTakeMeHome -> navigateToHome(createdAccount = true) }.exhaustive } @@ -239,18 +244,12 @@ class FtueAuthVariant( } 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) { @@ -384,4 +383,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() + } } diff --git a/vector/src/main/res/drawable/ic_add_reaction_small.xml b/vector/src/main/res/drawable/ic_add_reaction_small.xml index ddd4367ce0..7c6fbb8fa7 100644 --- a/vector/src/main/res/drawable/ic_add_reaction_small.xml +++ b/vector/src/main/res/drawable/ic_add_reaction_small.xml @@ -1,4 +1,10 @@ - - + + diff --git a/vector/src/main/res/layout/fragment_ftue_account_created.xml b/vector/src/main/res/layout/fragment_ftue_account_created.xml new file mode 100644 index 0000000000..1985af1d5e --- /dev/null +++ b/vector/src/main/res/layout/fragment_ftue_account_created.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + +