providing the full SSOProvider instead of selection instead of just the id

This commit is contained in:
Adam Brown 2022-05-10 19:59:40 +01:00
parent 9110fe8a6a
commit e89f9eae1a
10 changed files with 84 additions and 26 deletions

View File

@ -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) }
} }

View File

@ -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) }
} }

View File

@ -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) }

View File

@ -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) }
} }

View File

@ -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) }
} }

View File

@ -0,0 +1,47 @@
/*
* 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 im.vector.app.features.onboarding.AuthenticationDescription.AuthenticationType
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
sealed interface AuthenticationDescription {
object Login : AuthenticationDescription
data class AccountCreated(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
}

View File

@ -255,7 +255,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 +289,12 @@ 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 = AuthenticationDescription.AccountCreated(
AuthenticationDescription.AuthenticationType.Password
)
)
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))
@ -499,7 +504,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 +529,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 +558,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 +569,15 @@ class OnboardingViewModel @AssistedInject constructor(
authenticationService.reset() authenticationService.reset()
session.configureAndStart(applicationContext) session.configureAndStart(applicationContext)
when (isAccountCreated) { when (authenticationDescription) {
true -> { is AuthenticationDescription.AccountCreated -> {
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 +608,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) }
} }

View File

@ -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.getSsoUrl(
redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL, redirectUrl = SSORedirectRouterActivity.VECTOR_REDIRECT_URL,
deviceId = deviceId, deviceId = deviceId,
providerId = id providerId = provider?.id
)?.let { openInCustomTab(it) } )?.let { openInCustomTab(it) }
} }
} }

View File

@ -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.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) }
} }

View File

@ -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.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) }
} }