import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/base.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; typedef SelectionBuilderString = String Function(dynamic); class SelectionFullScreenDialog extends StatefulWidget { final List? items; final T? selectedItem; // Now nullable final T? disableItem; // Now nullable final String title; final bool showCancel; final SelectionBuilderString builderString; final Function(T?) onSelect; const SelectionFullScreenDialog({Key? key, this.items, this.selectedItem, this.disableItem, this.title = "", required this.builderString, this.showCancel = false, required this.onSelect}) : super(key: key); @override _SelectionBottomSheetState createState() => _SelectionBottomSheetState(); } class _SelectionBottomSheetState extends State> with SingleTickerProviderStateMixin { T? _selectedValue; // Now nullable String query = ""; late AnimationController _animationController; List? get filteredList => widget.items?.where((element) => widget.builderString(element).toLowerCase().contains(query.toLowerCase())).toList(); @override void initState() { _selectedValue = widget.selectedItem; super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 1200), vsync: this, ); _animationController.forward(); } FocusNode searchFocusNode = FocusNode(); @override void dispose() { _animationController.dispose(); searchFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: widget.title.heading5(context).custom(color: AppColor.textStyleColor(context)), actions: [ if (widget.showCancel) AnimatedContainer( height: 24, duration: const Duration(milliseconds: 250), margin: const EdgeInsets.only(right: 16), decoration: BoxDecoration(color: _selectedValue != null ? const Color(0xffF63939).withOpacity(.75) : Colors.grey.withOpacity(.75), borderRadius: BorderRadius.circular(30)), padding: const EdgeInsets.only(left: 4, right: 8, top: 4, bottom: 4), alignment: Alignment.center, child: Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon(Icons.clear, color: Colors.white, size: 16), 4.width, const Text( "Clear", style: TextStyle(fontSize: 14, color: Colors.white, height: 1), ) ], ).onPress(_selectedValue != null ? () { Navigator.pop(context); widget.onSelect(null); } : null), ), ], ), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SearchBar( focusNode: searchFocusNode, elevation: WidgetStateProperty.all(0), backgroundColor: WidgetStateProperty.all(AppColor.background(context)), leading: Icon(Icons.search, color: AppColor.iconColor(context)), textStyle: WidgetStateProperty.all( TextStyle(color: AppColor.textColor(context), fontSize: 16.0), ), hintStyle: WidgetStateProperty.all( TextStyle(color: AppColor.textColor(context), fontSize: 14.0), ), hintText: 'Search by name', onChanged: (queryString) { query = queryString; setState(() {}); }, ).paddingOnly(top: 16, start: 16, end: 16, bottom: 8), // TextField( // onChanged: (queryString) { // query = queryString; // setState(() {}); // }, // style: const TextStyle(fontSize: 14), // focusNode: searchFocusNode, // decoration: InputDecoration( // hintText: 'Search by name', // labelText: 'Search', // hintStyle: const TextStyle(fontSize: 14), // focusedBorder: OutlineInputBorder( // borderSide: BorderSide(color: AppColor.blueStatus(context), width: 2.0), // borderRadius: const BorderRadius.all(Radius.circular(12.0)), // ), // enabledBorder: OutlineInputBorder( // borderSide: BorderSide(color: AppColor.blueStatus(context), width: 1.0), // borderRadius: const BorderRadius.all(Radius.circular(12.0)), // ), // contentPadding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), // ), // ), 8.height, Expanded( child: ListView.builder( itemCount: filteredList?.length, padding: EdgeInsets.only(bottom: _selectedValue != null ? 4.toScreenHeight : 48.toScreenHeight), itemBuilder: (cxt, index) { // Calculate staggered animation delay final delay = index * 0.08; final animation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: Interval( delay.clamp(0.0, 0.8), (delay + 0.3).clamp(0.0, 1.0), curve: Curves.easeOut, ), ), ); final slideAnimation = Tween( begin: const Offset(0.0, 0.3), end: Offset.zero, ).animate( CurvedAnimation( parent: _animationController, curve: Interval( delay.clamp(0.0, 0.8), (delay + 0.3).clamp(0.0, 1.0), curve: Curves.easeOutCubic, ), ), ); bool isDisabledItem = widget.disableItem != null && widget.disableItem?.identifier == filteredList![index].identifier; return FadeTransition( opacity: animation, child: SlideTransition( position: slideAnimation, child: Theme( data: Theme.of(context).copyWith( radioTheme: RadioThemeData( fillColor: MaterialStateColor.resolveWith((states) { if (states.contains(MaterialState.selected)) { return AppColor.primary10; // Active color } return AppColor.icon2Color(context).withValues(alpha: .5); }), ), ), child: RadioListTile( // Specify type for RadioListTile value: filteredList![index], dense: true, contentPadding: const EdgeInsets.only(left: 16, right: 16), groupValue: _selectedValue, // activeColor: AppColor.iconColor(context), // activeColor: AppColor.primary10,colo // checkColor: AppColor.white10, hoverColor: Colors.transparent, onChanged: isDisabledItem ? null : (value) { _selectedValue = value; searchFocusNode.unfocus(); setState(() {}); }, title: Text( widget.builderString(filteredList![index]).cleanupWhitespace.capitalizeFirstOfEach ?? "", style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: isDisabledItem ? AppColor.neutral20 : null), ), ), ), ), ); }), ), 8.height, if (_selectedValue != null) FooterActionButton.footerContainer( context: context, child: AppFilledButton( label: context.translation.select, maxWidth: true, onPressed: () { Navigator.pop(context); widget.onSelect(_selectedValue); }, )), ], ), ); } }