Add more fixes to the country picker.

This commit is contained in:
Michelle Tang
2025-02-06 16:19:43 -05:00
committed by GitHub
parent 254b0dacc3
commit 5173916699
24 changed files with 425 additions and 355 deletions

View File

@@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.registration.data.network.Challenge
import org.thoughtcrime.securesms.registration.data.network.RegisterAccountResult
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
import org.thoughtcrime.securesms.registrationv3.ui.countrycode.Country
import org.whispersystems.signalservice.api.svr.Svr3Credentials
import org.whispersystems.signalservice.internal.push.AuthCredentials
import kotlin.time.Duration
@@ -54,8 +53,7 @@ data class RegistrationState(
val networkError: Throwable? = null,
val sessionCreationError: RegistrationSessionResult? = null,
val sessionStateError: VerificationCodeRequestResult? = null,
val registerAccountError: RegisterAccountResult? = null,
val country: Country? = null
val registerAccountError: RegisterAccountResult? = null
) {
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }

View File

@@ -75,7 +75,6 @@ import org.thoughtcrime.securesms.registration.ui.toE164
import org.thoughtcrime.securesms.registration.util.RegistrationUtil
import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet
import org.thoughtcrime.securesms.registrationv3.data.RegistrationRepository
import org.thoughtcrime.securesms.registrationv3.ui.countrycode.Country
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.dualsim.MccMncProducer
@@ -129,9 +128,6 @@ 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)) {
@@ -1046,18 +1042,6 @@ class RegistrationViewModel : ViewModel() {
.firstOrNull()
}
fun setCurrentCountryPicked(country: Country) {
store.update {
it.copy(country = country)
}
}
fun clearCountry() {
store.update {
it.copy(country = null)
}
}
companion object {
private val TAG = Log.tag(RegistrationViewModel::class.java)

View File

@@ -1,11 +0,0 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.registrationv3.ui.countrycode
/**
* Data class string describing useful characteristics of countries when selecting one. Used in the [CountryCodeState]
*/
data class Country(val emoji: String, val name: String, val countryCode: String)

View File

@@ -4,9 +4,10 @@ package org.thoughtcrime.securesms.registrationv3.ui.countrycode
import android.os.Bundle
import android.view.View
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@@ -14,6 +15,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.CircularProgressIndicator
@@ -25,9 +27,11 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -45,19 +49,24 @@ 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
import androidx.fragment.app.activityViewModels
import androidx.core.os.bundleOf
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.fragment.findNavController
import kotlinx.coroutines.launch
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
import org.signal.core.util.getParcelableCompat
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.compose.ComposeFragment
import org.thoughtcrime.securesms.registrationv3.ui.RegistrationViewModel
import org.thoughtcrime.securesms.registration.ui.countrycode.Country
import org.thoughtcrime.securesms.registration.ui.countrycode.CountryCodeState
import org.thoughtcrime.securesms.registration.ui.countrycode.CountryCodeViewModel
/**
* Country picker fragment used in registration V3
@@ -66,10 +75,12 @@ class CountryCodeFragment : ComposeFragment() {
companion object {
private val TAG = Log.tag(CountryCodeFragment::class.java)
const val REQUEST_KEY_COUNTRY = "request_key_country"
const val REQUEST_COUNTRY = "country"
const val RESULT_COUNTRY = "country"
}
private val viewModel: CountryCodeViewModel by viewModels()
private val sharedViewModel by activityViewModels<RegistrationViewModel>()
@Composable
override fun FragmentContent() {
@@ -77,10 +88,16 @@ class CountryCodeFragment : ComposeFragment() {
Screen(
state = state,
title = stringResource(R.string.CountryCodeFragment__your_country),
onSearch = { search -> viewModel.filterCountries(search) },
onDismissed = { findNavController().popBackStack() },
onClick = { country ->
sharedViewModel.setCurrentCountryPicked(country)
setFragmentResult(
REQUEST_KEY_COUNTRY,
bundleOf(
RESULT_COUNTRY to country
)
)
findNavController().popBackStack()
}
)
@@ -89,14 +106,16 @@ class CountryCodeFragment : ComposeFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.loadCountries()
val initialCountry = arguments?.getParcelableCompat(REQUEST_COUNTRY, Country::class.java)
viewModel.loadCountries(initialCountry)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
private fun Screen(
fun Screen(
state: CountryCodeState,
title: String,
onSearch: (String) -> Unit = {},
onDismissed: () -> Unit = {},
onClick: (Country) -> Unit = {}
@@ -104,7 +123,7 @@ private fun Screen(
Scaffold(
topBar = {
Scaffolds.DefaultTopAppBar(
title = stringResource(R.string.CountryCodeFragment__your_country),
title = title,
titleContent = { _, title ->
Text(text = title, style = MaterialTheme.typography.titleLarge)
},
@@ -113,16 +132,19 @@ private fun Screen(
)
}
) { padding ->
val listState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
LazyColumn(
state = listState,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(padding)
) {
item {
stickyHeader {
SearchBar(
text = state.query,
onSearch = onSearch
)
Spacer(modifier = Modifier.size(18.dp))
}
if (state.countryList.isEmpty()) {
@@ -132,12 +154,14 @@ private fun Screen(
)
}
} else if (state.query.isEmpty()) {
items(state.commonCountryList) { country ->
CountryItem(country, onClick)
}
if (state.commonCountryList.isNotEmpty()) {
items(state.commonCountryList) { country ->
CountryItem(country, onClick)
}
item {
Dividers.Default()
item {
Dividers.Default()
}
}
items(state.countryList) { country ->
@@ -149,6 +173,12 @@ private fun Screen(
}
}
}
LaunchedEffect(state.startingIndex) {
coroutineScope.launch {
listState.scrollToItem(index = state.startingIndex)
}
}
}
}
@@ -160,7 +190,7 @@ fun CountryItem(
) {
val emoji = country.emoji
val name = country.name
val code = country.countryCode
val code = "+${country.countryCode}"
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@@ -253,21 +283,30 @@ fun SearchBar(
onValueChange = { onSearch(it) },
placeholder = { Text(hint) },
trailingIcon = {
IconButton(onClick = {
showKeyboard = !showKeyboard
focusRequester.requestFocus()
}) {
if (showKeyboard) {
if (text.isNotEmpty()) {
IconButton(onClick = { onSearch("") }) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.symbol_keyboard_24),
contentDescription = null
)
} else {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.symbol_number_pad_24),
imageVector = ImageVector.vectorResource(R.drawable.symbol_x_24),
contentDescription = null
)
}
} else {
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(
@@ -279,10 +318,11 @@ fun SearchBar(
),
shape = RoundedCornerShape(32.dp),
modifier = modifier
.background(MaterialTheme.colorScheme.background)
.padding(bottom = 18.dp, start = 16.dp, end = 16.dp)
.fillMaxWidth()
.height(54.dp)
.focusRequester(focusRequester)
.padding(horizontal = 16.dp),
.focusRequester(focusRequester),
visualTransformation = VisualTransformation.None,
colors = TextFieldDefaults.colors(
// TODO move to SignalTheme
@@ -302,15 +342,16 @@ private fun ScreenPreview() {
Screen(
state = CountryCodeState(
countryList = mutableListOf(
Country("\uD83C\uDDFA\uD83C\uDDF8", "United States", "+1"),
Country("\uD83C\uDDE8\uD83C\uDDE6", "Canada", "+2"),
Country("\uD83C\uDDF2\uD83C\uDDFD", "Mexico", "+3")
Country("\uD83C\uDDFA\uD83C\uDDF8", "United States", 1, "US"),
Country("\uD83C\uDDE8\uD83C\uDDE6", "Canada", 2, "CA"),
Country("\uD83C\uDDF2\uD83C\uDDFD", "Mexico", 3, "MX")
),
commonCountryList = mutableListOf(
Country("\uD83C\uDDFA\uD83C\uDDF8", "United States", "+4"),
Country("\uD83C\uDDE8\uD83C\uDDE6", "Canada", "+5")
Country("\uD83C\uDDFA\uD83C\uDDF8", "United States", 4, "US"),
Country("\uD83C\uDDE8\uD83C\uDDE6", "Canada", 5, "CA")
)
)
),
title = "Your country"
)
}
}
@@ -322,7 +363,8 @@ private fun LoadingScreenPreview() {
Screen(
state = CountryCodeState(
countryList = emptyList()
)
),
title = "Your country"
)
}
}

View File

@@ -1,16 +0,0 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.registrationv3.ui.countrycode
/**
* State managed by [CountryCodeViewModel]. Includes country list and allows for searching
*/
data class CountryCodeState(
val query: String = "",
val countryList: List<Country> = emptyList(),
val commonCountryList: List<Country> = emptyList(),
val filteredList: List<Country> = emptyList()
)

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.registrationv3.ui.countrycode
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.i18n.phonenumbers.PhoneNumberUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.registration.ui.countrycode.CountryUtils
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter
import java.util.Locale
/**
* View model to support [CountryCodeFragment] and track the countries
*/
class CountryCodeViewModel : ViewModel() {
companion object {
private val TAG = Log.tag(CountryCodeViewModel::class.java)
}
private val internalState = MutableStateFlow(CountryCodeState())
val state = internalState.asStateFlow()
fun filterCountries(filterBy: String) {
if (filterBy.isEmpty()) {
internalState.update {
it.copy(
query = filterBy,
filteredList = emptyList()
)
}
} else {
internalState.update {
it.copy(
query = filterBy,
filteredList = state.value.countryList.filter { country: Country ->
country.name.contains(filterBy, ignoreCase = true) || country.countryCode.contains(filterBy)
}
)
}
}
}
fun loadCountries() {
loadCommonCountryList()
viewModelScope.launch(Dispatchers.IO) {
val regions = PhoneNumberUtil.getInstance().supportedRegions
val countries = mutableListOf<Country>()
for (region in regions) {
val c = Country(
name = PhoneNumberFormatter.getRegionDisplayName(region).orElse(""),
emoji = CountryUtils.countryToEmoji(region),
countryCode = "+" + PhoneNumberUtil.getInstance().getCountryCodeForRegion(region)
)
countries.add(c)
}
val sortedCountries = countries.sortedWith { lhs, rhs ->
lhs.name.lowercase(Locale.getDefault()).compareTo(rhs.name.lowercase(Locale.getDefault()))
}
internalState.update {
it.copy(
countryList = sortedCountries
)
}
}
}
private fun loadCommonCountryList() {
viewModelScope.launch(Dispatchers.IO) {
val countries = mutableListOf<Country>()
for (region in CountryUtils.COMMON_COUNTRIES) {
val c = Country(
name = PhoneNumberFormatter.getRegionDisplayName(region).orElse(""),
emoji = CountryUtils.countryToEmoji(region),
countryCode = "+" + PhoneNumberUtil.getInstance().getCountryCodeForRegion(region)
)
countries.add(c)
}
internalState.update {
it.copy(
commonCountryList = countries
)
}
}
}
}

View File

@@ -38,6 +38,7 @@ import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
import org.signal.core.util.ThreadUtil
import org.signal.core.util.getParcelableCompat
import org.signal.core.util.isNotNullOrBlank
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.LoggingFragment
@@ -54,13 +55,14 @@ import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionC
import org.thoughtcrime.securesms.registration.data.network.RegistrationSessionResult
import org.thoughtcrime.securesms.registration.data.network.VerificationCodeRequestResult
import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView
import org.thoughtcrime.securesms.registration.ui.countrycode.Country
import org.thoughtcrime.securesms.registration.ui.countrycode.CountryCodeFragment
import org.thoughtcrime.securesms.registration.ui.toE164
import org.thoughtcrime.securesms.registration.util.CountryPrefix
import org.thoughtcrime.securesms.registrationv3.data.RegistrationRepository
import org.thoughtcrime.securesms.registrationv3.ui.RegistrationCheckpoint
import org.thoughtcrime.securesms.registrationv3.ui.RegistrationState
import org.thoughtcrime.securesms.registrationv3.ui.RegistrationViewModel
import org.thoughtcrime.securesms.registrationv3.ui.countrycode.Country
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.Dialogs
import org.thoughtcrime.securesms.util.PlayServicesUtil
@@ -114,6 +116,14 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
moveToCountryPickerScreen()
}
parentFragmentManager.setFragmentResultListener(
CountryCodeFragment.REQUEST_KEY_COUNTRY,
this
) { _, bundle ->
val country: Country = bundle.getParcelableCompat(CountryCodeFragment.RESULT_COUNTRY, Country::class.java)!!
fragmentViewModel.setCountry(country.countryCode, country)
}
spinnerAdapter = ArrayAdapter<CountryPrefix>(
requireContext(),
R.layout.registration_country_code_dropdown_item,
@@ -167,9 +177,11 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
.map { it.phoneNumberRegionCode }
.distinctUntilChanged()
.observe(viewLifecycleOwner) { regionCode ->
currentPhoneNumberFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(regionCode)
reformatText(phoneNumberInputLayout.text)
phoneNumberInputLayout.requestFocus()
if (regionCode.isNotNullOrBlank()) {
currentPhoneNumberFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(regionCode)
reformatText(phoneNumberInputLayout.text)
phoneNumberInputLayout.requestFocus()
}
}
fragmentViewModel.uiState.observe(viewLifecycleOwner) { fragmentState ->
@@ -189,18 +201,12 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
initializeInputFields()
val existingPhoneNumber = sharedViewModel.phoneNumber
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) {
if (existingPhoneNumber != null) {
fragmentViewModel.restoreState(existingPhoneNumber)
spinnerView.setText(existingPhoneNumber.countryCode.toString())
phoneNumberInputLayout.setText(existingPhoneNumber.nationalNumber.toString())
} else {
spinnerView.setText(fragmentViewModel.countryPrefix().toString())
} else if (spinnerView.text?.isEmpty() == true) {
spinnerView.setText(fragmentViewModel.getDefaultCountryCode(requireContext()).toString())
}
if (enterPhoneNumberMode == EnterPhoneNumberMode.RESTART_AFTER_COLLECTION && (savedInstanceState == null && !processedResumeMode)) {
@@ -213,8 +219,15 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
private fun updateCountrySelection(country: Country?) {
if (country != null) {
binding.countryEmoji.visible = true
binding.countryEmoji.text = country.emoji
binding.country.text = country.name
if (spinnerView.text.toString() != country.countryCode.toString()) {
spinnerView.setText(country.countryCode.toString())
}
} else {
binding.countryEmoji.visible = false
binding.country.text = getString(R.string.RegistrationActivity_select_a_country)
}
}
@@ -252,21 +265,13 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
private fun initializeInputFields() {
binding.countryCode.editText?.addTextChangedListener { s ->
if (s.isNotNullOrBlank()) {
val formatted = s.toString().replace("+", "").let { "+$it" }
if (formatted != s.toString()) {
s.replace(0, s.length, formatted)
}
}
val sanitized = s.toString().filter { c -> c.isDigit() }
if (sanitized.isNotNullOrBlank()) {
val countryCode: Int = sanitized.toInt()
if (sharedViewModel.country != null) {
fragmentViewModel.setCountry(countryCode, sharedViewModel.country)
sharedViewModel.clearCountry()
} else {
fragmentViewModel.setCountry(countryCode)
}
fragmentViewModel.setCountry(countryCode)
} else {
binding.countryCode.editText?.setHint(R.string.RegistrationActivity_default_country_code)
fragmentViewModel.clearCountry()
}
}
@@ -681,7 +686,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
}
private fun moveToCountryPickerScreen() {
findNavController().safeNavigate(R.id.action_countryPicker)
findNavController().safeNavigate(EnterPhoneNumberFragmentDirections.actionCountryPicker(fragmentViewModel.country))
}
private fun popBackStack() {

View File

@@ -5,8 +5,8 @@
package org.thoughtcrime.securesms.registrationv3.ui.phonenumber
import org.thoughtcrime.securesms.registration.ui.countrycode.Country
import org.thoughtcrime.securesms.registrationv3.data.RegistrationRepository
import org.thoughtcrime.securesms.registrationv3.ui.countrycode.Country
/**
* State holder for the phone number entry screen, including phone number and Play Services errors.

View File

@@ -5,6 +5,7 @@
package org.thoughtcrime.securesms.registrationv3.ui.phonenumber
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import com.google.i18n.phonenumbers.NumberParseException
@@ -13,10 +14,11 @@ import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.registration.ui.countrycode.Country
import org.thoughtcrime.securesms.registration.ui.countrycode.CountryUtils
import org.thoughtcrime.securesms.registration.util.CountryPrefix
import org.thoughtcrime.securesms.registrationv3.data.RegistrationRepository
import org.thoughtcrime.securesms.registrationv3.ui.countrycode.Country
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter
/**
@@ -54,23 +56,73 @@ class EnterPhoneNumberViewModel : ViewModel() {
it.copy(mode = value)
}
fun countryPrefix(): CountryPrefix = supportedCountryPrefixes[store.value.countryPrefixIndex]
fun getDefaultCountryCode(context: Context): Int {
val existingCountry = store.value.country
val maybeRegionCode = Util.getNetworkCountryIso(context)
val regionCode = if (maybeRegionCode != null && supportedCountryPrefixes.any { it.regionCode == maybeRegionCode }) {
maybeRegionCode
} else {
Log.w(TAG, "Could not find region code")
"US"
}
val countryCode = PhoneNumberUtil.getInstance().getCountryCodeForRegion(regionCode)
store.update {
it.copy(
country = existingCountry ?: Country(
name = PhoneNumberFormatter.getRegionDisplayName(regionCode).orElse(""),
emoji = CountryUtils.countryToEmoji(regionCode),
countryCode = countryCode,
regionCode = regionCode
)
)
}
return existingCountry?.countryCode ?: countryCode
}
val country: Country?
get() = store.value.country
fun setPhoneNumber(phoneNumber: String?) {
store.update { it.copy(phoneNumber = phoneNumber ?: "") }
}
fun clearCountry() {
store.update {
it.copy(
country = null,
phoneNumberRegionCode = "",
countryPrefixIndex = 0
)
}
}
fun setCountry(digits: Int, country: Country? = null) {
val matchingIndex = countryCodeToAdapterIndex(digits)
if (matchingIndex == -1) {
Log.d(TAG, "Invalid country code specified $digits")
if (country == null && digits == store.value.country?.countryCode) {
return
}
val matchingIndex = countryCodeToAdapterIndex(digits)
if (matchingIndex == -1) {
Log.d(TAG, "Invalid country code specified $digits")
store.update {
it.copy(
country = null,
phoneNumberRegionCode = "",
countryPrefixIndex = 0
)
}
return
}
val regionCode = supportedCountryPrefixes[matchingIndex].regionCode
val matchedCountry = Country(
name = PhoneNumberFormatter.getRegionDisplayName(supportedCountryPrefixes[matchingIndex].regionCode).orElse(""),
emoji = CountryUtils.countryToEmoji(supportedCountryPrefixes[matchingIndex].regionCode),
countryCode = digits.toString()
name = PhoneNumberFormatter.getRegionDisplayName(regionCode).orElse(""),
emoji = CountryUtils.countryToEmoji(regionCode),
countryCode = digits,
regionCode = regionCode
)
store.update {
@@ -88,7 +140,8 @@ class EnterPhoneNumberViewModel : ViewModel() {
fun isEnteredNumberPossible(state: EnterPhoneNumberState): Boolean {
return try {
PhoneNumberUtil.getInstance().isPossibleNumber(parsePhoneNumber(state))
state.country != null &&
PhoneNumberUtil.getInstance().isPossibleNumber(parsePhoneNumber(state))
} catch (ex: NumberParseException) {
false
}