Improve welcome bottom sheet UI in regV5.

This commit is contained in:
Greyson Parrelli
2026-03-10 16:32:32 -04:00
committed by jeffrey-signal
parent 5d92fb1cc4
commit cd24691130
6 changed files with 108 additions and 52 deletions

View File

@@ -179,21 +179,6 @@ interface NetworkController {
*/
suspend fun setAccountAttributes(attributes: AccountAttributes): RegistrationNetworkResult<Unit, SetAccountAttributesError>
// TODO
// /**
// * Validates the provided SVR2 auth credentials, returning information on their usability.
// *
// * `POST /v2/svr/auth/check`
// */
// suspend fun validateSvr2AuthCredential(e164: String, usernamePasswords: List<String>)
//
// /**
// * Validates the provided SVR3 auth credentials, returning information on their usability.
// *
// * `POST /v3/backup/auth/check`
// */
// suspend fun validateSvr3AuthCredential(e164: String, usernamePasswords: List<String>)
//
// /**
// * Set [RestoreMethod] enum on the server for use by the old device to update UX.
// */

View File

@@ -67,7 +67,7 @@ sealed interface RegistrationRoute : NavKey, Parcelable {
data object Welcome : RegistrationRoute
@Serializable
data class Permissions(val forRestore: Boolean = false) : RegistrationRoute
data class Permissions(val nextRoute: RegistrationRoute) : RegistrationRoute
@Serializable
data object PhoneNumberEntry : RegistrationRoute
@@ -100,10 +100,13 @@ sealed interface RegistrationRoute : NavKey, Parcelable {
data object PinCreate : RegistrationRoute
@Serializable
data object Restore : RegistrationRoute
data object ChooseRestoreOptionBeforeRegistration : RegistrationRoute
@Serializable
data object RestoreViaQr : RegistrationRoute
data object ChooseRestoreOptionAfterRegistration : RegistrationRoute
@Serializable
data object QuickRestoreQrScan : RegistrationRoute
@Serializable
data object Transfer : RegistrationRoute
@@ -203,9 +206,9 @@ private fun EntryProviderScope<NavKey>.navigationEntries(
WelcomeScreen(
onEvent = { event ->
when (event) {
WelcomeScreenEvents.Continue -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(forRestore = false))
WelcomeScreenEvents.DoesNotHaveOldPhone -> parentEventEmitter.navigateTo(RegistrationRoute.Restore)
WelcomeScreenEvents.HasOldPhone -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(forRestore = true))
WelcomeScreenEvents.Continue -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(nextRoute = RegistrationRoute.PhoneNumberEntry))
WelcomeScreenEvents.HasOldPhone -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(nextRoute = RegistrationRoute.QuickRestoreQrScan))
WelcomeScreenEvents.DoesNotHaveOldPhone -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(nextRoute = RegistrationRoute.ChooseRestoreOptionBeforeRegistration))
}
}
)
@@ -216,11 +219,7 @@ private fun EntryProviderScope<NavKey>.navigationEntries(
PermissionsScreen(
permissionsState = permissionsState,
onProceed = {
if (key.forRestore) {
parentEventEmitter.navigateTo(RegistrationRoute.RestoreViaQr)
} else {
parentEventEmitter.navigateTo(RegistrationRoute.PhoneNumberEntry)
}
parentEventEmitter.navigateTo(key.nextRoute)
}
)
}
@@ -399,11 +398,11 @@ private fun EntryProviderScope<NavKey>.navigationEntries(
)
}
entry<RegistrationRoute.Restore> {
entry<RegistrationRoute.ChooseRestoreOptionAfterRegistration> {
// TODO: Implement RestoreScreen
}
entry<RegistrationRoute.RestoreViaQr> {
entry<RegistrationRoute.QuickRestoreQrScan> {
RestoreViaQrScreen(
state = RestoreViaQrState(),
onEvent = { event ->

View File

@@ -8,14 +8,20 @@
package org.signal.registration.screens.welcome
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SheetState
import androidx.compose.material3.Text
@@ -29,6 +35,8 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
@@ -40,7 +48,9 @@ import org.signal.core.ui.compose.BottomSheets
import org.signal.core.ui.compose.Buttons
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.SignalIcons
import org.signal.core.ui.compose.dismissWithAnimation
import org.signal.core.ui.compose.horizontalGutters
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.registration.R
import org.signal.registration.test.TestTags
@@ -169,40 +179,79 @@ private fun RestoreOrTransferBottomSheetContent(
onEvent: (WelcomeScreenEvents) -> Unit
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
.padding(bottom = 54.dp)
) {
Buttons.LargeTonal(
onClick = {
Spacer(modifier = Modifier.size(26.dp))
RestoreActionRow(
icon = SignalIcons.QrCode.painter,
title = stringResource(R.string.WelcomeFragment_restore_action_i_have_my_old_phone),
subtitle = stringResource(R.string.WelcomeFragment_restore_action_scan_qr),
modifier = Modifier.testTag(TestTags.WELCOME_RESTORE_HAS_OLD_PHONE_BUTTON),
onRowClick = {
sheetState.dismissWithAnimation(scope) {
onEvent(WelcomeScreenEvents.HasOldPhone)
}
},
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.WELCOME_RESTORE_HAS_OLD_PHONE_BUTTON)
) {
Text("I have my old phone")
}
}
)
Spacer(modifier = Modifier.height(12.dp))
Buttons.LargeTonal(
onClick = {
RestoreActionRow(
icon = painterResource(R.drawable.symbol_no_phone_44),
title = stringResource(R.string.WelcomeFragment_restore_action_i_dont_have_my_old_phone),
subtitle = stringResource(R.string.WelcomeFragment_restore_action_reinstalling),
modifier = Modifier.testTag(TestTags.WELCOME_RESTORE_NO_OLD_PHONE_BUTTON),
onRowClick = {
sheetState.dismissWithAnimation(scope) {
onEvent(WelcomeScreenEvents.DoesNotHaveOldPhone)
}
},
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.WELCOME_RESTORE_NO_OLD_PHONE_BUTTON)
) {
Text("I don't have my old phone")
}
}
)
}
}
Spacer(modifier = Modifier.height(16.dp))
@Composable
private fun RestoreActionRow(
icon: Painter,
title: String,
subtitle: String,
modifier: Modifier = Modifier,
onRowClick: () -> Unit = {}
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.horizontalGutters()
.padding(vertical = 8.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(18.dp))
.background(MaterialTheme.colorScheme.background)
.clickable(enabled = true, onClick = onRowClick)
.padding(horizontal = 24.dp, vertical = 16.dp)
) {
Icon(
painter = icon,
tint = MaterialTheme.colorScheme.primary,
contentDescription = null,
modifier = Modifier.size(44.dp)
)
Column(
modifier = Modifier.padding(start = 16.dp)
) {
Text(
text = title,
style = MaterialTheme.typography.bodyLarge
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
@@ -217,7 +266,7 @@ private fun WelcomeScreenPreview() {
@DayNightPreviews
@Composable
private fun RestoreOrTransferBottomSheetPreview() {
Previews.BottomSheetPreview(forceRtl = true) {
Previews.BottomSheetPreview {
RestoreOrTransferBottomSheetContent(
sheetState = rememberModalBottomSheetState(),
scope = rememberCoroutineScope(),

View File

@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="44dp"
android:height="44dp"
android:viewportWidth="44"
android:viewportHeight="44">
<path
android:pathData="M31.22,26.773V7.624C31.22,5.783 30.252,4.853 28.354,4.853H26.02C25.754,4.853 25.602,5.005 25.602,5.271V5.612C25.602,6.315 25.147,6.808 24.426,6.808H19.605C18.884,6.808 18.429,6.315 18.429,5.612V5.271C18.429,5.005 18.277,4.853 17.992,4.853H15.658C13.76,4.853 12.792,5.764 12.792,7.605V8.326L10.743,6.277L10.837,5.897C11.255,3.677 12.887,2.5 15.373,2.5H28.639C31.694,2.5 33.573,4.341 33.573,7.301V29.126L31.22,26.773ZM36.571,38.273L5.827,7.548C5.391,7.112 5.391,6.371 5.827,5.954C6.283,5.48 7.004,5.517 7.44,5.954L38.166,36.679C38.602,37.115 38.621,37.837 38.166,38.273C37.729,38.71 37.008,38.729 36.571,38.273ZM15.373,41.575C12.337,41.575 10.458,39.753 10.458,36.793V15.101L12.792,17.455V36.451C12.792,38.311 13.76,39.241 15.658,39.241H28.354C30.214,39.241 31.163,38.349 31.22,36.565V35.844L33.212,37.894C33.193,38.007 33.155,38.14 33.136,38.273C32.662,40.418 31.087,41.575 28.639,41.575H15.373ZM18.087,37.894C17.65,37.894 17.328,37.59 17.328,37.153C17.328,36.698 17.65,36.394 18.087,36.394H25.944C26.38,36.394 26.703,36.698 26.703,37.153C26.703,37.59 26.38,37.894 25.944,37.894H18.087Z"
android:strokeWidth="0.4"
android:fillColor="#000000"
android:strokeColor="#000000"/>
</vector>

View File

@@ -84,4 +84,14 @@
<string name="VerificationCodeScreen__registration_error">Registration failed. Please try again.</string>
<!-- Button text for having trouble with verification -->
<string name="VerificationCodeScreen__having_trouble">Having trouble?</string>
<!-- RestoreWelcomeBottomSheet -->
<!-- Row title for restore/transfer using a previous registered phone/device -->
<string name="WelcomeFragment_restore_action_i_have_my_old_phone">I have my old phone</string>
<!-- Row subtitle for restore/transfer using a previous registered phone/device -->
<string name="WelcomeFragment_restore_action_scan_qr">Scan a QR code from your current Signal account to get started quickly</string>
<!-- Row title for restore/transfer without using a previous device -->
<string name="WelcomeFragment_restore_action_i_dont_have_my_old_phone">I don\'t have my old phone</string>
<!-- Row subtitle for restore/transfer without using a previous device -->
<string name="WelcomeFragment_restore_action_reinstalling">Or you\'re reinstalling Signal on the same device</string>
</resources>