Skip to content

Instantly share code, notes, and snippets.

@faustobdls
Created January 4, 2021 13:16
Show Gist options
  • Save faustobdls/094f8aacb29befa13eeeaf687c6a9ea3 to your computer and use it in GitHub Desktop.
Save faustobdls/094f8aacb29befa13eeeaf687c6a9ea3 to your computer and use it in GitHub Desktop.
error
// 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