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:
@@ -86,9 +86,7 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
|
||||
// Demander la permission et obtenir la position
|
||||
final position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: const LocationSettings(
|
||||
accuracy: LocationAccuracy.high,
|
||||
),
|
||||
desiredAccuracy: LocationAccuracy.high,
|
||||
);
|
||||
|
||||
setState(() {
|
||||
@@ -232,12 +230,9 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
_qualityUpdateTimer =
|
||||
Timer.periodic(const Duration(seconds: 5), (timer) async {
|
||||
// Vérifier la connexion réseau
|
||||
final connectivityResults = await Connectivity().checkConnectivity();
|
||||
final connectivityResult = await Connectivity().checkConnectivity();
|
||||
setState(() {
|
||||
// Prendre le premier résultat de la liste
|
||||
_connectivityResult = connectivityResults.isNotEmpty
|
||||
? connectivityResults.first
|
||||
: ConnectivityResult.none;
|
||||
_connectivityResult = connectivityResult;
|
||||
});
|
||||
|
||||
// Vérifier si le GPS est activé
|
||||
@@ -274,7 +269,7 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
if (_currentPosition == null) return;
|
||||
|
||||
final passagesBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);
|
||||
final allPassages = passagesBox.values.where((p) => p.fkType == 2).toList();
|
||||
final allPassages = passagesBox.values.toList(); // Tous les types de passages
|
||||
|
||||
// Calculer les distances et trier
|
||||
final passagesWithDistance = allPassages.map((passage) {
|
||||
@@ -295,8 +290,7 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
|
||||
setState(() {
|
||||
_nearbyPassages = passagesWithDistance
|
||||
.take(50) // Limiter à 50 passages
|
||||
.where((entry) => entry.value <= 2000) // Max 2km
|
||||
.where((entry) => entry.value <= 500) // Max 500m
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
});
|
||||
@@ -339,7 +333,7 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
|
||||
void _startCompass() {
|
||||
_magnetometerSubscription =
|
||||
magnetometerEventStream().listen((MagnetometerEvent event) {
|
||||
magnetometerEvents.listen((MagnetometerEvent event) {
|
||||
setState(() {
|
||||
// Calculer l'orientation à partir du magnétomètre
|
||||
_heading = math.atan2(event.y, event.x) * (180 / math.pi);
|
||||
@@ -375,6 +369,7 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
passageRepository: passageRepository,
|
||||
userRepository: userRepository,
|
||||
operationRepository: operationRepository,
|
||||
amicaleRepository: amicaleRepository,
|
||||
onSuccess: () {
|
||||
// Rafraîchir les passages après modification
|
||||
_updateNearbyPassages();
|
||||
@@ -985,22 +980,43 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
);
|
||||
}
|
||||
|
||||
// Assombrir une couleur pour les bordures
|
||||
Color _darkenColor(Color color, [double amount = 0.3]) {
|
||||
assert(amount >= 0 && amount <= 1);
|
||||
|
||||
final hsl = HSLColor.fromColor(color);
|
||||
final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
|
||||
|
||||
return hslDark.toColor();
|
||||
}
|
||||
|
||||
List<Marker> _buildPassageMarkers() {
|
||||
if (_currentPosition == null) return [];
|
||||
|
||||
return _nearbyPassages.map((passage) {
|
||||
// Déterminer la couleur selon nbPassages
|
||||
Color fillColor;
|
||||
if (passage.nbPassages == 0) {
|
||||
fillColor = const Color(0xFFFFFFFF); // couleur1: Blanc
|
||||
} else if (passage.nbPassages == 1) {
|
||||
fillColor = const Color(0xFFF7A278); // couleur2: Orange
|
||||
} else {
|
||||
fillColor = const Color(0xFFE65100); // couleur3: Orange foncé
|
||||
// Déterminer la couleur selon le type de passage
|
||||
Color fillColor = Colors.grey; // Couleur par défaut
|
||||
|
||||
if (AppKeys.typesPassages.containsKey(passage.fkType)) {
|
||||
final typeInfo = AppKeys.typesPassages[passage.fkType]!;
|
||||
|
||||
if (passage.fkType == 2) {
|
||||
// Type 2 (À finaliser) : adapter la couleur selon nbPassages
|
||||
if (passage.nbPassages == 0) {
|
||||
fillColor = Color(typeInfo['couleur1'] as int);
|
||||
} else if (passage.nbPassages == 1) {
|
||||
fillColor = Color(typeInfo['couleur2'] as int);
|
||||
} else {
|
||||
fillColor = Color(typeInfo['couleur3'] as int);
|
||||
}
|
||||
} else {
|
||||
// Autres types : utiliser couleur2 par défaut
|
||||
fillColor = Color(typeInfo['couleur2'] as int);
|
||||
}
|
||||
}
|
||||
|
||||
// Bordure toujours orange (couleur2)
|
||||
const borderColor = Color(0xFFF7A278);
|
||||
// Bordure : version assombrie de la couleur de remplissage
|
||||
final borderColor = _darkenColor(fillColor, 0.3);
|
||||
|
||||
// Convertir les coordonnées GPS string en double
|
||||
final double lat = double.tryParse(passage.gpsLat) ?? 0;
|
||||
@@ -1029,8 +1045,10 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
child: Text(
|
||||
'${passage.numero}${(passage.rueBis.isNotEmpty) ? passage.rueBis.substring(0, 1).toLowerCase() : ''}',
|
||||
style: TextStyle(
|
||||
color:
|
||||
fillColor == Colors.white ? Colors.black : Colors.white,
|
||||
// Texte noir sur fond clair, blanc sur fond foncé
|
||||
color: fillColor.computeLuminance() > 0.5
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: AppTheme.r(context, 12),
|
||||
),
|
||||
@@ -1120,14 +1138,18 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
color: Colors.white,
|
||||
child: PassagesListWidget(
|
||||
passages: filteredPassages,
|
||||
showFilters: false, // Pas de filtres, juste la liste
|
||||
showSearch: false, // La recherche est déjà dans l'interface
|
||||
showActions: true,
|
||||
sortBy: 'distance', // Tri par distance pour le mode terrain
|
||||
excludePassageTypes: const [], // Afficher tous les types (notamment le type 2)
|
||||
showAddButton: true, // Activer le bouton de création
|
||||
// Le widget gère maintenant le flux conditionnel par défaut
|
||||
onPassageSelected: null,
|
||||
onPassageEdit: (passage) {
|
||||
// Retrouver le PassageModel original pour l'édition
|
||||
final passageId = passage['id'] as int;
|
||||
final originalPassage = _nearbyPassages.firstWhere(
|
||||
(p) => p.id == passageId,
|
||||
orElse: () => _nearbyPassages.first,
|
||||
);
|
||||
_openPassageForm(originalPassage);
|
||||
},
|
||||
onAddPassage: () async {
|
||||
// Ouvrir le dialogue de création de passage
|
||||
await showDialog(
|
||||
@@ -1139,6 +1161,7 @@ class _UserFieldModePageState extends State<UserFieldModePage>
|
||||
passageRepository: passageRepository,
|
||||
userRepository: userRepository,
|
||||
operationRepository: operationRepository,
|
||||
amicaleRepository: amicaleRepository,
|
||||
onSuccess: () {
|
||||
// Le widget se rafraîchira automatiquement via ValueListenableBuilder
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user