From 0dd09905230f6c9fa4b320f5e91fa35aa6a366e7 Mon Sep 17 00:00:00 2001 From: Lucas Date: Thu, 5 Sep 2024 17:27:38 -0300 Subject: [PATCH] =?UTF-8?q?Feat:=20Cria=C3=A7=C3=A3o=20de=20um=20component?= =?UTF-8?q?=20de=20Select=20e=20de=20Upload=20de=20Media.=20Tentativa=20de?= =?UTF-8?q?=20criar=20validadores=20para=20o=20formul=C3=A1rio.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom_datepicker.dart | 119 +++++---- .../custom_select.dart | 99 +++++++ .../media_upload_button.dart | 173 +++++++++++++ lib/pages/pets_page/pets_page_model.dart | 68 ++++- lib/pages/pets_page/pets_page_widget.dart | 244 +++++++++++++++--- 5 files changed, 598 insertions(+), 105 deletions(-) create mode 100644 lib/components/atomic_components/shared_components_atoms/custom_select.dart create mode 100644 lib/components/atomic_components/shared_components_atoms/media_upload_button.dart diff --git a/lib/components/atomic_components/shared_components_atoms/custom_datepicker.dart b/lib/components/atomic_components/shared_components_atoms/custom_datepicker.dart index 6cdbe09e..b82c0519 100644 --- a/lib/components/atomic_components/shared_components_atoms/custom_datepicker.dart +++ b/lib/components/atomic_components/shared_components_atoms/custom_datepicker.dart @@ -5,23 +5,27 @@ import 'package:hub/flutter_flow/flutter_flow_util.dart'; class CustomDatePickerUtil extends StatefulWidget { final TextEditingController? controller; + final FocusNode? focusNode; final String hintText; final String dateFormat; final String locale; final DateTime? initialDate; final DateTime firstDate; - final DateTime lastDate; + final DateTime? lastDate; + final bool timePicker; final FormFieldValidator? validator; const CustomDatePickerUtil({ Key? key, this.controller, + this.focusNode, required this.hintText, required this.dateFormat, required this.locale, + required this.timePicker, this.initialDate, required this.firstDate, - required this.lastDate, + this.lastDate, this.validator, }) : super(key: key); @@ -44,7 +48,7 @@ class _CustomDatePickerState extends State { context: context, initialDate: _selectedDate ?? DateTime.now(), firstDate: widget.firstDate, - lastDate: widget.lastDate, + lastDate: widget.lastDate ?? DateTime(2100), builder: (context, child) { return wrapInMaterialDatePickerTheme( context, @@ -70,48 +74,64 @@ class _CustomDatePickerState extends State { ); if (pickedDate != null) { - final TimeOfDay? pickedTime = await showTimePicker( - context: context, - initialTime: TimeOfDay.fromDateTime(_selectedDate ?? DateTime.now()), - builder: (context, child) { - return wrapInMaterialTimePickerTheme( - context, - child!, - headerBackgroundColor: FlutterFlowTheme.of(context).primary, - headerForegroundColor: FlutterFlowTheme.of(context).info, - headerTextStyle: FlutterFlowTheme.of(context) - .headlineLarge - .override( - fontFamily: FlutterFlowTheme.of(context).headlineLargeFamily, - fontSize: 32.0, - letterSpacing: 0.0, - fontWeight: FontWeight.w600, - useGoogleFonts: GoogleFonts.asMap().containsKey( - FlutterFlowTheme.of(context).headlineLargeFamily), - ), - pickerBackgroundColor: - FlutterFlowTheme.of(context).primaryBackground, - pickerForegroundColor: FlutterFlowTheme.of(context).info, - selectedDateTimeBackgroundColor: - FlutterFlowTheme.of(context).primary, - selectedDateTimeForegroundColor: FlutterFlowTheme.of(context).info, - pickerDialForegroundColor: FlutterFlowTheme.of(context).primaryText, - actionButtonForegroundColor: - FlutterFlowTheme.of(context).primaryText, - iconSize: 24.0, - ); - }, - ); + if (widget.timePicker == true) { + final TimeOfDay? pickedTime = await showTimePicker( + context: context, + initialTime: TimeOfDay.fromDateTime(_selectedDate ?? DateTime.now()), + builder: (context, child) { + return wrapInMaterialTimePickerTheme( + context, + child!, + headerBackgroundColor: FlutterFlowTheme.of(context).primary, + headerForegroundColor: FlutterFlowTheme.of(context).info, + headerTextStyle: + FlutterFlowTheme.of(context).headlineLarge.override( + fontFamily: + FlutterFlowTheme.of(context).headlineLargeFamily, + fontSize: 32.0, + letterSpacing: 0.0, + fontWeight: FontWeight.w600, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).headlineLargeFamily), + ), + pickerBackgroundColor: + FlutterFlowTheme.of(context).primaryBackground, + pickerForegroundColor: FlutterFlowTheme.of(context).info, + selectedDateTimeBackgroundColor: + FlutterFlowTheme.of(context).primary, + selectedDateTimeForegroundColor: + FlutterFlowTheme.of(context).info, + pickerDialForegroundColor: + FlutterFlowTheme.of(context).primaryText, + actionButtonForegroundColor: + FlutterFlowTheme.of(context).primaryText, + iconSize: 24.0, + ); + }, + ); - if (pickedTime != null) { + if (pickedTime != null) { + setState(() { + _selectedDate = DateTime( + pickedDate.year, + pickedDate.month, + pickedDate.day, + pickedTime.hour, + pickedTime.minute, + ); + widget.controller?.text = dateTimeFormat( + widget.dateFormat, + _selectedDate, + locale: widget.locale, + ); + widget.controller?.selection = TextSelection.collapsed( + offset: widget.controller!.text.length, + ); + }); + } + } else { setState(() { - _selectedDate = DateTime( - pickedDate.year, - pickedDate.month, - pickedDate.day, - pickedTime.hour, - pickedTime.minute, - ); + _selectedDate = pickedDate; widget.controller?.text = dateTimeFormat( widget.dateFormat, _selectedDate, @@ -140,6 +160,7 @@ class _CustomDatePickerState extends State { const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0), child: TextFormField( controller: widget.controller, + focusNode: widget.focusNode, readOnly: true, autovalidateMode: AutovalidateMode.onUserInteraction, autofocus: false, @@ -170,31 +191,31 @@ class _CustomDatePickerState extends State { ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( - color: FlutterFlowTheme.of(context).accent4, + color: FlutterFlowTheme.of(context).customColor6, width: 0.5, ), - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(10.0), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: FlutterFlowTheme.of(context).primary, width: 0.5, ), - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(10.0), ), errorBorder: OutlineInputBorder( borderSide: BorderSide( color: FlutterFlowTheme.of(context).error, width: 0.5, ), - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(10.0), ), focusedErrorBorder: OutlineInputBorder( borderSide: BorderSide( color: FlutterFlowTheme.of(context).error, width: 0.5, ), - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(10.0), ), suffixIcon: Icon( Icons.date_range, @@ -226,7 +247,7 @@ class _CustomDatePickerState extends State { width: double.infinity, height: 80.0, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), + borderRadius: BorderRadius.circular(10.0), ), ), ), diff --git a/lib/components/atomic_components/shared_components_atoms/custom_select.dart b/lib/components/atomic_components/shared_components_atoms/custom_select.dart new file mode 100644 index 00000000..5ee8e7fc --- /dev/null +++ b/lib/components/atomic_components/shared_components_atoms/custom_select.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hub/flutter_flow/flutter_flow_drop_down.dart'; +import 'package:hub/flutter_flow/flutter_flow_theme.dart'; +import 'package:hub/flutter_flow/flutter_flow_util.dart'; +import 'package:hub/flutter_flow/flutter_flow_widgets.dart'; +import 'package:hub/flutter_flow/form_field_controller.dart'; + +class CustomSelect extends StatefulWidget { + final List options; + final List optionsLabel; + final String hintText; + final FormFieldController? controller; + + const CustomSelect({ + Key? key, + required this.options, + required this.optionsLabel, + required this.hintText, + this.controller, + }) : super(key: key); + + @override + _CustomSelectState createState() => _CustomSelectState(); +} + +class _CustomSelectState extends State { + late FormFieldController _controller; + + @override + void initState() { + super.initState(); + _controller = widget.controller ?? FormFieldController(null); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsetsDirectional.fromSTEB(0, 0.0, 0, 10.0), + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsetsDirectional.fromSTEB( + 24.0, 0.0, 24.0, 0.0), + child: Container( + width: 100.0, + height: 48.0, + decoration: const BoxDecoration(), + child: FlutterFlowDropDown( + fillColor: + FlutterFlowTheme.of(context).secondaryBackground, + controller: _controller, + options: widget.options, + optionLabels: widget.optionsLabel, + onChanged: (val) { + setState(() => _controller.value = val); + }, + width: double.infinity, + height: double.infinity, + textStyle: FlutterFlowTheme.of(context) + .bodyMedium + .override( + fontFamily: + FlutterFlowTheme.of(context).bodyMediumFamily, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).bodyMediumFamily), + ), + hintText: widget.hintText, + icon: Icon( + Icons.keyboard_arrow_down_rounded, + color: FlutterFlowTheme.of(context).accent1, + size: 24.0, + ), + elevation: 2.0, + borderColor: FlutterFlowTheme.of(context).customColor6, + borderWidth: 0.5, + borderRadius: 10.0, + margin: const EdgeInsetsDirectional.fromSTEB( + 12.0, 0.0, 16.0, 0.0), + hidesUnderline: true, + isOverButton: true, + isSearchable: false, + isMultiSelect: false, + ), + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/components/atomic_components/shared_components_atoms/media_upload_button.dart b/lib/components/atomic_components/shared_components_atoms/media_upload_button.dart new file mode 100644 index 00000000..f496a5a3 --- /dev/null +++ b/lib/components/atomic_components/shared_components_atoms/media_upload_button.dart @@ -0,0 +1,173 @@ +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hub/flutter_flow/flutter_flow_theme.dart'; +import 'package:hub/flutter_flow/flutter_flow_widgets.dart'; +import 'package:hub/flutter_flow/internationalization.dart'; +import 'package:hub/flutter_flow/upload_data.dart'; +import 'package:hub/flutter_flow/uploaded_file.dart'; + +class MediaUploadButtonUtil extends StatefulWidget { + final FFUploadedFile uploadedFile; + final bool isUploading; + final String labelText; + + const MediaUploadButtonUtil( + {Key? key, + required this.uploadedFile, + required this.isUploading, + required this.labelText}) + : super(key: key); + + @override + State createState() => _MediaUploadButtonUtilState(); +} + +class _MediaUploadButtonUtilState extends State { + late FFUploadedFile _uploadedFile; + late bool _isUploading; + @override + void initState() { + super.initState(); + _uploadedFile = widget.uploadedFile ?? FFUploadedFile(); + _isUploading = widget.isUploading ?? false; + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsetsDirectional.fromSTEB(24.0, 0.0, 24.0, 0.0), + child: Builder( + builder: (context) { + if ((_uploadedFile.bytes?.isNotEmpty ?? false)) { + return InkWell( + splashColor: Colors.transparent, + focusColor: Colors.transparent, + hoverColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: () async { + setState(() { + _isUploading = false; + _uploadedFile = FFUploadedFile(bytes: Uint8List.fromList([])); + }); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: Image.memory( + _uploadedFile.bytes ?? Uint8List.fromList([]), + width: 300.0, + height: 200.0, + fit: BoxFit.cover, + ), + ), + ); + } else { + return Stack( + children: [ + Align( + alignment: const AlignmentDirectional(0.0, 0.0), + child: FFButtonWidget( + onPressed: () async { + final selectedMedia = + await selectMediaWithSourceBottomSheet( + context: context, + imageQuality: 100, + allowPhoto: true, + includeDimensions: true, + ); + if (selectedMedia != null) { + setState(() => _isUploading = true); + var selectedUploadedFiles = []; + + try { + showUploadMessage( + context, + 'Uploading file...', + showLoading: true, + ); + selectedUploadedFiles = selectedMedia + .map((m) => FFUploadedFile( + name: m.storagePath.split('/').last, + bytes: m.bytes, + height: m.dimensions?.height, + width: m.dimensions?.width, + // blurHash: m.blurHash, + )) + .toList(); + } finally { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + _isUploading = false; + } + if (selectedUploadedFiles.length == + selectedMedia.length) { + setState(() { + _uploadedFile = selectedUploadedFiles.first; + }); + showUploadMessage(context, 'Success!'); + } else { + setState(() {}); + showUploadMessage(context, 'Failed to upload data'); + return; + } + } + }, + text: '', + icon: Icon( + Icons.photo_camera, + color: FlutterFlowTheme.of(context).accent1, + size: 30.0, + ), + options: FFButtonOptions( + width: double.infinity, + height: 120.0, + padding: const EdgeInsetsDirectional.fromSTEB( + 0.0, 0.0, 0.0, 20.0), + iconPadding: const EdgeInsetsDirectional.fromSTEB( + 14.0, 0.0, 0.0, 20.0), + color: FlutterFlowTheme.of(context).primaryBackground, + textStyle: FlutterFlowTheme.of(context) + .titleSmall + .override( + fontFamily: + FlutterFlowTheme.of(context).titleSmallFamily, + color: FlutterFlowTheme.of(context).primaryText, + fontSize: 16.0, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).titleSmallFamily), + ), + borderSide: BorderSide( + color: FlutterFlowTheme.of(context).accent1, + width: 0.2, + ), + borderRadius: BorderRadius.circular(8.0), + ), + ), + ), + Align( + alignment: const AlignmentDirectional(0.0, 0.0), + child: Padding( + padding: const EdgeInsetsDirectional.fromSTEB( + 10.0, 65.0, 10.0, 0.0), + child: Text( + widget.labelText, + style: FlutterFlowTheme.of(context).bodyMedium.override( + fontFamily: + FlutterFlowTheme.of(context).bodyMediumFamily, + color: FlutterFlowTheme.of(context).primaryText, + letterSpacing: 0.0, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context).bodyMediumFamily), + ), + ), + ), + ), + ], + ); + } + }, + ), + ); + } +} diff --git a/lib/pages/pets_page/pets_page_model.dart b/lib/pages/pets_page/pets_page_model.dart index 75d37d05..b1d327f7 100644 --- a/lib/pages/pets_page/pets_page_model.dart +++ b/lib/pages/pets_page/pets_page_model.dart @@ -1,31 +1,61 @@ -import 'dart:async'; - +import 'dart:developer'; import 'package:flutter/material.dart'; -import 'package:hub/flutter_flow/flutter_flow_model.dart'; import 'package:hub/flutter_flow/flutter_flow_util.dart'; -import 'package:hub/flutter_flow/uploaded_file.dart'; +import 'package:hub/flutter_flow/form_field_controller.dart'; import 'package:hub/pages/pets_page/pets_page_widget.dart'; class PetsPageModel extends FlutterFlowModel { late final TabController tabBarController; - Timer? _debounceTimer; final unfocusNode = FocusNode(); + + // Controller para o Upload de Arquivos bool isDataUploading = false; FFUploadedFile uploadedLocalFile = FFUploadedFile(bytes: Uint8List.fromList([])); - void debounce(Function() fn, Duration time) { - if (_debounceTimer != null) { - _debounceTimer!.cancel(); + // Controller para o DropDown + String? dropDownValue1; + FormFieldController? dropDownValueController1; + + String? dropDownValue2; + FormFieldController? dropDownValueController2; + + // Controller para o TextField + FocusNode? textFieldFocusName; + TextEditingController? textControllerName; + String? Function(BuildContext, String?)? textControllerNameValidator; + String? _textControllerNameValidator(BuildContext context, String? val) { + log('Chamou esta merda'); + if (val == null || val.isEmpty) { + return FFLocalizations.of(context).getVariableText( + enText: 'This field is required', + ptText: 'Este campo é obrigatório', + ); } - _debounceTimer = Timer(time, fn); + + return null; } - @override - void dispose() { - tabBarController.dispose(); - } + FocusNode? textFieldFocusSpecies; + TextEditingController? textControllerSpecies; + String? Function(BuildContext, String?)? textControllerSpeciesValidator; + + FocusNode? textFieldFocusRace; + TextEditingController? textControllerRace; + String? Function(BuildContext, String?)? textControllerRaceValidator; + + FocusNode? textFieldFocusColor; + TextEditingController? textControllerColor; + String? Function(BuildContext, String?)? textControllerColorValidator; + + FocusNode? textFieldFocusData; + TextEditingController? textControllerData; + String? Function(BuildContext, String?)? textControllerDataValidator; + + FocusNode? textFieldFocusObservation; + TextEditingController? textControllerObservation; + String? Function(BuildContext, String?)? textControllerObservationValidator; @override void initState(BuildContext context) { @@ -34,5 +64,17 @@ class PetsPageModel extends FlutterFlowModel { vsync: Navigator.of(context), length: 2, ); + + textFieldFocusName = FocusNode(); + textControllerName = TextEditingController(); + textControllerNameValidator = + (context, value) => _textControllerNameValidator(context, value); + } + + @override + void dispose() { + tabBarController.dispose(); + textFieldFocusName?.dispose(); + textControllerName?.dispose(); } } diff --git a/lib/pages/pets_page/pets_page_widget.dart b/lib/pages/pets_page/pets_page_widget.dart index 4c52f661..35661e22 100644 --- a/lib/pages/pets_page/pets_page_widget.dart +++ b/lib/pages/pets_page/pets_page_widget.dart @@ -1,21 +1,25 @@ -import 'package:easy_debounce/easy_debounce.dart'; +import 'dart:developer'; + import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; + import 'package:flutter/services.dart'; + import 'package:google_fonts/google_fonts.dart'; + import 'package:hub/components/atomic_components/shared_components_atoms/appbar.dart'; import 'package:hub/components/atomic_components/shared_components_atoms/custom_datepicker.dart'; import 'package:hub/components/atomic_components/shared_components_atoms/custom_input.dart'; +import 'package:hub/components/atomic_components/shared_components_atoms/custom_select.dart'; +import 'package:hub/components/atomic_components/shared_components_atoms/media_upload_button.dart'; import 'package:hub/components/atomic_components/shared_components_atoms/tabview.dart'; -import 'package:hub/flutter_flow/flutter_flow_icon_button.dart'; -import 'package:hub/flutter_flow/flutter_flow_model.dart'; import 'package:hub/flutter_flow/flutter_flow_theme.dart'; import 'package:hub/flutter_flow/flutter_flow_util.dart'; import 'package:hub/flutter_flow/flutter_flow_widgets.dart'; import 'package:hub/flutter_flow/internationalization.dart'; import 'package:hub/flutter_flow/nav/nav.dart'; import 'package:hub/flutter_flow/upload_data.dart'; + import 'package:hub/pages/pets_page/pets_page_model.dart'; class PetsPageWidget extends StatefulWidget { @@ -34,6 +38,11 @@ class _PetsPageWidgetState extends State super.initState(); _model = PetsPageModel(); _model.tabBarController = TabController(length: 2, vsync: this); + + _model.textControllerName ??= TextEditingController(); + _model.textFieldFocusName ??= FocusNode(); + + _model.textControllerSpecies ??= TextEditingController(); } @override @@ -42,11 +51,17 @@ class _PetsPageWidgetState extends State super.dispose(); } + void _onTextChanged() { + setState(() {}); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: appBarPets(context), - body: tabViewPets(context, _model, _model.tabBarController)); + backgroundColor: FlutterFlowTheme.of(context).primaryBackground, + body: tabViewPets( + context, _model, _model.tabBarController, safeSetState, setState)); } } @@ -54,19 +69,33 @@ PreferredSizeWidget appBarPets(BuildContext context) { return AppBarUtil(title: 'Pets', onBackButtonPressed: () => context.pop()); } -Widget tabViewPets(BuildContext context, PetsPageModel _model, controller) { +Widget tabViewPets(BuildContext context, PetsPageModel _model, controller, + Function safeSetState, Function setState) { return TabViewUtil( context: context, model: _model, labelTab1: 'Cadastrar', labelTab2: 'Consultar', controller: controller, - widget1: formAddPets(context), + widget1: formAddPets(context, _model, safeSetState, setState), widget2: Center(child: Text('Consultar')), ); } -Widget formAddPets(BuildContext context) { +Widget formAddPets(BuildContext context, PetsPageModel _model, + Function safeSetState, Function setState) { + bool _isFormValid(BuildContext context) { + log('Validando Formulário'); + if (_model.uploadedLocalFile.bytes?.isEmpty ?? true) { + return false; + } + if (_model.textControllerName.text.isEmpty) { + return false; + } + return true; + } + + final _formKey = GlobalKey(); return SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.max, @@ -91,12 +120,26 @@ Widget formAddPets(BuildContext context) { ), ), Form( + key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0, 10, 0, 20), + child: MediaUploadButtonUtil( + uploadedFile: _model.uploadedLocalFile, + isUploading: _model.isDataUploading, + labelText: FFLocalizations.of(context).getVariableText( + ptText: 'Clique para adicionar a foto de seu Pet', + enText: 'Click to add your Pet\'s photo'), + ), + ), CustomInputUtil( + controller: _model.textControllerName, + validator: + _model.textControllerNameValidator.asValidator(context), labelText: FFLocalizations.of(context) .getVariableText(ptText: 'Nome', enText: 'Name'), hintText: FFLocalizations.of(context) @@ -105,45 +148,160 @@ Widget formAddPets(BuildContext context) { haveMaxLength: true, maxLength: 80, ), - CustomInputUtil( - labelText: FFLocalizations.of(context) - .getVariableText(ptText: 'Espécie', enText: 'Species'), - hintText: FFLocalizations.of(context) - .getVariableText(ptText: 'Espécie', enText: 'Species'), - suffixIcon: Icons.pest_control, - haveMaxLength: false, + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 15), + child: CustomInputUtil( + controller: _model.textControllerSpecies, + labelText: FFLocalizations.of(context).getVariableText( + ptText: 'Espécie', enText: 'Species'), + hintText: FFLocalizations.of(context).getVariableText( + ptText: 'Espécie', enText: 'Species'), + suffixIcon: Icons.pest_control, + haveMaxLength: false, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 15), + child: CustomInputUtil( + controller: _model.textControllerRace, + labelText: FFLocalizations.of(context) + .getVariableText(ptText: 'Raça', enText: 'Race'), + hintText: FFLocalizations.of(context) + .getVariableText(ptText: 'Raça', enText: 'Race'), + suffixIcon: Icons.pets, + haveMaxLength: false, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 15), + child: CustomInputUtil( + controller: _model.textControllerColor, + labelText: FFLocalizations.of(context) + .getVariableText(ptText: 'Cor', enText: 'Color'), + hintText: FFLocalizations.of(context) + .getVariableText(ptText: 'Cor', enText: 'Color'), + suffixIcon: Icons.invert_colors, + haveMaxLength: false, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 15), + child: CustomDatePickerUtil( + controller: _model.textControllerData, + focusNode: _model.textFieldFocusData, + hintText: FFLocalizations.of(context).getVariableText( + ptText: 'Data de Nascimento', enText: 'Birth Date'), + dateFormat: 'dd/MM/yyyy HH:mm:ss', + locale: FFLocalizations.of(context).languageCode, + firstDate: DateTime(2000), + lastDate: DateTime.now(), + timePicker: false, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Por favor, selecione uma data'; + } + return null; + }, + ), + ), + Align( + alignment: const AlignmentDirectional(-1.0, 0.0), + child: Padding( + padding: const EdgeInsetsDirectional.fromSTEB( + 24.0, 0, 0.0, 15), + child: Text( + FFLocalizations.of(context).getVariableText( + ptText: 'Selecione as opções disponíveis', + enText: 'Select the available options', + ), + textAlign: TextAlign.start, + style: FlutterFlowTheme.of(context).bodySmall.override( + fontFamily: + FlutterFlowTheme.of(context).bodySmallFamily, + letterSpacing: 0.0, + fontWeight: FontWeight.w600, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context) + .bodyMediumFamily), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 15), + child: CustomSelect( + options: const ['MAC', 'FEM'], + controller: _model.dropDownValueController1, + optionsLabel: [ + FFLocalizations.of(context) + .getVariableText(ptText: 'Macho', enText: 'Male'), + FFLocalizations.of(context).getVariableText( + ptText: 'Fêmea', enText: 'Female') + ], + hintText: FFLocalizations.of(context).getVariableText( + ptText: 'Selecione o gênero do Pet', + enText: 'Select the gender of the Pet')), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 15), + child: CustomSelect( + options: const ['MIN', 'PEQ', 'MED', 'GRA', 'GIG'], + controller: _model.dropDownValueController1, + optionsLabel: [ + FFLocalizations.of(context) + .getVariableText(ptText: 'Mini', enText: 'Mini'), + FFLocalizations.of(context).getVariableText( + ptText: 'Pequeno', enText: 'Small'), + FFLocalizations.of(context).getVariableText( + ptText: 'Médio', enText: 'Medium'), + FFLocalizations.of(context) + .getVariableText(ptText: 'Grande', enText: 'Big'), + FFLocalizations.of(context).getVariableText( + ptText: 'Gigante', enText: 'Giant'), + ], + hintText: FFLocalizations.of(context).getVariableText( + ptText: 'Selecione o porte do Pet', + enText: 'Select the size of the Pet')), + ), + Align( + alignment: const AlignmentDirectional(-1.0, 0.0), + child: Padding( + padding: const EdgeInsetsDirectional.fromSTEB( + 24.0, 0, 0.0, 15), + child: Text( + FFLocalizations.of(context).getVariableText( + ptText: 'Você tem alguma observação sobre o seu Pet?', + enText: + 'Do you have any observations about your Pet?', + ), + textAlign: TextAlign.start, + style: FlutterFlowTheme.of(context).bodySmall.override( + fontFamily: + FlutterFlowTheme.of(context).bodySmallFamily, + letterSpacing: 0.0, + fontWeight: FontWeight.w600, + useGoogleFonts: GoogleFonts.asMap().containsKey( + FlutterFlowTheme.of(context) + .bodyMediumFamily), + ), + ), + ), ), CustomInputUtil( - labelText: FFLocalizations.of(context) - .getVariableText(ptText: 'Raça', enText: 'Race'), - hintText: FFLocalizations.of(context) - .getVariableText(ptText: 'Raça', enText: 'Race'), - suffixIcon: Icons.pets, - haveMaxLength: false, - ), - CustomInputUtil( - labelText: FFLocalizations.of(context) - .getVariableText(ptText: 'Cor', enText: 'Color'), - hintText: FFLocalizations.of(context) - .getVariableText(ptText: 'Cor', enText: 'Color'), - suffixIcon: Icons.invert_colors, - haveMaxLength: false, - ), - CustomDatePickerUtil( - // controller: , + controller: _model.textControllerObservation, + labelText: FFLocalizations.of(context).getVariableText( + ptText: 'Escreva as suas observações aqui...', + enText: 'Write your observations here...'), hintText: FFLocalizations.of(context).getVariableText( - ptText: 'Data de Nascimento', enText: 'Birth Date'), - dateFormat: 'dd/MM/yyyy HH:mm:ss', - locale: FFLocalizations.of(context).languageCode, - firstDate: DateTime(2000), - lastDate: DateTime(2050), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por favor, selecione uma data'; - } - return null; - }, + ptText: 'Escreva as suas observações aqui...', + enText: 'Write your observations here...'), + suffixIcon: Icons.text_fields, + haveMaxLength: true, + maxLength: 80, ), + ElevatedButton( + onPressed: _isFormValid(context) ? () {} : () {}, + child: Text('Cadastrar')), ])), ], ),