feat: synchronisation mode deconnecte fin chat et stats

This commit is contained in:
2025-08-31 18:21:20 +02:00
parent 41a4505b4b
commit 604294af96
149 changed files with 285769 additions and 250633 deletions

View File

@@ -0,0 +1,286 @@
import 'package:flutter/material.dart';
import 'package:geosector_app/core/services/api_service.dart';
import 'package:geosector_app/core/services/connectivity_service.dart';
import 'package:geosector_app/core/utils/api_exception.dart';
import 'package:geosector_app/core/data/models/user_model.dart';
import 'package:uuid/uuid.dart';
/// Widget de test pour vérifier le fonctionnement de la file d'attente offline
/// À utiliser uniquement en développement
class OfflineTestButton extends StatefulWidget {
const OfflineTestButton({Key? key}) : super(key: key);
@override
State<OfflineTestButton> createState() => _OfflineTestButtonState();
}
class _OfflineTestButtonState extends State<OfflineTestButton> {
final _uuid = const Uuid();
bool _isProcessing = false;
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Test de synchronisation offline',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Utilisez ces boutons pour tester la mise en file d\'attente des requêtes',
style: TextStyle(fontSize: 12, color: Colors.grey),
),
const SizedBox(height: 16),
// Indicateur de connectivité
ListenableBuilder(
listenable: ConnectivityService(),
builder: (context, child) {
final isConnected = ConnectivityService().isConnected;
return Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isConnected ? Colors.green.shade100 : Colors.red.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(
isConnected ? Icons.wifi : Icons.wifi_off,
color: isConnected ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
isConnected ? 'Connecté' : 'Hors ligne',
style: TextStyle(
color: isConnected ? Colors.green : Colors.red,
fontWeight: FontWeight.bold,
),
),
],
),
);
},
),
const SizedBox(height: 16),
// Boutons de test
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: _isProcessing ? null : _testGetRequest,
icon: const Icon(Icons.download),
label: const Text('Test GET'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
),
),
ElevatedButton.icon(
onPressed: _isProcessing ? null : _testPostRequest,
icon: const Icon(Icons.upload),
label: const Text('Test POST'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
),
),
ElevatedButton.icon(
onPressed: _isProcessing ? null : _testPutRequest,
icon: const Icon(Icons.edit),
label: const Text('Test PUT'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
),
),
ElevatedButton.icon(
onPressed: _isProcessing ? null : _testDeleteRequest,
icon: const Icon(Icons.delete),
label: const Text('Test DELETE'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
),
ElevatedButton.icon(
onPressed: _isProcessing ? null : _processQueue,
icon: const Icon(Icons.sync),
label: const Text('Traiter la file'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
),
),
],
),
if (_isProcessing)
const Padding(
padding: EdgeInsets.only(top: 16),
child: Center(
child: CircularProgressIndicator(),
),
),
],
),
),
);
}
Future<void> _testGetRequest() async {
setState(() => _isProcessing = true);
try {
debugPrint('🧪 Test GET request');
final response = await ApiService.instance.get('/test/endpoint');
if (response.data['queued'] == true) {
if (mounted) {
ApiException.showSuccess(context, 'Requête GET mise en file d\'attente');
}
} else {
if (mounted) {
ApiException.showSuccess(context, 'Requête GET exécutée avec succès');
}
}
} catch (e) {
if (mounted) {
ApiException.showError(context, e);
}
} finally {
setState(() => _isProcessing = false);
}
}
Future<void> _testPostRequest() async {
setState(() => _isProcessing = true);
try {
final tempId = 'temp_${_uuid.v4()}';
debugPrint('🧪 Test POST request avec tempId: $tempId');
final testData = {
'name': 'Test User ${DateTime.now().millisecondsSinceEpoch}',
'email': 'test@example.com',
'timestamp': DateTime.now().toIso8601String(),
};
final response = await ApiService.instance.post(
'/test/create',
data: testData,
tempId: tempId,
);
if (response.data['queued'] == true) {
if (mounted) {
ApiException.showSuccess(context, 'Requête POST mise en file d\'attente (tempId: $tempId)');
}
} else {
if (mounted) {
ApiException.showSuccess(context, 'Requête POST exécutée avec succès');
}
}
} catch (e) {
if (mounted) {
ApiException.showError(context, e);
}
} finally {
setState(() => _isProcessing = false);
}
}
Future<void> _testPutRequest() async {
setState(() => _isProcessing = true);
try {
final tempId = 'temp_${_uuid.v4()}';
debugPrint('🧪 Test PUT request avec tempId: $tempId');
final testData = {
'id': 123,
'name': 'Updated User ${DateTime.now().millisecondsSinceEpoch}',
'email': 'updated@example.com',
'timestamp': DateTime.now().toIso8601String(),
};
final response = await ApiService.instance.put(
'/test/update/123',
data: testData,
tempId: tempId,
);
if (response.data['queued'] == true) {
if (mounted) {
ApiException.showSuccess(context, 'Requête PUT mise en file d\'attente (tempId: $tempId)');
}
} else {
if (mounted) {
ApiException.showSuccess(context, 'Requête PUT exécutée avec succès');
}
}
} catch (e) {
if (mounted) {
ApiException.showError(context, e);
}
} finally {
setState(() => _isProcessing = false);
}
}
Future<void> _testDeleteRequest() async {
setState(() => _isProcessing = true);
try {
final tempId = 'temp_${_uuid.v4()}';
debugPrint('🧪 Test DELETE request avec tempId: $tempId');
final response = await ApiService.instance.delete(
'/test/delete/123',
tempId: tempId,
);
if (response.data['queued'] == true) {
if (mounted) {
ApiException.showSuccess(context, 'Requête DELETE mise en file d\'attente (tempId: $tempId)');
}
} else {
if (mounted) {
ApiException.showSuccess(context, 'Requête DELETE exécutée avec succès');
}
}
} catch (e) {
if (mounted) {
ApiException.showError(context, e);
}
} finally {
setState(() => _isProcessing = false);
}
}
Future<void> _processQueue() async {
setState(() => _isProcessing = true);
try {
debugPrint('🧪 Traitement manuel de la file d\'attente');
await ApiService.instance.processPendingRequests();
if (mounted) {
ApiException.showSuccess(context, 'File d\'attente traitée');
}
} catch (e) {
if (mounted) {
ApiException.showError(context, e);
}
} finally {
setState(() => _isProcessing = false);
}
}
}