mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 12:38:33 +00:00
Add fixes to country picker.
This commit is contained in:
committed by
Greyson Parrelli
parent
e840efcecc
commit
02e7c035aa
@@ -113,6 +113,9 @@ class RegistrationViewModel : ViewModel() {
|
||||
val phoneNumber: Phonenumber.PhoneNumber?
|
||||
get() = store.value.phoneNumber
|
||||
|
||||
val country: Country?
|
||||
get() = store.value.country
|
||||
|
||||
fun maybePrefillE164(context: Context) {
|
||||
Log.v(TAG, "maybePrefillE164()")
|
||||
if (Permissions.hasAll(context, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS)) {
|
||||
|
||||
@@ -15,8 +15,10 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
@@ -24,8 +26,13 @@ import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
@@ -34,6 +41,7 @@ import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -42,6 +50,7 @@ import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.signal.core.ui.Dividers
|
||||
import org.signal.core.ui.IconButtons.IconButton
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.Scaffolds
|
||||
import org.signal.core.ui.SignalPreview
|
||||
@@ -236,21 +245,43 @@ fun SearchBar(
|
||||
hint: String = stringResource(R.string.CountryCodeFragment__search_by),
|
||||
onSearch: (String) -> Unit = {}
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
var showKeyboard by remember { mutableStateOf(false) }
|
||||
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { onSearch(it) },
|
||||
placeholder = { Text(hint) },
|
||||
// TODO(michelle): Add keyboard switch to dialpad
|
||||
// trailingIcon = {
|
||||
// Icon(
|
||||
// imageVector = ImageVector.vectorResource(R.drawable.symbol_number_pad_24),
|
||||
// contentDescription = "Search icon"
|
||||
// )
|
||||
// },
|
||||
trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
showKeyboard = !showKeyboard
|
||||
focusRequester.requestFocus()
|
||||
}) {
|
||||
if (showKeyboard) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_keyboard_24),
|
||||
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
|
||||
.fillMaxWidth()
|
||||
.height(54.dp)
|
||||
.focusRequester(focusRequester)
|
||||
.padding(horizontal = 16.dp),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
colors = TextFieldDefaults.colors(
|
||||
|
||||
@@ -125,7 +125,6 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
sharedViewModel.uiState.observe(viewLifecycleOwner) { sharedState ->
|
||||
presentRegisterButton(sharedState)
|
||||
updateEnabledControls(sharedState.inProgress, sharedState.isReRegister)
|
||||
updateCountrySelection(sharedState.country)
|
||||
|
||||
sharedState.networkError?.let {
|
||||
presentNetworkError(it)
|
||||
@@ -185,7 +184,13 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
initializeInputFields()
|
||||
|
||||
val existingPhoneNumber = sharedViewModel.phoneNumber
|
||||
if (existingPhoneNumber != null) {
|
||||
val country = sharedViewModel.country
|
||||
|
||||
if (country != null) {
|
||||
binding.countryEmoji.text = country.emoji
|
||||
binding.country.text = country.name
|
||||
spinnerView.setText(country.countryCode)
|
||||
} else if (existingPhoneNumber != null) {
|
||||
fragmentViewModel.restoreState(existingPhoneNumber)
|
||||
spinnerView.setText(existingPhoneNumber.countryCode.toString())
|
||||
phoneNumberInputLayout.setText(existingPhoneNumber.nationalNumber.toString())
|
||||
@@ -200,9 +205,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
if (country != null) {
|
||||
binding.countryEmoji.text = country.emoji
|
||||
binding.country.text = country.name
|
||||
binding.countryCode.editText?.setText(country.countryCode)
|
||||
}
|
||||
sharedViewModel.clearCountry()
|
||||
}
|
||||
|
||||
private fun reformatText(text: Editable?) {
|
||||
@@ -248,7 +251,12 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
val sanitized = s.toString().filter { c -> c.isDigit() }
|
||||
if (sanitized.isNotNullOrBlank()) {
|
||||
val countryCode: Int = sanitized.toInt()
|
||||
fragmentViewModel.setCountry(countryCode)
|
||||
if (sharedViewModel.country != null) {
|
||||
fragmentViewModel.setCountry(countryCode, sharedViewModel.country)
|
||||
sharedViewModel.clearCountry()
|
||||
} else {
|
||||
fragmentViewModel.setCountry(countryCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,22 +62,24 @@ class EnterPhoneNumberViewModel : ViewModel() {
|
||||
store.update { it.copy(phoneNumber = phoneNumber ?: "") }
|
||||
}
|
||||
|
||||
fun setCountry(digits: Int) {
|
||||
fun setCountry(digits: Int, country: Country? = null) {
|
||||
val matchingIndex = countryCodeToAdapterIndex(digits)
|
||||
if (matchingIndex == -1) {
|
||||
Log.d(TAG, "Invalid country code specified $digits")
|
||||
return
|
||||
}
|
||||
|
||||
val matchedCountry = Country(
|
||||
name = PhoneNumberFormatter.getRegionDisplayName(supportedCountryPrefixes[matchingIndex].regionCode).orElse(""),
|
||||
emoji = CountryUtils.countryToEmoji(supportedCountryPrefixes[matchingIndex].regionCode),
|
||||
countryCode = digits.toString()
|
||||
)
|
||||
|
||||
store.update {
|
||||
it.copy(
|
||||
countryPrefixIndex = matchingIndex,
|
||||
phoneNumberRegionCode = supportedCountryPrefixes[matchingIndex].regionCode,
|
||||
country = Country(
|
||||
name = PhoneNumberFormatter.getRegionDisplayName(supportedCountryPrefixes[matchingIndex].regionCode).orElse(""),
|
||||
emoji = CountryUtils.countryToEmoji(supportedCountryPrefixes[matchingIndex].regionCode),
|
||||
countryCode = digits.toString()
|
||||
)
|
||||
country = country ?: matchedCountry
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,9 @@ class RegistrationViewModel : ViewModel() {
|
||||
val phoneNumber: Phonenumber.PhoneNumber?
|
||||
get() = store.value.phoneNumber
|
||||
|
||||
val country: Country?
|
||||
get() = store.value.country
|
||||
|
||||
fun maybePrefillE164(context: Context) {
|
||||
Log.v(TAG, "maybePrefillE164()")
|
||||
if (Permissions.hasAll(context, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -25,8 +26,13 @@ import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
@@ -35,6 +41,7 @@ import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -43,6 +50,7 @@ import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.signal.core.ui.Dividers
|
||||
import org.signal.core.ui.IconButtons.IconButton
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.Scaffolds
|
||||
import org.signal.core.ui.SignalPreview
|
||||
@@ -237,21 +245,43 @@ fun SearchBar(
|
||||
hint: String = stringResource(R.string.CountryCodeFragment__search_by),
|
||||
onSearch: (String) -> Unit = {}
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
var showKeyboard by remember { mutableStateOf(false) }
|
||||
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { onSearch(it) },
|
||||
placeholder = { Text(hint) },
|
||||
trailingIcon = {
|
||||
// TODO(michelle): Add keyboard switch to dialpad
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_number_pad_24),
|
||||
contentDescription = "Search icon"
|
||||
)
|
||||
IconButton(onClick = {
|
||||
showKeyboard = !showKeyboard
|
||||
focusRequester.requestFocus()
|
||||
}) {
|
||||
if (showKeyboard) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_keyboard_24),
|
||||
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
|
||||
.fillMaxWidth()
|
||||
.height(54.dp)
|
||||
.focusRequester(focusRequester)
|
||||
.padding(horizontal = 16.dp),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
colors = TextFieldDefaults.colors(
|
||||
|
||||
@@ -130,7 +130,6 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
sharedViewModel.uiState.observe(viewLifecycleOwner) { sharedState ->
|
||||
presentRegisterButton(sharedState)
|
||||
updateEnabledControls(sharedState.inProgress, sharedState.isReRegister)
|
||||
updateCountrySelection(sharedState.country)
|
||||
|
||||
sharedState.networkError?.let {
|
||||
presentNetworkError(it)
|
||||
@@ -190,7 +189,13 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
initializeInputFields()
|
||||
|
||||
val existingPhoneNumber = sharedViewModel.phoneNumber
|
||||
if (existingPhoneNumber != null) {
|
||||
|
||||
val country = sharedViewModel.country
|
||||
if (country != null) {
|
||||
binding.countryEmoji.text = country.emoji
|
||||
binding.country.text = country.name
|
||||
spinnerView.setText(country.countryCode)
|
||||
} else if (existingPhoneNumber != null) {
|
||||
fragmentViewModel.restoreState(existingPhoneNumber)
|
||||
spinnerView.setText(existingPhoneNumber.countryCode.toString())
|
||||
phoneNumberInputLayout.setText(existingPhoneNumber.nationalNumber.toString())
|
||||
@@ -210,9 +215,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
if (country != null) {
|
||||
binding.countryEmoji.text = country.emoji
|
||||
binding.country.text = country.name
|
||||
binding.countryCode.editText?.setText(country.countryCode)
|
||||
}
|
||||
sharedViewModel.clearCountry()
|
||||
}
|
||||
|
||||
private fun reformatText(text: Editable?) {
|
||||
@@ -258,7 +261,12 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
|
||||
val sanitized = s.toString().filter { c -> c.isDigit() }
|
||||
if (sanitized.isNotNullOrBlank()) {
|
||||
val countryCode: Int = sanitized.toInt()
|
||||
fragmentViewModel.setCountry(countryCode)
|
||||
if (sharedViewModel.country != null) {
|
||||
fragmentViewModel.setCountry(countryCode, sharedViewModel.country)
|
||||
sharedViewModel.clearCountry()
|
||||
} else {
|
||||
fragmentViewModel.setCountry(countryCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,22 +60,24 @@ class EnterPhoneNumberViewModel : ViewModel() {
|
||||
store.update { it.copy(phoneNumber = phoneNumber ?: "") }
|
||||
}
|
||||
|
||||
fun setCountry(digits: Int) {
|
||||
fun setCountry(digits: Int, country: Country? = null) {
|
||||
val matchingIndex = countryCodeToAdapterIndex(digits)
|
||||
if (matchingIndex == -1) {
|
||||
Log.d(TAG, "Invalid country code specified $digits")
|
||||
return
|
||||
}
|
||||
|
||||
val matchedCountry = Country(
|
||||
name = PhoneNumberFormatter.getRegionDisplayName(supportedCountryPrefixes[matchingIndex].regionCode).orElse(""),
|
||||
emoji = CountryUtils.countryToEmoji(supportedCountryPrefixes[matchingIndex].regionCode),
|
||||
countryCode = digits.toString()
|
||||
)
|
||||
|
||||
store.update {
|
||||
it.copy(
|
||||
countryPrefixIndex = matchingIndex,
|
||||
phoneNumberRegionCode = supportedCountryPrefixes[matchingIndex].regionCode,
|
||||
country = Country(
|
||||
name = PhoneNumberFormatter.getRegionDisplayName(supportedCountryPrefixes[matchingIndex].regionCode).orElse(""),
|
||||
emoji = CountryUtils.countryToEmoji(supportedCountryPrefixes[matchingIndex].regionCode),
|
||||
countryCode = digits.toString()
|
||||
)
|
||||
country = country ?: matchedCountry
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user