From ccd9c5ae05ad21597eadbbc968aca4ab401beab5 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Tue, 10 Jun 2025 15:39:49 +0200 Subject: [PATCH] create new dropdown --- .../mih_dropdwn_field.dart | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart diff --git a/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart new file mode 100644 index 00000000..2c22327f --- /dev/null +++ b/Frontend/lib/mih_components/mih_package_components/mih_dropdwn_field.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import '../../main.dart'; + +class MihDropdownField extends StatefulWidget { + final TextEditingController controller; + final String hintText; + final bool requiredText; + final List dropdownOptions; + final bool editable; + final bool enableSearch; + final FormFieldValidator? validator; + + const MihDropdownField({ + super.key, + required this.controller, + required this.hintText, + required this.dropdownOptions, + required this.requiredText, + required this.editable, + required this.enableSearch, + this.validator, + }); + + @override + State createState() => _MihDropdownFieldState(); +} + +class _MihDropdownFieldState extends State { + late List> menu; + + List> buildMenuOptions(List options) { + List> menuList = []; + final theme = MzanziInnovationHub.of(context)!.theme; + for (final i in options) { + menuList.add(DropdownMenuEntry( + value: i, + label: i, + style: ButtonStyle( + foregroundColor: WidgetStatePropertyAll(theme.primaryColor()), + ), + )); + } + return menuList; + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + menu = buildMenuOptions(widget.dropdownOptions); + } + + @override + void initState() { + super.initState(); + menu = widget.dropdownOptions + .map((e) => DropdownMenuEntry(value: e, label: e)) + .toList(); + } + + @override + Widget build(BuildContext context) { + final theme = MzanziInnovationHub.of(context)!.theme; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.hintText, + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + if (!widget.requiredText) + Text( + "(Optional)", + style: TextStyle( + color: theme.secondaryColor(), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 4), + FormField( + validator: widget.validator, + autovalidateMode: AutovalidateMode.onUserInteraction, + initialValue: widget.controller.text, + builder: (field) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Theme( + data: Theme.of(context).copyWith( + textSelectionTheme: TextSelectionThemeData( + selectionColor: + theme.primaryColor().withValues(alpha: 0.3), + selectionHandleColor: theme.primaryColor(), + ), + ), + child: DropdownMenu( + controller: widget.controller, + dropdownMenuEntries: menu, + enableSearch: widget.enableSearch, + enableFilter: widget.enableSearch, + enabled: widget.editable, + menuHeight: 400, + expandedInsets: EdgeInsets.zero, + textStyle: TextStyle( + color: theme.primaryColor(), + fontWeight: FontWeight.w500, + ), + trailingIcon: Icon( + Icons.arrow_drop_down, + color: theme.primaryColor(), + ), + selectedTrailingIcon: Icon( + Icons.arrow_drop_up, + color: theme.primaryColor(), + ), + leadingIcon: IconButton( + onPressed: () { + widget.controller.clear(); + field.didChange(''); + }, + icon: Icon( + Icons.delete_outline_rounded, + color: theme.primaryColor(), + ), + ), + onSelected: (String? selectedValue) { + field.didChange(selectedValue); + }, + menuStyle: MenuStyle( + backgroundColor: + WidgetStatePropertyAll(theme.secondaryColor()), + side: WidgetStatePropertyAll( + BorderSide(color: theme.primaryColor(), width: 1.0), + ), + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 10), // Increase for more roundness + ), + ), + ), + inputDecorationTheme: InputDecorationTheme( + errorStyle: const TextStyle(height: 0, fontSize: 0), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 8.0), + filled: true, + fillColor: theme.secondaryColor(), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: field.hasError + ? theme.errorColor() + : theme.secondaryColor(), + width: 3.0, + ), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide( + color: theme.errorColor(), + width: 3.0, + ), + ), + ), + ), + ), + if (field.hasError) + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 4.0), + child: Text( + field.errorText ?? '', + style: TextStyle( + fontSize: 12, + color: theme.errorColor(), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ); + }, + ), + ], + ); + } +}