334 lines
14 KiB
Dart
334 lines
14 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:maxdash/controller/forms/mask_controller.dart';
|
|
import 'package:maxdash/helpers/theme/app_theme.dart';
|
|
import 'package:maxdash/helpers/utils/mixins/ui_mixin.dart';
|
|
import 'package:maxdash/helpers/utils/my_shadow.dart';
|
|
import 'package:maxdash/helpers/utils/my_string_utils.dart';
|
|
import 'package:maxdash/helpers/widgets/my_breadcrumb.dart';
|
|
import 'package:maxdash/helpers/widgets/my_breadcrumb_item.dart';
|
|
import 'package:maxdash/helpers/widgets/my_card.dart';
|
|
import 'package:maxdash/helpers/widgets/my_flex.dart';
|
|
import 'package:maxdash/helpers/widgets/my_flex_item.dart';
|
|
import 'package:maxdash/helpers/widgets/my_spacing.dart';
|
|
import 'package:maxdash/helpers/widgets/my_text.dart';
|
|
import 'package:maxdash/helpers/widgets/my_text_style.dart';
|
|
import 'package:maxdash/view/layouts/layout.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
class MaskScreen extends StatefulWidget {
|
|
const MaskScreen({super.key});
|
|
|
|
@override
|
|
State<MaskScreen> createState() => _MaskScreenState();
|
|
}
|
|
|
|
class _MaskScreenState extends State<MaskScreen> with SingleTickerProviderStateMixin, UIMixin {
|
|
late MaskController controller;
|
|
|
|
@override
|
|
void initState() {
|
|
controller = MaskController();
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Layout(
|
|
child: GetBuilder(
|
|
init: controller,
|
|
tag: 'mask_controller',
|
|
builder: (controller) {
|
|
return Column(
|
|
children: [
|
|
Padding(
|
|
padding: MySpacing.x(flexSpacing),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
MyText.titleMedium("Form Mask", fontSize: 18, fontWeight: 600),
|
|
MyBreadcrumb(
|
|
children: [MyBreadcrumbItem(name: 'Form'), MyBreadcrumbItem(name: 'Mask', active: true)],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
MySpacing.height(flexSpacing),
|
|
Padding(
|
|
padding: MySpacing.x(flexSpacing / 2),
|
|
child: MyFlex(
|
|
children: [
|
|
MyFlexItem(
|
|
sizes: 'lg-6 md-6',
|
|
child: MyCard.bordered(
|
|
borderRadiusAll: 4,
|
|
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
|
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
|
paddingAll: 24,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
MyText.labelMedium(
|
|
"Date Style 1",
|
|
),
|
|
MySpacing.height(8),
|
|
TextFormField(
|
|
inputFormatters: [
|
|
DateTextFormatter(),
|
|
],
|
|
decoration: InputDecoration(
|
|
border: outlineInputBorder,
|
|
enabledBorder: outlineInputBorder,
|
|
focusedBorder: focusedInputBorder,
|
|
contentPadding: MySpacing.all(16),
|
|
isCollapsed: true,
|
|
helperText: '"dd/mm/yyy"',
|
|
helperStyle: MyTextStyle.bodySmall(muted: true)),
|
|
),
|
|
MySpacing.height(16),
|
|
MyText.labelMedium(
|
|
"Date Style 1",
|
|
),
|
|
MySpacing.height(8),
|
|
TextFormField(
|
|
inputFormatters: [
|
|
LengthLimitingTextInputFormatter(10),
|
|
PhoneInputFormatter(),
|
|
],
|
|
decoration: InputDecoration(
|
|
border: outlineInputBorder,
|
|
enabledBorder: outlineInputBorder,
|
|
focusedBorder: focusedInputBorder,
|
|
contentPadding: MySpacing.all(16),
|
|
isCollapsed: true,
|
|
helperText: '"123456789"',
|
|
helperStyle: MyTextStyle.bodySmall(muted: true)),
|
|
),
|
|
MySpacing.height(16),
|
|
MyText.labelMedium(
|
|
"Date Style 2",
|
|
),
|
|
MySpacing.height(8),
|
|
TextFormField(
|
|
inputFormatters: [
|
|
DateTextFormatter(),
|
|
],
|
|
decoration: InputDecoration(
|
|
border: outlineInputBorder,
|
|
enabledBorder: outlineInputBorder,
|
|
focusedBorder: focusedInputBorder,
|
|
contentPadding: MySpacing.all(16),
|
|
isCollapsed: true,
|
|
helperText: '"mm/dd/yyy"',
|
|
helperStyle: MyTextStyle.bodySmall(muted: true)),
|
|
),
|
|
],
|
|
),
|
|
)),
|
|
MyFlexItem(
|
|
sizes: 'lg-6 md-6',
|
|
child: MyCard.bordered(
|
|
borderRadiusAll: 4,
|
|
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
|
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
|
paddingAll: 24,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
MyText.labelMedium(
|
|
"Mask",
|
|
),
|
|
MySpacing.height(8),
|
|
TextFormField(
|
|
inputFormatters: [
|
|
MaskTextFormatter(),
|
|
],
|
|
decoration: InputDecoration(
|
|
border: outlineInputBorder,
|
|
enabledBorder: outlineInputBorder,
|
|
focusedBorder: focusedInputBorder,
|
|
contentPadding: MySpacing.all(16),
|
|
isCollapsed: true,
|
|
helperText: '"00-0000000"',
|
|
helperStyle: MyTextStyle.bodySmall(muted: true)),
|
|
),
|
|
MySpacing.height(16),
|
|
MyText.labelMedium(
|
|
"IP address",
|
|
),
|
|
MySpacing.height(8),
|
|
TextFormField(
|
|
inputFormatters: [
|
|
IpAddressInputFormatter(),
|
|
],
|
|
decoration: InputDecoration(
|
|
border: outlineInputBorder,
|
|
enabledBorder: outlineInputBorder,
|
|
focusedBorder: focusedInputBorder,
|
|
contentPadding: MySpacing.all(16),
|
|
isCollapsed: true,
|
|
helperText: '"99.99.99.99"',
|
|
helperStyle: MyTextStyle.bodySmall(muted: true)),
|
|
),
|
|
MySpacing.height(16),
|
|
MyText.labelMedium(
|
|
"Email address",
|
|
),
|
|
MySpacing.height(8),
|
|
Form(
|
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
|
child: TextFormField(
|
|
validator: (value) {
|
|
if (value != null && value.isEmpty) {
|
|
return 'Email is required';
|
|
}
|
|
if (value != null && !MyStringUtils.isEmail(value)) {
|
|
return 'Invalid Email';
|
|
}
|
|
return null;
|
|
},
|
|
decoration: InputDecoration(
|
|
border: outlineInputBorder,
|
|
enabledBorder: outlineInputBorder,
|
|
focusedBorder: focusedInputBorder,
|
|
contentPadding: MySpacing.all(16),
|
|
isCollapsed: true,
|
|
helperText: '"_@_._"',
|
|
helperStyle: MyTextStyle.bodySmall(muted: true)),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)),
|
|
],
|
|
)),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class DateTextFormatter extends TextInputFormatter {
|
|
static const _maxChars = 8;
|
|
|
|
@override
|
|
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
|
var text = _format(newValue.text, '/');
|
|
return newValue.copyWith(text: text, selection: updateCursorPosition(text));
|
|
}
|
|
|
|
String _format(String value, String separator) {
|
|
value = value.replaceAll(separator, '');
|
|
var newString = '';
|
|
for (int i = 0; i < min(value.length, _maxChars); i++) {
|
|
newString += value[i];
|
|
if ((i == 1 || i == 3) && i != value.length - 1) {
|
|
newString += separator;
|
|
}
|
|
}
|
|
return newString;
|
|
}
|
|
|
|
TextSelection updateCursorPosition(String text) {
|
|
return TextSelection.fromPosition(TextPosition(offset: text.length));
|
|
}
|
|
}
|
|
|
|
//-----------------------Phone Number-----------------------//
|
|
class PhoneInputFormatter extends TextInputFormatter {
|
|
@override
|
|
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
|
final text = newValue.text.replaceAll(RegExp(r'\D'), '');
|
|
|
|
return newValue.copyWith(
|
|
text: text.isNotEmpty ? '$text' : '',
|
|
selection: TextSelection.collapsed(offset: text.length),
|
|
);
|
|
}
|
|
}
|
|
|
|
//-----------------------IP address-----------------------//
|
|
class IpAddressInputFormatter extends TextInputFormatter {
|
|
@override
|
|
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
|
var text = newValue.text;
|
|
|
|
if (newValue.selection.baseOffset == 0) {
|
|
return newValue;
|
|
}
|
|
|
|
int dotCounter = 0;
|
|
var buffer = StringBuffer();
|
|
String ipField = "";
|
|
|
|
for (int i = 0; i < text.length; i++) {
|
|
if (dotCounter < 4) {
|
|
if (text[i] != ".") {
|
|
ipField += text[i];
|
|
if (ipField.length < 3) {
|
|
buffer.write(text[i]);
|
|
} else if (ipField.length == 3) {
|
|
if (int.parse(ipField) <= 255) {
|
|
buffer.write(text[i]);
|
|
} else {
|
|
if (dotCounter < 3) {
|
|
buffer.write(".");
|
|
dotCounter++;
|
|
buffer.write(text[i]);
|
|
ipField = text[i];
|
|
}
|
|
}
|
|
} else if (ipField.length == 4) {
|
|
if (dotCounter < 3) {
|
|
buffer.write(".");
|
|
dotCounter++;
|
|
buffer.write(text[i]);
|
|
ipField = text[i];
|
|
}
|
|
}
|
|
} else {
|
|
if (dotCounter < 3) {
|
|
buffer.write(".");
|
|
dotCounter++;
|
|
ipField = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var string = buffer.toString();
|
|
return newValue.copyWith(text: string, selection: TextSelection.collapsed(offset: string.length));
|
|
}
|
|
}
|
|
|
|
//-----------------------Mask Formatter-----------------------//
|
|
class MaskTextFormatter extends TextInputFormatter {
|
|
static const _maxChars = 10;
|
|
|
|
@override
|
|
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
|
var text = _format(newValue.text, '-');
|
|
return newValue.copyWith(text: text, selection: updateCursorPosition(text));
|
|
}
|
|
|
|
String _format(String value, String seperator) {
|
|
value = value.replaceAll(seperator, '');
|
|
var newString = '';
|
|
for (int i = 0; i < min(value.length, _maxChars); i++) {
|
|
newString += value[i];
|
|
if ((i == 1) && i != value.length - 1) {
|
|
newString += seperator;
|
|
}
|
|
}
|
|
return newString;
|
|
}
|
|
|
|
TextSelection updateCursorPosition(String text) {
|
|
return TextSelection.fromPosition(TextPosition(offset: text.length));
|
|
}
|
|
}
|