GithubHelp home page GithubHelp logo

abhilash-chandran / number_inc_dec Goto Github PK

View Code? Open in Web Editor NEW
10.0 3.0 7.0 10.98 MB

A flutter widget to accept numeric inputs with button to increment and decrement.

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

License: MIT License

Kotlin 0.09% Swift 1.20% Objective-C 0.03% Dart 67.97% HTML 0.78% C++ 15.01% C 1.67% Batchfile 1.15% CMake 11.77% Shell 0.33%
flutter widget number-inc-dec decrement increment

number_inc_dec's Introduction

Build,Test

pub package codecov Buy Me A Coffee

number_inc_dec

A flutter widget that accepts numbers along with buttons to increment and decrement. This is a simple TextFormField with buttons and logic to handle factored increments/decrements and with some additional properties like minimum and maximum allowed value. The factor of incrementing/decrementing is also configurable.

Please check the example section which provides granular examples for each options.

If you like this package give it a thumbs-up πŸ‘.

Breaking Changes from v0.7.x

Some major changes are introduced. I am bumping the version to 0.7.x because following changes may break existing users. Please do report for any issues in the repository, which I will try to address.

  1. autovalidate has been replaced with autovalidateMode. More details in TextFormField docs

    • In your code replace autovalidate: true to autovalidateMode: AutovalidateMode.always

    • In your code replace autovalidate: false to autovalidateMode: AutovalidateMode.disabled

  2. autovalidateMode is by default set to always. The morale behind this is to perform validations similar to html's <input type='number'> tag kind validation performed in chrome. Its not upto the specification but at least mimics to its best.

  3. New attribute enableMinMaxClamping is created to and handles the behaviour of clamping the values to min and max when provided. For example if min is -2 and user enter -5 this is auto-corrected to -2. By default this is attribute is set to true.

  4. New attribute onChanged is introduced which when provided will be called whenever the user edits the value. Note this callback will not be called if any validation error exists.

  5. By default the numbers will be validated for stepped increments like in browser and suggest valid nearest possible values. The intention is to mimic the behaviour of number field in Chrome.

Getting Started

  1. Install the latest version of the package by adding it to pubspec.yaml as noted in the install page.

  2. Import the number_inc_dec.dart as follows import 'package:number_inc_dec/number_inc_dec.dart';.

  3. Utilize the NumberIncrementDecrement as usual like any other flutter widget.

    • e.g.

      NumberInputWithIncrementDecrement(
         controller: TextEditingController(),
         min: -3,
         max: 3,
      ),

Demo with different options

Check the examples sections for the corresponding code snippets.

demo

Configurable options

NumberInputWithIncrementDecrementwidget comes with some configurable options. The same configurations are application for NumberInputPrefabbed widgets.

Property Type Purpose Default Value
controller TextEditingController A mandatory text editing controller to be used by the TextFormField. This is a mandatory field because its the easiest way to access the field's value, when not using a Form widget.
buttonArrangement ButtonArrangement Decides the layout of the increment/decrement buttons. Following values are possible.
1. leftEnd
2. rightEnd
3. incLeftDecRight
4.incRightDecLeft
ButtonArrangement.rightEnd
autovalidate bool This is passed down to the TextFormField. It auto-validates the field with the provided validators. Check TextFormField documentation for more details. true
autovalidateMode AutovalidateMode This is passed down to underlying TextFormField. However this is by default to set to AutovalidateMode.alwaysΒ to perform some default validations like minΒ , maxΒ and incDecFactorΒ based validations. This validation closely mimics html's <input type='number'> tag available in chrome. AutovalidateMode.always
min num Minimum acceptable value for this numeric field. Note: No error message will be shown. To show error a validator can be used and the widget should wrapped in Form widget. 0
max num Maximum acceptable value for this numeric field. Note: No error message will be shown. To show error a validator can be used and the widget should wrapped in Form widget. double.infinity
enableMinMaxClamping bool Clamp the values to either minΒ or maxΒ depending on which value is exceeded. e.g if minΒ is 3 andΒ max is 5 and user enters 7 it will clamped to 5 and if user enters 1 it will be clamped to 3. true
incDecFactor num Factor by which the increment or decrement should happen. e.g. setting it 0.5 increments/decrements the field value by 0.5. This also decides what are valid steps of increment or decrement starting from the minΒ value. 1
initialValue num An initial value to be set to the field. 0
isInt bool A flag to indicate if the field only accepts integer values. To use double values set this field to false. true
numberFieldDecoration InputDecoration This decoration will be used by the TextFormField to handle its decoration. An InputDecoration with an OutlineInputBorder to create a circular border.
widgetContainerDecoration Decoration This is the decoration for the Container that wraps this widget. A simple BoxDecoration with a circular border in Colors.bluegrey color.
enable bool Passed down to the enableΒ attribute of TextFormField. Note, this also disables the inc/dec buttons to avoid accidental changes. true
validator FormFieldValidator A validator function which accepts a string and performs some validation. This is called when this field is wrapped inside a Form widget and called during its validate cycle. The error message to be shown should be returned form this method. A validator that parses the number into a intΒ or doubleΒ is enabled by default. Additionally it enables a min/max validator if enableMinMaxClampingΒ is false.Β  Refer the API documentation for more details.
style TextStyle Passed down to the style attribute of TextFormField null
fractionDigits int The number of digits after the decimal point. Used only if isInt is false. 2
incIcon IconData The icon to be used for the increment button. Icons.arrow_drop_up
decIcon IconData The icon to be used for the decrement button. Icons.arrow_drop_down
incIconDecoration Decoration Decoration for the Increment Icon Defaults to a black border in the bottomΒ  and/or top depending on the buttonArrangement.
decIconDecoration Decoration Decoration for the decrement Icon Defaults to a black border in the bottomΒ  and/or top depending on the buttonArrangement.
incIconColor Color Icon color to be used for Increment button. Defaults to color defined in IconTheme
decIconColor Color Icon color to be used for Decrement button. Defaults to color defined in IconThemeΒ Β 
incIconSize double Icon size to be used for Increment button. Defaults to size defined in IconTheme
decIconSize double Icon size to be used for Decrement button. Defaults to size defined in IconTheme
onIncrement DiffIncDecCallBack A call back function to be called on successful increment.Β This will not be called if the internal validators fail. null
onDecrement DiffIncDecCallBack A call back function to be called on successful decrement.Β This will not be called if the internal validators fail. null
onSubmitted ValueCallBack A call back function to be called on users action denoting completion of editing the value. e.g. pressing the tick mark button. This will not be called if the internal validators fail. If enableMinMaxClamplingΒ is trueΒ and the value is entered is out of the range min to max it is corrected to be equal to either min or max - depending on which side of the range was exceeded. null
onChanged ValueCallBack A call back function to be called on users action editing the value. e.g. typing a new number. This will not be called if the internal validators fail. If enableMinMaxClampling is true and the value is entered is out of the range min to max it is corrected to be equal to either min or max - depending on which side of the range was exceeded. null
scaleWidth double A scaling factor for the width of the widget. 1.0
scaleHeight double A scaling factor for the height of the widget. 1.0
separateIcons bool Show a transparent separator between the increment & decrement buttons. false
incDecBgColor Color Background color of the increment decrement button.
This is set to Colors.lightGreenΒ for all theΒ NumberInputPrefabbedΒ widgets to capture users attention.
widget tonull

number_inc_dec's People

Contributors

abhilash-chandran avatar abulka avatar not-holar avatar rmsmani avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

number_inc_dec's Issues

Expose key property for all the widgets.

Currently none of widgets, accept key as a property. This should be exposed as a new attribute to the NumberInputWithIncrementDecrement and all theNumberInputPrefabbed widgets.

how to style the TextFormField inside this widget?

There doesn't seem to be a way of styling the TextFormField inside the widget.

Normally I can pass in a style to a TextFormField

TextFormField(
                          initialValue: 'initial',
                          style: TextStyle(
                            color: Colors.green,
                            fontSize: 28,
                          ))

however in the NumberInput widget there is no parameter which passes in the style? Quoting from the source code .../number_inc_dec-0.6.0+3/lib/src/number_increment_decrement.dart I cannot see a style:

TextFormField(
                validator: widget.validator ?? _minMaxValidator,
                textAlign: TextAlign.center,
                autovalidate: widget.autovalidate,
                decoration: widget.numberFieldDecoration ??
                    InputDecoration(
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(5.0),
                      ),
                    ),
                controller: _controller,
                keyboardType: TextInputType.numberWithOptions(
                  decimal: !widget.isInt,
                  signed: true,
                ),
                inputFormatters: <TextInputFormatter>[
                  widget.isInt
                      ? WhitelistingTextInputFormatter.digitsOnly
                      : WhitelistingTextInputFormatter(
                          RegExp("[0-9.]"),
                        )
                ],
              )

I want to make a big bold counter number textfield - am I missing something?

ClampAndUpdate inconsitent while editing.

As @abulka noted in the comments of another discusssion.

Clamping to min and max, does not happen unless an onSubmitted callback is created. Clamping should happen always. For example example2() lets you enter in anything you want using text editing - it disregards min/max. This bug presumably was there prior to the onSubmitted enhancement.

This needs to be addressed for all the manual edits.

Initial Thoughts: Exposing all form of callbacks in TextFormField and handling clamping could fix this issue.

_tryParse method not working correctly

/// try to parse the given string into a number. num? _tryParse(String value) { final newValue = num.tryParse(value) - forget here return newValue; }
you forget to add = ?? 0;

and one more

here

if (newValue.isEmpty) { // _defaultValidator(newValue) == null

you can check like this.

please fix this in your code.
An error comes

Thank you

Instead of wrapping TextformField see if it can be extended.

In it current form we wrap the TextformField in the widget and pass attributes down. Which means we hide existing TextFormField attributes. Instead investigate approaches for directly extending the TextformField an overriding the build method or builder of the same to achieve a similar result.

This could reduce naming conflicts while exposing existing attributes.

Fixed Size

Should be able to pass size as argument to this widget.Thanks.

Using this widget inside a `ListView` shows the artifacts outside the `ListView` boundary.

Using both the NumberInputWithIncrementDecrement and NumberInputPrefabbed inside a ListView shows the respective background decoration of the increment/decrement buttons outside the ListView. This is a known issue in flutter and is related to the Ink widget used internally.

A different approach should be created perhaps using the MaterialButton widget. But this means the type of decoration of the increment and decrement button should be adapted and its a breaking change. 😞 So I will wait for the main issue to be fixed at at first and then provide.

Another option is to deprecate the existing option and use a different implementation without affecting existing users.

Existing users can use change the cacheExtent of ListView to 0 to avoid this issue. However this may lead to performance issue in the ListView scrolling.

TzvZgAvcET.mp4

Validation errors causes inc/dec button decoration to displace.

Whenever a validation error is shown, the inc/dec buttons borders are displaced.

image

This is partially due to the way the Ink widget works and cannot be fixed in its current form. An Ink widget is required to give the ripple effect. But the border issue is cause t due to Ink widget not applying the decoration to its child. Check this.

flutter/flutter#21074

So it can be replaced with the solution proposed in the following issue until the above issue is fixed.
flutter/flutter#3782

Basically replace Ink with a Material widget and type as transparency and wrap it in a container to enforce the decoration.

NumberInputPrefabbed class unnecessarily re-declares attributes

This is not a bug but an observation re possibly improving the code. The NumberInputPrefabbed class re-declares all the attributes of its parent class NumberInputWithIncrementDecrement. This means the two attribute areas are duplicates of each other and need to be constantly synchronised and maintained, incl. the comments.

I don't think it is necessary for NumberInputPrefabbed to re-declare and mirror the attributes of its parent class - isn't that what super() is for? I did an experiment and mocked up the existing architecture, adding a few dummy types just to reduce complexity and dependencies:

// trying to understand why we have to declare 
// all the attributes twice

// dart example/temp2_inherit_eg.dart

class NumberInputPrefabbed extends NumberInputWithIncrementDecrement {
  final bool enabled;
  final num min;
  final num max;
  final int incIconDecoration; // dummy type
  final int decIconDecoration; // dummy type

  NumberInputPrefabbed.squaredButtons({
    this.enabled = true,
    this.min = -2,
    this.max = double.infinity,
  })  : incIconDecoration = 555,
        decIconDecoration = 777;
}

class NumberInputWithIncrementDecrement extends StatefulWidgetDummy { // dummy type
  final bool enabled;
  final num min;
  final num max;
  final int incIconDecoration; // dummy type
  final int decIconDecoration; // dummy type

  NumberInputWithIncrementDecrement({
    this.enabled = true,
    this.min = 0,
    this.max = double.infinity,
    this.incIconDecoration,
    this.decIconDecoration,
  });

  void build() {
    print(
        'enabled $enabled min $min max $max incIconDecoration $incIconDecoration decIconDecoration $decIconDecoration');
  }
}

class StatefulWidgetDummy {} // dummy type

main() {
  var widget = NumberInputWithIncrementDecrement(
      enabled: true,
      min: -2,
      max: 4,
      incIconDecoration: 11,
      decIconDecoration: 12);
  widget.build();

  var widget2 = NumberInputPrefabbed.squaredButtons(
      enabled: true,
      min: -1,
      max: 4,
      // no need to supply these, as these are built for us by the '.squaredButtons' constructor
      // incIconDecoration: 11,
      // decIconDecoration: 12
      );
  widget2.build();
}

output

enabled true min -2 max 4 incIconDecoration 11 decIconDecoration 12
enabled true min -1 max 4 incIconDecoration 555 decIconDecoration 777

Now let's implement NumberInputPrefabbed differently, without duplicating all the attributes and simply calling super instead:

class NumberInputPrefabbedNew extends NumberInputWithIncrementDecrement {
  // All attributes have been removed!
  NumberInputPrefabbedNew.squaredButtons({bool enabled, num min, num max})
      : super(
            enabled: enabled,
            min: min,
            max: max,
            incIconDecoration: 555,
            decIconDecoration: 777);
}

it works:

main() {
  var widget3 = NumberInputPrefabbedNew.squaredButtons(
    enabled: true,
    min: -55,
    max: 66,
  );
  widget3.build();
}

output

enabled true min -55 max 66 incIconDecoration 555 decIconDecoration 777

I think making this change would simplify the codebase and reduce duplication - perhaps I'm missing something?

Shows a separator even when separated Icons are left to true. [bug]

image
image

 NumberInputWithIncrementDecrement(
      controller: TextEditingController(),
      min: 1,
      enabled: true,
      decIcon: Icons.remove,
      incIcon: Icons.add,
      separateIcons: true,
      // decIconDecoration: BoxDecoration(
      //     border: Border.all(
      //         color: Colors.transparent,
      //         style: BorderStyle.none)),
      decIconColor: Colors.red[400],
      incIconColor: greenHeading,
      widgetContainerDecoration:
          BoxDecoration(
              border: Border.all(
                  color: Colors
                      .transparent)),
      numberFieldDecoration:
          InputDecoration(
        enabledBorder:
            UnderlineInputBorder(
          borderSide: BorderSide(
              color: headingtextColor),
        ),
        focusedBorder:
            UnderlineInputBorder(
          borderSide: BorderSide(
              color: headingtextColor),
        ),
        fillColor: Colors.transparent,
      ),
      scaleHeight: 0.8,
      scaleWidth: 0.8,
      max: 50,
    ),

State Management issue

hello, I have been working with the library this morning but I faced an error in the package when I use data from a provider. so the scenario is the next: I have a list of items stocked in a provider (cart) every time the user picks a new item I add it to the stack in the provider. each item has a quantity so the user can increment/decrement. I was using your library I found that in case the user delete an item from the stack. the library keeps an old value. ex: (item 1 - q = 50 / item 2 - q10) if I delete item 1, the quantity of item 2 (using the library) change to 50!! I checked my provider, and everything is good. the problem is within the library it keeps a trace of an old stack so it still uses the index of the old library.

hope you fix this.

demo example won't compile - missing code fragment

Your example at the bottom of https://pub.dev/packages/number_inc_dec/example won't compile or run.

sWidget {     <------ MISSING CODE FRAGMENT ON JUST THIS LINE
  const Example1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return NumberInputWithIncrementDecrement(
      controller: TextEditingController(),
    );
  }
}

should be

class Example1 extends StatelessWidget {    <------ FIXED
  const Example1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return NumberInputWithIncrementDecrement(
      controller: TextEditingController(),
    );
  }
}

[Bug] Cursor position is not proper after using inc/dec buttons

Issue:
I am using this plugin to take user input for a demo.

What I have observed is that once the input field gets focus it shows cursor properly. But after the cursor is visible if you use the increment & decrement buttons then the cursor moves in the center of the text.

It seems that it can be solved by removing the focus from text field when user clicks any of the buttons.
This is my take on the solution, but I do not know the reason behind this, so this might be the exact solution.

If you need more details regarding this issue then please tag me in the comments of this issue, I'll try to get back to you as soon as possible.

Code I used to create the input field with customizations:

NumberInputWithIncrementDecrement(
  controller: _controller,
  initialValue: _units,
  isInt: true,
  widgetContainerDecoration: BoxDecoration(
     borderRadius: BorderRadius.circular(5.0),
     border: Border.all(
     color: Color(0xFFE0E0E0),
     width: 2.0,
    ),
  ),
  onIncrement: _updateUnits,
  onDecrement: _updateUnits,
  autovalidate: true,
  validator: (value) {
            // code omitted
  },
 ),

Please check the attached video for reproduction steps:

signal-2021-04-16-124902.mp4

Align number

There is a way to align the number on left or right?

The WhitelistingTextInputFormatter.digitsOnly is deprecated and should be replaced with FilteringTextInputFormatter.digitsOnly

The WhitelistingTextInputFormatter is deprecated in the flutter dev channel 1.21.0-9.0.pre, This will be case in the upcoming stable release of 1.21.0 which according to flutters release cycle be in November. So this should be handled alongside the respective flutter stable release.

https://github.com/Abhilash-Chandran/number_inc_dec/blob/master/lib/src/number_increment_decrement.dart#L619
Following is the current version of this part of code.

inputFormatters: <TextInputFormatter>[
                  widget.isInt
                      ? WhitelistingTextInputFormatter.digitsOnly
                      : WhitelistingTextInputFormatter(
                          RegExp("[0-9.]"),
                        )
                ],

The above should be replaced with the respective FilteringTextInputFormatter as the deprecation warning suggests.

Note this fix can only be released stable release in which this change FilteringTextInputFormatter is available. So it can't be release prior to that. A hotfix release can be made when the stable release is out earlier than expected(Novermber) πŸ˜„

Expose all the relevant attributes of TextFormField.

In its current, many of TextformField attributes are hidden from the user. While not all of attribute are relevant, a number of attributes should be exposed to the user. Following are relevant fields I find missing.

  1. FocusNode focusNode
  2. TextInputAction textInputAction
  3. StrutStyle strutStyle
  4. TextDirection textDirection
  5. TextAlign textAlign
  6. TextAlignVertical textAlignVertical
  7. bool autofocus
  8. bool readOnly
  9. ToolbarOptions toolbarOptions
  10. bool showCursor
  11. ValueChanged<String> onChanged already done
  12. GestureTapCallback onTap
  13. VoidCallback onEditingComplete
  14. ValueChanged<String> onFieldSubmitted already done
  15. FormFieldSetter<String> onSaved

If someone else finds any other relevant field missing, please comment below those fields.

Exception when NumberInputWithIncrementDecrement is a child of a Row

Placed two NumberInputWithIncrementDecrement inside a Row and it resulted in an exception:

═════════════════════════════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderDecoratedBox#25c34 relayoutBoundary=up6
'package:flutter[/src/rendering/box.dart]()':
package:flutter/…/rendering/box.dart:1
Failed assertion: line 1982 pos 12: 'hasSize'

The relevant error-causing widget was
NumberInputWithIncrementDecrement

Code sample to reproduce the issue:

Widget build(BuildContext context) {
    return Scaffold(
      body: Column(children: [
        Row(
          children: [
            NumberInputWithIncrementDecrement(
              controller: TextEditingController(),
            ),
            NumberInputWithIncrementDecrement(
              controller: TextEditingController(),
            )
          ],
        ),
      ]));
  }

Note: Same issue happens with only one NumberInputWithIncrementDecrement as a child of a Row.

What was I trying to achieve: In my project I could fit two spinners in the same row since the result number will be a maximum of 4 digits, i.e, 9999. Doing this would save a lot of space in the screen.

Padding Issue

In the prefabbed widget and normal widget, I want to add padding between buttons and the input field.
How can I achieve this?

While editing the numbers manually the incDecFactor is not considered.

When editing the numbers, user are able to enter different number without getting affected by the increment decrement factor.
manual_edit

As @abulka mentioned in another discussion:

  • A relaxed interpretation of what should happen would be that the user can enter anything in range, and the inc/dec works off that.
  • The other interpretation is that whatever the user enters is corrected to be a multiple of the inc/dec factor based off the min. This is bit trickier and also relies on correct settings of the min/max/inc widget values to be fully self consistent. For example I could set up min: -1 max: 4 inc: 2 and never be able to get to 4. I could enter 4 manually and it would auto-correct to a multiple of the inc. factor starting from min, which would be 3. The user might not be so happy, since the max is 4 !

Entering negative numbers when text editing is not possible

In its current form the widget doesn't allow the entering negative numbers. Meaning it doesn't allow entering the - minus symbol to be entered. A proper regular expression needs to be created for the same. Some of the requirements would be.

  1. The symbol - should only be allowed at the beginning of the entry.
  2. It should not be allowed for fields with min value greater than -1.

onIncrement/onDecrement: 'Null Function()' can't be assigned to 'void Function(num)'. How to use?

Unable to add any statement to onIncrement or onDecrement

Simple examples
onIncrement: () {var myInt = 1}
or
onIncrement: () => myMethod(),

results in

The argument type 'Null Function()' can't be assigned to the parameter type 'void Function(num)'.
and
The argument type 'dynamic Function()' can't be assigned to the parameter type 'void Function(num)'.

Can we get an example of how to use?? Is this right?

NumberInputWithIncrementDecrement(
                      controller: myTEC,
                      min: 1,
                      max: 10,
                      initialValue: 5,
                      onIncrement: myMethod(int.parse(myTEC)),
)

Getting Null error if numbers are removed from the tool

Getting the below error if the number is removed from the widget, with the help of emulator keyboard
image.

If no value is available the above error is thrown _clampAndUpdate function in number_increment_decrement.dart file.

Am using the latest version.
Version details : number_inc_dec: ^0.8.0

my code

NumberInputPrefabbed.roundedButtons(
  controller: _noOfPagesController,
  min: 1,
  max: 1000,
  initialValue: 5,
  incDecBgColor: Colors.blueAccent,
  enableMinMaxClamping: true,
  autovalidateMode: AutovalidateMode.always,
  buttonArrangement: ButtonArrangement.incRightDecLeft,
  validator: (value) {
    if (value == null || value.isEmpty) {
      return "1";
    }
  },
),

Getting the below error even after including the validator function any thoughts to fix this
image


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.