From 99daf454ef9f6b0a20f368e9a8a31a26d1764842 Mon Sep 17 00:00:00 2001 From: Shaikh Aman Date: Sat, 13 Nov 2021 14:08:47 +0530 Subject: [PATCH 1/6] fixed length as single digit --- example/pubspec.lock | 6 +++--- lib/otp_field.dart | 43 ++++++++++++++++++++++--------------------- pubspec.lock | 6 +++--- pubspec.yaml | 2 +- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 44ee69a..05c25b1 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.6.1" boolean_selector: dependency: transitive description: @@ -106,7 +106,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" stack_trace: dependency: transitive description: @@ -141,7 +141,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19" + version: "0.3.0" typed_data: dependency: transitive description: diff --git a/lib/otp_field.dart b/lib/otp_field.dart index 6c0f9a7..a10fd69 100644 --- a/lib/otp_field.dart +++ b/lib/otp_field.dart @@ -32,20 +32,20 @@ class OTPTextField extends StatefulWidget { final bool obscureText; /// Text Field Style - final OtpFieldStyle? otpFieldStyle; + final OtpFieldStyle otpFieldStyle; /// Text Field Style for field shape. /// default FieldStyle.underline [FieldStyle] final FieldStyle fieldStyle; /// Callback function, called when a change is detected to the pin. - final ValueChanged? onChanged; + final ValueChanged onChanged; /// Callback function, called when pin is completed. - final ValueChanged? onCompleted; + final ValueChanged onCompleted; OTPTextField( - {Key? key, + {Key key, this.length = 4, this.width = 10, this.fieldWidth = 30, @@ -66,25 +66,25 @@ class OTPTextField extends StatefulWidget { } class _OTPTextFieldState extends State { - late OtpFieldStyle _otpFieldStyle; - late List _focusNodes; - late List _textControllers; + OtpFieldStyle _otpFieldStyle; + List _focusNodes; + List _textControllers; - late List _textFields; - late List _pin; + List _textFields; + List _pin; @override void initState() { if (widget.otpFieldStyle == null) { _otpFieldStyle = OtpFieldStyle(); } else { - _otpFieldStyle = widget.otpFieldStyle!; + _otpFieldStyle = widget.otpFieldStyle; } super.initState(); - _focusNodes = List.filled(widget.length, null, growable: false); - _textControllers = List.filled(widget.length, null, + _focusNodes = List.filled(widget.length, null, growable: false); + _textControllers = List.filled(widget.length, null, growable: false); _pin = List.generate(widget.length, (int i) { @@ -98,7 +98,7 @@ class _OTPTextFieldState extends State { @override void dispose() { _textControllers - .forEach((TextEditingController? controller) => controller!.dispose()); + .forEach((TextEditingController controller) => controller.dispose()); super.dispose(); } @@ -131,6 +131,7 @@ class _OTPTextFieldState extends State { color: _otpFieldStyle.backgroundColor, borderRadius: BorderRadius.circular(widget.outlineBorderRadius)), child: TextField( + maxLength: 1, controller: _textControllers[i], keyboardType: widget.keyboardType, textAlign: TextAlign.center, @@ -154,8 +155,8 @@ class _OTPTextFieldState extends State { // If it is move focus to previous text field. if (str.isEmpty) { if (i == 0) return; - _focusNodes[i]!.unfocus(); - _focusNodes[i - 1]!.requestFocus(); + _focusNodes[i].unfocus(); + _focusNodes[i - 1].requestFocus(); } // Update the current pin @@ -164,7 +165,7 @@ class _OTPTextFieldState extends State { }); // Remove focus - if (str.isNotEmpty) _focusNodes[i]!.unfocus(); + if (str.isNotEmpty) _focusNodes[i].unfocus(); // Set focus to the next field if available if (i + 1 != widget.length && str.isNotEmpty) FocusScope.of(context).requestFocus(_focusNodes[i + 1]); @@ -176,11 +177,11 @@ class _OTPTextFieldState extends State { if (!_pin.contains(null) && !_pin.contains('') && currentPin.length == widget.length) { - widget.onCompleted!(currentPin); + widget.onCompleted(currentPin); } // Call the `onChanged` callback function - widget.onChanged!(currentPin); + widget.onChanged(currentPin); }, ), ); @@ -209,7 +210,7 @@ class _OTPTextFieldState extends State { for (int i = 0; i < str.length; i++) { String digit = str.substring(i, i + 1); - _textControllers[i]!.text = digit; + _textControllers[i].text = digit; _pin[i] = digit; } @@ -222,10 +223,10 @@ class _OTPTextFieldState extends State { if (!_pin.contains(null) && !_pin.contains('') && currentPin.length == widget.length) { - widget.onCompleted!(currentPin); + widget.onCompleted(currentPin); } // Call the `onChanged` callback function - widget.onChanged!(currentPin); + widget.onChanged(currentPin); } } diff --git a/pubspec.lock b/pubspec.lock index 49a0ce6..ad6d1df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.6.1" boolean_selector: dependency: transitive description: @@ -92,7 +92,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" stack_trace: dependency: transitive description: @@ -127,7 +127,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19" + version: "0.3.0" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cade573..79d0f0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 1.1.1 homepage: https://github.com/iamvivekkaushik/OTPTextField environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.7.0 <3.0.0' dependencies: flutter: From eaa89a851999093c7c5c69382631ba075eb3a7d4 Mon Sep 17 00:00:00 2001 From: Shaikh Aman Date: Sat, 13 Nov 2021 16:42:10 +0530 Subject: [PATCH 2/6] fixed single digit length for each text field --- example/lib/main.dart | 25 ++++++++++++++++++++++--- example/pubspec.yaml | 2 +- lib/otp_field.dart | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 605b9f8..9e98165 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,8 +20,8 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key? key, this.title}) : super(key: key); - final String? title; + MyHomePage({Key key, this.title}) : super(key: key); + final String title; @override _MyHomePageState createState() => _MyHomePageState(); @@ -32,7 +32,7 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return Scaffold( body: Center( - child: OTPTextField( + /*child: OTPTextField( length: 5, width: MediaQuery.of(context).size.width, textFieldAlignment: MainAxisAlignment.spaceAround, @@ -46,6 +46,25 @@ class _MyHomePageState extends State { onCompleted: (pin) { print("Completed: " + pin); }, + ),*/ + child: OTPTextField( + length: 4, + fieldWidth: 50, + style: TextStyle(color: Colors.white), + margin: EdgeInsets.zero, + fieldStyle: FieldStyle.box, + otpFieldStyle: OtpFieldStyle( + backgroundColor: Colors.black, + borderColor: Colors.transparent, + ), + textFieldAlignment: MainAxisAlignment.spaceEvenly, + width: MediaQuery.of(context).size.width, + onChanged: (pin) { + print(pin); + }, + onCompleted: (pin) { + print(pin); + }, ), ), ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fdc4ecb..86dcbc4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.7.0 <3.0.0' dependencies: flutter: diff --git a/lib/otp_field.dart b/lib/otp_field.dart index a10fd69..7fdf387 100644 --- a/lib/otp_field.dart +++ b/lib/otp_field.dart @@ -131,7 +131,6 @@ class _OTPTextFieldState extends State { color: _otpFieldStyle.backgroundColor, borderRadius: BorderRadius.circular(widget.outlineBorderRadius)), child: TextField( - maxLength: 1, controller: _textControllers[i], keyboardType: widget.keyboardType, textAlign: TextAlign.center, @@ -147,7 +146,36 @@ class _OTPTextFieldState extends State { errorBorder: _getBorder(_otpFieldStyle.errorBorderColor)), onChanged: (String str) { if (str.length > 1) { - _handlePaste(str); + if(str.length == widget.length){ + print('Handling Paste'); + _handlePaste(str); + } + else { + int len = str.length; + str = str[len-1]; + // Update the current pin + setState(() { + _textControllers[i].text = str; + _pin[i] = str; + }); + if (str.isNotEmpty) _focusNodes[i].unfocus(); + // Set focus to the next field if available + if (i + 1 != widget.length && str.isNotEmpty) + FocusScope.of(context).requestFocus(_focusNodes[i + 1]); + + String currentPin = _getCurrentPin(); + + // if there are no null values that means otp is completed + // Call the `onCompleted` callback function provided + if (!_pin.contains(null) && + !_pin.contains('') && + currentPin.length == widget.length) { + widget.onCompleted(currentPin); + } + + // Call the `onChanged` callback function + widget.onChanged(currentPin); + } return; } From bca912e3054bdb98bfdf96154cdad37ec6176130 Mon Sep 17 00:00:00 2001 From: Shaikh Aman Date: Sat, 13 Nov 2021 16:45:43 +0530 Subject: [PATCH 3/6] optimization --- lib/otp_field.dart | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/lib/otp_field.dart b/lib/otp_field.dart index 7fdf387..d574b0c 100644 --- a/lib/otp_field.dart +++ b/lib/otp_field.dart @@ -149,6 +149,7 @@ class _OTPTextFieldState extends State { if(str.length == widget.length){ print('Handling Paste'); _handlePaste(str); + return; } else { int len = str.length; @@ -156,27 +157,8 @@ class _OTPTextFieldState extends State { // Update the current pin setState(() { _textControllers[i].text = str; - _pin[i] = str; }); - if (str.isNotEmpty) _focusNodes[i].unfocus(); - // Set focus to the next field if available - if (i + 1 != widget.length && str.isNotEmpty) - FocusScope.of(context).requestFocus(_focusNodes[i + 1]); - - String currentPin = _getCurrentPin(); - - // if there are no null values that means otp is completed - // Call the `onCompleted` callback function provided - if (!_pin.contains(null) && - !_pin.contains('') && - currentPin.length == widget.length) { - widget.onCompleted(currentPin); - } - - // Call the `onChanged` callback function - widget.onChanged(currentPin); } - return; } // Check if the current value at this position is empty From a5119c97ac268416cc649153b800e847339f8d34 Mon Sep 17 00:00:00 2001 From: Shaikh Aman Date: Mon, 15 Nov 2021 11:38:02 +0530 Subject: [PATCH 4/6] migrated to null safety --- example/lib/main.dart | 4 ++-- example/pubspec.yaml | 2 +- lib/otp_field.dart | 44 +++++++++++++++++++++---------------------- pubspec.yaml | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 9e98165..bfc354c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,8 +20,8 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - final String title; + MyHomePage({Key? key, this.title}) : super(key: key); + final String? title; @override _MyHomePageState createState() => _MyHomePageState(); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 86dcbc4..fdc4ecb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: '>=2.7.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: diff --git a/lib/otp_field.dart b/lib/otp_field.dart index d574b0c..0af7d94 100644 --- a/lib/otp_field.dart +++ b/lib/otp_field.dart @@ -32,20 +32,20 @@ class OTPTextField extends StatefulWidget { final bool obscureText; /// Text Field Style - final OtpFieldStyle otpFieldStyle; + final OtpFieldStyle? otpFieldStyle; /// Text Field Style for field shape. /// default FieldStyle.underline [FieldStyle] final FieldStyle fieldStyle; /// Callback function, called when a change is detected to the pin. - final ValueChanged onChanged; + final ValueChanged? onChanged; /// Callback function, called when pin is completed. - final ValueChanged onCompleted; + final ValueChanged? onCompleted; OTPTextField( - {Key key, + {Key? key, this.length = 4, this.width = 10, this.fieldWidth = 30, @@ -66,25 +66,25 @@ class OTPTextField extends StatefulWidget { } class _OTPTextFieldState extends State { - OtpFieldStyle _otpFieldStyle; - List _focusNodes; - List _textControllers; + late OtpFieldStyle _otpFieldStyle; + late List _focusNodes; + late List _textControllers; - List _textFields; - List _pin; + late List _textFields; + late List _pin; @override void initState() { if (widget.otpFieldStyle == null) { _otpFieldStyle = OtpFieldStyle(); } else { - _otpFieldStyle = widget.otpFieldStyle; + _otpFieldStyle = widget.otpFieldStyle!; } super.initState(); - _focusNodes = List.filled(widget.length, null, growable: false); - _textControllers = List.filled(widget.length, null, + _focusNodes = List.filled(widget.length, null, growable: false); + _textControllers = List.filled(widget.length, null, growable: false); _pin = List.generate(widget.length, (int i) { @@ -98,7 +98,7 @@ class _OTPTextFieldState extends State { @override void dispose() { _textControllers - .forEach((TextEditingController controller) => controller.dispose()); + .forEach((TextEditingController? controller) => controller!.dispose()); super.dispose(); } @@ -156,7 +156,7 @@ class _OTPTextFieldState extends State { str = str[len-1]; // Update the current pin setState(() { - _textControllers[i].text = str; + _textControllers[i]!.text = str; }); } } @@ -165,8 +165,8 @@ class _OTPTextFieldState extends State { // If it is move focus to previous text field. if (str.isEmpty) { if (i == 0) return; - _focusNodes[i].unfocus(); - _focusNodes[i - 1].requestFocus(); + _focusNodes[i]!.unfocus(); + _focusNodes[i - 1]!.requestFocus(); } // Update the current pin @@ -175,7 +175,7 @@ class _OTPTextFieldState extends State { }); // Remove focus - if (str.isNotEmpty) _focusNodes[i].unfocus(); + if (str.isNotEmpty) _focusNodes[i]!.unfocus(); // Set focus to the next field if available if (i + 1 != widget.length && str.isNotEmpty) FocusScope.of(context).requestFocus(_focusNodes[i + 1]); @@ -187,11 +187,11 @@ class _OTPTextFieldState extends State { if (!_pin.contains(null) && !_pin.contains('') && currentPin.length == widget.length) { - widget.onCompleted(currentPin); + widget.onCompleted!(currentPin); } // Call the `onChanged` callback function - widget.onChanged(currentPin); + widget.onChanged!(currentPin); }, ), ); @@ -220,7 +220,7 @@ class _OTPTextFieldState extends State { for (int i = 0; i < str.length; i++) { String digit = str.substring(i, i + 1); - _textControllers[i].text = digit; + _textControllers[i]!.text = digit; _pin[i] = digit; } @@ -233,10 +233,10 @@ class _OTPTextFieldState extends State { if (!_pin.contains(null) && !_pin.contains('') && currentPin.length == widget.length) { - widget.onCompleted(currentPin); + widget.onCompleted!(currentPin); } // Call the `onChanged` callback function - widget.onChanged(currentPin); + widget.onChanged!(currentPin); } } diff --git a/pubspec.yaml b/pubspec.yaml index 79d0f0a..cade573 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 1.1.1 homepage: https://github.com/iamvivekkaushik/OTPTextField environment: - sdk: '>=2.7.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: From 034062836ec8f2249d5596b1b138c6898a190273 Mon Sep 17 00:00:00 2001 From: Shaikh Aman Date: Mon, 13 Jun 2022 11:58:10 +0530 Subject: [PATCH 5/6] fixed otp field to have single digit length and added override behaviour --- example/pubspec.lock | 25 +++++++++---------------- lib/otp_field.dart | 27 +++++++++++++++++++-------- pubspec.lock | 23 ++++++++--------------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 5f86f37..e0ee5f7 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" cupertino_icons: dependency: "direct main" description: @@ -56,7 +56,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" flutter: dependency: "direct main" description: flutter @@ -80,7 +80,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -94,14 +94,14 @@ packages: path: ".." relative: true source: path - version: "1.1.2" + version: "1.1.3" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" sky_engine: dependency: transitive description: flutter @@ -113,7 +113,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -148,20 +148,13 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" + version: "0.4.9" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=2.17.0-0 <3.0.0" diff --git a/lib/otp_field.dart b/lib/otp_field.dart index 23b7f52..c77b9ac 100644 --- a/lib/otp_field.dart +++ b/lib/otp_field.dart @@ -178,15 +178,21 @@ class _OTPTextFieldState extends State { right: isLast ? 0 : widget.spaceBetween, ), child: TextField( + onTap: () { + _textControllers[index]!.selection = TextSelection.fromPosition( + TextPosition(offset: _textControllers[index]!.text.length)); + }, controller: _textControllers[index], keyboardType: widget.keyboardType, textCapitalization: widget.textCapitalization, textAlign: TextAlign.center, style: widget.style, inputFormatters: widget.inputFormatter, - maxLength: 1, + //maxLength: 1, + maxLength: 2, focusNode: _focusNodes[index], obscureText: widget.obscureText, + showCursor: false, decoration: InputDecoration( isDense: widget.isDense, filled: true, @@ -204,18 +210,22 @@ class _OTPTextFieldState extends State { errorStyle: const TextStyle(height: 0, fontSize: 0), ), onChanged: (String str) { + debugPrint('Changed'); if (str.length > 1) { - if(str.length == widget.length){ + if (str.length == widget.length && index == widget.length - 1) { print('Handling Paste'); _handlePaste(str); return; - } - else { - int len = str.length; - str = str[len-1]; + } else { + if (_pin.length >= index + 1) { + str = str.replaceFirst(_pin[index], ''); + } else { + int len = str.length; + str = str[len - 1]; + } // Update the current pin setState(() { - _textControllers[i]!.text = str; + _textControllers[index]!.text = str; }); } } @@ -246,7 +256,8 @@ class _OTPTextFieldState extends State { // Call the `onCompleted` callback function provided if (!_pin.contains(null) && !_pin.contains('') && - currentPin.length == widget.length) { + currentPin.length == widget.length && + index + 1 == widget.length) { widget.onCompleted?.call(currentPin); } diff --git a/pubspec.lock b/pubspec.lock index 3317f5f..7d27b51 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,14 +42,14 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" flutter: dependency: "direct main" description: flutter @@ -73,7 +73,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -87,7 +87,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" sky_engine: dependency: transitive description: flutter @@ -99,7 +99,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -134,20 +134,13 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" + version: "0.4.9" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=2.17.0-0 <3.0.0" From 692e62db7c986e3023290fbcc25556affac6260a Mon Sep 17 00:00:00 2001 From: Shaikh Aman Date: Mon, 13 Jun 2022 13:45:51 +0530 Subject: [PATCH 6/6] some fixes --- example/lib/main.dart | 7 +------ lib/otp_field.dart | 6 ++++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 01dc3de..98520b1 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -37,11 +37,7 @@ class _MyHomePageState extends State { child: Icon(Icons.cleaning_services), onPressed: () { print("Floating button was pressed."); - otpController.set(['2', '3', '5', '5', '7']); - //otpController.clear(); - // otpController.set(['2', '3', '5', '5', '7']); - // otpController.setValue('3', 0); - // otpController.setFocus(1); + otpController.clear(); }, ), body: Center( @@ -59,7 +55,6 @@ class _MyHomePageState extends State { }, onCompleted: (pin) { print("Completed: " + pin); - otpController.setFocus(4); }), ), ); diff --git a/lib/otp_field.dart b/lib/otp_field.dart index c77b9ac..3d94350 100644 --- a/lib/otp_field.dart +++ b/lib/otp_field.dart @@ -210,16 +210,18 @@ class _OTPTextFieldState extends State { errorStyle: const TextStyle(height: 0, fontSize: 0), ), onChanged: (String str) { - debugPrint('Changed'); if (str.length > 1) { if (str.length == widget.length && index == widget.length - 1) { print('Handling Paste'); _handlePaste(str); return; } else { + // User modified same position if (_pin.length >= index + 1) { + // remove previously entered digit str = str.replaceFirst(_pin[index], ''); } else { + // Take the last entered digit as otp entry int len = str.length; str = str[len - 1]; } @@ -257,7 +259,7 @@ class _OTPTextFieldState extends State { if (!_pin.contains(null) && !_pin.contains('') && currentPin.length == widget.length && - index + 1 == widget.length) { + index + 1 == widget.length) { // Only call this when user is on last digit widget.onCompleted?.call(currentPin); }