Giter Site home page Giter Site logo

tkko / flutter_pinput Goto Github PK

View Code? Open in Web Editor NEW
687.0 8.0 171.0 7.8 MB

Flutter package to create Pin code input text field with every pixel customization possibility ๐ŸŽจ with beautiful animations, iOS autofill, Android autofill

Home Page: https://pub.dev/packages/pinput

License: MIT License

Dart 68.19% HTML 2.49% CMake 10.92% C++ 13.92% C 0.90% Kotlin 0.07% Ruby 1.74% Swift 1.24% Objective-C 0.02% Shell 0.50%
pin otp pincode flutter-pin-code verification verification-code flutter-package flutter-widget phone-verification autofill

flutter_pinput's Introduction

Flutter pin code input from Tornike & Great Contributors

Pub package Github starts style: effective dart pub package

Flutter Pinput is a package that provides an easy-to-use and customizable Pin code input field. It offers several features such as animated decoration switching, form validation, SMS autofill, custom cursor, copying from clipboard, and more. It also provides beautiful examples that you can choose from.

If you are using Flutter version <3.7.0 you have to use Pinput version 2.2.21

Features:

  • Animated Decoration Switching
  • Form validation
  • SMS Autofill on iOS
  • SMS Autofill on Android
  • Standard Cursor
  • Custom Cursor
  • Cursor Animation
  • Copy From Clipboard
  • Ready For Custom Keyboard
  • Standard Paste option
  • Obscuring Character
  • Obscuring Widget
  • Haptic Feedback
  • Close Keyboard After Completion
  • Beautiful Examples

Support

PRs Welcome

Discord Channel

Examples app on Github has multiple templates to choose from

Don't forget to give it a star โญ

Demo

Live Demo Rounded With Shadows Rounded With Cursor
Rounded Filled With Bottom Cursor Filled

Getting Started

We should set project kotlin version to 1.8.0 or above because of the new requirement for sdk 34 RECEIVER_EXPORTED. Or we would get duplicate class error in different kotlin versions.

so in the android level build.gradle file update the kotlin version like below:

// android/build.gradle

buildscript {
    ext.kotlin_version = '1.8.0'
}

The pin has 6 states default focused, submitted, following, disabled, error, you can customize each state by specifying theme parameter. Pin smoothly animates from one state to another automatically. PinTheme Class

Property Default/Type
width 56.0
height 60.0
textStyle TextStyle()
margin EdgeInsetsGeometry
padding EdgeInsetsGeometry
constraints BoxConstraints

You can use standard Pinput like so

Widget buildPinPut() {
  return Pinput(
    onCompleted: (pin) => print(pin),
  );
}

If you want to customize it, create defaultPinTheme first.

final defaultPinTheme = PinTheme(
  width: 56,
  height: 56,
  textStyle: TextStyle(fontSize: 20, color: Color.fromRGBO(30, 60, 87, 1), fontWeight: FontWeight.w600),
  decoration: BoxDecoration(
    border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
    borderRadius: BorderRadius.circular(20),
  ),
);

if you want all pins to be the same don't pass other theme parameters, If not, create focusedPinTheme, submittedPinTheme, followingPinTheme, errorPinTheme from defaultPinTheme

final focusedPinTheme = defaultPinTheme.copyDecorationWith(
  border: Border.all(color: Color.fromRGBO(114, 178, 238, 1)),
  borderRadius: BorderRadius.circular(8),
);

final submittedPinTheme = defaultPinTheme.copyWith(
  decoration: defaultPinTheme.decoration.copyWith(
    color: Color.fromRGBO(234, 239, 243, 1),
  ),
);

Put everything together

final defaultPinTheme = PinTheme(
  width: 56,
  height: 56,
  textStyle: TextStyle(fontSize: 20, color: Color.fromRGBO(30, 60, 87, 1), fontWeight: FontWeight.w600),
  decoration: BoxDecoration(
    border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
    borderRadius: BorderRadius.circular(20),
  ),
);

final focusedPinTheme = defaultPinTheme.copyDecorationWith(
  border: Border.all(color: Color.fromRGBO(114, 178, 238, 1)),
  borderRadius: BorderRadius.circular(8),
);

final submittedPinTheme = defaultPinTheme.copyWith(
  decoration: defaultPinTheme.decoration.copyWith(
    color: Color.fromRGBO(234, 239, 243, 1),
  ),
);

return Pinput(
  defaultPinTheme: defaultPinTheme,
  focusedPinTheme: focusedPinTheme,
  submittedPinTheme: submittedPinTheme,
  validator: (s) {
    return s == '2222' ? null : 'Pin is incorrect';
  },
  pinputAutovalidateMode: PinputAutovalidateMode.onSubmit,
  showCursor: true,
  onCompleted: (pin) => print(pin),
);

SMS Autofill

iOS

Works out of the box, by tapping the code on top of the keyboard

Android

If you are using firebase_auth you have to set androidSmsAutofillMethod to AndroidSmsAutofillMethod.none and set controller's value in verificationCompleted callback, here is an example code:

    Pinput(
      androidSmsAutofillMethod: AndroidSmsAutofillMethod.none,
      controller: pinController,
    );

And set pinController's value in verificationCompleted callback:

    await FirebaseAuth.instance.verifyPhoneNumber(
      verificationCompleted: (PhoneAuthCredential credential) {
        pinController.setText(credential.smsCode);
      },
      verificationFailed: (FirebaseAuthException e) {},
      codeSent: (String verificationId, int? resendToken) {},
      codeAutoRetrievalTimeout: (String verificationId) {},
    );

If you aren't using firebase_auth, you have two options, SMS Retriever API and SMS User Consent API,

SmartAuth is a wrapper package for Flutter for these APIs and it is behind the autofill support of Pinput

SMS Retriever API

To use Retriever API you need The App signature, Pinput calculates the hash for you and prints it in the console Sms code will be automatically applied, without user interaction.

Note that The App Signature might be different for debug and release mode

return Pinput(
  androidSmsAutofillMethod:  AndroidSmsAutofillMethod.smsRetrieverApi,
);

Example of printed signature Pinput: App Signature for SMS Retriever API Is: kg+TZ3A5qzS

SMS User Consent API

You don't need the App signature, the user will be prompted to confirm reading the message

return Pinput(
  androidSmsAutofillMethod:  AndroidSmsAutofillMethod.smsUserConsentApi,
);

Request Hint

SmartAuth

If autofill support doesn't fit your needs, you can use SmartAuth to implement autofill, Also, you can suggest a phone number by showing native Android dialog.

No need to add SmartAuth dependency, it is already added

See Example app for more templates

Tips

  • Controller

/// Create Controller  
final pinController = TextEditingController();  

/// Set text programmatically  
pinController.setText('1222');  

/// Append typed character, useful if you are using custom keyboard  
pinController.append('1', 4);  

/// Delete last character  
pinController.delete();  

/// Don't call setText, append, delete in build method, this is just illustration.  

return Pinput(  
  controller: pinController,  
);  
  • Focus

/// Create FocusNode  
final pinputFocusNode = FocusNode();  

/// Focus pinput  
pinputFocusNode.requestFocus();  

/// UnFocus pinput  
pinputFocusNode.unfocus();  

/// Don't call requestFocus, unfocus in build method, this is just illustration.  

return Pinput(  
  focusNode: pinputFocusNode,  
);  
  • Validation

/// Create key
final formKey = GlobalKey<FormState>();

/// Validate manually
/// Don't call validate in build method, this is just illustration.
formKey.currentState!.validate();

return Form(
  key: formKey,
  child: Pinput(
    // Without Validator
    // If true error state will be applied no matter what validator returns
    forceErrorState: true,
    // Text will be displayed under the Pinput
    errorText: 'Error',

    /// ------------
    /// With Validator
    /// Auto validate after user tap on keyboard done button, or completes Pinput
    pinputAutovalidateMode: PinputAutovalidateMode.onSubmit,
    validator: (pin) {
      if (pin == '2224') return null;

      /// Text will be displayed under the Pinput
      return 'Pin is incorrect';
    },
  ),
);

FAQ

autofill isn't working on iOS?

  • Make sure you are using real device, not simulator
  • Temporary replace Pinput with TextField, and check if autofill works. If, not it's probably a problem with SMS you are getting, autofill doesn't work with most of the languages
  • If you are using non stable version of Flutter that might be cause because something might be broken inside the Framework

are you using firebase_auth?

Set androidSmsAutofillMethod to AndroidSmsAutofillMethod.none and set controller's value in verificationCompleted callback, here is an example code:

    Pinput(
      androidSmsAutofillMethod: AndroidSmsAutofillMethod.none,
      controller: pinController,
    );
    
    await FirebaseAuth.instance.verifyPhoneNumber(
      verificationCompleted: (PhoneAuthCredential credential) {
        pinController.setText(credential.smsCode);
      },
      verificationFailed: (FirebaseAuthException e) {},
      codeSent: (String verificationId, int? resendToken) {},
      codeAutoRetrievalTimeout: (String verificationId) {},
    );

Properties

const Pinput({
  this.length = PinputConstants._defaultLength,
  this.defaultPinTheme,
  this.focusedPinTheme,
  this.submittedPinTheme,
  this.followingPinTheme,
  this.disabledPinTheme,
  this.errorPinTheme,
  this.onChanged,
  this.onCompleted,
  this.onSubmitted,
  this.onTap,
  this.onLongPress,
  this.controller,
  this.focusNode,
  this.preFilledWidget,
  this.separatorBuilder,
  this.smsCodeMatcher = PinputConstants.defaultSmsCodeMatcher,
  this.senderPhoneNumber,
  this.androidSmsAutofillMethod = AndroidSmsAutofillMethod.none,
  this.listenForMultipleSmsOnAndroid = false,
  this.mainAxisAlignment = MainAxisAlignment.center,
  this.crossAxisAlignment = CrossAxisAlignment.start,
  this.pinContentAlignment = Alignment.center,
  this.animationCurve = Curves.easeIn,
  this.animationDuration = PinputConstants._animationDuration,
  this.pinAnimationType = PinAnimationType.scale,
  this.enabled = true,
  this.readOnly = false,
  this.useNativeKeyboard = true,
  this.toolbarEnabled = true,
  this.autofocus = false,
  this.obscureText = false,
  this.showCursor = true,
  this.isCursorAnimationEnabled = true,
  this.enableIMEPersonalizedLearning = false,
  this.enableSuggestions = true,
  this.hapticFeedbackType = HapticFeedbackType.disabled,
  this.closeKeyboardWhenCompleted = true,
  this.keyboardType = TextInputType.number,
  this.textCapitalization = TextCapitalization.none,
  this.slideTransitionBeginOffset,
  this.cursor,
  this.keyboardAppearance,
  this.inputFormatters = const [],
  this.textInputAction,
  this.autofillHints,
  this.obscuringCharacter = 'โ€ข',
  this.obscuringWidget,
  this.selectionControls,
  this.restorationId,
  this.onClipboardFound,
  this.onAppPrivateCommand,
  this.mouseCursor,
  this.forceErrorState = false,
  this.errorText,
  this.validator,
  this.errorBuilder,
  this.errorTextStyle,
  this.pinputAutovalidateMode = PinputAutovalidateMode.onSubmit,
  this.scrollPadding = const EdgeInsets.all(20),
  this.contextMenuBuilder = _defaultContextMenuBuilder,
  this.onTapOutside,
  Key? key,
  })  : assert(obscuringCharacter.length == 1),
        assert(length > 0),
        assert(
        textInputAction != TextInputAction.newline,
        'Pinput is not multiline',
        ),
        super(key: key);

/// Theme of the pin in default state
final PinTheme? defaultPinTheme;

/// Theme of the pin in focused state
final PinTheme? focusedPinTheme;

/// Theme of the pin in submitted state
final PinTheme? submittedPinTheme;

/// Theme of the pin in following state
final PinTheme? followingPinTheme;

/// Theme of the pin in disabled state
final PinTheme? disabledPinTheme;

/// Theme of the pin in error state
final PinTheme? errorPinTheme;

/// If true keyboard will be closed
final bool closeKeyboardWhenCompleted;

/// Displayed fields count. PIN code length.
final int length;

/// By default Android autofill is Disabled, you cane enable it by using any of options listed below
///
/// First option is [AndroidSmsAutofillMethod.smsRetrieverApi] it automatically reads sms without user interaction
/// More about Sms Retriever API https://developers.google.com/identity/sms-retriever/overview?hl=en
///
/// Second option requires user interaction to confirm reading a SMS, See readme for more details
/// [AndroidSmsAutofillMethod.smsUserConsentApi]
/// More about SMS User Consent API https://developers.google.com/identity/sms-retriever/user-consent/overview
final AndroidSmsAutofillMethod androidSmsAutofillMethod;

/// If true [androidSmsAutofillMethod] is not [AndroidSmsAutofillMethod.none]
/// Pinput will listen multiple sms codes, helpful if user request another sms code
final bool listenForMultipleSmsOnAndroid;

/// Used to extract code from SMS for Android Autofill if [androidSmsAutofillMethod] is enabled
/// By default it is [PinputConstants.defaultSmsCodeMatcher]
final String smsCodeMatcher;

/// Fires when user completes pin input
final ValueChanged<String>? onCompleted;

/// Called every time input value changes.
final ValueChanged<String>? onChanged;

/// See [EditableText.onSubmitted]
final ValueChanged<String>? onSubmitted;

/// Called when user clicks on PinPut
final VoidCallback? onTap;

/// Triggered when a pointer has remained in contact with the Pinput at the
/// same location for a long period of time.
final VoidCallback? onLongPress;

/// Used to get, modify PinPut value and more.
/// Don't forget to dispose controller
/// ``` dart
///   @override
///   void dispose() {
///     controller.dispose();
///     super.dispose();
///   }
/// ```
final TextEditingController? controller;

/// Defines the keyboard focus for this
/// To give the keyboard focus to this widget, provide a [focusNode] and then
/// use the current [FocusScope] to request the focus:
/// Don't forget to dispose focusNode
/// ``` dart
///   @override
///   void dispose() {
///     focusNode.dispose();
///     super.dispose();
///   }
/// ```
final FocusNode? focusNode;

/// Widget that is displayed before field submitted.
final Widget? preFilledWidget;

/// Builds a Pinput separator
final JustIndexedWidgetBuilder? separatorBuilder;

/// Defines how [Pinput] fields are being placed inside [Row]
final MainAxisAlignment mainAxisAlignment;

/// Defines how [Pinput] and ([errorText] or [errorBuilder]) are being placed inside [Column]
final CrossAxisAlignment crossAxisAlignment;

/// Defines how each [Pinput] field are being placed within the container
final AlignmentGeometry pinContentAlignment;

/// curve of every [Pinput] Animation
final Curve animationCurve;

/// Duration of every [Pinput] Animation
final Duration animationDuration;

/// Animation Type of each [Pinput] field
/// options:
/// none, scale, fade, slide, rotation
final PinAnimationType pinAnimationType;

/// Begin Offset of ever [Pinput] field when [pinAnimationType] is slide
final Offset? slideTransitionBeginOffset;

/// Defines [Pinput] state
final bool enabled;

/// See [EditableText.readOnly]
final bool readOnly;

/// See [EditableText.autofocus]
final bool autofocus;

/// Whether to use Native keyboard or custom one
/// when flag is set to false [Pinput] wont be focusable anymore
/// so you should set value of [Pinput]'s [TextEditingController] programmatically
final bool useNativeKeyboard;

/// If true, paste button will appear on longPress event
final bool toolbarEnabled;

/// Whether show cursor or not
/// Default cursor '|' or [cursor]
final bool showCursor;

final bool isCursorAnimationEnabled;

/// Whether to enable that the IME update personalized data such as typing history and user dictionary data.
//
// This flag only affects Android. On iOS, there is no equivalent flag.
//
// Defaults to false. Cannot be null.
final bool enableIMEPersonalizedLearning;

/// If [showCursor] true the focused field will show passed Widget
final Widget? cursor;

/// The appearance of the keyboard.
/// This setting is only honored on iOS devices.
/// If unset, defaults to [ThemeData.brightness].
final Brightness? keyboardAppearance;

/// See [EditableText.inputFormatters]
final List<TextInputFormatter> inputFormatters;

/// See [EditableText.keyboardType]
final TextInputType keyboardType;

/// Provide any symbol to obscure each [Pinput] pin
/// Recommended โ—
final String obscuringCharacter;

/// IF [obscureText] is true typed text will be replaced with passed Widget
final Widget? obscuringWidget;

/// Whether hide typed pin or not
final bool obscureText;

/// See [EditableText.textCapitalization]
final TextCapitalization textCapitalization;

/// The type of action button to use for the keyboard.
///
/// Defaults to [TextInputAction.newline] if [keyboardType] is
/// [TextInputType.multiline] and [TextInputAction.done] otherwise.
final TextInputAction? textInputAction;

/// See [EditableText.autofillHints]
final Iterable<String>? autofillHints;

/// See [EditableText.enableSuggestions]
final bool enableSuggestions;

/// See [EditableText.selectionControls]
final TextSelectionControls? selectionControls;

/// See [TextField.restorationId]
final String? restorationId;

/// Fires when clipboard has text of Pinput's length
final ValueChanged<String>? onClipboardFound;

/// Use haptic feedback everytime user types on keyboard
/// See more details in [HapticFeedback]
final HapticFeedbackType hapticFeedbackType;

/// See [EditableText.onAppPrivateCommand]
final AppPrivateCommandCallback? onAppPrivateCommand;

/// See [EditableText.mouseCursor]
final MouseCursor? mouseCursor;

/// If true [errorPinTheme] will be applied and [errorText] will be displayed under the Pinput
final bool forceErrorState;

/// Text displayed under the Pinput if Pinput is invalid
final String? errorText;

/// Style of error text
final TextStyle? errorTextStyle;

/// If [Pinput] has error and [errorBuilder] is passed it will be rendered under the Pinput
final PinputErrorBuilder? errorBuilder;

/// Return null if pin is valid or any String otherwise
final FormFieldValidator<String>? validator;

/// Return null if pin is valid or any String otherwise
final PinputAutovalidateMode pinputAutovalidateMode;

/// When this widget receives focus and is not completely visible (for example scrolled partially
/// off the screen or overlapped by the keyboard)
/// then it will attempt to make itself visible by scrolling a surrounding [Scrollable], if one is present.
/// This value controls how far from the edges of a [Scrollable] the TextField will be positioned after the scroll.
final EdgeInsets scrollPadding;

/// Optional parameter for Android SMS User Consent API.
final String? senderPhoneNumber;

/// {@macro flutter.widgets.EditableText.contextMenuBuilder}
///
/// If not provided, will build a default menu based on the platform.
///
/// See also:
///
///  * [AdaptiveTextSelectionToolbar], which is built by default.
final EditableTextContextMenuBuilder? contextMenuBuilder;

/// A callback to be invoked when a tap is detected outside of this [TapRegion]
/// The [PointerDownEvent] passed to the function is the event that caused the
/// notification. If this region is part of a group
/// then it's possible that the event may be outside of this immediate region,
/// although it will be within the region of one of the group members.
/// This is useful if you want to unfocus the [Pinput] when user taps outside of it
final TapRegionCallback? onTapOutside;

flutter_pinput's People

Contributors

adrianflutur avatar almeynman avatar andrelmlins avatar cogivn avatar datvtwkm avatar furaiev avatar holofox avatar inromualdo avatar khulegu-ua avatar mdddj avatar mervyn-wee avatar mwgriffiths88 avatar proyekriad avatar shliama avatar thanhdatvo avatar tkko avatar xang555 avatar xportation avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter_pinput's Issues

deprecated hideCurrentSnackBar showSnackBar

Scaffold.of(context)
..hideCurrentSnackBar()
..showSnackBar(snackBar);

Can be changed to:

ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(snackBar);

border shows when unfocused

Widget get _hiddenTextField

You need to turn off all the borders

  border: InputBorder.none,
  disabledBorder: InputBorder.none,
  enabledBorder: InputBorder.none,
  focusedBorder: InputBorder.none,
  errorBorder: InputBorder.none,
  focusedErrorBorder: InputBorder.none,

Submit without clearing inputs

Hi, i'm submiting the input after it's fill, and hiding keyboard, but it disapear the inputs value.

Grabacion.de.pantalla.2021-09-01.a.la.s.23.14.30.mov

Nice library, Thank you so much.

Would it be posible to show typed value for x time before obscuring text?

Hey there!

I was wondering if it would be possible to show the typed value for some amount of time before obscuring it? Similar to how regular TextFields handle obscured text.

Current behavior:

  1. PinPut with obscureText = '*'
  2. user types character
  3. character is obscured

Requested behavior:

  1. PinPut with obscureText = '*'
  2. user types a character
  3. character is shown for 1s
  4. Then it obscures itself

I think this could be a really good feature to have, maybe opt-in. This way the user can see if an incorrect character has been entered.

I wouldn't mind filing a PR if the feature is accepted, just let me know!

Cheers

Allow for `TextCapitalization`

Flutter has a textCapitalization property for TextField, which allows auto-capitalisation to be specified on characters, sentences, and words.

It would be useful is this was also added to PinPut, particularly for cases where the keyboardType is set to TextInputType.text.

pin re-input

nice to have a 2nd screen to have a user input the pin again, sort of like a verification when the user wants to set his own pin.

Custom Numpad

Hi, is it possible to disable the devices keyboard, just like with the usual 'readOnly' setting for text fields, and use a custom numpad for input?
The iOS and Android numpads aren't suitable for my app.

multiple submission when used with Visibility widget

Hi,
So I encountered this issue while trying to show a loader after the submition of the pin. If the pin is wrong, I go back to the initial state and show back the loader.

I used Visibility to achieve this.

The problem is, every time my PinPut widget is re-redered after being hidden, the onSubmit callback is called one time more, e.g. if I hide and show it 6 time, the next time I complete the form the onSubmit callback will be called 6 times.

Here is the content to past in main.dart to reproduce the issue :

import 'package:flutter/material.dart';
import 'package:pinput/pin_put/pin_put.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _pinPutController = TextEditingController();
  final FocusNode _pinPutFocusNode = FocusNode();
  int counter = 1;
  bool showPinPut = true;

  BoxDecoration get _pinPutDecoration {
    return BoxDecoration(
      border: Border.all(color: Colors.black),
      borderRadius: BorderRadius.circular(5),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          child: Visibility(
            visible: showPinPut == true,
            replacement: Container(),
            child: PinPut(
              fieldsCount: 4,
              textStyle: TextStyle(color: Colors.black),
              eachFieldHeight: 50,
              eachFieldWidth: 50,
              followingFieldDecoration: _pinPutDecoration,
              preFilledChar: "-",
              onSubmit: (String pin) {
                print('submitted $counter times');
                counter++;
              },
              focusNode: _pinPutFocusNode,
              controller: _pinPutController,
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() {
          this.showPinPut = !this.showPinPut;
        }),
        tooltip: 'show/hide',
        child: Icon(Icons.remove_red_eye),
      ),
    );
  }
}

After hiding and showing the pinput widget 4 times, this is the output I get when I finally submit it :
pinput_results

As a workaround, I tried resetting the _pinputController at the beginning of a build cycle. This fixed the issue, but made it impossible to access the properties (text, etc...), so it clearly is not ideal.

Any thoughts?

EDIT :
As a working workaround, I wrapped both my pinput and my loader in a stack :

// Previous widgets
                     child: Stack(
                        children: [
                          Visibility(
                            visible: !state.isLoading,
                            // This is what allows to fix the issue
                            maintainState: true,
                            child: PinPut(
                              // Some PinPut properties
                            ),
                          ),
                          Visibility(
                            visible: state.isLoading,
                            child: Loading(
                                // Some Loading properties
                                ),
                          ),

Set PinPut value programmatically

So many changes since last time I'm using this awesome package. Bravo and good job to the developers.
Right now, I have a case like this. a user wants to fill up the pin put field automatically when authentication sms received. Let say I can retrieve the auth code programmatically and then want to set the code as pinput value and show it to user. How can I do that?

multiple submission when clear TextEditingController in onSubmit

My package version is pinput: 1.2.0

When clear the controller, multiple submissions occur.

import 'package:flutter/material.dart';
import 'package:pinput/pin_put/pin_put.dart';

class TestScreen extends StatefulWidget {
  const TestScreen({Key key}) : super(key: key);

  @override
  _TestScreenState createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  final TextEditingController _pinputController = TextEditingController();
  final FocusNode _pinputFocusNode = FocusNode();

  BoxDecoration get _pinPutDecoration {
    return BoxDecoration(
      border: Border.all(color: Colors.blue),
      borderRadius: BorderRadius.circular(10),
    );
  }

  onSubmit(String pin) {
    print(pin);

    _pinputController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox(
          height: 100,
          child: Center(
            child: Container(
              margin: const EdgeInsets.symmetric(
                horizontal: 20.0,
                vertical: 10.0,
              ),
              padding: const EdgeInsets.all(20.0),
              child: PinPut(
                autofocus: true,
                fieldsCount: 6,
                obscureText: "โ—",
                onSubmit: onSubmit,
                focusNode: _pinputFocusNode,
                controller: _pinputController,
                submittedFieldDecoration: _pinPutDecoration.copyWith(
                  border: Border.all(
                    color: Theme.of(context).scaffoldBackgroundColor,
                  ),
                ),
                selectedFieldDecoration: _pinPutDecoration,
                followingFieldDecoration: _pinPutDecoration.copyWith(
                  border: Border.all(
                    color: Colors.blue.withOpacity(.5),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

To avoid multiple sumission, I should change onSubmit like this.
But it's just quick fix solution. Is there a better solution...?

onSubmit(String pin) async {
    print(pin);

    await Future.delayed(Duration(milliseconds: 5), () => false);
    _pinputController.clear();
  }

Error: No named parameter with the name 'floatingLabelStyle'.

I get this error message from pinput-v1.2.2 :

/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/pinput-1.2.2/lib/pin_put/pin_put_state.dart:35:7: Error: No named parameter with the name 'floatingLabelStyle'.
      floatingLabelStyle: hiddenTextStyle,
      ^^^^^^^^^^^^^^^^^^
/C:/src/flutter/packages/flutter/lib/src/material/input_decorator.dart:2517:9: Context: Found this candidate, but the arguments don't match.
  const InputDecoration({
        ^^^^^^^^^^^^^^^
3

FAILURE: Build failed with an exception.

* Where:
Script 'C:\src\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 1035

* What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.
> Process 'command 'C:\src\flutter\bin\flutter.bat'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 24s
Exception: Gradle task assembleDebug failed with exit code 1
Exited (sigterm)

Unexpected container behind the PinPut fields

Hello,

please take a look on screenshot below:
Simulator Screen Shot - iPhone 11 - 2021-02-04 at 13 17 49

I don't get why there is this rounded container behind the PinPut fields? I'm using the latest version of package.

Here is my code:

import 'package:flutter/material.dart';
import 'package:pinput/pin_put/pin_put.dart';

class PinputPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Pinput page',
        ),
      ),
      body: Center(child: _buildPinput()),
    );
  }

  Widget _buildPinput() {
    BoxDecoration defaultDecor = BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(25),
      border: Border.all(
        color: Colors.blue,
        width: .2,
      ),
    );

    return PinPut(
        fieldsAlignment: MainAxisAlignment.center,
        eachFieldWidth: 45,
        eachFieldHeight: 45,
        fieldsCount: 4,
        submittedFieldDecoration: defaultDecor.copyWith(
          color: Colors.grey[300],
        ),
        selectedFieldDecoration: defaultDecor.copyWith(
            border: Border.all(
          color: Colors.blue,
          width: .6,
        )),
        followingFieldDecoration: defaultDecor,
        pinAnimationType: PinAnimationType.scale,
        textStyle: const TextStyle(
          color: Colors.blue,
          fontSize: 16,
        ),
        onSubmit: (value) => print('onSubmit $value'));
  }
}

RTL not needed

The application is in Hebrew having HE culture set. This normal text input is expected to be of RTL. But for PIN it should remain LTR as this will be numbers only. Can you suggest how to do so?

Reentering pin

Thanks for the library,

In my app PinPut pin is used to enter user pin, then used again to re-enter the users pin to confirm.

To do this i do the the following in onSubmit:

onSubmit: (String pin) { _pinPutController.text = ''; _pinPutFocusNode.requestFocus(); print('hasPrimaryFocus ' + _pinPutFocusNode.hasPrimaryFocus.toString()); print('hasFocus ' + _pinPutFocusNode.hasFocus.toString()); },

It clears the pin text and the controller has focus and primary focus.

But when I go to re-enter the pin nothing happens, I have to click on the pinput boxes to be able to type.

I have autoFocus set to true;

I thought if the field had focus it should be able to type without having to click on the field again, am I missing something or is there an issue with the library?

Thanks

Notification when using clipboard

If there is some text stored in the clipboard, and the app is using a Clipboard.getData('text/plain') method, an {app name} pasted from {source app name} notification is shown. That means, when using the PinPut lib, every time the app is resumed, users see that notification even if the clipboard's content is not used at all. Is there any way to fix that?

Example image from Internet

onClear handler

Can you please add handler on clear button, like on paste (onSubmit).

Need way to unfocus TextFields

My app has a button "Continue without PIN", which allows the user to continue using the app but with limited access. When this button is pressed, I move on to the next page, but the keyboard is still up and in the way. I've tried the "FocusScope.of(context).requestFocus(FocusNode())" trick, but that doesn't work. I need a way to unfocus the currently focused node before navigating off the page.

onChanged method execute Twice when pipput text is change

my package version is pinput: ^0.2.6

when the pinput text was change the onchange method execute twice like this implementation print the text in two time

Widget darkRoundedPinPut() {
final BoxDecoration pinPutDecoration = BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(20.0),
);
return PinPut(
onChanged: (text){
print(text);
},
eachFieldWidth: 65.0,
eachFieldHeight: 65.0,
fieldsCount: 4,
focusNode: _pinPutFocusNode,
controller: _pinPutController,
onSubmit: (String pin) => _showSnackBar(pin),
submittedFieldDecoration: pinPutDecoration,
selectedFieldDecoration: pinPutDecoration,
followingFieldDecoration: pinPutDecoration,
pinAnimationType: PinAnimationType.scale,
textStyle: const TextStyle(color: Colors.white, fontSize: 20.0),
);
}

my flutter doctor result:
Doctor summary (to see all details, run flutter doctor -v):
[โˆš] Flutter (Channel master, 1.24.0-8.0.pre.356, on Microsoft Windows [Version
10.0.18363.1198], locale fa-IR)
[โˆš] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[โˆš] Android Studio (version 3.6)
[โˆš] Connected device (1 available)

โ€ข No issues found!

getting unexpected borders behind pinput

image

final BoxDecoration pinPutDecoration = BoxDecoration(
color: kPrimaryColor,
borderRadius: BorderRadius.circular(5.0),
);

boxedPinPutWithPreFilledSymbol() {
return PinPut(
withCursor: true,
fieldsCount: 6,
textStyle: const TextStyle(fontSize: 25.0, color: Colors.white),
eachFieldWidth: getProportionateScreenWidth(50),
eachFieldHeight: getProportionateScreenHeight(50),
onSubmit: (String pin) async {
try {
await auth
.signInWithCredential(PhoneAuthProvider.credential(
verificationId: _verificationCode, smsCode: pin))
.then((value) async {
if (value.user != null) {
phone_uid = auth.currentUser.uid;
auth.signOut();
String password = await _userServices.getKeyPass(phone_uid);
print("password is $password");
await _auth.signIn(
email: number + "@orev.user", password: password);
var uid_real = _auth.user.uid;
print("Email UID is $uid_real");
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
UpdatePasswordScreen(phone_uid: phone_uid)));
}
});
} catch (e) {
print(e);
}
},
focusNode: _pinPutFocusNode,
controller: _pinPutController,
submittedFieldDecoration: pinPutDecoration,
selectedFieldDecoration:
pinPutDecoration.copyWith(color: Colors.lightGreen),
followingFieldDecoration: pinPutDecoration,
);
}

How to change the space between boxes?

Is it possible to change the horizontal space between individual fields? I've tried to set eachFieldMargin to EdgetInsets.zero but I got the error below:

type 'Null' is not a subtype of type 'EdgeInsetsGeometry' in type cast

Text color

On line 46 on pin_put_view_model.dart, you style the text of the input boxes with the color black. This is bad when the user has chosen a dark theme. Simply remove the color argument, and the fields will use the theme's default.

Validation not working

I am using GlobalKey based form validation. Validation always returning true.

PinPut(
fieldsCount: 6,
autoValidate: false,
autofocus: true,
onSubmit: (String pin) async{

                     print('pin is' + pin);                       

                  },
                  //focusNode: _pinPutFocusNode,
                  controller: _pinPutController,
                  submittedFieldDecoration: _pinPutDecoration.copyWith(
                    borderRadius: BorderRadius.circular(20)),
                  selectedFieldDecoration: _pinPutDecoration,
                  followingFieldDecoration: _pinPutDecoration.copyWith(
                    borderRadius: BorderRadius.circular(5),
                    border: Border.all(
                      color: Colors.black,
                    ),
                  ),
                ),

===========

onPressed: () async {
if (_formKey.currentState.validate()) {
print('pin is');
int score = await Future.delayed(
const Duration(milliseconds: 4000), () => 42);
setState(() {
//_pageState = 2;
});

                    }
                  },
                ),

Hint text not show

I've added hint text but it's not showing when run, even though I've changed the hint style

Screen Shot 2021-08-23 at 11 40 34

Screen Shot 2021-08-23 at 11 41 11

can't run example

Running "flutter pub get" in example...
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Warning
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Your Flutter application is created using an older version of the Android
embedding. It's being deprecated in favor of Android embedding v2. Follow the
steps at
https://flutter.dev/go/android-project-migration
to migrate your project.
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Launching lib/main.dart on HD1905 in debug mode...
lib/main.dart:1

FAILURE: Build failed with an exception.

  • Where:
    Build file '/home/steve/google/Flutter_PinPut/example/android/build.gradle'

  • What went wrong:
    Could not compile build file '/home/steve/google/Flutter_PinPut/example/android/build.gradle'.

startup failed:
General error during semantic analysis: Unsupported class file major version 57

java.lang.IllegalArgumentException: Unsupported class file major version 57
at groovyjarjarasm.asm.ClassReader.(ClassReader.java:184)
at groovyjarjarasm.asm.ClassReader.(ClassReader.java:166)
at groovyjarjarasm.asm.ClassReader.(ClassReader.java:152)
at groovyjarjarasm.asm.ClassReader.(ClassReader.java:273)

Read only the text field.

Hey, I am writing this because I need to disable the pin Field while submitting the pin then request to the server.
In between disable the text field.

Then enable the field if the request results in an error.

Vulnerable to Intent Redirection

Hi,

When I use the PinPut package, when I send the application to the market, I get a warning like the following and my application is reject.

"Your app(s) are vulnerable to Intent Redirection."

I think he listens to sms because of his onClipboardFound feature and this causes a security vulnerability. Is there a situation you can suggest or a setting where I can turn this off? What should I do about it?

Tapping on the textfield don't open (virtual) keyboard

Hello there,
Hope you are doing fine.
I want to inform you about just one last issue. When keyboard isn't visible, if I tap on the textfields exactly, it does not open the keyboard. However, If I tap on the black space in between the text fields, the keyboard shows up.
My code for PinPut is as follows:
PinPut( fieldsCount: 6, autofocus: false, onSubmit: (otp) { if (otp.length == 6) _submitOTP(otp); print('otp submitted'); }, eachFieldPadding: EdgeInsets.all(5), focusNode: _otpFocusNode, controller: _otpController, onClipboardFound: (value) => _otpController.text = value, pinAnimationType: PinAnimationType.fade, textStyle: TextStyle( fontSize: 20, color: Colors.white, fontWeight: FontWeight.w800, ), selectedFieldDecoration: _pinPutDecoration, submittedFieldDecoration: _pinPutDecoration.copyWith( color: appMainColorLight, border: Border.all(color: appMainColorLight)), followingFieldDecoration: _pinPutDecoration.copyWith( color: Colors.white, border: Border.all(color: Colors.white)), )

I am attaching a screenshot for your reference.
Thank you for your time and support.
screencast-Genymotion-2020-04-16_13 42 38 037

Throw an error if clipboard is empty

Unhandled Exception: NoSuchMethodError: The getter 'isNotEmpty' was called on null.
Receiver: null
Tried calling: isNotEmpty

pin_put_bloc.dart -> line 55 -> return _clp.isNotEmpty;

_clp is null

Steps to reproduce:

  1. Errase all content on the device

Screen Shot 2019-06-14 at 12 26 04 AM

  1. Open the page with PinPut widget

Screen Shot 2019-06-14 at 12 24 39 AM

enableSuggestions: false

Error message when running app

`Compiler message:

/D:/flutter/.pub-cache/hosted/pub.dartlang.org/pinput-0.2.0/lib/pin_put/pin_put_state.dart:92:7: Error: No named parameter with the name 'enableSuggestions'.

  enableSuggestions: false,

  ^^^^^^^^^^^^^^^^^

/D:/flutter/packages/flutter/lib/src/material/text_form_field.dart:77:3: Context: Found this candidate, but the arguments don't match.

TextFormField({

^

Compiler failed on D:\Android\flutterTest\flutter_app\lib\main.dart

FAILURE: Build failed with an exception.

  • Where:

Script 'D:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 765

  • What went wrong:

Execution failed for task ':app:compileFlutterBuildDebugArm64'.

Process 'command 'D:\flutter\bin\flutter.bat'' finished with non-zero exit value 1

  • Try:

Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

BUILD FAILED in 17s
Running Gradle task 'assembleDebug'... 17.9s
Gradle task assembleDebug failed with exit code 1`

My flutter doctor

`Doctor summary (to see all details, run flutter doctor -v):
[โˆš] Flutter (Channel stable, v1.9.1+hotfix.4, on Microsoft Windows [Version 6.1.7601], locale en-US)
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
X Android license status unknown.
Try re-installing or updating your Android SDK Manager.
See https://developer.android.com/studio/#downloads or visit https://flutter.dev/setup/#android-setup for detailed instructions.
[โˆš] Android Studio (version 3.5)
[โˆš] VS Code (version 1.49.3)
[โˆš] Connected device (1 available)

! Doctor found issues in 1 category.`

No way to cancel operation

Works fine when allowed to complete. But I have a button on my page "Continue without PIN", which allows the user to continue using the app, just with limited access to some features. When I use this, the PinPut's current FocusNode retains focus, and so the keyboard is left up for my next screen, interfering with it. I've tried the "FocusScope.of(context).requestFocus(FocusNode())" trick to dismiss the keyboard, but it doesn't work. I need some way to call unfocus() on the currently focused TextField before moving on to my next screen.

inverts input on web

image
I entered 1, then 2 then 3.... This was reproduced on many environments... As you enter the numbers, it is possible to see the controls "flash" and I'm pretty sure what I've seen is the fields being redrawn in the wrong order. I'm going to have a quick look at your code to see if I can figure it out. This was working not long ago and is not an issue on android.

used version:

$ flutter --version
Flutter 2.5.3 โ€ข channel stable โ€ข https://github.com/flutter/flutter.git
Framework โ€ข revision 18116933e7 (26 hours ago) โ€ข 2021-10-15 10:46:35 -0700
Engine โ€ข revision d3ea636dc5
Tools โ€ข Dart 2.14.4

and used dependencies:

dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.17.0
logging: ^1.0.2
cupertino_icons: ^1.0.2
flutter_spinkit: ^5.1.0
intl_phone_field: ^2.1.0
pinput: ^1.2.1
toml: ^0.12.0
hive: ^2.0.4
hive_flutter: ^1.1.0
http: ^0.13.3
uuid: ^3.0.4
device_info_plus: ^3.0.1

Keyboard Bug

Steps to Reproduce

  1. Tap the PinPut field to open or show the keyboard.
  2. Tap again the PinPut field while the keyboard is open.

Problem:
The Keyboard is closing then showing again.

Actual:
If the keyboard is already shown tapping the Pinput field again would not cause the keyboard to hide and show again. It should be expected to do nothing unless the keyboard is hidden at first

fieldDecoration not applied when native keyboard disabled

When using pinput with native keyboard disabled, submittedFieldDecoration is not applied.

 PinPut(
    fieldsCount: 4,
    controller: pinPutController,
    obscureText: "โ—",
    useNativeKeyboard: false,
    pinAnimationType: PinAnimationType.scale,
    submittedFieldDecoration: BoxDecoration(
         color: AppColors.accent,
         borderRadius: BorderRadius.circular(20),
    ),
    selectedFieldDecoration: pinPutDecoration.copyWith(
        color: Colors.black,
    ),
    followingFieldDecoration: pinPutDecoration,
    eachFieldConstraints: BoxConstraints.tight(Size(32, 32)),
    textStyle: TextStyle(
      fontSize: 20,
      color: AppColors.accent,
    ),
    onChanged: (val) {
      print("onChanged : $val");
    },
 )

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.