From 6ad72f00afba3e0a07ebd8a30ebbed4e39743484 Mon Sep 17 00:00:00 2001 From: Nicholas Tinsley Date: Fri, 19 Apr 2024 17:57:56 -0400 Subject: [PATCH] Fix phone number formatter in Registration V2. --- .../ui/{shared => }/RegistrationCheckpoint.kt | 2 +- .../v2/ui/RegistrationV2Activity.kt | 1 - .../v2/ui/{shared => }/RegistrationV2State.kt | 2 +- .../{shared => }/RegistrationV2ViewModel.kt | 3 +- .../v2/ui/entercode/EnterCodeV2Fragment.kt | 4 +- .../GrantPermissionsV2Fragment.kt | 6 +-- .../phonenumber/EnterPhoneNumberV2Fragment.kt | 53 +++++++++++++------ .../ui/phonenumber/EnterPhoneNumberV2State.kt | 4 +- .../EnterPhoneNumberV2ViewModel.kt | 17 ++++++ .../v2/ui/welcome/WelcomeV2Fragment.kt | 17 +++--- .../fragment_registration_welcome_v2.xml | 1 + 11 files changed, 73 insertions(+), 37 deletions(-) rename app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/{shared => }/RegistrationCheckpoint.kt (91%) rename app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/{shared => }/RegistrationV2State.kt (91%) rename app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/{shared => }/RegistrationV2ViewModel.kt (98%) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationCheckpoint.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationCheckpoint.kt similarity index 91% rename from app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationCheckpoint.kt rename to app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationCheckpoint.kt index 744268df98..1af548b418 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationCheckpoint.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationCheckpoint.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.registration.v2.ui.shared +package org.thoughtcrime.securesms.registration.v2.ui /** * An ordered list of checkpoints of the registration process. diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2Activity.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2Activity.kt index 8592149509..032da33b02 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2Activity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2Activity.kt @@ -12,7 +12,6 @@ import androidx.activity.viewModels import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.BaseActivity import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2ViewModel /** * Activity to hold the entire registration process. diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationV2State.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2State.kt similarity index 91% rename from app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationV2State.kt rename to app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2State.kt index 45511acf0b..6eba43dcd8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationV2State.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2State.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.registration.v2.ui.shared +package org.thoughtcrime.securesms.registration.v2.ui import com.google.i18n.phonenumbers.Phonenumber diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationV2ViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2ViewModel.kt similarity index 98% rename from app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationV2ViewModel.kt rename to app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2ViewModel.kt index e20449fe92..8d75e5cf7f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/shared/RegistrationV2ViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/RegistrationV2ViewModel.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package org.thoughtcrime.securesms.registration.v2.ui.shared +package org.thoughtcrime.securesms.registration.v2.ui import android.content.Context import androidx.lifecycle.ViewModel @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.registration.RegistrationData import org.thoughtcrime.securesms.registration.RegistrationUtil import org.thoughtcrime.securesms.registration.v2.data.RegistrationRepository -import org.thoughtcrime.securesms.registration.v2.ui.toE164 import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.dualsim.MccMncProducer diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/entercode/EnterCodeV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/entercode/EnterCodeV2Fragment.kt index 565f0705b7..ee0b9f2e1e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/entercode/EnterCodeV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/entercode/EnterCodeV2Fragment.kt @@ -24,8 +24,8 @@ import org.thoughtcrime.securesms.profiles.edit.CreateProfileActivity import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView import org.thoughtcrime.securesms.registration.fragments.SignalStrengthPhoneStateListener -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationCheckpoint -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2ViewModel +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationCheckpoint +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2ViewModel /** * The final screen of account registration, where the user enters their verification code. diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/grantpermissions/GrantPermissionsV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/grantpermissions/GrantPermissionsV2Fragment.kt index e61987787c..903bd31a32 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/grantpermissions/GrantPermissionsV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/grantpermissions/GrantPermissionsV2Fragment.kt @@ -21,9 +21,9 @@ import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.compose.ComposeFragment import org.thoughtcrime.securesms.registration.compose.GrantPermissionsScreen import org.thoughtcrime.securesms.registration.fragments.WelcomePermissions -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationCheckpoint -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2State -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2ViewModel +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationCheckpoint +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2State +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2ViewModel import org.thoughtcrime.securesms.util.BackupUtil import org.thoughtcrime.securesms.util.navigation.safeNavigate diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2Fragment.kt index cca66bb7e7..90702878a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2Fragment.kt @@ -8,6 +8,7 @@ package org.thoughtcrime.securesms.registration.v2.ui.phonenumber import android.content.Context import android.os.Bundle import android.text.SpannableStringBuilder +import android.text.TextWatcher import android.view.KeyEvent import android.view.Menu import android.view.MenuInflater @@ -38,9 +39,9 @@ import org.thoughtcrime.securesms.databinding.FragmentRegistrationEnterPhoneNumb import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView import org.thoughtcrime.securesms.registration.util.CountryPrefix -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationCheckpoint -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2State -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2ViewModel +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationCheckpoint +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2State +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2ViewModel import org.thoughtcrime.securesms.registration.v2.ui.toE164 import org.thoughtcrime.securesms.util.PlayServicesUtil import org.thoughtcrime.securesms.util.SpanUtil @@ -63,8 +64,11 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio private lateinit var phoneNumberInputLayout: TextInputEditText private lateinit var spinnerView: MaterialAutoCompleteTextView + private var currentPhoneNumberFormatter: TextWatcher? = null + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + setDebugLogSubmitMultiTapView(binding.verifyHeader) requireActivity().onBackPressedDispatcher.addCallback( viewLifecycleOwner, object : OnBackPressedCallback(true) { @@ -80,25 +84,14 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio R.layout.registration_country_code_dropdown_item, fragmentViewModel.supportedCountryPrefixes ) - setDebugLogSubmitMultiTapView(binding.verifyHeader) binding.registerButton.setOnClickListener { onRegistrationButtonClicked() } - binding.toolbar.title = null + binding.toolbar.title = "" val activity = requireActivity() as AppCompatActivity activity.setSupportActionBar(binding.toolbar) requireActivity().addMenuProvider(UseProxyMenuProvider(), viewLifecycleOwner) - val existingPhoneNumber = sharedViewModel.uiState.value?.phoneNumber - if (existingPhoneNumber != null) { - fragmentViewModel.restoreState(existingPhoneNumber) - fragmentViewModel.phoneNumber()?.let { - phoneNumberInputLayout.setText(it.nationalNumber.toString()) - } - } else if (spinnerView.editableText.isBlank()) { - spinnerView.setText(fragmentViewModel.countryPrefix().toString()) - } - sharedViewModel.uiState.observe(viewLifecycleOwner) { sharedState -> presentRegisterButton(sharedState) presentProgressBar(sharedState.inProgress, sharedState.isReRegister) @@ -108,6 +101,19 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio } fragmentViewModel.uiState.observe(viewLifecycleOwner) { fragmentState -> + + fragmentState.phoneNumberFormatter?.let { + if (it != currentPhoneNumberFormatter) { + currentPhoneNumberFormatter?.let { oldWatcher -> + Log.d(TAG, "Removing current phone number formatter in fragment") + phoneNumberInputLayout.removeTextChangedListener(oldWatcher) + } + phoneNumberInputLayout.addTextChangedListener(it) + currentPhoneNumberFormatter = it + Log.d(TAG, "Updating phone number formatter in fragment") + } + } + if (fragmentViewModel.isEnteredNumberValid(fragmentState)) { sharedViewModel.setPhoneNumber(fragmentViewModel.parsePhoneNumber(fragmentState)) } else { @@ -121,12 +127,26 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio initializeInputFields() + val existingPhoneNumber = sharedViewModel.uiState.value?.phoneNumber + if (existingPhoneNumber != null) { + fragmentViewModel.restoreState(existingPhoneNumber) + fragmentViewModel.phoneNumber()?.let { + phoneNumberInputLayout.setText(it.nationalNumber.toString()) + } + } else if (spinnerView.editableText.isBlank()) { + spinnerView.setText(fragmentViewModel.countryPrefix().toString()) + } + ViewUtil.focusAndShowKeyboard(phoneNumberInputLayout) } private fun initializeInputFields() { + binding.countryCode.editText?.addTextChangedListener { s -> + val countryCode: Int = s.toString().toInt() + fragmentViewModel.setCountry(countryCode) + } + phoneNumberInputLayout.addTextChangedListener { - // TODO [regv2]: country code as you type formatter fragmentViewModel.setPhoneNumber(it?.toString()) } phoneNumberInputLayout.onFocusChangeListener = View.OnFocusChangeListener { _: View?, hasFocus: Boolean -> @@ -155,7 +175,6 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio } fragmentViewModel.supportedCountryPrefixes.firstOrNull { it.toString() == s.toString() }?.let { - // TODO [regv2]: setCountryFormatter(it.regionCode) fragmentViewModel.setCountry(it.digits) val numberLength: Int = phoneNumberInputLayout.text?.length ?: 0 phoneNumberInputLayout.setSelection(numberLength, numberLength) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2State.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2State.kt index 6f399443f6..d311bcaa6e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2State.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2State.kt @@ -5,10 +5,12 @@ package org.thoughtcrime.securesms.registration.v2.ui.phonenumber +import android.text.TextWatcher + /** * State holder for the phone number entry screen, including phone number and Play Services errors. */ -data class EnterPhoneNumberV2State(val countryPrefixIndex: Int, val phoneNumber: String, val error: Error = Error.NONE) { +data class EnterPhoneNumberV2State(val countryPrefixIndex: Int, val phoneNumber: String, val phoneNumberFormatter: TextWatcher? = null, val error: Error = Error.NONE) { companion object { @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2ViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2ViewModel.kt index 4a7804f67e..7920f69038 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2ViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/phonenumber/EnterPhoneNumberV2ViewModel.kt @@ -5,13 +5,18 @@ package org.thoughtcrime.securesms.registration.v2.ui.phonenumber +import android.telephony.PhoneNumberFormattingTextWatcher import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope import com.google.i18n.phonenumbers.NumberParseException import com.google.i18n.phonenumbers.PhoneNumberUtil import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.registration.util.CountryPrefix @@ -51,6 +56,18 @@ class EnterPhoneNumberV2ViewModel : ViewModel() { store.update { it.copy(countryPrefixIndex = matchingIndex) } + + viewModelScope.launch { + withContext(Dispatchers.Default) { + val regionCode = PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(digits) + val textWatcher = PhoneNumberFormattingTextWatcher(regionCode) + + store.update { + Log.d(TAG, "Updating phone number formatter in state") + it.copy(phoneNumberFormatter = textWatcher) + } + } + } } fun parsePhoneNumber(state: EnterPhoneNumberV2State): PhoneNumber { diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/welcome/WelcomeV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/welcome/WelcomeV2Fragment.kt index 1abb0512ba..cf4ca9b2bf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/welcome/WelcomeV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/v2/ui/welcome/WelcomeV2Fragment.kt @@ -9,7 +9,6 @@ import android.Manifest import android.content.pm.PackageManager import android.os.Bundle import android.view.View -import android.widget.Toast import androidx.core.content.ContextCompat import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.NavHostFragment @@ -21,9 +20,10 @@ import org.thoughtcrime.securesms.databinding.FragmentRegistrationWelcomeV2Bindi import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.registration.fragments.RegistrationViewDelegate.setDebugLogSubmitMultiTapView import org.thoughtcrime.securesms.registration.fragments.WelcomePermissions +import org.thoughtcrime.securesms.registration.v2.ui.RegistrationV2ViewModel import org.thoughtcrime.securesms.registration.v2.ui.grantpermissions.GrantPermissionsV2Fragment -import org.thoughtcrime.securesms.registration.v2.ui.shared.RegistrationV2ViewModel import org.thoughtcrime.securesms.util.BackupUtil +import org.thoughtcrime.securesms.util.CommunicationActions import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.navigation.safeNavigate @@ -33,7 +33,6 @@ import kotlin.jvm.optionals.getOrNull * First screen that is displayed on the very first app launch. */ class WelcomeV2Fragment : LoggingFragment(R.layout.fragment_registration_welcome_v2) { - private val TAG = Log.tag(WelcomeV2Fragment::class.java) private val sharedViewModel by activityViewModels() private val binding: FragmentRegistrationWelcomeV2Binding by ViewBinderDelegate(FragmentRegistrationWelcomeV2Binding::bind) @@ -44,7 +43,6 @@ class WelcomeV2Fragment : LoggingFragment(R.layout.fragment_registration_welcome setDebugLogSubmitMultiTapView(binding.title) binding.welcomeContinueButton.setOnClickListener { onContinueClicked() } binding.welcomeTermsButton.setOnClickListener { onTermsClicked() } - binding.welcomeTransferOrRestore.setOnClickListener { onRestoreFromBackupClicked() } } private fun onContinueClicked() { @@ -65,12 +63,8 @@ class WelcomeV2Fragment : LoggingFragment(R.layout.fragment_registration_welcome NavHostFragment.findNavController(this).safeNavigate(WelcomeV2FragmentDirections.actionSkipRestore()) } - private fun onRestoreFromBackupClicked() { - Toast.makeText(requireContext(), "Not yet implemented.", Toast.LENGTH_SHORT).show() - } - private fun onTermsClicked() { - Toast.makeText(requireContext(), "Not yet implemented.", Toast.LENGTH_SHORT).show() + CommunicationActions.openBrowserLink(requireContext(), TERMS_AND_CONDITIONS_URL) } private fun maybePrefillE164() { @@ -87,4 +81,9 @@ class WelcomeV2Fragment : LoggingFragment(R.layout.fragment_registration_welcome Log.i(TAG, "No phone permission.") } } + + companion object { + private val TAG = Log.tag(WelcomeV2Fragment::class.java) + private const val TERMS_AND_CONDITIONS_URL = "https://signal.org/legal" + } } diff --git a/app/src/main/res/layout/fragment_registration_welcome_v2.xml b/app/src/main/res/layout/fragment_registration_welcome_v2.xml index 5f5a350be4..e4914c5f42 100644 --- a/app/src/main/res/layout/fragment_registration_welcome_v2.xml +++ b/app/src/main/res/layout/fragment_registration_welcome_v2.xml @@ -55,6 +55,7 @@ app:layout_goneMarginBottom="@dimen/registration_button_bottom_margin" app:materialThemeOverlay="@style/ThemeOverlay.Signal.CircularProgressIndicator.Tonal" /> +