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/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 SelectionBottomSheet extends StatefulWidget { final List items; final T? selectedItem; // Now nullable final String title; final SelectionBuilderString builderString; const SelectionBottomSheet({Key? key, this.items = const [], this.selectedItem, this.title = "", required this.builderString}) : super(key: key); @override _SelectionBottomSheetState createState() => _SelectionBottomSheetState(); } class _SelectionBottomSheetState extends State> { T? _selectedValue; // Now nullable String query = ""; List get filteredList => widget.items.where((element) => widget.builderString(element).toLowerCase().contains(query.toLowerCase())).toList(); @override void initState() { _selectedValue = widget.selectedItem; super.initState(); } FocusNode searchFocusNode = FocusNode(); @override void dispose() { searchFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( height: MediaQuery.of(context).size.height * .7, padding: const EdgeInsets.all(21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ widget.title.heading5(context), 16.height, 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( // Wrap ListView with Expanded child: ListView.builder( itemCount: filteredList.length, padding: const EdgeInsets.only(top: 8), itemBuilder: (cxt, index) => RadioListTile( // Specify type for RadioListTile value: filteredList[index], dense: true, contentPadding: EdgeInsets.zero, groupValue: _selectedValue, activeColor: Colors.black87, onChanged: (value) { _selectedValue = value; searchFocusNode.unfocus(); setState(() {}); }, title: Text( widget.builderString(filteredList[index]).cleanupWhitespace?.capitalizeFirstOfEach ?? "", style: Theme.of(context).textTheme.bodyLarge, ), ), ), ), 8.height, if (_selectedValue != null) AppFilledButton( label: context.translation.select, maxWidth: true, onPressed: () { Navigator.pop(context, _selectedValue); }, ), ], ), ); } }