Phase 2 du MVP Flutter : vérification PIN locale, application des règles par famille, suivi des mouvements et correction avec plancher à 0. Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
3.3 KiB
Dart
96 lines
3.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../../data/database/app_database.dart';
|
|
|
|
class RulesGrid extends StatelessWidget {
|
|
const RulesGrid({
|
|
super.key,
|
|
required this.rules,
|
|
required this.isApplying,
|
|
required this.onRuleTap,
|
|
});
|
|
|
|
final List<Regle> rules;
|
|
final bool isApplying;
|
|
final void Function(int ruleId) onRuleTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final groups = <String, List<Regle>>{};
|
|
for (final rule in rules) {
|
|
groups.putIfAbsent(rule.famille, () => []).add(rule);
|
|
}
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: groups.entries.map((entry) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Text(
|
|
entry.key,
|
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Wrap(
|
|
spacing: 8,
|
|
runSpacing: 8,
|
|
children: entry.value.map((rule) {
|
|
final positive = rule.points >= 0;
|
|
return Material(
|
|
color: positive
|
|
? Colors.green.shade50
|
|
: Colors.red.shade50,
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: InkWell(
|
|
onTap: isApplying ? null : () => onRuleTap(rule.id),
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: Container(
|
|
width: 160,
|
|
padding: const EdgeInsets.all(10),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(
|
|
color: positive
|
|
? Colors.green.shade200
|
|
: Colors.red.shade200,
|
|
),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'${rule.icone} ${rule.libelle}',
|
|
style: const TextStyle(fontSize: 13),
|
|
maxLines: 3,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'${rule.points > 0 ? '+' : ''}${rule.points}',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: positive
|
|
? Colors.green.shade800
|
|
: Colors.red.shade800,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
);
|
|
}
|
|
}
|