101 lines
2.9 KiB
Dart
101 lines
2.9 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
/// Composant générique pour réordonner une liste avec heading et actions
|
||
class ReorderableCustomList<T> extends StatefulWidget {
|
||
final List<T> items;
|
||
final ValueChanged<List<T>> onChanged;
|
||
final Widget Function(BuildContext context, int index, T item) itemBuilder;
|
||
|
||
/// Liste d’actions (icônes) par item, ex: delete, edit
|
||
final List<Widget Function(BuildContext context, int index, T item)>? actions;
|
||
|
||
final EdgeInsets? padding;
|
||
final bool shrinkWrap;
|
||
|
||
const ReorderableCustomList({
|
||
Key? key,
|
||
required this.items,
|
||
required this.onChanged,
|
||
required this.itemBuilder,
|
||
this.actions,
|
||
this.padding,
|
||
this.shrinkWrap = false,
|
||
}) : super(key: key);
|
||
|
||
@override
|
||
State<ReorderableCustomList<T>> createState() => _ReorderableCustomListState<T>();
|
||
}
|
||
|
||
class _ReorderableCustomListState<T> extends State<ReorderableCustomList<T>> {
|
||
late List<T> itemsMiddle;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
itemsMiddle = List<T>.from(widget.items);
|
||
}
|
||
|
||
void _onReorder(int oldIndex, int newIndex) {
|
||
setState(() {
|
||
if (newIndex > oldIndex) newIndex -= 1;
|
||
|
||
final T item = itemsMiddle.removeAt(oldIndex);
|
||
itemsMiddle.insert(newIndex, item);
|
||
|
||
widget.onChanged(itemsMiddle);
|
||
});
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Column(
|
||
children: [
|
||
ReorderableListView.builder(
|
||
shrinkWrap: widget.shrinkWrap,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
padding: widget.padding,
|
||
itemCount: itemsMiddle.length,
|
||
buildDefaultDragHandles: false,
|
||
onReorder: _onReorder,
|
||
itemBuilder: (context, index) {
|
||
final item = itemsMiddle[index];
|
||
return Container(
|
||
key: ValueKey(item),
|
||
margin: const EdgeInsets.symmetric(vertical: 4),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
border: Border.all(color: Colors.grey.shade300),
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
ReorderableDragStartListener(
|
||
index: index,
|
||
child: const Padding(
|
||
padding: EdgeInsets.all(8.0),
|
||
child: Icon(Icons.drag_handle, color: Colors.grey),
|
||
),
|
||
),
|
||
|
||
// Contenu de l’item
|
||
Expanded(
|
||
child: widget.itemBuilder(context, index, item),
|
||
),
|
||
|
||
// Actions personnalisées
|
||
if (widget.actions != null)
|
||
Row(
|
||
children: widget.actions!
|
||
.map((builder) => builder(context, index, item))
|
||
.toList(),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
},
|
||
),
|
||
],
|
||
);
|
||
}
|
||
}
|