Skip to content

Commit ba2f44d

Browse files
committed
Rename LoginHelper to AuthenticationHelper since it also handles account creation
Do the same for other `Login*` classes that handle both login and account creation
1 parent 04e9e4d commit ba2f44d

23 files changed

+181
-162
lines changed

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginHelper.kt renamed to features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/AuthenticationHelper.kt

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,37 @@ import io.element.android.libraries.oidc.api.OidcAction
3030
import io.element.android.libraries.oidc.api.OidcActionFlow
3131

3232
/**
33-
* This class is responsible for managing the login flow, including handling OIDC actions and
33+
* This class is responsible for managing the login and account creation flows, including handling OIDC actions and
3434
* submitting login requests.
3535
* It's a helper to avoid code duplication. It is used by [OnBoardingPresenter], [ConfirmAccountProviderPresenter]
3636
* and [ChooseAccountProviderPresenter].
3737
*/
3838
@SingleIn(AuthScope::class)
3939
@Inject
40-
class LoginHelper(
40+
class AuthenticationHelper(
4141
private val oidcActionFlow: OidcActionFlow,
4242
private val authenticationService: MatrixAuthenticationService,
4343
private val webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever,
4444
) {
45-
private val loginModeState: MutableState<AsyncData<LoginMode>> = mutableStateOf(AsyncData.Uninitialized)
45+
private val authenticationModeState: MutableState<AsyncData<AuthenticationMode>> = mutableStateOf(AsyncData.Uninitialized)
4646

4747
// To remember if the current flow is account creation or login
4848
private var isAccountCreation: Boolean = false
4949

5050
@Composable
51-
fun collectLoginMode(): State<AsyncData<LoginMode>> {
51+
fun collectAuthenticationMode(): State<AsyncData<AuthenticationMode>> {
5252
LaunchedEffect(Unit) {
5353
oidcActionFlow.collect { oidcAction ->
5454
if (oidcAction != null) {
5555
onOidcAction(oidcAction)
5656
}
5757
}
5858
}
59-
return loginModeState
59+
return authenticationModeState
6060
}
6161

6262
fun clearError() {
63-
loginModeState.value = AsyncData.Uninitialized
63+
authenticationModeState.value = AsyncData.Uninitialized
6464
}
6565

6666
suspend fun submit(
@@ -70,27 +70,27 @@ class LoginHelper(
7070
) {
7171
this.isAccountCreation = isAccountCreation
7272

73-
loginModeState.value = AsyncData.Loading()
73+
authenticationModeState.value = AsyncData.Loading()
7474
suspend {
7575
authenticationService.setHomeserver(homeserverUrl).map { matrixHomeServerDetails ->
7676
if (matrixHomeServerDetails.supportsOidcLogin) {
7777
// Retrieve the details right now
7878
val oidcPrompt = if (isAccountCreation) OidcPrompt.Create else OidcPrompt.Login
79-
LoginMode.Oidc(
79+
AuthenticationMode.Oidc(
8080
authenticationService.getOidcUrl(prompt = oidcPrompt, loginHint = loginHint).getOrThrow(),
8181
isAccountCreation,
8282
)
8383
} else if (isAccountCreation) {
8484
val url = webClientUrlForAuthenticationRetriever.retrieve(homeserverUrl)
85-
LoginMode.AccountCreation(url)
85+
AuthenticationMode.AccountCreation(url)
8686
} else if (matrixHomeServerDetails.supportsPasswordLogin) {
87-
LoginMode.PasswordLogin
87+
AuthenticationMode.PasswordLogin
8888
} else {
8989
error("Unsupported login flow")
9090
}
9191
}.getOrThrow()
9292
}.runCatchingUpdatingState(
93-
loginModeState,
93+
authenticationModeState,
9494
errorTransform = { exception ->
9595
when (exception) {
9696
is AccountCreationNotSupported -> exception
@@ -101,26 +101,26 @@ class LoginHelper(
101101
}
102102

103103
private suspend fun onOidcAction(oidcAction: OidcAction) {
104-
if (oidcAction is OidcAction.GoBack && oidcAction.toUnblock && loginModeState.value !is AsyncData.Loading) {
104+
if (oidcAction is OidcAction.GoBack && oidcAction.toUnblock && authenticationModeState.value !is AsyncData.Loading) {
105105
// Ignore GoBack action if the current state is not Loading. This GoBack action is coming from LoginFlowNode.
106106
// This can happen if there is an error, for instance attempt to login again on the same account.
107107
return
108108
}
109-
loginModeState.value = AsyncData.Loading()
109+
authenticationModeState.value = AsyncData.Loading()
110110
when (oidcAction) {
111111
is OidcAction.GoBack -> {
112112
authenticationService.cancelOidcLogin()
113113
.onSuccess {
114-
loginModeState.value = AsyncData.Uninitialized
114+
authenticationModeState.value = AsyncData.Uninitialized
115115
}
116116
.onFailure { failure ->
117-
loginModeState.value = AsyncData.Failure(failure)
117+
authenticationModeState.value = AsyncData.Failure(failure)
118118
}
119119
}
120120
is OidcAction.Success -> {
121121
authenticationService.loginWithOidc(callbackUrl = oidcAction.url, isAccountCreation = this.isAccountCreation)
122122
.onFailure { failure ->
123-
loginModeState.value = AsyncData.Failure(failure)
123+
authenticationModeState.value = AsyncData.Failure(failure)
124124
}
125125
}
126126
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2025 Element Creations Ltd.
3+
* Copyright 2025 New Vector Ltd.
4+
*
5+
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
6+
* Please see LICENSE files in the repository root for full details.
7+
*/
8+
9+
package io.element.android.features.login.impl.login
10+
11+
import io.element.android.libraries.matrix.api.auth.OidcDetails
12+
13+
/**
14+
* Represents the different authentication modes available.
15+
*/
16+
sealed interface AuthenticationMode {
17+
/**
18+
* Password-based login mode. Added for backwards compatibility.
19+
*/
20+
data object PasswordLogin : AuthenticationMode
21+
22+
/**
23+
* Account creation mode, using a non-OIDC web flow. It's the registration counterpart to [PasswordLogin].
24+
*/
25+
data class AccountCreation(val url: String) : AuthenticationMode
26+
27+
/**
28+
* OIDC-based authentication mode.
29+
* @param oidcDetails Details required for OIDC authentication.
30+
* @param isAccountCreation Whether this mode is for account creation or login.
31+
*/
32+
data class Oidc(val oidcDetails: OidcDetails, val isAccountCreation: Boolean) : AuthenticationMode
33+
}

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginModeView.kt renamed to features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/AuthenticationModeView.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,18 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails
2828
import io.element.android.libraries.ui.strings.CommonStrings
2929

3030
@Composable
31-
fun LoginModeView(
32-
loginMode: AsyncData<LoginMode>,
31+
fun AuthenticationModeView(
32+
authenticationMode: AsyncData<AuthenticationMode>,
3333
onClearError: () -> Unit,
3434
onLearnMoreClick: () -> Unit,
3535
onOidcDetails: (OidcDetails) -> Unit,
3636
onNeedLoginPassword: () -> Unit,
3737
onCreateAccountContinue: (url: String) -> Unit
3838
) {
3939
val context = LocalContext.current
40-
when (loginMode) {
40+
when (authenticationMode) {
4141
is AsyncData.Failure -> {
42-
when (val error = loginMode.error) {
42+
when (val error = authenticationMode.error) {
4343
is ChangeServerError -> {
4444
when (error) {
4545
ChangeServerError.InvalidServer ->
@@ -117,10 +117,10 @@ fun LoginModeView(
117117
}
118118
is AsyncData.Loading -> Unit // The Continue button shows the loading state
119119
is AsyncData.Success -> {
120-
when (val loginModeData = loginMode.data) {
121-
is LoginMode.Oidc -> onOidcDetails(loginModeData.oidcDetails)
122-
LoginMode.PasswordLogin -> onNeedLoginPassword()
123-
is LoginMode.AccountCreation -> onCreateAccountContinue(loginModeData.url)
120+
when (val loginModeData = authenticationMode.data) {
121+
is AuthenticationMode.Oidc -> onOidcDetails(loginModeData.oidcDetails)
122+
AuthenticationMode.PasswordLogin -> onNeedLoginPassword()
123+
is AuthenticationMode.AccountCreation -> onCreateAccountContinue(loginModeData.url)
124124
}
125125
// Also clear the data, to let the next screen be able to go back
126126
onClearError()
@@ -131,10 +131,10 @@ fun LoginModeView(
131131

132132
@PreviewsDayNight
133133
@Composable
134-
internal fun LoginModeViewPreview(@PreviewParameter(LoginModeViewErrorProvider::class) error: Throwable) {
134+
internal fun AuthenticationModeViewPreview(@PreviewParameter(LoginModeViewErrorProvider::class) error: Throwable) {
135135
ElementPreview {
136-
LoginModeView(
137-
loginMode = AsyncData.Failure(error),
136+
AuthenticationModeView(
137+
authenticationMode = AsyncData.Failure(error),
138138
onClearError = {},
139139
onLearnMoreClick = {},
140140
onOidcDetails = {},

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginMode.kt

Lines changed: 0 additions & 17 deletions
This file was deleted.

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import io.element.android.appconfig.AuthenticationConfig
1919
import io.element.android.features.enterprise.api.EnterpriseService
2020
import io.element.android.features.login.impl.accountprovider.AccountProvider
2121
import io.element.android.features.login.impl.di.AuthScope
22-
import io.element.android.features.login.impl.login.LoginHelper
22+
import io.element.android.features.login.impl.login.AuthenticationHelper
2323
import io.element.android.libraries.architecture.AsyncData
2424
import io.element.android.libraries.architecture.Presenter
2525
import io.element.android.libraries.core.uri.ensureProtocol
@@ -29,20 +29,20 @@ import kotlinx.coroutines.launch
2929
@ContributesBinding(AuthScope::class)
3030
class ChooseAccountProviderPresenter(
3131
private val enterpriseService: EnterpriseService,
32-
private val loginHelper: LoginHelper,
32+
private val authenticationHelper: AuthenticationHelper,
3333
) : Presenter<ChooseAccountProviderState> {
3434
@Composable
3535
override fun present(): ChooseAccountProviderState {
3636
val localCoroutineScope = rememberCoroutineScope()
37-
val loginMode by loginHelper.collectLoginMode()
37+
val loginMode by authenticationHelper.collectAuthenticationMode()
3838

3939
var selectedAccountProvider: AccountProvider? by remember { mutableStateOf(null) }
4040

4141
fun handleEvent(event: ChooseAccountProviderEvents) {
4242
when (event) {
4343
ChooseAccountProviderEvents.Continue -> localCoroutineScope.launch {
4444
selectedAccountProvider?.let {
45-
loginHelper.submit(
45+
authenticationHelper.submit(
4646
isAccountCreation = false,
4747
homeserverUrl = it.url,
4848
loginHint = null,
@@ -55,7 +55,7 @@ class ChooseAccountProviderPresenter(
5555
selectedAccountProvider = event.accountProvider
5656
}
5757
}
58-
ChooseAccountProviderEvents.ClearError -> loginHelper.clearError()
58+
ChooseAccountProviderEvents.ClearError -> authenticationHelper.clearError()
5959
}
6060
}
6161

@@ -77,7 +77,7 @@ class ChooseAccountProviderPresenter(
7777
return ChooseAccountProviderState(
7878
accountProviders = staticAccountProviderList,
7979
selectedAccountProvider = selectedAccountProvider,
80-
loginMode = loginMode,
80+
authenticationMode = loginMode,
8181
eventSink = ::handleEvent,
8282
)
8383
}

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
package io.element.android.features.login.impl.screens.chooseaccountprovider
1010

1111
import io.element.android.features.login.impl.accountprovider.AccountProvider
12-
import io.element.android.features.login.impl.login.LoginMode
12+
import io.element.android.features.login.impl.login.AuthenticationMode
1313
import io.element.android.libraries.architecture.AsyncData
1414
import kotlinx.collections.immutable.ImmutableList
1515

1616
data class ChooseAccountProviderState(
1717
val accountProviders: ImmutableList<AccountProvider>,
1818
val selectedAccountProvider: AccountProvider?,
19-
val loginMode: AsyncData<LoginMode>,
19+
val authenticationMode: AsyncData<AuthenticationMode>,
2020
val eventSink: (ChooseAccountProviderEvents) -> Unit,
2121
) {
2222
val submitEnabled: Boolean
23-
get() = selectedAccountProvider != null && (loginMode is AsyncData.Uninitialized || loginMode is AsyncData.Loading)
23+
get() = selectedAccountProvider != null && (authenticationMode is AsyncData.Uninitialized || authenticationMode is AsyncData.Loading)
2424
}

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateProvider.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider
1111
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
1212
import io.element.android.features.login.impl.accountprovider.AccountProvider
1313
import io.element.android.features.login.impl.accountprovider.anAccountProvider
14-
import io.element.android.features.login.impl.login.LoginMode
14+
import io.element.android.features.login.impl.login.AuthenticationMode
1515
import io.element.android.libraries.architecture.AsyncData
1616
import kotlinx.collections.immutable.toImmutableList
1717

@@ -58,7 +58,7 @@ open class ChooseAccountProviderStateProvider : PreviewParameterProvider<ChooseA
5858
server3,
5959
),
6060
selectedAccountProvider = server2,
61-
loginMode = AsyncData.Loading(),
61+
authenticationMode = AsyncData.Loading(),
6262
),
6363
// Add other state here
6464
)
@@ -69,11 +69,11 @@ fun aChooseAccountProviderState(
6969
anAccountProvider()
7070
),
7171
selectedAccountProvider: AccountProvider? = null,
72-
loginMode: AsyncData<LoginMode> = AsyncData.Uninitialized,
72+
authenticationMode: AsyncData<AuthenticationMode> = AsyncData.Uninitialized,
7373
eventSink: (ChooseAccountProviderEvents) -> Unit = {},
7474
) = ChooseAccountProviderState(
7575
accountProviders = accountProviders.toImmutableList(),
7676
selectedAccountProvider = selectedAccountProvider,
77-
loginMode = loginMode,
77+
authenticationMode = authenticationMode,
7878
eventSink = eventSink,
7979
)

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderView.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import androidx.compose.ui.unit.dp
3333
import io.element.android.compound.tokens.generated.CompoundIcons
3434
import io.element.android.features.login.impl.R
3535
import io.element.android.features.login.impl.accountprovider.AccountProviderView
36-
import io.element.android.features.login.impl.login.LoginModeView
36+
import io.element.android.features.login.impl.login.AuthenticationModeView
3737
import io.element.android.libraries.architecture.AsyncData
3838
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
3939
import io.element.android.libraries.designsystem.components.BigIcon
@@ -56,9 +56,9 @@ fun ChooseAccountProviderView(
5656
onCreateAccountContinue: (url: String) -> Unit,
5757
modifier: Modifier = Modifier,
5858
) {
59-
val isLoading by remember(state.loginMode) {
59+
val isLoading by remember(state.authenticationMode) {
6060
derivedStateOf {
61-
state.loginMode is AsyncData.Loading
61+
state.authenticationMode is AsyncData.Loading
6262
}
6363
}
6464

@@ -123,8 +123,8 @@ fun ChooseAccountProviderView(
123123
)
124124
Spacer(modifier = Modifier.height(48.dp))
125125
}
126-
LoginModeView(
127-
loginMode = state.loginMode,
126+
AuthenticationModeView(
127+
authenticationMode = state.authenticationMode,
128128
onClearError = {
129129
state.eventSink(ChooseAccountProviderEvents.ClearError)
130130
},

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import dev.zacsweers.metro.AssistedInject
1818
import dev.zacsweers.metro.ContributesBinding
1919
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
2020
import io.element.android.features.login.impl.di.AuthScope
21-
import io.element.android.features.login.impl.login.LoginHelper
21+
import io.element.android.features.login.impl.login.AuthenticationHelper
2222
import io.element.android.features.login.impl.screens.confirmaccountprovider.ConfirmAccountProviderPresenter.Params
2323
import io.element.android.libraries.architecture.Presenter
2424
import kotlinx.coroutines.launch
@@ -27,7 +27,7 @@ import kotlinx.coroutines.launch
2727
class ConfirmAccountProviderPresenter(
2828
@Assisted private val params: Params,
2929
private val accountProviderDataSource: AccountProviderDataSource,
30-
private val loginHelper: LoginHelper,
30+
private val authenticationHelper: AuthenticationHelper,
3131
) : Presenter<ConfirmAccountProviderState> {
3232
data class Params(
3333
val isAccountCreation: Boolean,
@@ -44,25 +44,25 @@ class ConfirmAccountProviderPresenter(
4444
val accountProvider by accountProviderDataSource.flow.collectAsState()
4545
val localCoroutineScope = rememberCoroutineScope()
4646

47-
val loginMode by loginHelper.collectLoginMode()
47+
val loginMode by authenticationHelper.collectAuthenticationMode()
4848

4949
fun handleEvent(event: ConfirmAccountProviderEvents) {
5050
when (event) {
5151
ConfirmAccountProviderEvents.Continue -> localCoroutineScope.launch {
52-
loginHelper.submit(
52+
authenticationHelper.submit(
5353
isAccountCreation = params.isAccountCreation,
5454
homeserverUrl = accountProvider.url,
5555
loginHint = null,
5656
)
5757
}
58-
ConfirmAccountProviderEvents.ClearError -> loginHelper.clearError()
58+
ConfirmAccountProviderEvents.ClearError -> authenticationHelper.clearError()
5959
}
6060
}
6161

6262
return ConfirmAccountProviderState(
6363
accountProvider = accountProvider,
6464
isAccountCreation = params.isAccountCreation,
65-
loginMode = loginMode,
65+
authenticationMode = loginMode,
6666
eventSink = ::handleEvent,
6767
)
6868
}

0 commit comments

Comments
 (0)