feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API
- Mise à jour VERSION vers 3.3.4 - Optimisations et révisions architecture API (deploy-api.sh, scripts de migration) - Ajout documentation Stripe Tap to Pay complète - Migration vers polices Inter Variable pour Flutter - Optimisations build Android et nettoyage fichiers temporaires - Amélioration système de déploiement avec gestion backups - Ajout scripts CRON et migrations base de données 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,39 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Si useValueListenable, construire avec ValueListenableBuilder centralisé
|
||||
if (useValueListenable) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: Hive.box<PassageModel>(AppKeys.passagesBoxName).listenable(),
|
||||
builder: (context, Box<PassageModel> passagesBox, child) {
|
||||
// Calculer les données une seule fois
|
||||
final passagesCounts = _calculatePassagesCounts(passagesBox);
|
||||
final totalUserPassages = passagesCounts.values.fold(0, (sum, count) => sum + count);
|
||||
|
||||
return _buildCardContent(
|
||||
context,
|
||||
totalUserPassages: totalUserPassages,
|
||||
passagesCounts: passagesCounts,
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Données statiques
|
||||
final totalPassages = passagesByType?.values.fold(0, (sum, count) => sum + count) ?? 0;
|
||||
return _buildCardContent(
|
||||
context,
|
||||
totalUserPassages: totalPassages,
|
||||
passagesCounts: passagesByType ?? {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Construit le contenu de la card avec les données calculées
|
||||
Widget _buildCardContent(
|
||||
BuildContext context, {
|
||||
required int totalUserPassages,
|
||||
required Map<int, int> passagesCounts,
|
||||
}) {
|
||||
return Card(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
@@ -102,9 +135,7 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Titre avec comptage
|
||||
useValueListenable
|
||||
? _buildTitleWithValueListenable()
|
||||
: _buildTitleWithStaticData(context),
|
||||
_buildTitle(context, totalUserPassages),
|
||||
const Divider(height: 24),
|
||||
// Contenu principal
|
||||
Expanded(
|
||||
@@ -115,9 +146,7 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
// Liste des passages à gauche
|
||||
Expanded(
|
||||
flex: isDesktop ? 1 : 2,
|
||||
child: useValueListenable
|
||||
? _buildPassagesListWithValueListenable()
|
||||
: _buildPassagesListWithStaticData(context),
|
||||
child: _buildPassagesList(context, passagesCounts),
|
||||
),
|
||||
|
||||
// Séparateur vertical
|
||||
@@ -129,9 +158,10 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: PassagePieChart(
|
||||
useValueListenable: useValueListenable,
|
||||
passagesByType: passagesByType ?? {},
|
||||
useValueListenable: false, // Utilise les données calculées
|
||||
passagesByType: passagesCounts,
|
||||
excludePassageTypes: excludePassageTypes,
|
||||
showAllPassages: showAllPassages,
|
||||
userId: showAllPassages ? null : userId,
|
||||
size: double.infinity,
|
||||
labelSize: 12,
|
||||
@@ -155,53 +185,8 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction du titre avec ValueListenableBuilder
|
||||
Widget _buildTitleWithValueListenable() {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable:
|
||||
Hive.box<PassageModel>(AppKeys.passagesBoxName).listenable(),
|
||||
builder: (context, Box<PassageModel> passagesBox, child) {
|
||||
final totalUserPassages = _calculateUserPassagesCount(passagesBox);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
if (titleIcon != null) ...[
|
||||
Icon(
|
||||
titleIcon,
|
||||
color: titleColor,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: AppTheme.r(context, 16),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
customTotalDisplay?.call(totalUserPassages) ??
|
||||
totalUserPassages.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: AppTheme.r(context, 20),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: titleColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction du titre avec données statiques
|
||||
Widget _buildTitleWithStaticData(BuildContext context) {
|
||||
final totalPassages =
|
||||
passagesByType?.values.fold(0, (sum, count) => sum + count) ?? 0;
|
||||
|
||||
/// Construction du titre
|
||||
Widget _buildTitle(BuildContext context, int totalUserPassages) {
|
||||
return Row(
|
||||
children: [
|
||||
if (titleIcon != null) ...[
|
||||
@@ -222,7 +207,8 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
customTotalDisplay?.call(totalPassages) ?? totalPassages.toString(),
|
||||
customTotalDisplay?.call(totalUserPassages) ??
|
||||
totalUserPassages.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: AppTheme.r(context, 20),
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -233,30 +219,28 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction de la liste des passages avec ValueListenableBuilder
|
||||
Widget _buildPassagesListWithValueListenable() {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable:
|
||||
Hive.box<PassageModel>(AppKeys.passagesBoxName).listenable(),
|
||||
builder: (context, Box<PassageModel> passagesBox, child) {
|
||||
final passagesCounts = _calculatePassagesCounts(passagesBox);
|
||||
|
||||
return _buildPassagesList(context, passagesCounts);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Construction de la liste des passages avec données statiques
|
||||
Widget _buildPassagesListWithStaticData(BuildContext context) {
|
||||
return _buildPassagesList(context, passagesByType ?? {});
|
||||
}
|
||||
|
||||
/// Construction de la liste des passages
|
||||
Widget _buildPassagesList(BuildContext context, Map<int, int> passagesCounts) {
|
||||
// Vérifier si le type Lot doit être affiché
|
||||
bool showLotType = true;
|
||||
final currentUser = userRepository.getCurrentUser();
|
||||
if (currentUser != null && currentUser.fkEntite != null) {
|
||||
final userAmicale = amicaleRepository.getAmicaleById(currentUser.fkEntite!);
|
||||
if (userAmicale != null) {
|
||||
showLotType = userAmicale.chkLotActif;
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...AppKeys.typesPassages.entries.map((entry) {
|
||||
...AppKeys.typesPassages.entries.where((entry) {
|
||||
// Exclure le type Lot (5) si chkLotActif = false
|
||||
if (entry.key == 5 && !showLotType) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).map((entry) {
|
||||
final int typeId = entry.key;
|
||||
final Map<String, dynamic> typeData = entry.value;
|
||||
final int count = passagesCounts[typeId] ?? 0;
|
||||
@@ -303,54 +287,45 @@ class PassageSummaryCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// Calcule le nombre total de passages pour l'utilisateur
|
||||
int _calculateUserPassagesCount(Box<PassageModel> passagesBox) {
|
||||
if (showAllPassages) {
|
||||
// Pour les administrateurs : tous les passages sauf ceux exclus
|
||||
return passagesBox.values
|
||||
.where((passage) => !excludePassageTypes.contains(passage.fkType))
|
||||
.length;
|
||||
} else {
|
||||
// Pour les utilisateurs : seulement leurs passages
|
||||
final currentUser = userRepository.getCurrentUser();
|
||||
final targetUserId = userId ?? currentUser?.id;
|
||||
|
||||
if (targetUserId == null) return 0;
|
||||
|
||||
return passagesBox.values
|
||||
.where((passage) =>
|
||||
passage.fkUser == targetUserId &&
|
||||
!excludePassageTypes.contains(passage.fkType))
|
||||
.length;
|
||||
}
|
||||
}
|
||||
|
||||
/// Calcule les compteurs de passages par type
|
||||
Map<int, int> _calculatePassagesCounts(Box<PassageModel> passagesBox) {
|
||||
final Map<int, int> counts = {};
|
||||
|
||||
// Vérifier si le type Lot doit être affiché
|
||||
bool showLotType = true;
|
||||
final currentUser = userRepository.getCurrentUser();
|
||||
if (currentUser != null && currentUser.fkEntite != null) {
|
||||
final userAmicale = amicaleRepository.getAmicaleById(currentUser.fkEntite!);
|
||||
if (userAmicale != null) {
|
||||
showLotType = userAmicale.chkLotActif;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialiser tous les types
|
||||
for (final typeId in AppKeys.typesPassages.keys) {
|
||||
// Exclure le type Lot (5) si chkLotActif = false
|
||||
if (typeId == 5 && !showLotType) {
|
||||
continue;
|
||||
}
|
||||
// Exclure les types non désirés
|
||||
if (excludePassageTypes.contains(typeId)) {
|
||||
continue;
|
||||
}
|
||||
counts[typeId] = 0;
|
||||
}
|
||||
|
||||
if (showAllPassages) {
|
||||
// Pour les administrateurs : compter tous les passages
|
||||
for (final passage in passagesBox.values) {
|
||||
counts[passage.fkType] = (counts[passage.fkType] ?? 0) + 1;
|
||||
// L'API filtre déjà les passages côté serveur
|
||||
// On compte simplement tous les passages de la box
|
||||
for (final passage in passagesBox.values) {
|
||||
// Exclure le type Lot (5) si chkLotActif = false
|
||||
if (passage.fkType == 5 && !showLotType) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Pour les utilisateurs : compter seulement leurs passages
|
||||
final currentUser = userRepository.getCurrentUser();
|
||||
final targetUserId = userId ?? currentUser?.id;
|
||||
|
||||
if (targetUserId != null) {
|
||||
for (final passage in passagesBox.values) {
|
||||
if (passage.fkUser == targetUserId) {
|
||||
counts[passage.fkType] = (counts[passage.fkType] ?? 0) + 1;
|
||||
}
|
||||
}
|
||||
// Exclure les types non désirés
|
||||
if (excludePassageTypes.contains(passage.fkType)) {
|
||||
continue;
|
||||
}
|
||||
counts[passage.fkType] = (counts[passage.fkType] ?? 0) + 1;
|
||||
}
|
||||
|
||||
return counts;
|
||||
|
||||
Reference in New Issue
Block a user