Merge pull request #6042 from vector-im/feature/adm/ftue-analytics
FTUE - Sign up analytics
This commit is contained in:
commit
a5f404f247
1
changelog.d/5285.wip
Normal file
1
changelog.d/5285.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
FTUE - Adds Sign Up tracking
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.analytics.extensions
|
||||||
|
|
||||||
|
import im.vector.app.features.analytics.plan.Signup
|
||||||
|
import im.vector.app.features.onboarding.AuthenticationDescription
|
||||||
|
|
||||||
|
fun AuthenticationDescription.AuthenticationType.toAnalyticsType() = when (this) {
|
||||||
|
AuthenticationDescription.AuthenticationType.Password -> Signup.AuthenticationType.Password
|
||||||
|
AuthenticationDescription.AuthenticationType.Apple -> Signup.AuthenticationType.Apple
|
||||||
|
AuthenticationDescription.AuthenticationType.Facebook -> Signup.AuthenticationType.Facebook
|
||||||
|
AuthenticationDescription.AuthenticationType.GitHub -> Signup.AuthenticationType.GitHub
|
||||||
|
AuthenticationDescription.AuthenticationType.GitLab -> Signup.AuthenticationType.GitLab
|
||||||
|
AuthenticationDescription.AuthenticationType.Google -> Signup.AuthenticationType.Google
|
||||||
|
AuthenticationDescription.AuthenticationType.SSO -> Signup.AuthenticationType.SSO
|
||||||
|
AuthenticationDescription.AuthenticationType.Other -> Signup.AuthenticationType.Other
|
||||||
|
}
|
@ -56,6 +56,7 @@ import im.vector.app.features.matrixto.MatrixToBottomSheet
|
|||||||
import im.vector.app.features.matrixto.OriginOfMatrixTo
|
import im.vector.app.features.matrixto.OriginOfMatrixTo
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
|
import im.vector.app.features.onboarding.AuthenticationDescription
|
||||||
import im.vector.app.features.permalink.NavigationInterceptor
|
import im.vector.app.features.permalink.NavigationInterceptor
|
||||||
import im.vector.app.features.permalink.PermalinkHandler
|
import im.vector.app.features.permalink.PermalinkHandler
|
||||||
import im.vector.app.features.permalink.PermalinkHandler.Companion.MATRIX_TO_CUSTOM_SCHEME_URL_BASE
|
import im.vector.app.features.permalink.PermalinkHandler.Companion.MATRIX_TO_CUSTOM_SCHEME_URL_BASE
|
||||||
@ -91,7 +92,7 @@ import javax.inject.Inject
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
data class HomeActivityArgs(
|
data class HomeActivityArgs(
|
||||||
val clearNotification: Boolean,
|
val clearNotification: Boolean,
|
||||||
val accountCreation: Boolean,
|
val authenticationDescription: AuthenticationDescription? = null,
|
||||||
val hasExistingSession: Boolean = false,
|
val hasExistingSession: Boolean = false,
|
||||||
val inviteNotificationRoomId: String? = null
|
val inviteNotificationRoomId: String? = null
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
@ -612,13 +613,13 @@ class HomeActivity :
|
|||||||
fun newIntent(
|
fun newIntent(
|
||||||
context: Context,
|
context: Context,
|
||||||
clearNotification: Boolean = false,
|
clearNotification: Boolean = false,
|
||||||
accountCreation: Boolean = false,
|
authenticationDescription: AuthenticationDescription? = null,
|
||||||
existingSession: Boolean = false,
|
existingSession: Boolean = false,
|
||||||
inviteNotificationRoomId: String? = null
|
inviteNotificationRoomId: String? = null
|
||||||
): Intent {
|
): Intent {
|
||||||
val args = HomeActivityArgs(
|
val args = HomeActivityArgs(
|
||||||
clearNotification = clearNotification,
|
clearNotification = clearNotification,
|
||||||
accountCreation = accountCreation,
|
authenticationDescription = authenticationDescription,
|
||||||
hasExistingSession = existingSession,
|
hasExistingSession = existingSession,
|
||||||
inviteNotificationRoomId = inviteNotificationRoomId
|
inviteNotificationRoomId = inviteNotificationRoomId
|
||||||
)
|
)
|
||||||
|
@ -28,8 +28,12 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import im.vector.app.features.analytics.AnalyticsTracker
|
||||||
|
import im.vector.app.features.analytics.extensions.toAnalyticsType
|
||||||
|
import im.vector.app.features.analytics.plan.Signup
|
||||||
import im.vector.app.features.analytics.store.AnalyticsStore
|
import im.vector.app.features.analytics.store.AnalyticsStore
|
||||||
import im.vector.app.features.login.ReAuthHelper
|
import im.vector.app.features.login.ReAuthHelper
|
||||||
|
import im.vector.app.features.onboarding.AuthenticationDescription
|
||||||
import im.vector.app.features.raw.wellknown.ElementWellKnown
|
import im.vector.app.features.raw.wellknown.ElementWellKnown
|
||||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||||
import im.vector.app.features.raw.wellknown.isSecureBackupRequired
|
import im.vector.app.features.raw.wellknown.isSecureBackupRequired
|
||||||
@ -38,8 +42,11 @@ import im.vector.app.features.session.coroutineScope
|
|||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onCompletion
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.flow.takeWhile
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.auth.UIABaseAuth
|
import org.matrix.android.sdk.api.auth.UIABaseAuth
|
||||||
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
|
||||||
@ -73,7 +80,8 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
private val reAuthHelper: ReAuthHelper,
|
private val reAuthHelper: ReAuthHelper,
|
||||||
private val analyticsStore: AnalyticsStore,
|
private val analyticsStore: AnalyticsStore,
|
||||||
private val lightweightSettingsStorage: LightweightSettingsStorage,
|
private val lightweightSettingsStorage: LightweightSettingsStorage,
|
||||||
private val vectorPreferences: VectorPreferences
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
private val analyticsTracker: AnalyticsTracker
|
||||||
) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) {
|
) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
@ -85,7 +93,7 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
override fun initialState(viewModelContext: ViewModelContext): HomeActivityViewState? {
|
override fun initialState(viewModelContext: ViewModelContext): HomeActivityViewState? {
|
||||||
val activity: HomeActivity = viewModelContext.activity()
|
val activity: HomeActivity = viewModelContext.activity()
|
||||||
val args: HomeActivityArgs? = activity.intent.getParcelableExtra(Mavericks.KEY_ARG)
|
val args: HomeActivityArgs? = activity.intent.getParcelableExtra(Mavericks.KEY_ARG)
|
||||||
return args?.let { HomeActivityViewState(accountCreation = it.accountCreation) }
|
return args?.let { HomeActivityViewState(authenticationDescription = it.authenticationDescription) }
|
||||||
?: super.initialState(viewModelContext)
|
?: super.initialState(viewModelContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,9 +122,32 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
|
when (val recentAuthentication = initialState.authenticationDescription) {
|
||||||
|
is AuthenticationDescription.Register -> {
|
||||||
|
viewModelScope.launch {
|
||||||
|
analyticsStore.onUserGaveConsent {
|
||||||
|
analyticsTracker.capture(Signup(authenticationType = recentAuthentication.type.toAnalyticsType()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthenticationDescription.Login -> {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
null -> {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun AnalyticsStore.onUserGaveConsent(action: () -> Unit) {
|
||||||
|
userConsentFlow
|
||||||
|
.takeWhile { !it }
|
||||||
|
.onCompletion { action() }
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
private fun cleanupFiles() {
|
private fun cleanupFiles() {
|
||||||
// Mitigation: delete all cached decrypted files each time the application is started.
|
// Mitigation: delete all cached decrypted files each time the application is started.
|
||||||
activeSessionHolder.getSafeActiveSession()?.fileService()?.clearDecryptedCache()
|
activeSessionHolder.getSafeActiveSession()?.fileService()?.clearDecryptedCache()
|
||||||
@ -191,10 +222,10 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
.asFlow()
|
.asFlow()
|
||||||
.onEach { status ->
|
.onEach { status ->
|
||||||
when (status) {
|
when (status) {
|
||||||
is SyncStatusService.Status.Idle -> {
|
is SyncStatusService.Status.Idle -> {
|
||||||
maybeVerifyOrBootstrapCrossSigning()
|
maybeVerifyOrBootstrapCrossSigning()
|
||||||
}
|
}
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
@ -285,7 +316,7 @@ class HomeActivityViewModel @AssistedInject constructor(
|
|||||||
val isSecureBackupRequired = elementWellKnown?.isSecureBackupRequired() ?: false
|
val isSecureBackupRequired = elementWellKnown?.isSecureBackupRequired() ?: false
|
||||||
|
|
||||||
// In case of account creation, it is already done before
|
// In case of account creation, it is already done before
|
||||||
if (initialState.accountCreation) {
|
if (initialState.authenticationDescription is AuthenticationDescription.Register) {
|
||||||
if (isSecureBackupRequired) {
|
if (isSecureBackupRequired) {
|
||||||
_viewEvents.post(HomeActivityViewEvents.StartRecoverySetupFlow)
|
_viewEvents.post(HomeActivityViewEvents.StartRecoverySetupFlow)
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,9 +17,10 @@
|
|||||||
package im.vector.app.features.home
|
package im.vector.app.features.home
|
||||||
|
|
||||||
import com.airbnb.mvrx.MavericksState
|
import com.airbnb.mvrx.MavericksState
|
||||||
|
import im.vector.app.features.onboarding.AuthenticationDescription
|
||||||
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
import org.matrix.android.sdk.api.session.initsync.SyncStatusService
|
||||||
|
|
||||||
data class HomeActivityViewState(
|
data class HomeActivityViewState(
|
||||||
val syncStatusServiceStatus: SyncStatusService.Status = SyncStatusService.Status.Idle,
|
val syncStatusServiceStatus: SyncStatusService.Status = SyncStatusService.Status.Idle,
|
||||||
val accountCreation: Boolean = false
|
val authenticationDescription: AuthenticationDescription? = null
|
||||||
) : MavericksState
|
) : MavericksState
|
||||||
|
@ -42,6 +42,7 @@ import im.vector.app.features.analytics.plan.MobileScreen
|
|||||||
import im.vector.app.features.home.HomeActivity
|
import im.vector.app.features.home.HomeActivity
|
||||||
import im.vector.app.features.login.terms.LoginTermsFragment
|
import im.vector.app.features.login.terms.LoginTermsFragment
|
||||||
import im.vector.app.features.login.terms.LoginTermsFragmentArgument
|
import im.vector.app.features.login.terms.LoginTermsFragmentArgument
|
||||||
|
import im.vector.app.features.onboarding.AuthenticationDescription
|
||||||
import im.vector.app.features.pin.UnlockedActivity
|
import im.vector.app.features.pin.UnlockedActivity
|
||||||
import org.matrix.android.sdk.api.auth.registration.FlowResult
|
import org.matrix.android.sdk.api.auth.registration.FlowResult
|
||||||
import org.matrix.android.sdk.api.auth.registration.Stage
|
import org.matrix.android.sdk.api.auth.registration.Stage
|
||||||
@ -218,10 +219,8 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), UnlockedA
|
|||||||
// change the screen name
|
// change the screen name
|
||||||
analyticsScreenName = MobileScreen.ScreenName.Register
|
analyticsScreenName = MobileScreen.ScreenName.Register
|
||||||
}
|
}
|
||||||
val intent = HomeActivity.newIntent(
|
val authDescription = inferAuthDescription(loginViewState)
|
||||||
this,
|
val intent = HomeActivity.newIntent(this, authenticationDescription = authDescription)
|
||||||
accountCreation = loginViewState.signMode == SignMode.SignUp
|
|
||||||
)
|
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
@ -231,6 +230,13 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), UnlockedA
|
|||||||
views.loginLoading.isVisible = loginViewState.isLoading()
|
views.loginLoading.isVisible = loginViewState.isLoading()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun inferAuthDescription(loginViewState: LoginViewState) = when (loginViewState.signMode) {
|
||||||
|
SignMode.Unknown -> null
|
||||||
|
SignMode.SignUp -> AuthenticationDescription.Register(type = AuthenticationDescription.AuthenticationType.Other)
|
||||||
|
SignMode.SignIn -> AuthenticationDescription.Login
|
||||||
|
SignMode.SignInWithMatrixId -> AuthenticationDescription.Login
|
||||||
|
}
|
||||||
|
|
||||||
private fun onWebLoginError(onWebLoginError: LoginViewEvents.OnWebLoginError) {
|
private fun onWebLoginError(onWebLoginError: LoginViewEvents.OnWebLoginError) {
|
||||||
// Pop the backstack
|
// Pop the backstack
|
||||||
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
||||||
|
@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.combine
|
|||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
import org.matrix.android.sdk.api.failure.MatrixError
|
import org.matrix.android.sdk.api.failure.MatrixError
|
||||||
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
||||||
@ -202,11 +203,11 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
|
|||||||
views.loginSocialLoginContainer.isVisible = true
|
views.loginSocialLoginContainer.isVisible = true
|
||||||
views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
|
views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
|
||||||
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(provider: SsoIdentityProvider?) {
|
||||||
loginViewModel.getSsoUrl(
|
loginViewModel.getSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = id
|
providerId = provider?.id
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import com.airbnb.mvrx.withState
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.toReducedUrl
|
import im.vector.app.core.extensions.toReducedUrl
|
||||||
import im.vector.app.databinding.FragmentLoginSignupSigninSelectionBinding
|
import im.vector.app.databinding.FragmentLoginSignupSigninSelectionBinding
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,11 +75,11 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi
|
|||||||
views.loginSignupSigninSignInSocialLoginContainer.isVisible = true
|
views.loginSignupSigninSignInSocialLoginContainer.isVisible = true
|
||||||
views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders()?.sorted()
|
views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders()?.sorted()
|
||||||
views.loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
views.loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(provider: SsoIdentityProvider?) {
|
||||||
loginViewModel.getSsoUrl(
|
loginViewModel.getSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = id
|
providerId = provider?.id
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class SocialLoginButtonsView @JvmOverloads constructor(context: Context, attrs:
|
|||||||
LinearLayout(context, attrs, defStyle) {
|
LinearLayout(context, attrs, defStyle) {
|
||||||
|
|
||||||
fun interface InteractionListener {
|
fun interface InteractionListener {
|
||||||
fun onProviderSelected(id: String?)
|
fun onProviderSelected(provider: SsoIdentityProvider?)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
@ -113,7 +113,7 @@ class SocialLoginButtonsView @JvmOverloads constructor(context: Context, attrs:
|
|||||||
button.text = getButtonTitle(identityProvider.name)
|
button.text = getButtonTitle(identityProvider.name)
|
||||||
button.setTag(R.id.loginSignupSigninSocialLoginButtons, identityProvider.id)
|
button.setTag(R.id.loginSignupSigninSocialLoginButtons, identityProvider.id)
|
||||||
button.setOnClickListener {
|
button.setOnClickListener {
|
||||||
listener?.onProviderSelected(identityProvider.id)
|
listener?.onProviderSelected(identityProvider)
|
||||||
}
|
}
|
||||||
addView(button)
|
addView(button)
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ class SocialLoginButtonsView @JvmOverloads constructor(context: Context, attrs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SocialLoginButtonsView.render(ssoProviders: List<SsoIdentityProvider>?, mode: SocialLoginButtonsView.Mode, listener: (String?) -> Unit) {
|
fun SocialLoginButtonsView.render(ssoProviders: List<SsoIdentityProvider>?, mode: SocialLoginButtonsView.Mode, listener: (SsoIdentityProvider?) -> Unit) {
|
||||||
this.mode = mode
|
this.mode = mode
|
||||||
this.ssoIdentityProviders = ssoProviders?.sorted()
|
this.ssoIdentityProviders = ssoProviders?.sorted()
|
||||||
this.listener = SocialLoginButtonsView.InteractionListener { listener(it) }
|
this.listener = SocialLoginButtonsView.InteractionListener { listener(it) }
|
||||||
|
@ -35,6 +35,7 @@ import im.vector.app.features.login.SocialLoginButtonsView
|
|||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import reactivecircus.flowbinding.android.widget.textChanges
|
import reactivecircus.flowbinding.android.widget.textChanges
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -96,11 +97,11 @@ class LoginFragmentSignupUsername2 @Inject constructor() : AbstractSSOLoginFragm
|
|||||||
views.loginSocialLoginContainer.isVisible = true
|
views.loginSocialLoginContainer.isVisible = true
|
||||||
views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
|
views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
|
||||||
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(provider: SsoIdentityProvider?) {
|
||||||
loginViewModel.getSsoUrl(
|
loginViewModel.getSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = id
|
providerId = provider?.id
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.combine
|
|||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
import org.matrix.android.sdk.api.failure.MatrixError
|
import org.matrix.android.sdk.api.failure.MatrixError
|
||||||
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
||||||
@ -123,11 +124,11 @@ class LoginFragmentToAny2 @Inject constructor() : AbstractSSOLoginFragment2<Frag
|
|||||||
views.loginSocialLoginContainer.isVisible = true
|
views.loginSocialLoginContainer.isVisible = true
|
||||||
views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
|
views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
|
||||||
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(provider: SsoIdentityProvider?) {
|
||||||
loginViewModel.getSsoUrl(
|
loginViewModel.getSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = id
|
providerId = provider?.id
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import im.vector.app.features.onboarding.AuthenticationDescription.AuthenticationType
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
|
|
||||||
|
sealed interface AuthenticationDescription : Parcelable {
|
||||||
|
@Parcelize
|
||||||
|
object Login : AuthenticationDescription
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class Register(val type: AuthenticationType) : AuthenticationDescription
|
||||||
|
|
||||||
|
enum class AuthenticationType {
|
||||||
|
Password,
|
||||||
|
Apple,
|
||||||
|
Facebook,
|
||||||
|
GitHub,
|
||||||
|
GitLab,
|
||||||
|
Google,
|
||||||
|
SSO,
|
||||||
|
Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SsoIdentityProvider?.toAuthenticationType() = when (this?.brand) {
|
||||||
|
SsoIdentityProvider.BRAND_GOOGLE -> AuthenticationType.Google
|
||||||
|
SsoIdentityProvider.BRAND_GITHUB -> AuthenticationType.GitHub
|
||||||
|
SsoIdentityProvider.BRAND_APPLE -> AuthenticationType.Apple
|
||||||
|
SsoIdentityProvider.BRAND_FACEBOOK -> AuthenticationType.Facebook
|
||||||
|
SsoIdentityProvider.BRAND_GITLAB -> AuthenticationType.GitLab
|
||||||
|
SsoIdentityProvider.BRAND_TWITTER -> AuthenticationType.SSO
|
||||||
|
null -> AuthenticationType.SSO
|
||||||
|
else -> AuthenticationType.SSO
|
||||||
|
}
|
@ -276,7 +276,7 @@ class Login2Variant(
|
|||||||
is LoginViewEvents2.OnLoginModeNotSupported ->
|
is LoginViewEvents2.OnLoginModeNotSupported ->
|
||||||
onLoginModeNotSupported(event.supportedTypes)
|
onLoginModeNotSupported(event.supportedTypes)
|
||||||
is LoginViewEvents2.OnSessionCreated -> handleOnSessionCreated(event)
|
is LoginViewEvents2.OnSessionCreated -> handleOnSessionCreated(event)
|
||||||
is LoginViewEvents2.Finish -> terminate(true)
|
is LoginViewEvents2.Finish -> terminate()
|
||||||
is LoginViewEvents2.CancelRegistration -> handleCancelRegistration()
|
is LoginViewEvents2.CancelRegistration -> handleCancelRegistration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,14 +296,13 @@ class Login2Variant(
|
|||||||
option = commonOption
|
option = commonOption
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
terminate(false)
|
terminate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun terminate(newAccount: Boolean) {
|
private fun terminate() {
|
||||||
val intent = HomeActivity.newIntent(
|
val intent = HomeActivity.newIntent(
|
||||||
activity,
|
activity
|
||||||
accountCreation = newAccount
|
|
||||||
)
|
)
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
activity.finish()
|
activity.finish()
|
||||||
|
@ -54,6 +54,7 @@ import kotlinx.coroutines.launch
|
|||||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||||
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import org.matrix.android.sdk.api.auth.login.LoginWizard
|
import org.matrix.android.sdk.api.auth.login.LoginWizard
|
||||||
import org.matrix.android.sdk.api.auth.registration.FlowResult
|
import org.matrix.android.sdk.api.auth.registration.FlowResult
|
||||||
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
||||||
@ -255,7 +256,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val result = safeLoginWizard.loginWithToken(action.loginToken)
|
val result = safeLoginWizard.loginWithToken(action.loginToken)
|
||||||
onSessionCreated(result, isAccountCreated = false)
|
onSessionCreated(result, authenticationDescription = AuthenticationDescription.Login)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
setState { copy(isLoading = false) }
|
setState { copy(isLoading = false) }
|
||||||
_viewEvents.post(OnboardingViewEvents.Failure(failure))
|
_viewEvents.post(OnboardingViewEvents.Failure(failure))
|
||||||
@ -289,7 +290,11 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else -> when (it) {
|
else -> when (it) {
|
||||||
is RegistrationResult.Complete -> onSessionCreated(it.session, isAccountCreated = true)
|
is RegistrationResult.Complete -> onSessionCreated(
|
||||||
|
it.session,
|
||||||
|
authenticationDescription = awaitState().selectedAuthenticationState.description
|
||||||
|
?: AuthenticationDescription.Register(AuthenticationDescription.AuthenticationType.Other)
|
||||||
|
)
|
||||||
is RegistrationResult.NextStep -> onFlowResponse(it.flowResult, onNextRegistrationStepAction)
|
is RegistrationResult.NextStep -> onFlowResponse(it.flowResult, onNextRegistrationStepAction)
|
||||||
is RegistrationResult.SendEmailSuccess -> _viewEvents.post(OnboardingViewEvents.OnSendEmailSuccess(it.email))
|
is RegistrationResult.SendEmailSuccess -> _viewEvents.post(OnboardingViewEvents.OnSendEmailSuccess(it.email))
|
||||||
is RegistrationResult.Error -> _viewEvents.post(OnboardingViewEvents.Failure(it.cause))
|
is RegistrationResult.Error -> _viewEvents.post(OnboardingViewEvents.Failure(it.cause))
|
||||||
@ -319,6 +324,10 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
private fun OnboardingViewState.hasSelectedMatrixOrg() = selectedHomeserver.userFacingUrl == matrixOrgUrl
|
private fun OnboardingViewState.hasSelectedMatrixOrg() = selectedHomeserver.userFacingUrl == matrixOrgUrl
|
||||||
|
|
||||||
private fun handleRegisterWith(action: AuthenticateAction.Register) {
|
private fun handleRegisterWith(action: AuthenticateAction.Register) {
|
||||||
|
setState {
|
||||||
|
val authDescription = AuthenticationDescription.Register(AuthenticationDescription.AuthenticationType.Password)
|
||||||
|
copy(selectedAuthenticationState = SelectedAuthenticationState(authDescription))
|
||||||
|
}
|
||||||
reAuthHelper.data = action.password
|
reAuthHelper.data = action.password
|
||||||
handleRegisterAction(
|
handleRegisterAction(
|
||||||
RegisterAction.CreateAccount(
|
RegisterAction.CreateAccount(
|
||||||
@ -499,7 +508,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
setState { copy(isLoading = true) }
|
setState { copy(isLoading = true) }
|
||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launch {
|
||||||
directLoginUseCase.execute(action, homeServerConnectionConfig).fold(
|
directLoginUseCase.execute(action, homeServerConnectionConfig).fold(
|
||||||
onSuccess = { onSessionCreated(it, isAccountCreated = false) },
|
onSuccess = { onSessionCreated(it, authenticationDescription = AuthenticationDescription.Login) },
|
||||||
onFailure = {
|
onFailure = {
|
||||||
setState { copy(isLoading = false) }
|
setState { copy(isLoading = false) }
|
||||||
_viewEvents.post(OnboardingViewEvents.Failure(it))
|
_viewEvents.post(OnboardingViewEvents.Failure(it))
|
||||||
@ -524,7 +533,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
action.initialDeviceName
|
action.initialDeviceName
|
||||||
)
|
)
|
||||||
reAuthHelper.data = action.password
|
reAuthHelper.data = action.password
|
||||||
onSessionCreated(result, isAccountCreated = false)
|
onSessionCreated(result, authenticationDescription = AuthenticationDescription.Login)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
setState { copy(isLoading = false) }
|
setState { copy(isLoading = false) }
|
||||||
_viewEvents.post(OnboardingViewEvents.Failure(failure))
|
_viewEvents.post(OnboardingViewEvents.Failure(failure))
|
||||||
@ -553,7 +562,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
internalRegisterAction(RegisterAction.RegisterDummy, onNextRegistrationStepAction)
|
internalRegisterAction(RegisterAction.RegisterDummy, onNextRegistrationStepAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onSessionCreated(session: Session, isAccountCreated: Boolean) {
|
private suspend fun onSessionCreated(session: Session, authenticationDescription: AuthenticationDescription) {
|
||||||
val state = awaitState()
|
val state = awaitState()
|
||||||
state.useCase?.let { useCase ->
|
state.useCase?.let { useCase ->
|
||||||
session.vectorStore(applicationContext).setUseCase(useCase)
|
session.vectorStore(applicationContext).setUseCase(useCase)
|
||||||
@ -564,15 +573,15 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
authenticationService.reset()
|
authenticationService.reset()
|
||||||
session.configureAndStart(applicationContext)
|
session.configureAndStart(applicationContext)
|
||||||
|
|
||||||
when (isAccountCreated) {
|
when (authenticationDescription) {
|
||||||
true -> {
|
is AuthenticationDescription.Register -> {
|
||||||
val personalizationState = createPersonalizationState(session, state)
|
val personalizationState = createPersonalizationState(session, state)
|
||||||
setState {
|
setState {
|
||||||
copy(isLoading = false, personalizationState = personalizationState)
|
copy(isLoading = false, personalizationState = personalizationState)
|
||||||
}
|
}
|
||||||
_viewEvents.post(OnboardingViewEvents.OnAccountCreated)
|
_viewEvents.post(OnboardingViewEvents.OnAccountCreated)
|
||||||
}
|
}
|
||||||
false -> {
|
AuthenticationDescription.Login -> {
|
||||||
setState { copy(isLoading = false) }
|
setState { copy(isLoading = false) }
|
||||||
_viewEvents.post(OnboardingViewEvents.OnAccountSignedIn)
|
_viewEvents.post(OnboardingViewEvents.OnAccountSignedIn)
|
||||||
}
|
}
|
||||||
@ -603,7 +612,7 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val result = authenticationService.createSessionFromSso(homeServerConnectionConfigFinal, action.credentials)
|
val result = authenticationService.createSessionFromSso(homeServerConnectionConfigFinal, action.credentials)
|
||||||
onSessionCreated(result, isAccountCreated = false)
|
onSessionCreated(result, authenticationDescription = AuthenticationDescription.Login)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
setState { copy(isLoading = false) }
|
setState { copy(isLoading = false) }
|
||||||
}
|
}
|
||||||
@ -745,8 +754,12 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
return loginConfig?.homeServerUrl
|
return loginConfig?.homeServerUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSsoUrl(redirectUrl: String, deviceId: String?, providerId: String?): String? {
|
fun fetchSsoUrl(redirectUrl: String, deviceId: String?, provider: SsoIdentityProvider?): String? {
|
||||||
return authenticationService.getSsoUrl(redirectUrl, deviceId, providerId)
|
setState {
|
||||||
|
val authDescription = AuthenticationDescription.Register(provider.toAuthenticationType())
|
||||||
|
copy(selectedAuthenticationState = SelectedAuthenticationState(authDescription))
|
||||||
|
}
|
||||||
|
return authenticationService.getSsoUrl(redirectUrl, deviceId, provider?.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFallbackUrl(forSignIn: Boolean, deviceId: String?): String? {
|
fun getFallbackUrl(forSignIn: Boolean, deviceId: String?): String? {
|
||||||
|
@ -51,6 +51,9 @@ data class OnboardingViewState(
|
|||||||
@PersistState
|
@PersistState
|
||||||
val selectedHomeserver: SelectedHomeserverState = SelectedHomeserverState(),
|
val selectedHomeserver: SelectedHomeserverState = SelectedHomeserverState(),
|
||||||
|
|
||||||
|
@PersistState
|
||||||
|
val selectedAuthenticationState: SelectedAuthenticationState = SelectedAuthenticationState(),
|
||||||
|
|
||||||
@PersistState
|
@PersistState
|
||||||
val personalizationState: PersonalizationState = PersonalizationState()
|
val personalizationState: PersonalizationState = PersonalizationState()
|
||||||
) : MavericksState
|
) : MavericksState
|
||||||
@ -80,3 +83,8 @@ data class PersonalizationState(
|
|||||||
|
|
||||||
fun supportsPersonalization() = supportsChangingDisplayName || supportsChangingProfilePicture
|
fun supportsPersonalization() = supportsChangingDisplayName || supportsChangingProfilePicture
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class SelectedAuthenticationState(
|
||||||
|
val description: AuthenticationDescription? = null,
|
||||||
|
) : Parcelable
|
||||||
|
@ -90,10 +90,10 @@ abstract class AbstractSSOFtueAuthFragment<VB : ViewBinding> : AbstractFtueAuthF
|
|||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
if (state.selectedHomeserver.preferredLoginMode.hasSso() && state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders().isNullOrEmpty()) {
|
if (state.selectedHomeserver.preferredLoginMode.hasSso() && state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders().isNullOrEmpty()) {
|
||||||
// in this case we can prefetch (not other cases for privacy concerns)
|
// in this case we can prefetch (not other cases for privacy concerns)
|
||||||
viewModel.getSsoUrl(
|
viewModel.fetchSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = null
|
provider = null
|
||||||
)
|
)
|
||||||
?.let { prefetchUrl(it) }
|
?.let { prefetchUrl(it) }
|
||||||
}
|
}
|
||||||
|
@ -131,10 +131,10 @@ class FtueAuthCombinedLoginFragment @Inject constructor(
|
|||||||
views.ssoGroup.isVisible = ssoProviders?.isNotEmpty() == true
|
views.ssoGroup.isVisible = ssoProviders?.isNotEmpty() == true
|
||||||
views.ssoButtonsHeader.isVisible = views.ssoGroup.isVisible && views.loginEntryGroup.isVisible
|
views.ssoButtonsHeader.isVisible = views.ssoGroup.isVisible && views.loginEntryGroup.isVisible
|
||||||
views.ssoButtons.render(ssoProviders, SocialLoginButtonsView.Mode.MODE_CONTINUE) { id ->
|
views.ssoButtons.render(ssoProviders, SocialLoginButtonsView.Mode.MODE_CONTINUE) { id ->
|
||||||
viewModel.getSsoUrl(
|
viewModel.fetchSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
providerId = id
|
provider = id
|
||||||
)?.let { openInCustomTab(it) }
|
)?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,11 +164,11 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu
|
|||||||
|
|
||||||
private fun renderSsoProviders(deviceId: String?, ssoProviders: List<SsoIdentityProvider>?) {
|
private fun renderSsoProviders(deviceId: String?, ssoProviders: List<SsoIdentityProvider>?) {
|
||||||
views.ssoGroup.isVisible = ssoProviders?.isNotEmpty() == true
|
views.ssoGroup.isVisible = ssoProviders?.isNotEmpty() == true
|
||||||
views.ssoButtons.render(ssoProviders, SocialLoginButtonsView.Mode.MODE_CONTINUE) { id ->
|
views.ssoButtons.render(ssoProviders, SocialLoginButtonsView.Mode.MODE_CONTINUE) { provider ->
|
||||||
viewModel.getSsoUrl(
|
viewModel.fetchSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
providerId = id
|
provider = provider
|
||||||
)?.let { openInCustomTab(it) }
|
)?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ import kotlinx.coroutines.flow.combine
|
|||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
||||||
import org.matrix.android.sdk.api.failure.isInvalidUsername
|
import org.matrix.android.sdk.api.failure.isInvalidUsername
|
||||||
import org.matrix.android.sdk.api.failure.isLoginEmailUnknown
|
import org.matrix.android.sdk.api.failure.isLoginEmailUnknown
|
||||||
@ -216,11 +217,11 @@ class FtueAuthLoginFragment @Inject constructor() : AbstractSSOFtueAuthFragment<
|
|||||||
views.loginSocialLoginContainer.isVisible = true
|
views.loginSocialLoginContainer.isVisible = true
|
||||||
views.loginSocialLoginButtons.ssoIdentityProviders = state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders?.sorted()
|
views.loginSocialLoginButtons.ssoIdentityProviders = state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders?.sorted()
|
||||||
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(provider: SsoIdentityProvider?) {
|
||||||
viewModel.getSsoUrl(
|
viewModel.fetchSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = id
|
provider = provider
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import im.vector.app.features.login.SocialLoginButtonsView
|
|||||||
import im.vector.app.features.login.ssoIdentityProviders
|
import im.vector.app.features.login.ssoIdentityProviders
|
||||||
import im.vector.app.features.onboarding.OnboardingAction
|
import im.vector.app.features.onboarding.OnboardingAction
|
||||||
import im.vector.app.features.onboarding.OnboardingViewState
|
import im.vector.app.features.onboarding.OnboardingViewState
|
||||||
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,11 +82,11 @@ class FtueAuthSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOF
|
|||||||
views.loginSignupSigninSignInSocialLoginContainer.isVisible = true
|
views.loginSignupSigninSignInSocialLoginContainer.isVisible = true
|
||||||
views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders()?.sorted()
|
views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders()?.sorted()
|
||||||
views.loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
views.loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(provider: SsoIdentityProvider?) {
|
||||||
viewModel.getSsoUrl(
|
viewModel.fetchSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = id
|
provider = provider
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
}
|
}
|
||||||
@ -123,10 +124,10 @@ class FtueAuthSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOF
|
|||||||
|
|
||||||
private fun submit() = withState(viewModel) { state ->
|
private fun submit() = withState(viewModel) { state ->
|
||||||
if (state.selectedHomeserver.preferredLoginMode is LoginMode.Sso) {
|
if (state.selectedHomeserver.preferredLoginMode is LoginMode.Sso) {
|
||||||
viewModel.getSsoUrl(
|
viewModel.fetchSsoUrl(
|
||||||
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
|
||||||
deviceId = state.deviceId,
|
deviceId = state.deviceId,
|
||||||
providerId = null
|
provider = null
|
||||||
)
|
)
|
||||||
?.let { openInCustomTab(it) }
|
?.let { openInCustomTab(it) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -216,7 +216,7 @@ class FtueAuthVariant(
|
|||||||
is OnboardingViewEvents.OnAccountCreated -> onAccountCreated()
|
is OnboardingViewEvents.OnAccountCreated -> onAccountCreated()
|
||||||
OnboardingViewEvents.OnAccountSignedIn -> onAccountSignedIn()
|
OnboardingViewEvents.OnAccountSignedIn -> onAccountSignedIn()
|
||||||
OnboardingViewEvents.OnChooseDisplayName -> onChooseDisplayName()
|
OnboardingViewEvents.OnChooseDisplayName -> onChooseDisplayName()
|
||||||
OnboardingViewEvents.OnTakeMeHome -> navigateToHome(createdAccount = true)
|
OnboardingViewEvents.OnTakeMeHome -> navigateToHome()
|
||||||
OnboardingViewEvents.OnChooseProfilePicture -> onChooseProfilePicture()
|
OnboardingViewEvents.OnChooseProfilePicture -> onChooseProfilePicture()
|
||||||
OnboardingViewEvents.OnPersonalizationComplete -> onPersonalizationComplete()
|
OnboardingViewEvents.OnPersonalizationComplete -> onPersonalizationComplete()
|
||||||
OnboardingViewEvents.OnBack -> activity.popBackstack()
|
OnboardingViewEvents.OnBack -> activity.popBackstack()
|
||||||
@ -467,7 +467,7 @@ class FtueAuthVariant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onAccountSignedIn() {
|
private fun onAccountSignedIn() {
|
||||||
navigateToHome(createdAccount = false)
|
navigateToHome()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onAccountCreated() {
|
private fun onAccountCreated() {
|
||||||
@ -479,10 +479,12 @@ class FtueAuthVariant(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToHome(createdAccount: Boolean) {
|
private fun navigateToHome() {
|
||||||
val intent = HomeActivity.newIntent(activity, accountCreation = createdAccount)
|
withState(onboardingViewModel) {
|
||||||
activity.startActivity(intent)
|
val intent = HomeActivity.newIntent(activity, authenticationDescription = it.selectedAuthenticationState.description)
|
||||||
activity.finish()
|
activity.startActivity(intent)
|
||||||
|
activity.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onChooseDisplayName() {
|
private fun onChooseDisplayName() {
|
||||||
|
Loading…
Reference in New Issue
Block a user