You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
uco-mobile-poc/lib/app/custom_widgets/Fields/input_field.dart

536 lines
21 KiB
Dart

import 'dart:ui';
import 'package:country_code_picker/country_code_picker.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:get/get.dart';
import '../../core/constants/translation_keys.dart';
import '../../res/app_colors.dart';
import '../../res/app_theme.dart';
import '../custom_dropdown.dart';
import '../custom_text.dart';
import 'custom_dropdown_bottom_sheet.dart';
class InputField extends GetView {
final FormFieldValidator<String>? validator;
GlobalKey<FormFieldState>? refKey;
String labelText = "";
String hintText = "";
RxString errorTextMessage = "".obs;
final RxBool _passwordVisible = true.obs;
int? radius = 100;
EdgeInsetsGeometry? contentPadding = const EdgeInsets.symmetric(horizontal: 15, vertical: 15);
// String errorText = "";
bool isRequired = true;
bool requiredPasswordIcon = false;
Function(String?)? onChanged;
FocusNode? focusNode = FocusNode();
Function(DropDown?)? onItemSelected;
Rx<CountryCode> selectedCountryCode = CountryCode().obs;
Rx<DropDown>? selectedOption;
// DropDown? selectedOption;
final bool enabled;
bool isDropDown = false;
bool isTopMarginRequired = true;
bool isCountryPicker = false;
bool isBoxDecoration = true;
bool showLabel = true;
String? dropDownType = DropDownType.NORMAL;
List<DropDown>? items;
final AutovalidateMode autovalidateMode;
final String? restorationId;
InputDecoration? decoration;
TextEditingController? controller;
TextInputType? keyboardType;
final TextInputAction? textInputAction;
final TextCapitalization textCapitalization;
final TextStyle? style;
final StrutStyle? strutStyle;
TextAlign textAlign;
final TextAlignVertical? textAlignVertical;
final TextDirection? textDirection;
final bool autofocus;
final String obscuringCharacter;
bool isPassword = false;
bool autocorrect = false;
final SmartDashesType? smartDashesType;
final SmartQuotesType? smartQuotesType;
final bool enableSuggestions;
int maxLines;
int minLines;
bool expands;
final int? maxLength;
final MaxLengthEnforcement? maxLengthEnforcement;
final VoidCallback? onEditingComplete;
final ValueChanged<String?>? onSubmitted;
final List<TextInputFormatter>? inputFormatters;
bool showCursor = true;
double cursorWidth = 5.0;
double cursorHeight = 15.0;
Radius cursorRadius = const Radius.circular(10.0);
Color cursorColor = AppThemeData.inputTextColor;
final BoxHeightStyle selectionHeightStyle;
final BoxWidthStyle selectionWidthStyle;
final Brightness? keyboardAppearance;
final EdgeInsets scrollPadding;
final bool enableInteractiveSelection;
Widget? prefixIcon;
Widget? suffixIcon;
final DragStartBehavior dragStartBehavior;
final Function()? onClick;
final TapRegionCallback? onTapOutside;
final MouseCursor? mouseCursor;
final InputCounterWidgetBuilder? buildCounter;
final ScrollPhysics? scrollPhysics;
final ScrollController? scrollController;
final Iterable<String>? autofillHints;
final TextMagnifierConfiguration? magnifierConfiguration;
bool readOnly;
final ContentInsertionConfiguration? contentInsertionConfiguration;
SpellCheckConfiguration? spellCheckConfiguration;
final String? prefixText;
final String? prefixCode;
final double? inputFontSize;
final FontWeight? inputFontWeight;
final Color? inputColor;
final Rx<Color> inputErrorColor = Rx<Color>(Colors.black);
final Rx<Color> inputErrorBorderColor = Rx<Color>(Colors.black);
RxBool isError = false.obs;
InputField({
this.refKey,
this.controller,
this.labelText = "",
this.hintText = "",
// this.errorText = "",
this.isRequired = true,
this.requiredPasswordIcon = false,
this.isBoxDecoration = true,
this.showLabel = true,
this.isTopMarginRequired = true,
this.isDropDown = false,
this.isCountryPicker = false,
this.dropDownType,
this.inputFontSize,
this.inputFontWeight,
this.inputColor,
this.validator,
this.contentPadding = const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
this.items,
this.radius = 100,
this.decoration,
this.focusNode,
this.onChanged,
this.onItemSelected,
this.prefixIcon,
this.suffixIcon,
this.selectedOption,
this.enabled = true,
this.autovalidateMode = AutovalidateMode.disabled,
this.restorationId,
this.readOnly = false,
this.isPassword = false,
this.textCapitalization = TextCapitalization.none,
this.scrollPadding = const EdgeInsets.all(20.0),
this.enableInteractiveSelection = true,
this.maxLengthEnforcement,
this.textAlign = TextAlign.start,
this.autofocus = false,
this.autocorrect = false,
this.cursorWidth = 5.0,
this.cursorHeight = 20.0,
this.cursorRadius = const Radius.circular(10.0),
this.keyboardType,
this.style,
this.textInputAction,
this.strutStyle,
this.textDirection,
this.maxLength,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.cursorColor = AppThemeData.inputTextColor,
this.keyboardAppearance,
this.buildCounter,
this.expands = false,
this.minLines = 1,
this.maxLines = 1,
this.showCursor = true,
this.onClick,
this.onTapOutside,
this.enableSuggestions = true,
this.textAlignVertical,
this.dragStartBehavior = DragStartBehavior.start,
this.scrollController,
this.scrollPhysics,
this.selectionWidthStyle = BoxWidthStyle.tight,
this.smartDashesType,
this.smartQuotesType,
this.selectionHeightStyle = BoxHeightStyle.tight,
this.autofillHints,
this.obscuringCharacter = '',
this.mouseCursor,
this.magnifierConfiguration,
this.contentInsertionConfiguration,
this.spellCheckConfiguration,
this.prefixText,
this.prefixCode,
}) : errorTextMessage = "".obs {
// errorText = errorTextMessage.value;
}
void setText(String text) {
controller!.text = text;
markFieldAsValid();
}
void clear() {
controller!.clear();
markFieldAsValid();
}
void setError(String errorMessage) {
inputErrorBorderColor.value = AppThemeData.inputErrorBorderColor;
inputErrorColor.value = AppThemeData.inputErrorColor;
errorTextMessage.value = errorMessage;
isError.value = true;
}
void markFieldAsValid() {
inputErrorBorderColor.value = AppThemeData.inputBackgroundColor;
inputErrorColor.value = AppThemeData.inputErrorColor;
errorTextMessage.value = "";
isError.value = false;
}
void markFieldAsInvalid() {
print("=============================");
inputErrorBorderColor.value = AppThemeData.inputErrorBorderColor;
inputErrorColor.value = AppThemeData.inputErrorColor;
errorTextMessage.value = TranslationKeys.makeTranslation(TranslationKeys.textErrorRequired);
isError.value = true;
}
void setDropDownOption(DropDown option) {
selectedOption = Rx<DropDown>(option);
setText(selectedOption!.value.label);
markFieldAsValid();
}
bool validate(String value) {
if (isRequired) {
if (value.isEmpty) {
markFieldAsInvalid();
return false;
}
markFieldAsValid();
return true;
}
markFieldAsValid();
return true;
}
@override
Widget build(BuildContext context) {
return Obx(() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: isTopMarginRequired ? 15 : 0),
Visibility(
visible: isBoxDecoration && showLabel,
child: Column(
children: [
CustomText(labelText, style: AppThemeData.labelStyle),
const SizedBox(height: 5),
],
),
),
FormBuilderTextField(
key: refKey,
name: "",
focusNode: focusNode,
decoration: isCountryPicker ? countryCodeDecoration() : (isBoxDecoration ? boxedDecoration() : normalFieldDecoration()),
enabled: enabled,
autovalidateMode: autovalidateMode,
restorationId: restorationId,
readOnly: isDropDown ? true : readOnly,
validator: (value) {
validate(value!);
return null;
},
onChanged: (value) {
if (value!.isNotEmpty) {
markFieldAsValid();
}
if (onChanged != null) {
onChanged!(value);
}
},
textCapitalization: textCapitalization,
scrollPadding: scrollPadding,
enableInteractiveSelection: enableInteractiveSelection,
maxLengthEnforcement: maxLengthEnforcement,
textAlign: textAlign,
autofocus: isDropDown ? false : autofocus,
autocorrect: autocorrect,
keyboardType: keyboardType,
style: AppThemeData.inputStyle.copyWith(height: 1, fontSize: double.parse((inputFontSize ?? "0.0").toString()) == 0 ? AppThemeData.inputStyle.fontSize : double.parse((inputFontSize ?? "0.0").toString()), fontWeight: inputFontWeight ?? AppThemeData.inputStyle.fontWeight, color: inputColor ?? AppThemeData.inputStyle.color),
controller: controller,
textInputAction: textInputAction ?? TextInputAction.done,
strutStyle: strutStyle,
textDirection: textDirection,
maxLength: maxLength,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
inputFormatters: inputFormatters,
cursorColor: cursorColor,
// cursorWidth: 1.5,
// cursorHeight: 15,
// cursorRadius: Radius.circular(10.0),
keyboardAppearance: keyboardAppearance,
buildCounter: buildCounter,
expands: expands,
maxLines: isPassword ? maxLines = 1 : maxLines,
obscureText: isPassword && _passwordVisible.value,
minLines: isPassword ? minLines = 1 : minLines,
showCursor: isDropDown ? false : showCursor,
onTap: () {
if (onClick != null) {
onClick!();
}
if (isDropDown && items != null && items!.isNotEmpty) {
//
FocusScope.of(context).requestFocus(FocusNode());
CustomDropDownBottomSheet().showBottomSheet(context, items!, dropDownType ?? DropDownType.NORMAL, (selectedItem) {
setText(selectedItem.label);
selectedOption = Rx<DropDown>(selectedItem);
if (onItemSelected != null) {
onItemSelected!(selectedItem);
}
});
}
},
onTapOutside: onTapOutside,
enableSuggestions: enableSuggestions,
textAlignVertical: textAlignVertical,
dragStartBehavior: dragStartBehavior,
scrollController: scrollController,
scrollPhysics: scrollPhysics,
selectionWidthStyle: selectionWidthStyle,
smartDashesType: smartDashesType,
smartQuotesType: smartQuotesType,
selectionHeightStyle: BoxHeightStyle.tight,
autofillHints: autofillHints,
obscuringCharacter: obscuringCharacter,
mouseCursor: mouseCursor,
magnifierConfiguration: magnifierConfiguration,
contentInsertionConfiguration: contentInsertionConfiguration,
spellCheckConfiguration: spellCheckConfiguration,
),
],
);
});
}
InputDecoration normalFieldDecoration() {
return InputDecoration(
filled: true,
prefixIcon: prefixIcon,
fillColor: AppColors.transparent,
isDense: true,
contentPadding: const EdgeInsets.only(bottom: 5),
labelText: labelText,
labelStyle: AppThemeData.labelStyle,
errorStyle: AppThemeData.errorStyle.copyWith(color: inputErrorColor.value),
errorBorder: UnderlineInputBorder(borderSide: BorderSide(color: inputErrorBorderColor.value)),
focusedBorder: const UnderlineInputBorder(borderSide: BorderSide(color: AppThemeData.inputFocusedBorderColor, width: 1.5)),
enabledBorder: const UnderlineInputBorder(borderSide: BorderSide(color: AppThemeData.inputEnabledBorderColor, width: 1.5)),
errorText: errorTextMessage.value.isEmpty ? null : errorTextMessage.value,
hintText: hintText.isEmpty ? null : hintText,
hintStyle: AppThemeData.hintStyle,
prefixText: prefixText,
prefixStyle: AppThemeData.hintStyle,
suffixIcon: Icon(
Icons.arrow_forward_ios_outlined,
color: AppColors.colorGrey500,
size: isDropDown ? 22 : 0,
),
);
}
InputDecoration boxedDecoration() {
return InputDecoration(
isDense: true,
contentPadding: contentPadding ?? const EdgeInsets.symmetric(horizontal: 15, vertical: 15) /*EdgeInsets.all(10)*/,
labelText: isBoxDecoration ? null : (labelText.isNotEmpty ? labelText : null),
labelStyle: AppThemeData.labelStyle,
prefixIcon: prefixIcon,
errorStyle: AppThemeData.errorStyle.copyWith(color: inputErrorColor.value),
// border: OutlineInputBorder(borderSide: BorderSide(color: inputErrorBorderColor.value), borderRadius: BorderRadius.all(Radius.circular(10))),
focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: inputErrorBorderColor.value), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
errorBorder: OutlineInputBorder(borderSide: BorderSide(color: inputErrorBorderColor.value), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
focusedBorder: OutlineInputBorder(borderSide: const BorderSide(color: AppThemeData.inputFocusedBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
enabledBorder: OutlineInputBorder(borderSide: const BorderSide(color: AppThemeData.inputEnabledBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
errorText: errorTextMessage.value.isEmpty ? null : errorTextMessage.value,
hintText: hintText.isEmpty ? null : hintText,
hintStyle: AppThemeData.hintStyle,
prefixText: prefixText,
// prefixStyle: AppThemeData.hintStyle,
suffixIcon: suffixIcon ?? addSuffixIcon(),
);
}
Widget? addSuffixIcon() {
if (requiredPasswordIcon) {
return IconButton(
icon: Icon(size: 18, color: AppColors.colorGrey500, _passwordVisible.value ? Icons.visibility : Icons.visibility_off_rounded),
onPressed: () {
_passwordVisible.value = !_passwordVisible.value;
},
);
} else if (isDropDown) {
return const Icon(
Icons.arrow_forward_ios_outlined,
color: AppColors.colorGrey500,
size: 22,
);
}
return null;
}
InputDecoration countryCodeDecoration() {
return InputDecoration(
prefixIcon: CountryCodePicker(
initialSelection: 'PK',
onInit: (code) {
selectedCountryCode.value = code!;
},
showFlagDialog: true,
showCountryOnly: true,
countryFilter: const [
'pk',
'us',
'it',
],
emptySearchBuilder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 15),
CustomText("No Results", style: Theme.of(context).textTheme.bodyMedium!.copyWith(fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.inputLabelColor)),
],
);
},
onChanged: (val) {
selectedCountryCode.value = val;
},
searchDecoration: InputDecoration(
filled: false,
fillColor: AppColors.transparent,
isDense: false,
alignLabelWithHint: true,
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
errorStyle: AppThemeData.errorStyle.copyWith(color: AppThemeData.inputErrorColor),
errorBorder: const OutlineInputBorder(borderSide: BorderSide(color: AppThemeData.inputErrorBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(10))),
focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: AppThemeData.inputFocusedBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(10))),
enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: AppThemeData.inputEnabledBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(10))),
prefixStyle: AppThemeData.hintStyle,
),
searchStyle: AppThemeData.inputStyle.copyWith(height: 1),
// textStyle: AppThemeData.inputStyle.copyWith(height: 1),
),
isDense: true,
contentPadding: const EdgeInsets.all(10),
labelText: isBoxDecoration ? null : (labelText.isNotEmpty ? labelText : null),
labelStyle: AppThemeData.labelStyle,
errorStyle: AppThemeData.errorStyle.copyWith(color: inputErrorColor.value),
focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: inputErrorBorderColor.value), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
errorBorder: OutlineInputBorder(borderSide: BorderSide(color: inputErrorBorderColor.value), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
focusedBorder: OutlineInputBorder(borderSide: const BorderSide(color: AppThemeData.inputFocusedBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
enabledBorder: OutlineInputBorder(borderSide: const BorderSide(color: AppThemeData.inputEnabledBorderColor, width: 1.5), borderRadius: BorderRadius.all(Radius.circular(radius == -1 ? 10 : double.parse(radius.toString())))),
// focusedErrorBorder: OutlineInputBorder(
// borderSide: BorderSide(color: inputErrorBorderColor.value),
// borderRadius: const BorderRadius.all(Radius.circular(10))),
// errorBorder: OutlineInputBorder(
// borderSide: BorderSide(color: inputErrorBorderColor.value),
// borderRadius: const BorderRadius.all(Radius.circular(10))),
// focusedBorder: const OutlineInputBorder(
// borderSide: BorderSide(
// color: AppThemeData.inputFocusedBorderColor,
// width: 1.5,
// ),
// borderRadius: BorderRadius.all(Radius.circular(10))),
// enabledBorder: const OutlineInputBorder(
// borderSide: BorderSide(
// color: AppThemeData.inputEnabledBorderColor, width: 1.5),
// borderRadius: BorderRadius.all(Radius.circular(10))),
errorText: errorTextMessage.value.isEmpty ? null : errorTextMessage.value,
hintText: hintText.isEmpty ? null : hintText,
hintStyle: AppThemeData.hintStyle,
prefixText: prefixText ?? "",
prefixStyle: AppThemeData.hintStyle,
suffixIcon: Icon(
Icons.arrow_forward_ios_outlined,
color: AppColors.colorGrey500,
size: isDropDown ? 22 : 0,
),
);
}
String getCustomText({bool isCountryCodeRequired = false, bool isPrefixRequired = false}) {
if (isCountryCodeRequired) {
if (isCountryPicker) {
return selectedCountryCode.value.dialCode! + controller!.text;
}
return controller!.text;
} else if (isPrefixRequired) {
return (prefixCode ?? "") + controller!.text;
}
return controller!.text;
}
}
class DropDownType {
static final String NORMAL = "01";
static final String SPECIAL = "02";
}
class InputType {
static final int INT_MAX_VALUE_ = 9223372036854775807;
static final FilteringTextInputFormatter NUMBER = FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'));
static final FilteringTextInputFormatter NUMBER_DECIMAL = FilteringTextInputFormatter.allow(RegExp(r'^[0-9]*\.?[0-9]*$'));
static List<TextInputFormatter> maxValueFilter(int maxNumber, bool isDecimal, int decimalPoint) {
return [
FilteringTextInputFormatter.allow(isDecimal ? RegExp(r'^\d+\.?\d{0,2}') : RegExp(r'^\d+$')),
TextInputFormatter.withFunction((oldValue, newValue) {
if (newValue.text.isEmpty) {
return newValue.copyWith(text: '', selection: const TextSelection.collapsed(offset: 0));
}
try {
final numericValue = double.parse(newValue.text);
if (numericValue <= maxNumber) {
return newValue;
}
} catch (e) {
return newValue;
}
return oldValue;
}),
];
}
}