Update regV5 country picker UI.

This commit is contained in:
Greyson Parrelli
2026-07-07 11:55:52 -04:00
parent 958236467f
commit 1358fefeee
15 changed files with 119 additions and 97 deletions
@@ -8,6 +8,7 @@ package org.signal.registration.screens.countrycode
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
@@ -62,6 +63,7 @@ import org.signal.core.ui.compose.LargeFontPreviews
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.Scaffolds
import org.signal.core.ui.compose.SignalIcons
import org.signal.core.ui.compose.TextFields
import org.signal.registration.R
import org.signal.registration.screens.OnePaneRegistrationScaffold
import org.signal.registration.screens.RegistrationScaffold
@@ -100,6 +102,7 @@ private fun OnePaneLayout(
params = layoutParams,
topBar = {
TopAppBar(
title = stringResource(R.string.CountryCodeSelectScreen__your_country),
scrollBehavior = topBarScrollBehavior,
onCloseClick = { onEvent(CountryCodePickerScreenEvents.Dismissed) }
)
@@ -111,7 +114,6 @@ private fun OnePaneLayout(
.nestedScroll(topBarScrollBehavior.nestedScrollConnection)
) {
CountryList(
showTitle = true,
state = state,
onEvent = onEvent,
contentPadding = paddingValues,
@@ -164,7 +166,6 @@ private fun TwoPaneLayout(
.padding(paddingValues)
) {
CountryList(
showTitle = false,
state = state,
onEvent = onEvent
)
@@ -177,11 +178,17 @@ private fun TwoPaneLayout(
@Composable
fun TopAppBar(
scrollBehavior: TopAppBarScrollBehavior,
onCloseClick: () -> Unit
onCloseClick: () -> Unit,
title: String = ""
) {
Scaffolds.DefaultTopAppBar(
title = "",
titleContent = { _, _ -> },
title = title,
titleContent = { _, titleText ->
Text(
text = titleText,
style = MaterialTheme.typography.titleLarge
)
},
navigationIconContent = {
IconButton(
onClick = onCloseClick,
@@ -204,8 +211,7 @@ private fun CountryList(
state: CountryCodeState,
onEvent: (CountryCodePickerScreenEvents) -> Unit,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(),
showTitle: Boolean
contentPadding: PaddingValues = PaddingValues()
) {
val listState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
@@ -213,23 +219,14 @@ private fun CountryList(
LazyColumn(
modifier = modifier,
state = listState,
contentPadding = contentPadding,
contentPadding = PaddingValues(
start = 24.dp,
end = 24.dp,
bottom = contentPadding.calculateBottomPadding()
),
horizontalAlignment = Alignment.CenterHorizontally
) {
item {
if (showTitle) {
Text(
text = stringResource(R.string.CountryCodeSelectScreen__your_country),
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 28.dp)
.attachDebugLogHelper()
)
}
}
stickyHeader {
SearchBar(
text = state.query,
onSearch = { onEvent(CountryCodePickerScreenEvents.Search(it)) }
@@ -282,7 +279,6 @@ private fun CountryItem(
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(horizontal = 24.dp)
.fillMaxWidth()
.defaultMinSize(minHeight = 56.dp)
.clickable { onEvent(CountryCodePickerScreenEvents.CountrySelected(country)) }
@@ -366,61 +362,68 @@ private fun SearchBar(
val focusRequester = remember { FocusRequester() }
var showKeyboard by remember { mutableStateOf(false) }
TextField(
value = text,
onValueChange = { onSearch(it) },
placeholder = { Text(hint) },
trailingIcon = {
if (text.isNotEmpty()) {
IconButton(onClick = { onSearch("") }) {
Icon(
imageVector = SignalIcons.X.imageVector,
contentDescription = null
)
}
} else {
IconButton(onClick = {
showKeyboard = !showKeyboard
focusRequester.requestFocus()
}) {
if (showKeyboard) {
Box(
modifier = modifier.padding(vertical = 10.dp)
) {
TextFields.TextField(
value = text,
onValueChange = { onSearch(it) },
placeholder = { Text(hint) },
trailingIcon = {
if (text.isNotEmpty()) {
IconButton(onClick = { onSearch("") }) {
Icon(
imageVector = SignalIcons.Keyboard.imageVector,
contentDescription = null
)
} else {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.symbol_number_pad_24),
imageVector = SignalIcons.X.imageVector,
contentDescription = null
)
}
} else {
IconButton(onClick = {
showKeyboard = !showKeyboard
focusRequester.requestFocus()
}) {
if (showKeyboard) {
Icon(
imageVector = SignalIcons.Keyboard.imageVector,
contentDescription = null
)
} else {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.symbol_number_pad_24),
contentDescription = null
)
}
}
}
}
},
keyboardOptions = KeyboardOptions(
keyboardType = if (showKeyboard) {
KeyboardType.Number
} else {
KeyboardType.Text
}
),
shape = RoundedCornerShape(32.dp),
modifier = modifier
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth()
.defaultMinSize(minHeight = 54.dp)
.focusRequester(focusRequester)
.testTag(TestTags.COUNTRY_CODE_SEARCH_FIELD),
visualTransformation = VisualTransformation.None,
colors = TextFieldDefaults.colors(
// TODO move to SignalTheme
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
},
keyboardOptions = KeyboardOptions(
keyboardType = if (showKeyboard) {
KeyboardType.Number
} else {
KeyboardType.Text
}
),
singleLine = true,
shape = RoundedCornerShape(32.dp),
modifier = modifier
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth()
.defaultMinSize(minHeight = 44.dp)
.padding(0.dp)
.focusRequester(focusRequester)
.testTag(TestTags.COUNTRY_CODE_SEARCH_FIELD),
visualTransformation = VisualTransformation.None,
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
colors = TextFieldDefaults.colors(
// TODO move to SignalTheme
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
)
)
)
}
}
@AllDevicePreviews
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:baae4a5d70aaf319323250b6bfca1808d1bbb9eeac4d927086a4cf720ceef936
size 83400
oid sha256:9b7e51398cea85f3404b97feab948c203eecdc4de6a12fe2fad94bba233a69ec
size 83184
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bf6119a78d4b5bee717f4b7559c2a2719b9afd4b307ba3ff114214ec10b1f03c
size 83708
oid sha256:fa5b4d32ef8cee6af099bcf9a6090e850408fc331f3e47547e6e9fa01dff4a3b
size 83533
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c6bc0f181264f3e6f8f5747da71d4013907c2cea4bd232377a981aa6820951f4
size 83659
oid sha256:cbfbb388a1799554adfdf07014c37504345615909f5e4de782a36378345387e0
size 83508
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:163f5ec137fde709e60e5404276179c08acaeda2ee71521438322c2c6e184802
size 41309
oid sha256:7fef464021e7503f25bd8d18f25bcdfc46845ae9cc0db90f1e316c5611d17c1d
size 52154
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:53e1ea5064d0e6a311f44ecb9692aca4d0f5ce41c3b2d812f2a1ae3a986bbb95
size 41475
oid sha256:38dade0d563899106dbd9da32b83800c7b6d03ff06c1170dd41bfc10ea02030b
size 52357
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5868f1caea0e0f96f85abcf30bd52178c536eea98686ea7bf2258eb0dcc1014b
size 64483
oid sha256:fa9c97dc084ac2dc3510b49328af2cfbe0f8f92c1743e1ffcdd5b0db56973a71
size 62221
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bf803bdd50fa32065734aa15c845f0dca30f6c5f7f105a70fad8da820f98c4ad
size 69809
oid sha256:c3caee50e6300746163871b8cdd06c4bfde402eeec364505c3b2b9832dbcc75d
size 68690
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f23da2e7baa4347deeb8bd6f15c3dc8e1ba9459dfb92c428686fa4105ec8dfcd
size 73006
oid sha256:985be97c43cc0aa03971220b5348a159128fdf75db85021c6ad9803fec1c6210
size 72693
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:309c52c63f71a1391d7c6dfd40d433a59a5c16836d40af219722aa9e4118c0cd
size 73285
oid sha256:ef9e4f34d418a9c2c6067d0f66b8b99dd7b752bc4a0dc0d9ee3f48729ae08c70
size 73013
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:014d160d3c7bfeeba7aea786740562cd555960b589348a9bf6d86c0c80760f05
size 73302
oid sha256:a01b794c109f79c64d78dd3e7140e3c8d28a9f56e16892b9b06c73e885af067b
size 75292
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4eaf10876ab9760040493868db2ed440c23c7a1a02616d78da7d4c20487ce6ee
size 90991
oid sha256:fb44a46f99f1f4a8318366be11890c58d96a9cc7650184526c2a675f8229f83b
size 90760
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fd93e417bf7b4973f305dd968f9f843e89116d7d77d972ea02472eea110d7478
size 91256
oid sha256:0d36171c9e95f14d743f2edc578db3b5d69d49cbf8394e7d852de44db008ff23
size 91007
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4d9e4ad1ae9b275aed59310a037d1315db32f668e908ead971198687401ad725
size 93948
oid sha256:166a2b77e7e77fe224556404d0e714695c317c5702b34247864f223301d93a56
size 91558
@@ -20,6 +20,7 @@ import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.signal.core.ui.CoreUiDependenciesRule
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.registration.R
import org.signal.registration.test.TestTags
/**
@@ -52,6 +53,24 @@ class CountryCodePickerScreenTest {
composeTestRule.onNodeWithTag(TestTags.COUNTRY_CODE_SEARCH_FIELD).assertIsDisplayed()
}
@Test
fun `screen displays title`() {
// Given
val title = ApplicationProvider.getApplicationContext<Application>().getString(R.string.CountryCodeSelectScreen__your_country)
composeTestRule.setContent {
SignalTheme {
CountryCodePickerScreen(
state = CountryCodeState(),
onEvent = {}
)
}
}
// Then
composeTestRule.onNodeWithText(title).assertIsDisplayed()
}
@Test
fun `when close button is clicked, Dismissed event is emitted`() {
// Given