Skip to content

Commit 14bd643

Browse files
gbourassaclaude
andauthored
Integrate contentType in Android PilotTextField for password obscuring and autofill. (#34)
- Created PilotTextContentType.composeValue extension mapping all content types to Compose ContentType for autofill hints - Updated PilotTextField to use PasswordVisualTransformation when contentType is Password or NewPassword - Applied contentType semantics for Android autofill support - Added .claude/ to .gitignore This brings Android behavior in line with iOS, where contentType controls password field obscuring. Password visibility can be toggled by the client changing contentType between Password and NotSet. Co-authored-by: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
1 parent b22d2a7 commit 14bd643

3 files changed

Lines changed: 55 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.idea/
22
.kotlin/
3+
.claude/
34
.gradle
45
*.iml
56
/local.properties

components/android/material3/src/main/kotlin/com/mirego/pilot/components/ui/material3/PilotTextField.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ import androidx.compose.runtime.getValue
1515
import androidx.compose.runtime.remember
1616
import androidx.compose.ui.Modifier
1717
import androidx.compose.ui.graphics.Shape
18+
import androidx.compose.ui.semantics.contentType
19+
import androidx.compose.ui.semantics.semantics
1820
import androidx.compose.ui.text.TextStyle
21+
import androidx.compose.ui.text.input.PasswordVisualTransformation
1922
import com.mirego.pilot.components.PilotTextField
23+
import com.mirego.pilot.components.type.PilotTextContentType
2024
import com.mirego.pilot.components.ui.PilotFormattedVisualTransformation
2125
import com.mirego.pilot.components.ui.mergeWith
2226
import com.mirego.pilot.components.ui.type.composeValue
@@ -50,6 +54,13 @@ public fun PilotTextField(
5054
val autoCorrect by pilotTextField.autoCorrect.collectAsState()
5155
val keyboardType by pilotTextField.keyboardType.collectAsState()
5256
val keyboardReturnKeyType by pilotTextField.keyboardReturnKeyType.collectAsState()
57+
val textContentType by pilotTextField.contentType.collectAsState()
58+
59+
val modifierWithSemantics = textContentType.composeValue?.let { composeContentType ->
60+
modifier.semantics {
61+
contentType = composeContentType
62+
}
63+
} ?: modifier
5364

5465
OutlinedTextField(
5566
value = textValue,
@@ -61,15 +72,18 @@ public fun PilotTextField(
6172
style = placeHolderStyle,
6273
)
6374
},
64-
modifier = modifier,
75+
modifier = modifierWithSemantics,
6576
textStyle = textStyle,
6677
label = label,
6778
leadingIcon = leadingIcon,
6879
trailingIcon = trailingIcon,
6980
prefix = prefix,
7081
suffix = suffix,
7182
supportingText = supportingText,
72-
visualTransformation = PilotFormattedVisualTransformation(pilotTextField.formatText),
83+
visualTransformation = when (textContentType) {
84+
PilotTextContentType.Password, PilotTextContentType.NewPassword -> PasswordVisualTransformation()
85+
else -> PilotFormattedVisualTransformation(pilotTextField.formatText)
86+
},
7387
isError = isError,
7488
keyboardActions = pilotTextField.mergeWith(keyboardActions),
7589
keyboardOptions = KeyboardOptions(
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.mirego.pilot.components.ui.type
2+
3+
import androidx.compose.ui.autofill.ContentType
4+
import com.mirego.pilot.components.InternalPilotComponentsApi
5+
import com.mirego.pilot.components.type.PilotTextContentType
6+
7+
@InternalPilotComponentsApi
8+
public val PilotTextContentType.composeValue: ContentType?
9+
get() = when (this) {
10+
PilotTextContentType.NotSet -> null
11+
PilotTextContentType.Name -> ContentType.PersonFullName
12+
PilotTextContentType.NamePrefix -> ContentType.PersonNamePrefix
13+
PilotTextContentType.GivenName -> ContentType.PersonFirstName
14+
PilotTextContentType.MiddleName -> ContentType.PersonMiddleName
15+
PilotTextContentType.FamilyName -> ContentType.PersonLastName
16+
PilotTextContentType.NameSuffix -> ContentType.PersonNameSuffix
17+
PilotTextContentType.Nickname -> ContentType.PersonFullName
18+
PilotTextContentType.JobTitle -> null
19+
PilotTextContentType.OrganizationName -> null
20+
PilotTextContentType.Location -> null
21+
PilotTextContentType.FullStreetAddress -> ContentType.AddressStreet
22+
PilotTextContentType.StreetAddressLine1 -> ContentType.AddressStreet
23+
PilotTextContentType.StreetAddressLine2 -> ContentType.AddressAuxiliaryDetails
24+
PilotTextContentType.AddressCity -> ContentType.AddressLocality
25+
PilotTextContentType.AddressState -> ContentType.AddressRegion
26+
PilotTextContentType.AddressCityAndState -> ContentType.AddressLocality + ContentType.AddressRegion
27+
PilotTextContentType.Sublocality -> ContentType.AddressLocality
28+
PilotTextContentType.CountryName -> ContentType.AddressCountry
29+
PilotTextContentType.PostalCode -> ContentType.PostalCode
30+
PilotTextContentType.TelephoneNumber -> ContentType.PhoneNumber
31+
PilotTextContentType.EmailAddress -> ContentType.EmailAddress
32+
PilotTextContentType.URL -> null
33+
PilotTextContentType.CreditCardNumber -> ContentType.CreditCardNumber
34+
PilotTextContentType.Username -> ContentType.Username
35+
PilotTextContentType.Password -> ContentType.Password
36+
PilotTextContentType.NewPassword -> ContentType.NewPassword
37+
PilotTextContentType.OneTimeCode -> ContentType.SmsOtpCode
38+
}

0 commit comments

Comments
 (0)