Skip to content

Commit

Permalink
Merge pull request #6 from benhurott/feat/money-symbols
Browse files Browse the repository at this point in the history
Feat/money symbols
  • Loading branch information
Ben-hur Santos Ott authored Jun 17, 2018
2 parents 33037d6 + 65f7eec commit fa943bf
Show file tree
Hide file tree
Showing 6 changed files with 471 additions and 173 deletions.
403 changes: 291 additions & 112 deletions .idea/workspace.xml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## [0.5.0] - 2018-jun-17.
* Adding left and right symbols.

## [0.4.1] - 2018-jun-11.
* Fixing not allowed characters on keyboard (thanks to [tobire](https://github.com/tobire)). Related: [issue#3](https://github.com/benhurott/flutter-masked-text/issues/3).

Expand Down
49 changes: 42 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Import the library
import 'package:flutter_masked_text/flutter_masked_text.dart';
```

## MaskedText

Create your mask controller:
```dart
var controller = new MaskedTextController(mask: '000.000.000-00');
Expand Down Expand Up @@ -44,21 +46,21 @@ This is the result:

![sample](doc/mask.mov.gif)

## Mask Options
#### Mask Options

In mask, you can use the following characters:
* `0`: accept numbers
* `A`: accept letters
* `@`: accept numbers and letters
* `*`: accept any character

## Initial Value
#### Initial Value
To start a mask with initial value, just use `text` property on constructor:
```dart
var controller = new MaskedTextController(mask: '000-000', text: '123456');
```

## Update text programaticaly
#### Update text programaticaly
If you want to set new text after controller initiatialization, use the `updateText` method:
```dart
var controller = new MaskedTextController(text: '', mask: '000-000');
Expand All @@ -67,7 +69,7 @@ controller.updateText('123456');
print(controller.text); //123-456
```

## Using custom translators
#### Using custom translators
If you want to use your custom regex to allow values, you can pass a custom translation dictionary:
```dart
const translator = {
Expand All @@ -88,9 +90,6 @@ controller.updateText('12345678');
print(controller.text); //1234 **** **** 5678
```

## Using default TextEditingController
The MaskedTextController extends TextEditingController. You can use all default native methods from this class.

## Money Mask
To use money mask, create a MoneyMaskedTextController:
```dart
Expand All @@ -100,21 +99,57 @@ var controller = new MoneyMaskedTextController();
new TextField(controller: controller, keyboardType: TextInputType.number)
```

#### Decimal and Thousand separator

It's possible to customize `decimal` and `thousand` separators:
```dart
var controller = new MoneyMaskedTextController(decimalSeparator: '.', thousandSeparator: ',');
```

#### Set value programaticaly

To set value programaticaly, use `updateValue`:
```dart
controller.updateValue(1234.0);
```


#### Get double value

To get the number value from masked text, use the `numberValue` property:
```dart
double val = controller.numberValue;
```


#### Using decoration symbols

You can use currency symbols if you want:
```dart
// left symbol
var controller = new MoneyMaskedTextController(leftSymbol: 'R\$ ');
controller.updateValue(123.45);
print(controller.text); //<-- R$ 123,45
// right symbol
var controller = new MoneyMaskedTextController(rightSymbol: ' US\$');
controller.updateValue(99.99);
print(controller.text); //<-- 99,99 US$
// both
var controller = new MoneyMaskedTextController(leftSymbol: 'to pay:', rightSymbol: ' US\$');
controller.updateValue(123.45);
print(controller.text); //<-- to pay: 123,45 US$
```

## Using default TextEditingController
The MaskedTextController and MoneyMaskedTextController extends TextEditingController. You can use all default native methods from this class.

## TODO
- [x] Custom translations
- [x] Money Mask
Expand Down
123 changes: 85 additions & 38 deletions lib/flutter_masked_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
import 'dart:math';

class MaskedTextController extends TextEditingController {

MaskedTextController({ String text, this.mask, Map<String, RegExp> translator }): super(text: text) {
MaskedTextController({String text, this.mask, Map<String, RegExp> translator})
: super(text: text) {
this.translator = translator ?? MaskedTextController.getDefaultTranslator();

this.addListener((){
this.addListener(() {
this.updateText(this.text);
});

Expand All @@ -27,7 +27,8 @@ class MaskedTextController extends TextEditingController {
void set text(String newText) {
if (super.text != newText) {
super.text = newText;
this.selection = new TextSelection.fromPosition(new TextPosition(offset: (newText ?? '').length));
this.selection = new TextSelection.fromPosition(
new TextPosition(offset: (newText ?? '').length));
}
}

Expand All @@ -46,7 +47,7 @@ class MaskedTextController extends TextEditingController {
var maskCharIndex = 0;
var valueCharIndex = 0;

while(true) {
while (true) {
// if mask is ended, break.
if (maskCharIndex == mask.length) {
break;
Expand All @@ -61,7 +62,7 @@ class MaskedTextController extends TextEditingController {
var valueChar = value[valueCharIndex];

// value equals mask, just set
if(maskChar == valueChar) {
if (maskChar == valueChar) {
result += maskChar;
valueCharIndex += 1;
maskCharIndex += 1;
Expand Down Expand Up @@ -89,58 +90,102 @@ class MaskedTextController extends TextEditingController {
}
}

/**
* Mask for monetary values.
*/
class MoneyMaskedTextController extends TextEditingController {

MoneyMaskedTextController({ double initialValue = 0.0, this.decimalSeparator = ',', this.thousandSeparator = '.' }) {
this.addListener((){
MoneyMaskedTextController(
{double initialValue = 0.0,
this.decimalSeparator = ',',
this.thousandSeparator = '.',
this.rightSymbol = '',
this.leftSymbol = ''}) {
_validateConfig();

this.addListener(() {
this.updateValue(this.numberValue);
});

this.updateValue(initialValue);
this.updateValue(initialValue);
}

final String decimalSeparator;
final String thousandSeparator;
final String rightSymbol;
final String leftSymbol;

// this is the maximum supported for double values.
final int _maxLength = 19;

void updateValue(double value) {
String masked = this._applyMask(value);
String masked = this._applyMask(value);

if (masked != this.text) {
this.text = masked;
}
}
if (masked.length > _maxLength) {
masked = masked.substring(0, _maxLength);
}

double get numberValue =>
double.parse(
_getSanitizedText(this.text)
) / 100.0;
if (rightSymbol.length > 0) {
masked += rightSymbol;
}

@override
set text(String newText) {
if (newText.length <= this._maxLength) {
super.text = newText;
if (leftSymbol.length > 0) {
masked = leftSymbol + masked;
}
else {
super.text = newText.substring(0, this._maxLength);

if (masked != this.text) {
this.text = masked;

var cursorPosition = super.text.length - this.rightSymbol.length;
this.selection = new TextSelection.fromPosition(
new TextPosition(offset: cursorPosition));
}
}

this.selection = new TextSelection.fromPosition(new TextPosition(offset: super.text.length));
double get numberValue => double.parse(_getSanitizedText(this.text)) / 100.0;

// @override
// set text(String newText) {
// String formattedText = "";
//
// if (newText.length <= _maxLengthForNumbers) {
// formattedText = newText;
// } else {
// formattedText = newText.substring(0, _maxLengthForNumbers);
// }
//
// super.text = formattedText + "${this.rightSymbol}";
//
// var cursorPosition = super.text.length - this.rightSymbol.length;
//
// this.selection = new TextSelection.fromPosition(
// new TextPosition(offset: cursorPosition));
// }

_validateConfig() {
bool rightSymbolHasNumbers = _getOnlyNumbers(this.rightSymbol).length > 0;

if (rightSymbolHasNumbers) {
throw new ArgumentError("rightSymbol must not have numbers.");
}
}

String _getSanitizedText(String text) {
String cleanedText = text;
String cleanedText = text;

var valuesToSanitize = [
this.thousandSeparator,
this.decimalSeparator
];
var valuesToSanitize = [this.thousandSeparator, this.decimalSeparator];

valuesToSanitize.forEach((val){
cleanedText = cleanedText.replaceAll(val, '');
valuesToSanitize.forEach((val) {
cleanedText = cleanedText.replaceAll(val, '');
});

cleanedText = _getOnlyNumbers(cleanedText);

return cleanedText;
}

String _getOnlyNumbers(String text) {
String cleanedText = text;

var onlyNumbersRegex = new RegExp(r'[^\d]');

cleanedText = cleanedText.replaceAll(onlyNumbersRegex, '');
Expand All @@ -149,11 +194,12 @@ class MoneyMaskedTextController extends TextEditingController {
}

String _applyMask(double value) {
String textRepresentation = value.toStringAsFixed(2).replaceAll('.', this.decimalSeparator);
String textRepresentation =
value.toStringAsFixed(2).replaceAll('.', this.decimalSeparator);

List<String> numberParts = [];

for(var i = 0; i < textRepresentation.length; i++) {
for (var i = 0; i < textRepresentation.length; i++) {
numberParts.add(textRepresentation[i]);
}

Expand All @@ -164,12 +210,13 @@ class MoneyMaskedTextController extends TextEditingController {

if (numberParts.length > l) {
numberParts.insert(numberParts.length - l, this.thousandSeparator);
}
else {
} else {
break;
}
}

return numberParts.join('');
String numberText = numberParts.join('');

return numberText;
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_masked_text
description: Masked text input for flutter.
version: 0.4.1
version: 0.5.0
author: Ben-hur Santos Ott <ben-hur@outlook.com>
homepage: https://github.com/benhurott/flutter-masked-text

Expand Down
Loading

0 comments on commit fa943bf

Please sign in to comment.