diff --git a/apps/flipcash/features/contact-verification/src/main/kotlin/com/flipcash/app/contact/verification/internal/phone/PhoneVerificationViewModel.kt b/apps/flipcash/features/contact-verification/src/main/kotlin/com/flipcash/app/contact/verification/internal/phone/PhoneVerificationViewModel.kt index 3b7aa8018..d5400125c 100644 --- a/apps/flipcash/features/contact-verification/src/main/kotlin/com/flipcash/app/contact/verification/internal/phone/PhoneVerificationViewModel.kt +++ b/apps/flipcash/features/contact-verification/src/main/kotlin/com/flipcash/app/contact/verification/internal/phone/PhoneVerificationViewModel.kt @@ -109,8 +109,23 @@ internal class PhoneVerificationViewModel @Inject constructor( .flatMapLatest { ts -> snapshotFlow { ts.text } } .distinctUntilChanged() .onEach { enteredNumber -> + val raw = enteredNumber.toString() + + // Handle autofilled international numbers (e.g. "+15551234567") + if (raw.contains("+")) { + val result = phoneUtils.parseInternationalNumber(raw) + if (result != null) { + val (locale, nationalNumber) = result + dispatchEvent(Event.OnCountrySelected(locale)) + stateFlow.value.numberTextFieldState.edit { + replace(0, length, nationalNumber) + } + return@onEach + } + } + val countryCode = stateFlow.value.selectedLocale.phoneCode.toString() - val phoneInputFiltered = enteredNumber.toString().replace("+$countryCode", "") + val phoneInputFiltered = raw.replace("+$countryCode", "") val phoneNumber = "+$countryCode$phoneInputFiltered" val formattedNumber = phoneUtils.formatNumber( number = phoneNumber, diff --git a/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/OtpInputField.kt b/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/OtpInputField.kt index abba90565..5fde12d4b 100644 --- a/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/OtpInputField.kt +++ b/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/OtpInputField.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import com.flipcash.app.theme.FlipcashPreview +import androidx.compose.ui.autofill.ContentType import com.getcode.theme.CodeTheme import com.getcode.theme.WindowSizeClass import com.getcode.ui.components.TextInput @@ -73,6 +74,7 @@ fun OtpInputField( } }, state = state, + contentType = ContentType.SmsOtpCode, keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), ) diff --git a/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/PhoneInputField.kt b/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/PhoneInputField.kt index 5f13fb883..4a46c47b4 100644 --- a/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/PhoneInputField.kt +++ b/apps/flipcash/shared/phone/src/main/kotlin/com/flipcash/app/phone/components/PhoneInputField.kt @@ -41,6 +41,7 @@ import com.flipcash.shared.phone.R import com.getcode.opencode.compose.ExchangeStub import com.getcode.opencode.compose.LocalExchange import com.getcode.theme.CodeTheme +import androidx.compose.ui.autofill.ContentType import com.getcode.ui.components.TextInput import com.getcode.ui.components.VerticalDivider import com.getcode.ui.core.rememberAnimationScale @@ -78,6 +79,7 @@ fun PhoneInputField( onKeyboardAction = { onSubmit() }, maxLines = 1, placeholder = placeholder, + contentType = ContentType.PhoneNumber + ContentType.PhoneNumberDevice, outputTransformation = outputTransformation, leadingIcon = { Row { diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/TextInput.kt b/ui/components/src/main/kotlin/com/getcode/ui/components/TextInput.kt index 6c816040a..7beac47cd 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/components/TextInput.kt +++ b/ui/components/src/main/kotlin/com/getcode/ui/components/TextInput.kt @@ -42,6 +42,9 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.datasource.LoremIpsum import androidx.compose.ui.unit.Dp +import androidx.compose.ui.autofill.ContentType +import androidx.compose.ui.semantics.contentType +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.getcode.theme.CodeTheme import com.getcode.theme.DesignSystem @@ -80,6 +83,7 @@ fun TextInput( constraintMode: ConstraintMode = ConstraintMode.Free, leadingIcon: (@Composable () -> Unit)? = null, trailingIcon: (@Composable () -> Unit)? = null, + contentType: ContentType? = null, scrollState: ScrollState = rememberScrollState(), ) { val backgroundColor by colors.backgroundColor(enabled = enabled) @@ -93,9 +97,20 @@ fun TextInput( var textSize by remember(style.fontSize) { mutableStateOf(style.fontSize) } + // Capture outside semantics lambda to avoid shadowing by + // SemanticsPropertyReceiver.contentType extension property. + val autofillContentType = contentType + Box(modifier = modifier) { BasicTextField( modifier = Modifier + .then( + if (autofillContentType != null) { + Modifier.semantics { this.contentType = autofillContentType } + } else { + Modifier + } + ) .background(backgroundColor, shape) .defaultMinSize(minHeight = minHeight) .constrain(