import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../about/internal/application/TextType.dart'; import '../../utils/Colors.dart'; import '../Component.dart'; import '../text/Text.dart'; /// The standard text field. Widget inputField( String label, TextEditingController controller, { String hint = "", String? Function(String?)? validator, TextInputType keyboard = TextInputType.text, bool obscure = false, int maxLines = 1, List? formatters, IconData? icon, ValueChanged? onChanged, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ text(label.toUpperCase(), 10, TextType.Bold, color: colorGrey2, letterSpacing: 0.8), const SizedBox(height: 8), TextFormField( controller: controller, validator: validator, keyboardType: keyboard, obscureText: obscure, maxLines: obscure ? 1 : maxLines, inputFormatters: formatters, onChanged: onChanged, style: TextStyle( fontFamily: getTextType(TextType.Regular), fontSize: 14, color: colorPrimaryDark, ), decoration: InputDecoration( hintText: hint, hintStyle: TextStyle( fontFamily: getTextType(TextType.Regular), fontSize: 13, color: colorGrey, ), prefixIcon: icon == null ? null : Icon(icon, size: 18, color: colorGrey2), filled: true, fillColor: colorWhite, contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorBorder, width: 1), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorPrimaryDark, width: 1.4), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorNegative, width: 1), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorNegative, width: 1.4), ), errorStyle: TextStyle( fontFamily: getTextType(TextType.Regular), fontSize: 11, color: colorNegative, ), ), ), ], ); } /// The excuse field. Deliberately unadorned — no templates, no quick-picks, a /// live character count that shows the minimum, because the friction is the /// feature rather than an obstacle to route around. Widget excuseField( TextEditingController controller, int minimumLength, { String? Function(String?)? validator, ValueChanged? onChanged, }) { final int length = controller.text.trim().length; final bool satisfied = length >= minimumLength; return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ text("WHY", 10, TextType.Bold, color: colorGrey2, letterSpacing: 0.8), text( satisfied ? "$length characters" : "$length / $minimumLength", 10, TextType.Bold, color: satisfied ? colorPositive : colorGrey, ), ], ), const SizedBox(height: 8), TextFormField( controller: controller, validator: validator, onChanged: onChanged, maxLines: 4, style: TextStyle( fontFamily: getTextType(TextType.Regular), fontSize: 14, color: colorPrimaryDark, height: 1.5, ), decoration: InputDecoration( hintText: "In your own words. No shortcuts here.", hintStyle: TextStyle( fontFamily: getTextType(TextType.Regular), fontSize: 13, color: colorGrey, ), filled: true, fillColor: colorWhite, contentPadding: const EdgeInsets.all(14), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorBorder, width: 1), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorPrimaryDark, width: 1.4), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorNegative, width: 1), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: colorNegative, width: 1.4), ), errorStyle: TextStyle( fontFamily: getTextType(TextType.Regular), fontSize: 11, color: colorNegative, ), ), ), ], ); } /// A read-only field that loads its options on tap rather than pre-loading /// them — the ViewModel fetches, then calls back to open the picker. Widget selectField( String label, String value, VoidCallback onTap, { String hint = "Select", IconData icon = Icons.expand_more_rounded, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ text(label.toUpperCase(), 10, TextType.Bold, color: colorGrey2, letterSpacing: 0.8), const SizedBox(height: 8), GestureDetector( onTap: onTap, child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 16), decoration: BoxDecoration( color: colorWhite, borderRadius: BorderRadius.circular(12), border: Border.all(color: colorBorder, width: 1), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: text( value.isEmpty ? hint : value, 14, value.isEmpty ? TextType.Regular : TextType.Bold, color: value.isEmpty ? colorGrey : colorPrimaryDark, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Icon(icon, size: 20, color: colorGrey2), ], ), ), ), ], ); }