You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/views/widgets/bottom_sheets/muliple_selection_bottom_sh...

173 lines
6.7 KiB
Dart

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/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 MultipleSelectionBottomSheet<T> extends StatefulWidget {
final List<T>? items;
final List<T> selectedItem; // Now nullable
final String title;
final SelectionBuilderString builderString;
final bool showCancel;
final Function(List<T>) onSelect;
const MultipleSelectionBottomSheet({Key? key, this.items = const [], this.selectedItem = const [], this.title = "", required this.builderString, this.showCancel = false, required this.onSelect})
: super(key: key);
@override
_MultipleSelectionBottomSheetState createState() => _MultipleSelectionBottomSheetState<T>();
}
class _MultipleSelectionBottomSheetState<T> extends State<MultipleSelectionBottomSheet<T>> {
late List<T> _selectedValue; // Now nullable
String query = "";
List<T>? 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,
color: Theme.of(context).scaffoldBackgroundColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
widget.title.heading5(context).expanded,
if (widget.showCancel)
AnimatedOpacity(
opacity: _selectedValue != null ? 1 : 0,
duration: const Duration(milliseconds: 250),
child: Container(
height: 30,
decoration: BoxDecoration(color: const Color(0xffF63939).withOpacity(.75), borderRadius: BorderRadius.circular(30)),
padding: const EdgeInsets.only(left: 8, right: 12, top: 4, bottom: 4),
alignment: Alignment.center,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.clear, color: Colors.white, size: 16),
4.width,
const Text(
"Clear",
style: TextStyle(fontSize: 14, color: Colors.white),
)
],
),
).onPress(_selectedValue.isNotEmpty
? () {
Navigator.pop(context);
widget.onSelect([]);
}
: null),
),
],
).paddingOnly(top: 16, start: 16, end: 16, bottom: 0),
TextField(
onChanged: (queryString) {
query = queryString;
setState(() {});
},
style: const TextStyle(fontSize: 14),
focusNode: searchFocusNode,
decoration: InputDecoration(
hintText: 'Search by name',
labelText: 'Search',
labelStyle: TextStyle(color: AppColor.textColor(context)),
filled: true,
fillColor: AppColor.fieldBgColor(context),
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),
),
).paddingOnly(top: 16, start: 16, end: 16, bottom: 16),
Expanded(
// Wrap ListView with Expanded
child: ListView.builder(
itemCount: filteredList?.length,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => Theme(
data: Theme.of(context).copyWith(
radioTheme: RadioThemeData(
fillColor: MaterialStateColor.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColor.textColor(context); // Active color
}
return Colors.grey; // Inactive color
}),
),
),
child: CheckboxListTile(
value: checkItContains(filteredList![index]),
dense: true,
// groupValue: _selectedValue,
activeColor: AppColor.textColor(context),
contentPadding: const EdgeInsets.only(left: 16, right: 16),
onChanged: (value) {
if (value == true) {
_selectedValue.add(filteredList![index]);
} else if (value == false) {
_selectedValue.remove(filteredList![index]);
}
searchFocusNode.unfocus();
setState(() {});
},
title: Text(
widget.builderString(filteredList![index]).cleanupWhitespace.capitalizeFirstOfEach ?? "",
style: Theme.of(context).textTheme.bodyLarge,
),
),
),
),
),
8.height,
if (_selectedValue.isNotEmpty)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: context.translation.select,
maxWidth: true,
onPressed: () {
Navigator.pop(context);
widget.onSelect(_selectedValue);
},
)),
],
),
);
}
bool? checkItContains(T) {
return widget.items?.contains(T);
}
}