Skip to content

Commit 9f018a0

Browse files
feat(android): add hint text parameters to CardFormField (#2296)
* feat(android): add hint text parameters to CardFormField Add numberHintText, expirationHintText, cvcHintText, and postalCodeHintText parameters to CardFormField widget for consistency with CardField. These parameters allow customizing placeholder text for card input fields. Note: This feature is Android-only as iOS's STPCardFormView does not support placeholder customization. Fixes #2277 * Regenerate code after giropay removal * ci: add server readiness check before integration tests --------- Co-authored-by: jonasbark <jonas.bark@gmx.de>
1 parent 52d2325 commit 9f018a0

File tree

2 files changed

+80
-2
lines changed

2 files changed

+80
-2
lines changed

.github/workflows/all_plugins.yaml

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,18 @@ jobs:
108108
working-directory: example/server
109109
run: yarn install && (yarn start:dev &)
110110

111+
- name: "Wait for server to be ready"
112+
run: |
113+
echo "Waiting for server to start..."
114+
for i in {1..30}; do
115+
if curl -s http://localhost:4242 > /dev/null 2>&1; then
116+
echo "Server is ready!"
117+
break
118+
fi
119+
echo "Attempt $i: Server not ready yet, waiting..."
120+
sleep 2
121+
done
122+
111123
- name: "Set IP address"
112124
working-directory: example
113125
run: |
@@ -161,6 +173,18 @@ jobs:
161173
working-directory: example/server
162174
run: yarn install && (yarn start:dev &)
163175

176+
- name: "Wait for server to be ready"
177+
run: |
178+
echo "Waiting for server to start..."
179+
for i in {1..30}; do
180+
if curl -s http://localhost:4242 > /dev/null 2>&1; then
181+
echo "Server is ready!"
182+
break
183+
fi
184+
echo "Attempt $i: Server not ready yet, waiting..."
185+
sleep 2
186+
done
187+
164188
- name: "Set IP address"
165189
working-directory: example
166190
run: |
@@ -172,9 +196,12 @@ jobs:
172196
with:
173197
api-level: 34
174198
arch: x86_64
175-
emulator-boot-timeout: 1400
199+
emulator-boot-timeout: 1800
200+
force-avd-creation: false
201+
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
202+
disable-animations: true
176203
working-directory: example
177-
script: |
204+
script: |
178205
sleep 15;
179206
flutter drive --driver test_driver/integration_test.dart --target=integration_test/run_all_tests.dart;
180207
cd android && ./gradlew :app:connectedDebugAndroidTest;

packages/stripe/lib/src/widgets/card_form_field.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class CardFormField extends StatefulWidget {
3030
this.disabled = false,
3131
this.controller,
3232
this.preferredNetworks,
33+
this.numberHintText,
34+
this.expirationHintText,
35+
this.cvcHintText,
36+
this.postalCodeHintText,
3337
super.key,
3438
});
3539

@@ -93,6 +97,18 @@ class CardFormField extends StatefulWidget {
9397
/// This value will only be used if your user hasn't selected a network themselves.
9498
final List<CardBrand>? preferredNetworks;
9599

100+
/// Android only: Hint text for the card number field.
101+
final String? numberHintText;
102+
103+
/// Android only: Hint text for the expiration date field.
104+
final String? expirationHintText;
105+
106+
/// Android only: Hint text for the cvc field.
107+
final String? cvcHintText;
108+
109+
/// Android only: Hint text for the postal code field.
110+
final String? postalCodeHintText;
111+
96112
@override
97113
// ignore: library_private_types_in_public_api
98114
_CardFormFieldState createState() => _CardFormFieldState();
@@ -207,6 +223,10 @@ class _CardFormFieldState extends State<CardFormField> {
207223
onFocus: widget.onFocus,
208224
countryCode: widget.countryCode,
209225
preferredNetworks: widget.preferredNetworks,
226+
numberHintText: widget.numberHintText,
227+
expirationHintText: widget.expirationHintText,
228+
cvcHintText: widget.cvcHintText,
229+
postalCodeHintText: widget.postalCodeHintText,
210230
);
211231
}
212232

@@ -232,6 +252,10 @@ class _MethodChannelCardFormField extends StatefulWidget {
232252
this.disabled = false,
233253
this.preferredNetworks,
234254
this.countryCode,
255+
this.numberHintText,
256+
this.expirationHintText,
257+
this.cvcHintText,
258+
this.postalCodeHintText,
235259
}) : assert(constraints == null || constraints.debugAssertIsValid()),
236260
constraints = (width != null || height != null)
237261
? constraints?.tighten(width: width, height: height) ??
@@ -251,6 +275,10 @@ class _MethodChannelCardFormField extends StatefulWidget {
251275
final bool dangerouslyUpdateFullCardDetails;
252276
final String? countryCode;
253277
final List<CardBrand>? preferredNetworks;
278+
final String? numberHintText;
279+
final String? expirationHintText;
280+
final String? cvcHintText;
281+
final String? postalCodeHintText;
254282

255283
// This is used in the platform side to register the view.
256284
static const _viewType = 'flutter.stripe/card_form_field';
@@ -312,6 +340,14 @@ class _MethodChannelCardFormFieldState
312340
Widget build(BuildContext context) {
313341
final style = resolveStyle(widget.style);
314342
// Pass parameters to the platform side.
343+
// Build placeholder map for hint text (Android only)
344+
final placeholder = <String, dynamic>{
345+
if (widget.numberHintText != null) 'number': widget.numberHintText,
346+
if (widget.expirationHintText != null) 'expiration': widget.expirationHintText,
347+
if (widget.cvcHintText != null) 'cvc': widget.cvcHintText,
348+
if (widget.postalCodeHintText != null) 'postalCode': widget.postalCodeHintText,
349+
};
350+
315351
final creationParams = <String, dynamic>{
316352
'cardStyle': style.toJson(),
317353
'postalCodeEnabled': widget.enablePostalCode,
@@ -326,6 +362,7 @@ class _MethodChannelCardFormFieldState
326362
.toList(),
327363
'disabled': widget.disabled,
328364
'defaultValues': {'countryCode': widget.countryCode},
365+
if (placeholder.isNotEmpty) 'placeholders': placeholder,
329366
};
330367

331368
Widget platform;
@@ -433,6 +470,20 @@ class _MethodChannelCardFormFieldState
433470
});
434471
}
435472
_lastStyle = style;
473+
// Handle placeholder/hint text changes (Android only)
474+
if (widget.numberHintText != oldWidget.numberHintText ||
475+
widget.expirationHintText != oldWidget.expirationHintText ||
476+
widget.cvcHintText != oldWidget.cvcHintText ||
477+
widget.postalCodeHintText != oldWidget.postalCodeHintText) {
478+
final placeholder = <String, dynamic>{
479+
if (widget.numberHintText != null) 'number': widget.numberHintText,
480+
if (widget.expirationHintText != null) 'expiration': widget.expirationHintText,
481+
if (widget.cvcHintText != null) 'cvc': widget.cvcHintText,
482+
if (widget.postalCodeHintText != null) 'postalCode': widget.postalCodeHintText,
483+
};
484+
// Use 'placeholders' as method name - Android delegate uses it as property name
485+
_methodChannel?.invokeMethod('placeholders', placeholder);
486+
}
436487
super.didUpdateWidget(oldWidget);
437488
}
438489

0 commit comments

Comments
 (0)