Created
January 4, 2021 13:16
-
-
Save faustobdls/094f8aacb29befa13eeeaf687c6a9ea3 to your computer and use it in GitHub Desktop.
error
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file | |
// for details. All rights reserved. Use of this source code is governed by a | |
// BSD-style license that can be found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/services.dart'; | |
import 'package:flutter/foundation.dart'; | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
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> { | |
int _counter = 0; | |
void _incrementCounter() { | |
setState(() { | |
_counter++; | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(widget.title), | |
), | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Text( | |
'You have pushed the button this many times:', | |
), | |
Text( | |
'$_counter', | |
style: Theme.of(context).textTheme.headline4, | |
), | |
BemolTextField(label: 'label', | |
rulesOnChange: (_) => (_?.length != 0) ? BemolTextInputMessage.error('ERRORR') : BemolTextInputMessage.none), | |
], | |
), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: _incrementCounter, | |
tooltip: 'Increment', | |
child: Icon(Icons.add), | |
), | |
); | |
} | |
} | |
class BemolTextField extends StatefulWidget { | |
/// Create a text field with the Bemol Account visual identity | |
BemolTextField({ | |
Key key, | |
@required this.label, | |
this.prefixIcon, | |
this.hintText, | |
@Deprecated('The internal logic of use of this parameter has been removed, having no real effects on the widget, it is recommended to use the rulesOnEnter, rulesOnChange and rulesOnLeave parameters instead') | |
this.validator, | |
this.maxLength = 100, | |
this.textCapitalization = TextCapitalization.words, | |
this.keyboardType, | |
this.inputFormatters, | |
@Deprecated('The internal logic of use of this parameter has been removed, having no real effects on the widget, it is recommended to use the rulesOnEnter, rulesOnChange and rulesOnLeave parameters instead') | |
this.controller, | |
this.obscureText = false, | |
this.rulesOnEnter, | |
this.rulesOnChange, | |
this.rulesOnLeave, | |
this.helperFixInfoMessage, | |
this.padding = const EdgeInsets.symmetric(horizontal: 28, vertical: 20), | |
this.enabled = true, | |
this.suffixIcon, | |
this.initialValue, | |
}) : super(key: key); | |
/// Padding of Text Field | |
final EdgeInsets padding; | |
/// Text displayed above the text field | |
final String label; | |
/// Icon displayed at the beginning of the text field | |
final IconData prefixIcon; | |
/// Help text shown while the field is empty (Placeholder) | |
final String hintText; | |
/// Function that validates the value entered in the field. Returns a string stating the error or null | |
final Function(String) validator; | |
///Fix in bottom, info message style. | |
/// | |
///If not informed, no message will be displayed below the field. | |
final BemolTextInputMessage Function() helperFixInfoMessage; | |
///This parameter receives a function that will be executed every time the user enters the field (focus on the field). | |
/// | |
///The return of this function will define which message and style should be shown below the text field. | |
/// | |
///The function's string parameter is the value read from the field itself. | |
/// | |
///If not informed, no message will be displayed below the field. | |
final BemolTextInputMessage Function(String) rulesOnEnter; | |
///This parameter receives a function that will be executed each time the field changes. | |
/// | |
///The return of this function will define which message and style should be shown below the text field. | |
/// | |
///The function's string parameter is the value read from the field itself. | |
/// | |
///If not informed, no message will be displayed below the field. | |
final BemolTextInputMessage Function(String) rulesOnChange; | |
///This parameter receives a function that will be executed every time the user leaves the field (remove focus from the field). | |
/// | |
///The return of this function will define which message and style should be shown below the text field. | |
/// | |
///The function's string parameter is the value read from the field itself. | |
/// | |
///If not informed, no message will be displayed below the field. | |
final BemolTextInputMessage Function(String) rulesOnLeave; | |
/// Maximum number of characters accepted in the text field. Default: 100. | |
final int maxLength; | |
/// Configures how the capitalization will happen. Default: By words. | |
final TextCapitalization textCapitalization; | |
/// Type of keyboard to be displayed when the user taps the text field | |
final TextInputType keyboardType; | |
/// Accepts a list of formatters (masks) that will be applied to the field at typing time | |
final List<TextInputFormatter> inputFormatters; | |
/// Associates a controller to this field, if not informed, the component will create one internally | |
final TextEditingController controller; | |
/// If set to true, hides characters as they are entered | |
final bool obscureText; | |
/// If true, it means that the field must be free to edit, otherwise it is blocked | |
final bool enabled; | |
/// The icon that will appear on the right side of the input text | |
final Widget suffixIcon; | |
/// Initial Value or setted value in field | |
final String initialValue; | |
@override | |
_BemolTextFieldState createState() => _BemolTextFieldState(); | |
} | |
class _BemolTextFieldState extends State<BemolTextField> with TickerProviderStateMixin { | |
TextEditingController _controller = TextEditingController(); | |
BemolTextInputMessage _bemolTextInputMessage = BemolTextInputMessage.none; | |
bool _hideText = true; | |
DefaultTheme theme = DefaultTheme(); | |
AnimationController _aController; | |
Animation<double> _animation; | |
@override | |
void initState() { | |
super.initState(); | |
_controller = widget.controller == null ? _controller : widget.controller; | |
if (widget.initialValue != null) { | |
_controller.text = widget.initialValue; | |
} | |
_aController = AnimationController( | |
duration: const Duration(milliseconds: 1000), | |
vsync: this, | |
value: 0, | |
lowerBound: 0, | |
upperBound: 1); | |
_animation = | |
CurvedAnimation(parent: _aController, curve: Curves.fastOutSlowIn); | |
} | |
@override | |
void dispose() { | |
_controller.dispose(); | |
super.dispose(); | |
} | |
void toogleAnimationError() { | |
if (_bemolTextInputMessage?.message != null && | |
_bemolTextInputMessage.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR) { | |
_aController.forward(from: 0); | |
} else { | |
_aController.forward(from: 1); | |
} | |
} | |
void _onChangeListener() { | |
if (_controller?.text != null && widget.rulesOnChange != null) { | |
setState(() { | |
_bemolTextInputMessage = widget.rulesOnChange(_controller?.text); | |
}); | |
} | |
toogleAnimationError(); | |
} | |
void _onEnterListener() { | |
if (_controller?.text != null && widget.rulesOnEnter != null) { | |
setState(() { | |
_bemolTextInputMessage = widget.rulesOnEnter(_controller?.text); | |
}); | |
} | |
} | |
void _onLeaveListener() { | |
if (_controller?.text != null && widget.rulesOnLeave != null) { | |
setState(() { | |
_bemolTextInputMessage = widget.rulesOnLeave(_controller?.text); | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
padding: widget.padding, | |
child: FocusScope( | |
onFocusChange: (hasFocus) => | |
hasFocus ? _onEnterListener() : _onLeaveListener(), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Text( | |
widget.label, | |
style: theme | |
.textFieldLabelStyle | |
.copyWith( | |
color: _bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: theme | |
.textFieldLabelColor, | |
), | |
), | |
SizedBox(height: 4), | |
TextFormField( | |
enabled: widget.enabled, | |
controller: _controller, | |
maxLength: widget.maxLength, | |
inputFormatters: widget.inputFormatters, | |
keyboardType: widget.keyboardType, | |
obscureText: widget.obscureText && _hideText, | |
textCapitalization: widget.textCapitalization, | |
cursorColor: | |
theme.primaryColorMain, | |
onChanged: (_) => _onChangeListener(), | |
decoration: InputDecoration( | |
// errorText: _bemolTextInputMessage?.message, | |
// errorStyle: theme | |
// .textFieldMessageStyle | |
// .copyWith( | |
// color: _bemolTextInputMessage | |
// ?.bemolTextInputMessageType == | |
// BemolTextInputMessageType.SUCCESS | |
// ? theme | |
// .colorScheme | |
// .success | |
// : _bemolTextInputMessage?.bemolTextInputMessageType == | |
// BemolTextInputMessageType.ERROR | |
// ? theme | |
// .colorScheme | |
// .danger | |
// : null, | |
// ), | |
filled: true, | |
fillColor: widget.enabled | |
? theme | |
.textFieldBackgroudColor | |
: theme | |
.shadesOfDark[100], | |
counter: Offstage(), | |
isDense: true, | |
prefixIcon: widget.prefixIcon != null | |
? Padding( | |
padding: const EdgeInsets.symmetric( | |
vertical: 12.0, horizontal: 12.0), | |
child: Icon( | |
widget.prefixIcon, | |
color: theme | |
.primaryColorMain, | |
), | |
) | |
: null, | |
prefixIconConstraints: BoxConstraints(minWidth: 18.0), | |
suffixIcon: widget.obscureText | |
? IconButton( | |
highlightColor: Colors.transparent, | |
splashColor: Colors.transparent, | |
padding: EdgeInsets.zero, | |
constraints: BoxConstraints(minWidth: 18.0), | |
icon: Icon( | |
_hideText ? Icons.visibility_off : Icons.visibility, | |
color: Colors.black, | |
semanticLabel: _hideText | |
? 'Senha oculta. Mostrar senha.' | |
: 'Senha visível. Ocultar senha.', | |
), | |
onPressed: () => setState(() { | |
_hideText = !_hideText; | |
}), | |
) | |
: widget.suffixIcon, | |
suffixIconConstraints: BoxConstraints(minWidth: 38.0), | |
border: OutlineInputBorder( | |
borderSide: widget.enabled == false | |
? BorderSide.none | |
: BorderSide( | |
color: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: Colors.transparent), | |
), | |
enabledBorder: OutlineInputBorder( | |
borderSide: widget.enabled == false | |
? BorderSide.none | |
: BorderSide( | |
color: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: Colors.transparent), | |
), | |
focusedBorder: OutlineInputBorder( | |
borderSide: widget.enabled == false | |
? BorderSide.none | |
: BorderSide( | |
color: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: Colors.transparent), | |
), | |
hintText: widget.hintText, | |
hintStyle: theme | |
.textFieldInputStyle, | |
errorBorder: OutlineInputBorder( | |
borderSide: BorderSide( | |
color: _bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: Colors.transparent, | |
), | |
), | |
focusedErrorBorder: OutlineInputBorder( | |
borderSide: BorderSide( | |
color: _bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: Colors.transparent, | |
), | |
), | |
), | |
), | |
if (_bemolTextInputMessage != null && | |
_bemolTextInputMessage.message != null) ...{ | |
// SizedBox(height: 4), | |
FadeTransition( | |
opacity: _animation, | |
child: Text( | |
_bemolTextInputMessage?.message, | |
style: theme | |
.textFieldMessageStyle | |
.copyWith( | |
color: | |
_bemolTextInputMessage?.bemolTextInputMessageType == | |
BemolTextInputMessageType.SUCCESS | |
? theme | |
.colorScheme | |
.success | |
: _bemolTextInputMessage | |
?.bemolTextInputMessageType == | |
BemolTextInputMessageType.ERROR | |
? theme | |
.colorScheme | |
.danger | |
: null, | |
), | |
), | |
), | |
}, | |
if (widget.helperFixInfoMessage != null && | |
widget.helperFixInfoMessage().message != null) ...{ | |
if (_bemolTextInputMessage != null && | |
_bemolTextInputMessage?.message != null) ...{ | |
SizedBox(height: 4), | |
}, | |
Text( | |
widget.helperFixInfoMessage().message, | |
style: theme | |
.textFieldMessageStyle, | |
), | |
} | |
], | |
), | |
), | |
); | |
} | |
} | |
enum BemolTextInputMessageType { ERROR, SUCCESS, HELPER } | |
class BemolTextInputMessage { | |
const BemolTextInputMessage(this.message, {this.bemolTextInputMessageType = BemolTextInputMessageType.HELPER}); | |
final String message; | |
final BemolTextInputMessageType bemolTextInputMessageType; | |
static BemolTextInputMessage error(String message) { | |
return BemolTextInputMessage(message, bemolTextInputMessageType: BemolTextInputMessageType.ERROR); | |
} | |
static BemolTextInputMessage success(String message) { | |
return BemolTextInputMessage(message, bemolTextInputMessageType: BemolTextInputMessageType.SUCCESS); | |
} | |
static BemolTextInputMessage helper(String message) { | |
return BemolTextInputMessage(message, bemolTextInputMessageType: BemolTextInputMessageType.HELPER); | |
} | |
static BemolTextInputMessage none = BemolTextInputMessage(null); | |
} | |
class DefaultTheme { | |
Color _primaryColor = Color(0xFF0286D1); | |
Color get primaryColorMain => _primaryColor; | |
Color get primaryOutlineColor => _primaryColor; | |
Color get primaryColorLighter => Color(0xFF02C2EF); | |
Color get primaryColorDarker => Color(0xFF0047A5); | |
Color _secondaryColor = Color(0xFFA66DD4); | |
Color get secondaryColor => _secondaryColor; | |
CustomColorScheme get colorScheme => CustomColorScheme( | |
primary: _primaryColor, | |
secondary: _secondaryColor, | |
success: Color(0xFF23C653), | |
warning: Color(0xFFEFB52D), | |
danger: Color(0xFFFF4539)); | |
Color get backgroundColor => Color(0xFFF7F7F7); | |
ColorSwatch<int> get gray => ColorSwatch<int>(50, { | |
50: Color(0xFFD6D6D6), | |
100: Color(0xFFF2F2F5), | |
200: Color(0xFF8E90A6), | |
300: Color(0xFF555770), | |
400: Color(0xFFEBEBF0), | |
800: Color(0xFF555555), | |
}); | |
ColorSwatch<int> get shadesOfLight => ColorSwatch<int>(100, { | |
100: Color(0xFFFFFFFF), | |
200: Color(0xFFFAFAFC), | |
300: Color(0xFFF2F2F5), | |
400: Color(0xFFEBEBF0), | |
500: Color(0xFFE3E4EB), | |
}); | |
ColorSwatch<int> get shadesOfDark => ColorSwatch<int>(100, { | |
100: Color(0xFFC7C8D9), | |
200: Color(0xFF8E90A6), | |
300: Color(0xFF555770), | |
400: Color(0xFF28293D), | |
500: Color(0xFF000000), | |
}); | |
ColorSwatch<int> get shadesOfGray => ColorSwatch<int>(600, { | |
100: shadesOfLight[100], | |
200: shadesOfLight[200], | |
300: shadesOfLight[300], | |
400: shadesOfLight[400], | |
500: shadesOfLight[500], | |
600: shadesOfDark[100], | |
700: shadesOfDark[200], | |
800: shadesOfDark[300], | |
900: shadesOfDark[400], | |
1000: shadesOfDark[500], | |
}); | |
ThemeData get theme => ThemeData( | |
primaryColor: this._primaryColor, | |
fontFamily: 'Open Sans', | |
appBarTheme: AppBarTheme( | |
color: primaryColorMain, | |
centerTitle: true, | |
elevation: 0, | |
iconTheme: IconThemeData( | |
size: 20, | |
color: shadesOfLight[100], | |
), | |
), | |
); | |
TextStyle get appBarFeatureSearch => TextStyle( | |
color: shadesOfDark[200], | |
fontSize: 16, | |
fontFamily: 'Montserrat', | |
fontWeight: FontWeight.w400, | |
); | |
Color get ribbonBemolRed => Color(0xFFFF4539); | |
Color get ribbonBemolBlue => Color(0xFF0286D1); | |
Color get ribbonBemolWhite => Color(0xFFFFFFFF); | |
TextStyle get appBarTitle => TextStyle( | |
color: shadesOfLight[100], | |
fontSize: 16, | |
fontFamily: 'Open Sans', | |
fontWeight: FontWeight.w600, | |
); | |
TextStyle get productName => TextStyle( | |
fontFamily: 'Open Sans', | |
fontSize: 14, | |
color: shadesOfDark[500], | |
fontWeight: FontWeight.w600, | |
); | |
TextStyle get productPrice => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 20, | |
color: primaryColorMain, | |
fontWeight: FontWeight.w600, | |
); | |
TextStyle get productPricePromotion => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 20, | |
color: colorScheme.danger, | |
fontWeight: FontWeight.w600, | |
); | |
TextStyle get productSupportTexts => TextStyle( | |
fontFamily: 'Open Sans', | |
fontSize: 12, | |
color: shadesOfDark[200], | |
fontWeight: FontWeight.w600, | |
); | |
Color get categoryIconLeftColor => colorScheme.danger; | |
TextStyle get categoryTitle => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 16, | |
color: primaryColorMain, | |
fontWeight: FontWeight.w700, | |
); | |
Color get categoryIconRightColor => primaryColorMain; | |
// Profile | |
TextStyle get signupButtonContinue => TextStyle( | |
fontFamily: "Montserrat", | |
fontSize: 14, | |
fontWeight: FontWeight.w700, | |
color: Colors.white, | |
); | |
TextStyle get signupButtonBack => TextStyle( | |
fontFamily: "Montserrat", | |
fontSize: 14, | |
fontWeight: FontWeight.w700, | |
color: primaryColorMain, | |
); | |
TextStyle get signupTextPersonType => TextStyle( | |
fontFamily: "Montserrat", | |
fontSize: 20, | |
fontWeight: FontWeight.w600, | |
); | |
TextStyle get signupTextDescription => TextStyle( | |
fontFamily: "Montserrat", | |
fontSize: 24, | |
fontWeight: FontWeight.w700, | |
); | |
TextStyle get signupTitle => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 16, | |
color: Colors.black, | |
fontWeight: FontWeight.w600, | |
); | |
TextStyle get signupLink => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 14, | |
color: primaryColorMain, | |
fontWeight: FontWeight.w500, | |
); | |
TextStyle get signupSubTitle => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 16, | |
color: shadesOfDark[200], | |
fontWeight: FontWeight.w400, | |
); | |
TextStyle get signupPostalCodeTitle => TextStyle( | |
fontFamily: 'Montserrat', | |
fontSize: 24, | |
color: Colors.black, | |
fontWeight: FontWeight.w500, | |
); | |
TextStyle get signupPostalCodeSubTitle => TextStyle( | |
color: shadesOfDark[300], | |
fontFamily: 'Montserrat', | |
fontSize: 14, | |
fontWeight: FontWeight.w600, | |
fontStyle: FontStyle.normal, | |
); | |
Color get textFieldLabelColor => shadesOfDark[500]; | |
TextStyle get textFieldLabelStyle => TextStyle( | |
fontFamily: 'Montserrat', | |
fontWeight: FontWeight.w400, | |
fontStyle: FontStyle.normal, | |
fontSize: 14, | |
); | |
Color get textFieldInputColor => shadesOfDark[300]; | |
TextStyle get textFieldInputStyle => TextStyle( | |
fontFamily: 'Open Sans', | |
fontWeight: FontWeight.w400, | |
fontStyle: FontStyle.normal, | |
fontSize: 16, | |
); | |
Color get textFieldBackgroudColor => shadesOfLight[400]; | |
TextStyle get textFieldMessageStyle => TextStyle( | |
fontFamily: 'Montserrat', | |
color: shadesOfDark[200], | |
fontWeight: FontWeight.w400, | |
fontStyle: FontStyle.normal, | |
fontSize: 14, | |
); | |
} | |
class CustomColorScheme with Diagnosticable { | |
final Color primary; | |
final Color secondary; | |
final Color danger; | |
final Color warning; | |
final Color success; | |
CustomColorScheme( | |
{@required this.primary, | |
@required this.secondary, | |
@required this.danger, | |
@required this.warning, | |
@required this.success}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment