library multiselect;
import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
class _TheState {}
var _theState = RM.inject(() => _TheState());
class RowWrapper extends InheritedWidget {
final dynamic data;
final bool Function() shouldNotify;
RowWrapper({
required Widget child,
this.data,
required this.shouldNotify,
}) : super(child: child);
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return true;
}
}
class _SelectRow extends StatefulWidget {
final Function(bool) onChange;
final bool selected;
final String text;
final String price;
final Color textColor;
final Function(String) onPriceChanged;
_SelectRow({
Key? key,
required this.onChange,
required this.selected,
required this.text,
required this.price,
required this.onPriceChanged,
this.textColor = Colors.blue,
}) : super(key: key);
@override
_SelectRowState createState() => _SelectRowState();
}
class _SelectRowState extends State<_SelectRow> {
bool isSelected = false;
@override
void initState() {
super.initState();
isSelected = widget.selected;
}
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
isSelected = !isSelected;
widget.onChange(isSelected);
widget.onPriceChanged(widget.price);
setState(() {});
},
child: Container(
height: kMinInteractiveDimension,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Checkbox(
value: isSelected,
onChanged: (x) {
isSelected = x!;
widget.onChange(x);
widget.onPriceChanged(widget.price);
setState(() {});
},
),
Text(
widget.text,
style: TextStyle(color: widget.textColor),
),
SizedBox(width: 8), // Add some spacing
Expanded(
child: GestureDetector(
onTap: () {
_editPrice(context);
},
child: Text(
widget.price,
style: TextStyle(color: widget.textColor),
),
),
),
],
),
),
);
}
void _editPrice(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Edit Price"),
content: TextFormField(
initialValue: widget.price,
keyboardType: TextInputType.numberWithOptions(decimal: true),
onChanged: (newPrice) {
widget.onPriceChanged(newPrice);
setState(() {});
},
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Cancel"),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Save"),
),
],
);
},
);
}
}
class DropDownMultiSelect<T> extends StatefulWidget {
final List<T> options;
final List<T> selectedValues;
final List<String> prices;
//final Function(List<T>, List<String>) onChanged;
final Function(List<T>, List<String>) onChanged;
final bool isDense;
final bool enabled;
final InputDecoration? decoration;
final String? whenEmpty;
final Widget Function(List<T> selectedValues)? childBuilder;
final Widget Function(T option)? menuItembuilder;
final String Function(T? selectedOptions)? validator;
final bool readOnly;
final Widget? icon;
final TextStyle? hintStyle;
final Widget? hint;
final TextStyle? selected_values_style;
final List<String> selectedAmountValues;
const DropDownMultiSelect({
Key? key,
required this.options,
required this.selectedValues,
required this.prices,
required this.onChanged,
this.whenEmpty,
this.icon,
this.hint,
this.hintStyle,
this.childBuilder,
this.selected_values_style,
this.menuItembuilder,
this.isDense = true,
this.enabled = true,
this.decoration,
this.validator,
this.readOnly = false,
required this.selectedAmountValues,
}) : super(key: key);
@override
_DropDownMultiSelectState createState() => _DropDownMultiSelectState<T>();
}
class _DropDownMultiSelectState<TState>
extends State<DropDownMultiSelect<TState>> {
@override
Widget build(BuildContext context) {
return Container(
child: Stack(
alignment: Alignment.centerLeft,
children: [
Container(
child: DropdownButtonFormField<TState>(
hint: widget.hint,
style: widget.hintStyle,
icon: widget.icon,
validator: widget.validator != null ? widget.validator : null,
decoration: widget.decoration != null
? widget.decoration
: InputDecoration(
border: OutlineInputBorder(),
isDense: true,
contentPadding: EdgeInsets.symmetric(
vertical: 15,
horizontal: 10,
),
),
isDense: widget.isDense,
onChanged: widget.enabled ? (x) {} : null,
isExpanded: false,
value: widget.selectedValues.length > 0
? widget.selectedValues[0] as TState
: null,
selectedItemBuilder: (context) {
return widget.options
.asMap()
.map(
(index, x) => MapEntry(
index,
DropdownMenuItem(
child: Container(
color: Colors.white,
),
),
),
)
.values
.toList();
},
items: widget.options
.asMap()
.map(
(index, x) => MapEntry(
index,
DropdownMenuItem<TState>(
child: _theState.rebuild(() {
return widget.menuItembuilder != null
? widget.menuItembuilder!(x)
: _SelectRow(
selected: widget.selectedValues.contains(x),
text: x.toString(),
price: widget.prices[index],
onChange: (isSelected) {
var ns = widget.selectedValues;
var sp = widget
.selectedAmountValues; // Update this line
if (isSelected) {
ns.add(x);
sp.add(widget.prices[index]);
} else {
ns.remove(x);
sp.remove(widget.prices[index]);
}
widget.onChanged(ns, sp);
},
onPriceChanged: (newPrice) {
setState(() {
widget.prices[index] = newPrice;
});
},
);
}),
value: x,
onTap: !widget.readOnly
? () {
if (widget.selectedValues.contains(x)) {
var ns = widget.selectedValues;
var sp = widget
.selectedAmountValues; // Update this line
ns.remove(x);
sp.add(widget.prices[index]);
widget.onChanged(ns, sp);
} else {
var ns = widget.selectedValues;
var sp = widget
.selectedAmountValues; // Update this line
ns.add(x);
sp.add(widget.prices[index]);
widget.onChanged(ns, sp);
}
}
: null,
),
),
)
.values
.toList(),
),
),
_theState.rebuild(() => widget.childBuilder != null
? widget.childBuilder!(widget.selectedValues)
: Padding(
padding: widget.decoration != null
? widget.decoration!.contentPadding != null
? widget.decoration!.contentPadding!
: EdgeInsets.symmetric(horizontal: 10)
: EdgeInsets.symmetric(horizontal: 20),
child: Padding(
padding: const EdgeInsets.only(right: 20),
child: Text(
widget.selectedValues.length > 0
? widget.selectedValues
.map((e) => e.toString())
.reduce(
(a, b) => a.toString() + ' , ' + b.toString())
: widget.whenEmpty ?? '',
style: widget.selected_values_style,
),
),
)),
],
),
);
}
}
List<String> fruits = ['Abhi', 'Avi', 'Nik', 'Sura'];
List<String> selectedFruits = [];
List<String> price = ['1.0', '2.0', '3.0', '4.0'];
List<String> selectedPrices = [];
DropDownMultiSelect(
selectedAmountValues: selectedPrices,
prices: price,
options: fruits,
selectedValues: selectedFruits,
onChanged: (selectedFruits, selectedPrices) {
print('Selected fruits: $selectedFruits');
print('Selected prices: $selectedPrices');
setState(() {
selectedFruits = selectedFruits;
selectedPrices = selectedPrices;
});
print(
'You have selected $selectedFruits fruits with prices $selectedPrices.');
},
),
Second one is my DropDownMultiSelect function which is calling the first one, which is a another file . it look like the image now if i click on 1.0 one alert dialog will be open and if i change the value to 11 and save it then my 1.0 is still showing and if i close that field and reopen then it work fine . I want to change the value 1.0 to 11 as soon as i would click the save button .
