diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d63701b3c..5371665da9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [0.7.5] +* Fixed bug in `AsYouTypeFormatter` that could throw a `RangeError` if the user typed non digit characters + ## [0.7.4] * Updated minimum os version on iOS * Updated dependencies diff --git a/README.md b/README.md index 13a66f82c0..ebe752a64f 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ A simple and customizable flutter package for inputting phone number in intl / i ### What's new + - Replace libphonenumber_plugin with dlibphonenumber - Updated libphonenumber and PhoneNumberToCarrierMapper on Android - Removed dependency on libphonenumber - Switch from libphonenumber-iOS to PhoneNumberKit on iOS @@ -20,7 +21,7 @@ A simple and customizable flutter package for inputting phone number in intl / i ### Features - - Web support. + - Support all Flutter platforms. - Support for RTL languages - Selector mode dropdown, bottom sheet and dialog - As You Type Formatter: formats inputs to its selected international format @@ -35,33 +36,6 @@ A simple and customizable flutter package for inputting phone number in intl / i `controller reference`.text = parsableNumber ``` -### Web Support - -In your app directory, edit `web/index.html` to add the following - -```html - - - -
- ... - - - - ... - - - - - ... - - - - -``` - -Or checkout `/example` folder from [Github](https://github.com/natintosh/intl_phone_number_input/tree/develop/example). - ### Note ``` dart @@ -195,7 +169,7 @@ Made with [contributors-img](https://contributors-img.web.app). # Dependencies -* [libphonenumber](https://pub.dev/packages/libphonenumber) +* [dlibphonenumber](https://pub.dev/packages/dlibphonenumber) * [equatable](https://pub.dev/packages/equatable) # Credits diff --git a/lib/src/models/country_list.dart b/lib/src/models/country_list.dart index 5ff4714025..d8664d0d15 100644 --- a/lib/src/models/country_list.dart +++ b/lib/src/models/country_list.dart @@ -7466,7 +7466,7 @@ class Countries { "num_code": "826", "alpha_2_code": "GB", "alpha_3_code": "GBR", - "en_short_name": "United Kingdom of Great Britain and Northern Ireland", + "en_short_name": "United Kingdom of Great Britain", "nationality": "British, UK", "dial_code": "+44", "nameTranslations": { diff --git a/lib/src/utils/formatter/as_you_type_formatter.dart b/lib/src/utils/formatter/as_you_type_formatter.dart index 411ee6a9d1..6d2ca22a09 100644 --- a/lib/src/utils/formatter/as_you_type_formatter.dart +++ b/lib/src/utils/formatter/as_you_type_formatter.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/services.dart'; import 'package:intl_phone_number_input/src/utils/phone_number/phone_number_util.dart'; @@ -38,61 +40,69 @@ class AsYouTypeFormatter extends TextInputFormatter { if (newValueLength > 0 && newValueLength > oldValueLength) { String newValueText = newValue.text; String rawText = newValueText.replaceAll(separatorChars, ''); - String textToParse = dialCode + rawText; - final _ = newValueText - .substring( - oldValue.selection.start == -1 ? 0 : oldValue.selection.start, - newValue.selection.end == -1 ? 0 : newValue.selection.end) - .replaceAll(separatorChars, ''); + int rawCursorPosition = newValue.selection.end; + + int digitsBeforeCursor = 0, digitsAfterCursor = 0; + + if (rawCursorPosition > 0 && rawCursorPosition <= newValueText.length) { + final rawTextBeforeCursor = newValueText + .substring(0, rawCursorPosition) + .replaceAll(separatorChars, ''); + final rawTextAfterCursor = newValueText + .substring(rawCursorPosition) + .replaceAll(separatorChars, ''); + + digitsBeforeCursor = rawTextBeforeCursor.length; + digitsAfterCursor = rawTextAfterCursor.length; + } + + String textToParse = dialCode + rawText; formatAsYouType(input: textToParse).then( (String? value) { String parsedText = parsePhoneNumber(value); - int offset = - newValue.selection.end == -1 ? 0 : newValue.selection.end; - - if (separatorChars.hasMatch(parsedText)) { - String valueInInputIndex = parsedText[offset - 1]; + int newCursorPosition = 0; - if (offset < parsedText.length) { - int offsetDifference = parsedText.length - offset; + if (digitsBeforeCursor > 0 || digitsAfterCursor > 0) { + for (var i = 0; i < parsedText.length; i++) { + final startCursor = i; - if (offsetDifference < 2) { - if (separatorChars.hasMatch(valueInInputIndex)) { - offset += 1; + if (allowedChars.hasMatch(parsedText[startCursor])) { + if (digitsBeforeCursor > 0) { + digitsBeforeCursor--; } else { - bool isLastChar; - try { - var _ = newValueText[newValue.selection.end]; - isLastChar = false; - } on RangeError { - isLastChar = true; - } - if (isLastChar) { - offset += offsetDifference; - } + newCursorPosition = startCursor + 1; + break; } - } else { - if (parsedText.length > offset - 1) { - if (separatorChars.hasMatch(valueInInputIndex)) { - offset += 1; - } + } + + final endCursor = parsedText.length - 1 - i; + + if (allowedChars.hasMatch(parsedText[endCursor])) { + if (digitsAfterCursor > 0) { + digitsAfterCursor--; + } else { + newCursorPosition = endCursor + 1; + break; } } } - - this.onInputFormatted( - TextEditingValue( - text: parsedText, - selection: TextSelection.collapsed(offset: offset), - ), - ); } + + newCursorPosition = min(max(newCursorPosition, 0), parsedText.length); + + this.onInputFormatted( + TextEditingValue( + text: parsedText, + selection: TextSelection.collapsed(offset: newCursorPosition), + ), + ); }, ); } + return newValue; } diff --git a/lib/src/utils/phone_number/phone_number_util.dart b/lib/src/utils/phone_number/phone_number_util.dart index ffabe47067..5dc8838281 100644 --- a/lib/src/utils/phone_number/phone_number_util.dart +++ b/lib/src/utils/phone_number/phone_number_util.dart @@ -1,8 +1,9 @@ +import 'package:dlibphonenumber/dlibphonenumber.dart' as p; import 'package:intl_phone_number_input/src/utils/phone_number.dart'; -import 'package:libphonenumber_plugin/libphonenumber_plugin.dart' as p; -/// A wrapper class [PhoneNumberUtil] that basically switch between plugin available for `Web` or `Android or IOS` and `Other platforms` when available. class PhoneNumberUtil { + static p.PhoneNumberUtil phoneUtil = p.PhoneNumberUtil.instance; + /// [isValidNumber] checks if a [phoneNumber] is valid. /// Accepts [phoneNumber] and [isoCode] /// Returns [Future