mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
Merge pull request #7918 from element-hq/feature/bma/iterateOnAddAccountUi
Add a back button to the server screen and iterate on the identity confirmation screen
This commit is contained in:
+2
-1
@@ -46,11 +46,12 @@ class ChooseSelfVerificationModeStatePreviewParam :
|
||||
fun aChooseSelfVerificationModeState(
|
||||
buttonsState: AsyncData<ChooseSelfVerificationModeState.ButtonsState> = AsyncData.Success(aButtonsState()),
|
||||
currentUser: MatrixUser = aMatrixUser(),
|
||||
eventSink: (ChooseSelfVerificationModeEvent) -> Unit = {},
|
||||
) = ChooseSelfVerificationModeState(
|
||||
currentUser = currentUser,
|
||||
buttonsState = buttonsState,
|
||||
directLogoutState = aDirectLogoutState(),
|
||||
eventSink = {},
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
fun aButtonsState(
|
||||
|
||||
+6
-1
@@ -36,6 +36,7 @@ import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.IconSource
|
||||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||
@@ -45,6 +46,9 @@ import io.element.android.libraries.matrix.ui.components.accountinfo.AccountInfo
|
||||
import io.element.android.libraries.matrix.ui.components.accountinfo.AccountInfoCardState
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
/**
|
||||
* Ref: https://www.figma.com/design/kEAcfun9iSpszeUDvdKZ6b/ER-351--Multi-account-in-EX?node-id=432-31813
|
||||
*/
|
||||
@Composable
|
||||
fun ChooseSelfVerificationModeView(
|
||||
state: ChooseSelfVerificationModeState,
|
||||
@@ -65,7 +69,7 @@ fun ChooseSelfVerificationModeView(
|
||||
title = {},
|
||||
actions = {
|
||||
TextButton(
|
||||
text = stringResource(CommonStrings.action_signout),
|
||||
text = stringResource(R.string.screen_identity_confirmation_sign_out),
|
||||
onClick = { state.eventSink(ChooseSelfVerificationModeEvent.SignOut) }
|
||||
)
|
||||
}
|
||||
@@ -141,6 +145,7 @@ private fun ChooseSelfVerificationModeButtons(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_identity_use_another_device),
|
||||
onClick = onUseAnotherDevice,
|
||||
leadingIcon = IconSource.Vector(CompoundIcons.Devices()),
|
||||
)
|
||||
}
|
||||
if (state.buttonsState.data.canUseRecoveryKey) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_identity_confirmation_cannot_confirm">"Can\'t confirm?"</string>
|
||||
<string name="screen_identity_confirmation_create_new_recovery_key">"Create a new recovery key"</string>
|
||||
<string name="screen_identity_confirmation_sign_out">"Sign out"</string>
|
||||
<string name="screen_identity_confirmation_subtitle">"Choose how to verify to set up secure messaging."</string>
|
||||
<string name="screen_identity_confirmation_title">"Confirm your digital identity"</string>
|
||||
<string name="screen_identity_confirmation_use_another_device">"Use another device"</string>
|
||||
|
||||
+11
@@ -18,6 +18,7 @@ import io.element.android.features.ftue.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.ensureCalledOnce
|
||||
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||
@@ -73,6 +74,16 @@ class ChooseSessionVerificationModeViewTest : RobolectricTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on sign out emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ChooseSelfVerificationModeEvent>()
|
||||
setChooseSelfVerificationModeView(
|
||||
aChooseSelfVerificationModeState(eventSink = eventsRecorder),
|
||||
)
|
||||
clickOn(R.string.screen_identity_confirmation_sign_out)
|
||||
eventsRecorder.assertSingle(ChooseSelfVerificationModeEvent.SignOut)
|
||||
}
|
||||
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setChooseSelfVerificationModeView(
|
||||
state: ChooseSelfVerificationModeState,
|
||||
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
||||
|
||||
+1
@@ -56,6 +56,7 @@ class ConfirmAccountProviderNode(
|
||||
ConfirmAccountProviderView(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
onBackClick = ::navigateUp,
|
||||
onOAuthDetails = callback::navigateToOAuth,
|
||||
onNeedLoginPassword = callback::navigateToLoginPassword,
|
||||
onLearnMoreClick = { openLearnMorePage(context) },
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ open class ConfirmAccountProviderStatePreviewParam : PreviewParameterProvider<Co
|
||||
)
|
||||
}
|
||||
|
||||
private fun aConfirmAccountProviderState(
|
||||
internal fun aConfirmAccountProviderState(
|
||||
accountProviderInput: String = "matrix.org",
|
||||
accountProviderSuggestion: String? = null,
|
||||
isAccountCreation: Boolean = false,
|
||||
|
||||
+12
-1
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -50,12 +51,14 @@ import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMo
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||
import io.element.android.libraries.permissions.api.localnetwork.LocalNetworkPermissionDialogView
|
||||
import io.element.android.libraries.testtags.TestTags
|
||||
@@ -71,6 +74,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||
@Composable
|
||||
fun ConfirmAccountProviderView(
|
||||
state: ConfirmAccountProviderState,
|
||||
onBackClick: () -> Unit,
|
||||
onOAuthDetails: (OAuthDetails) -> Unit,
|
||||
onNeedLoginPassword: () -> Unit,
|
||||
onLearnMoreClick: () -> Unit,
|
||||
@@ -118,9 +122,15 @@ fun ConfirmAccountProviderView(
|
||||
// Let the header and content scroll so the supporting text is not clipped by the footer when the
|
||||
// keyboard is visible and vertical space is reduced.
|
||||
isScrollable = true,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {},
|
||||
navigationIcon = { BackButton(onClick = onBackClick) },
|
||||
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
|
||||
)
|
||||
},
|
||||
header = {
|
||||
IconTitleSubtitleMolecule(
|
||||
modifier = Modifier.padding(top = 60.dp),
|
||||
iconStyle = BigIcon.Style.Default(CompoundIcons.UserProfileSolid()),
|
||||
title = stringResource(
|
||||
id = if (state.isAccountCreation) {
|
||||
@@ -272,6 +282,7 @@ internal fun ConfirmAccountProviderViewPreview(
|
||||
) = ElementPreview {
|
||||
ConfirmAccountProviderView(
|
||||
state = state,
|
||||
onBackClick = {},
|
||||
onOAuthDetails = {},
|
||||
onNeedLoginPassword = {},
|
||||
onLearnMoreClick = {},
|
||||
|
||||
+6
-2
@@ -180,6 +180,9 @@ private fun AddFirstAccountScaffold(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ref: https://www.figma.com/design/kEAcfun9iSpszeUDvdKZ6b/ER-351--Multi-account-in-EX?node-id=147-34607
|
||||
*/
|
||||
@Composable
|
||||
private fun AddOtherAccountScaffold(
|
||||
loginView: @Composable () -> Unit,
|
||||
@@ -189,8 +192,9 @@ private fun AddOtherAccountScaffold(
|
||||
) {
|
||||
FlowStepPage(
|
||||
modifier = modifier,
|
||||
title = stringResource(CommonStrings.common_add_account),
|
||||
iconStyle = BigIcon.Style.Default(CompoundIcons.HomeSolid()),
|
||||
title = stringResource(R.string.screen_onboarding_add_account_title),
|
||||
subTitle = stringResource(R.string.screen_onboarding_add_account_subtitle),
|
||||
iconStyle = BigIcon.Style.Default(CompoundIcons.Plus()),
|
||||
buttons = { buttons() },
|
||||
content = loginView,
|
||||
onBackClick = onBackClick,
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
<string name="screen_missing_key_backup_step_4">"Follow the instructions to enable your key storage"</string>
|
||||
<string name="screen_missing_key_backup_step_5">"Come back to %1$s"</string>
|
||||
<string name="screen_missing_key_backup_title">"Enable your key storage before proceeding to %1$s"</string>
|
||||
<string name="screen_onboarding_add_account_subtitle">"You can add multiple accounts to the app and switch between them easily."</string>
|
||||
<string name="screen_onboarding_add_account_title">"Sign in to another account"</string>
|
||||
<string name="screen_onboarding_app_version">"Version %1$s"</string>
|
||||
<string name="screen_onboarding_checking_account">"Checking account"</string>
|
||||
<string name="screen_onboarding_sign_in_manually">"Sign in manually"</string>
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.login.impl.screens.confirmaccountprovider
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||
import io.element.android.libraries.matrix.api.auth.OAuthDetails
|
||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.ensureCalledOnce
|
||||
import io.element.android.tests.testutils.pressBack
|
||||
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||
import org.junit.Test
|
||||
|
||||
class ConfirmAccountProviderViewTest : RobolectricTest() {
|
||||
@Test
|
||||
fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest {
|
||||
val eventSink = EventsRecorder<ConfirmAccountProviderEvent>(expectEvents = false)
|
||||
ensureCalledOnce {
|
||||
setConfirmAccountProviderView(
|
||||
state = aConfirmAccountProviderState(
|
||||
eventSink = eventSink,
|
||||
),
|
||||
onBackClick = it,
|
||||
)
|
||||
pressBack()
|
||||
}
|
||||
}
|
||||
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setConfirmAccountProviderView(
|
||||
state: ConfirmAccountProviderState,
|
||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||
onOAuthDetails: (OAuthDetails) -> Unit = EnsureNeverCalledWithParam(),
|
||||
onNeedLoginPassword: () -> Unit = EnsureNeverCalled(),
|
||||
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
||||
) {
|
||||
setContent {
|
||||
ConfirmAccountProviderView(
|
||||
state = state,
|
||||
onBackClick = onBackClick,
|
||||
onOAuthDetails = onOAuthDetails,
|
||||
onNeedLoginPassword = onNeedLoginPassword,
|
||||
onLearnMoreClick = onLearnMoreClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_identity_confirmation_cannot_confirm">"Can\'t confirm?"</string>
|
||||
<string name="screen_identity_confirmation_create_new_recovery_key">"Create a new recovery key"</string>
|
||||
<string name="screen_identity_confirmation_sign_out">"Sign out"</string>
|
||||
<string name="screen_identity_confirmation_subtitle">"Choose how to verify to set up secure messaging."</string>
|
||||
<string name="screen_identity_confirmation_title">"Confirm your digital identity"</string>
|
||||
<string name="screen_identity_confirmation_use_another_device">"Use another device"</string>
|
||||
|
||||
Reference in New Issue
Block a user