From cfe59868bff376cd35aca5fb30f3e9c5ccd0e535 Mon Sep 17 00:00:00 2001 From: cedvdb Date: Wed, 27 Mar 2024 10:00:30 +0100 Subject: [PATCH] Add country button style (#233) * saving * slots * saving * saving * country button style * saving * country button style --- CHANGELOG.md | 8 +++- example/lib/main.dart | 8 +++- example/pubspec.lock | 6 +-- lib/phone_form_field.dart | 1 + lib/src/country_button.dart | 18 ++++----- lib/src/country_button_style.dart | 57 +++++++++++++++++++++++++++++ lib/src/phone_form_field.dart | 41 +++++++++------------ lib/src/phone_form_field_state.dart | 24 +++++------- pubspec.yaml | 2 +- test/phone_form_field_test.dart | 12 ++++-- 10 files changed, 119 insertions(+), 58 deletions(-) create mode 100644 lib/src/country_button_style.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index fdac9c98..ea047147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ -## [9.1.1] +## [9.2.0] - add missing translation messages +- add Hungarian localization messages - fix RTL +- added `showDropdownIndicator` +- deprecate country button stylings properties in favor of one `countryButtonStyle` property +- add showDropdownIcon bool ## [9.1.0] @@ -33,7 +37,7 @@ - Added some missing countries - [Breaking] : no validation done by default - [Breaking] : provided validators now require a context parameter -- [Breaking] : `LocalizedCountryRegistry` removed. If you were using it to localize a country name, you should use `PhoneFieldLocalization.of(context).countryName(isoCode)`. +- [Breaking] : `LocalizedCountryRegistry` removed. If you were using it to localize a country name, you should use `CountrySelectorLocalization.of(context).countryName(isoCode)`. - [Deprecated] : `isCountryChipPersistent` in favor of `isCountryButtonPersistent`. - [Deprecated] : `shouldFormat`, it is now always ON by default - [Deprecated] : `defaultCountry`, you should now use either `initialValue` or provide a controller with an initial value. diff --git a/example/lib/main.dart b/example/lib/main.dart index 9bab2010..b3982800 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -61,8 +61,12 @@ class PhoneFieldView extends StatelessWidget { hintText: withLabel ? '' : 'Phone', ), enabled: true, - showIsoCodeInInput: false, - showFlagInInput: true, + countryButtonStyle: const CountryButtonStyle( + showFlag: true, + showIsoCode: false, + showDialCode: true, + showDropdownIcon: true, + ), validator: _getValidator(context), autovalidateMode: AutovalidateMode.onUserInteraction, cursorColor: Theme.of(context).colorScheme.primary, diff --git a/example/pubspec.lock b/example/pubspec.lock index 6f5eacae..9f062fde 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -222,15 +222,15 @@ packages: path: ".." relative: true source: path - version: "9.0.5" + version: "9.1.1" phone_numbers_parser: dependency: transitive description: name: phone_numbers_parser - sha256: d0dad4f5b61c3d959b069df088ef7242ffed42a3cf74c7549fd7c324e1eb964e + sha256: ebe08725e63218a6ae2bf9129b7130332cb2ababa4988f07d6ddce48b0c21e06 url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.2.1" sky_engine: dependency: transitive description: flutter diff --git a/lib/phone_form_field.dart b/lib/phone_form_field.dart index 3316582f..f3af5387 100644 --- a/lib/phone_form_field.dart +++ b/lib/phone_form_field.dart @@ -3,6 +3,7 @@ library phone_number_input; export 'src/phone_form_field.dart'; export 'src/country_selector_navigator.dart'; export 'src/country_button.dart'; +export 'src/country_button_style.dart'; export 'src/validation/phone_validator.dart'; export 'src/localization/localization.dart'; diff --git a/lib/src/country_button.dart b/lib/src/country_button.dart index 3566aa5d..3f7d16f2 100644 --- a/lib/src/country_button.dart +++ b/lib/src/country_button.dart @@ -8,13 +8,13 @@ typedef CountryChip = CountryButton; class CountryButton extends StatelessWidget { final Function()? onTap; final IsoCode isoCode; - final bool showFlag; - final bool showDialCode; final TextStyle? textStyle; final EdgeInsets padding; final double flagSize; - final TextDirection? textDirection; + final bool showFlag; + final bool showDialCode; final bool showIsoCode; + final bool showDropdownIcon; final bool enabled; const CountryButton({ @@ -22,19 +22,19 @@ class CountryButton extends StatelessWidget { required this.isoCode, required this.onTap, this.textStyle, - this.showFlag = true, - this.showDialCode = true, this.padding = const EdgeInsets.fromLTRB(12, 16, 4, 16), this.flagSize = 20, - this.textDirection, + this.showFlag = true, + this.showDialCode = true, this.showIsoCode = false, + this.showDropdownIcon = true, this.enabled = true, }); @override Widget build(BuildContext context) { final textStyle = this.textStyle ?? - Theme.of(context).textTheme.labelMedium ?? + Theme.of(context).textTheme.bodyMedium?.copyWith(fontSize: 16) ?? const TextStyle(); final countryLocalization = CountrySelectorLocalization.of(context) ?? CountrySelectorLocalizationEn(); @@ -71,10 +71,10 @@ class CountryButton extends StatelessWidget { style: textStyle.copyWith( color: enabled ? null : Theme.of(context).disabledColor, ), - textDirection: textDirection, ), ], - const ExcludeSemantics(child: Icon(Icons.arrow_drop_down)), + if (showDropdownIcon) + const ExcludeSemantics(child: Icon(Icons.arrow_drop_down)), ], ), ), diff --git a/lib/src/country_button_style.dart b/lib/src/country_button_style.dart new file mode 100644 index 00000000..5db0d9c7 --- /dev/null +++ b/lib/src/country_button_style.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +class CountryButtonStyle { + /// Text style of the country dial code inside the country button + final TextStyle? textStyle; + + /// padding inside country button, + /// this can be used to align the country button with the phone number + /// and is mostly useful when using [isCountryButtonPersistent] as true. + final EdgeInsets? padding; + + /// The radius of the flag in the country button + final double flagSize; + + /// Wether to show the country flag in the country button + final bool showFlag; + + /// Whether to show Dial Code in the country button + /// setting this to false will hide, for example, (+1) + final bool showDialCode; + + /// Wether to show the country iso code in the country button + final bool showIsoCode; + + /// Wether to show the dropdown icon in the country button + final bool showDropdownIcon; + + const CountryButtonStyle({ + this.textStyle, + this.padding, + this.flagSize = 20, + this.showFlag = true, + this.showDialCode = true, + this.showIsoCode = false, + this.showDropdownIcon = true, + }); + + CountryButtonStyle copyWith({ + TextStyle? textStyle, + EdgeInsets? padding, + double? flagSize, + bool? showFlag, + bool? showDialCode, + bool? showIsoCode, + bool? showDropdownIcon, + }) { + return CountryButtonStyle( + textStyle: textStyle ?? this.textStyle, + padding: padding ?? this.padding, + flagSize: flagSize ?? this.flagSize, + showFlag: showFlag ?? this.showFlag, + showDialCode: showDialCode ?? this.showDialCode, + showIsoCode: showIsoCode ?? this.showIsoCode, + showDropdownIcon: showDropdownIcon ?? this.showDropdownIcon, + ); + } +} diff --git a/lib/src/phone_form_field.dart b/lib/src/phone_form_field.dart index f1d149fe..30b64839 100644 --- a/lib/src/phone_form_field.dart +++ b/lib/src/phone_form_field.dart @@ -49,11 +49,6 @@ class PhoneFormField extends FormField { /// how to display the country selection final CountrySelectorNavigator countrySelectorNavigator; - /// padding inside country button, - /// this can be used to align the country button with the phone number - /// and is mostly useful when using [isCountryButtonPersistent] as true. - final EdgeInsets? countryButtonPadding; - /// whether the user can select a new country when pressing the country button final bool isCountrySelectionEnabled; @@ -63,24 +58,14 @@ class PhoneFormField extends FormField { /// the text field. final bool isCountryButtonPersistent; - /// show Dial Code or not in the country button - final bool showDialCode; - - /// show selected iso code or not in the country button - final bool showIsoCodeInInput; - - /// The size of the flag inside the country button - final double flagSize; - - /// whether the flag is shown inside the country button - final bool showFlagInInput; + /// The style of the country selector button + final CountryButtonStyle countryButtonStyle; // textfield inputs final InputDecoration decoration; final TextInputType keyboardType; final TextInputAction? textInputAction; final TextStyle? style; - final TextStyle? countryCodeStyle; final StrutStyle? strutStyle; final TextAlign? textAlign; final TextAlignVertical? textAlignVertical; @@ -122,19 +107,22 @@ class PhoneFormField extends FormField { this.shouldFormat = true, this.onChanged, this.focusNode, - this.showFlagInInput = true, this.countrySelectorNavigator = const CountrySelectorNavigator.page(), @Deprecated( 'Use [initialValue] or [controller] to set the initial phone number') this.defaultCountry = IsoCode.US, - this.flagSize = 16, this.isCountrySelectionEnabled = true, bool? isCountryButtonPersistent, @Deprecated('Use [isCountryButtonPersistent]') bool? isCountryChipPersistent, - this.showDialCode = true, - this.showIsoCodeInInput = false, - this.countryButtonPadding, + @Deprecated('Use [CountryButtonStyle] instead') bool? showFlagInInput, + @Deprecated('Use [CountryButtonStyle] instead') bool? showDialCode, + @Deprecated('Use [CountryButtonStyle] instead') bool? showIsoCodeInInput, + @Deprecated('Use [CountryButtonStyle] instead') + EdgeInsets? countryButtonPadding, + @Deprecated('Use [CountryButtonStyle] instead') double? flagSize, + @Deprecated('Use [CountryButtonStyle] instead') TextStyle? countryCodeStyle, + CountryButtonStyle countryButtonStyle = const CountryButtonStyle(), // form field inputs super.validator, PhoneNumber? initialValue, @@ -147,7 +135,6 @@ class PhoneFormField extends FormField { this.keyboardType = TextInputType.phone, this.textInputAction, this.style, - this.countryCodeStyle, this.strutStyle, @Deprecated('Has no effect, Change text directionality instead') this.textAlign, @@ -187,6 +174,14 @@ class PhoneFormField extends FormField { ), isCountryButtonPersistent = isCountryButtonPersistent ?? isCountryChipPersistent ?? true, + countryButtonStyle = countryButtonStyle.copyWith( + showFlag: showFlagInInput, + showDialCode: showDialCode, + showIsoCode: showIsoCodeInInput, + padding: countryButtonPadding, + flagSize: flagSize, + textStyle: countryCodeStyle, + ), super( builder: (state) => (state as PhoneFormFieldState).builder(), initialValue: controller?.value ?? initialValue, diff --git a/lib/src/phone_form_field_state.dart b/lib/src/phone_form_field_state.dart index 9da44474..3b0f9d79 100644 --- a/lib/src/phone_form_field_state.dart +++ b/lib/src/phone_form_field_state.dart @@ -175,16 +175,11 @@ class PhoneFormFieldState extends FormFieldState { isoCode: controller.value.isoCode, onTap: widget.enabled ? _selectCountry : null, padding: _computeCountryButtonPadding(context), - showFlag: widget.showFlagInInput, - showIsoCode: widget.showIsoCodeInInput, - showDialCode: widget.showDialCode, - textStyle: widget.countryCodeStyle ?? - widget.decoration.labelStyle ?? - TextStyle( - fontSize: 16, - color: Theme.of(context).textTheme.bodySmall?.color, - ), - flagSize: widget.flagSize, + showFlag: widget.countryButtonStyle.showFlag, + showIsoCode: widget.countryButtonStyle.showIsoCode, + showDialCode: widget.countryButtonStyle.showDialCode, + textStyle: widget.countryButtonStyle.textStyle, + flagSize: widget.countryButtonStyle.flagSize, enabled: widget.enabled, ), ), @@ -201,7 +196,7 @@ class PhoneFormFieldState extends FormFieldState { /// - is country button shown as a prefix or prefixIcon (isCountryChipPersistent) /// - text direction EdgeInsets _computeCountryButtonPadding(BuildContext context) { - final countryButtonPadding = widget.countryButtonPadding; + final userDefinedPadding = widget.countryButtonStyle.padding; final isUnderline = widget.decoration.border is UnderlineInputBorder; final hasLabel = widget.decoration.label != null || widget.decoration.labelText != null; @@ -210,9 +205,10 @@ class PhoneFormFieldState extends FormFieldState { EdgeInsets padding = isLtr ? const EdgeInsets.fromLTRB(12, 16, 4, 16) : const EdgeInsets.fromLTRB(4, 16, 12, 16); - if (countryButtonPadding != null) { - padding = countryButtonPadding; - } else if (!widget.isCountryButtonPersistent) { + if (userDefinedPadding != null) { + return userDefinedPadding; + } + if (!widget.isCountryButtonPersistent) { padding = isLtr ? const EdgeInsets.only(right: 4, left: 12) : const EdgeInsets.only(left: 4, right: 12); diff --git a/pubspec.yaml b/pubspec.yaml index e0431b9d..3f40d18f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: phone_form_field description: Flutter phone input integrated with flutter internationalization -version: 9.1.1 +version: 9.2.0 homepage: https://github.com/cedvdb/phone_form_field environment: diff --git a/test/phone_form_field_test.dart b/test/phone_form_field_test.dart index 68e4a63d..e7ec390b 100644 --- a/test/phone_form_field_test.dart +++ b/test/phone_form_field_test.dart @@ -34,8 +34,10 @@ void main() { onChanged: onChanged, onSaved: onSaved, onTapOutside: onTapOutside, - showFlagInInput: showFlagInInput, - showDialCode: showDialCode, + countryButtonStyle: CountryButtonStyle( + showFlag: showFlagInInput, + showDialCode: showDialCode, + ), controller: controller, validator: validatorBuilder?.call(context), enabled: enabled, @@ -167,13 +169,15 @@ void main() { ); }); - testWidgets('Should get value of controller as initial value', (tester) async { + testWidgets('Should get value of controller as initial value', + (tester) async { final controller = PhoneController(); final phoneNumber = PhoneNumber.parse('+33488997722'); controller.value = phoneNumber; await tester.pumpWidget(getWidget(controller: controller)); - final PhoneFormFieldState phoneFieldState = tester.state(find.byType(PhoneFormField)); + final PhoneFormFieldState phoneFieldState = + tester.state(find.byType(PhoneFormField)); expect(phoneFieldState.value, equals(phoneNumber)); });