Files
unionflow-client-quarkus-pr…/unionflow-mobile-apps/lib/features/backup/presentation/pages/backup_page.dart

567 lines
17 KiB
Dart

import 'package:flutter/material.dart';
/// Page Sauvegarde & Restauration - UnionFlow Mobile
///
/// Page complète de gestion des sauvegardes avec création, restauration,
/// planification et monitoring des sauvegardes système.
class BackupPage extends StatefulWidget {
const BackupPage({super.key});
@override
State<BackupPage> createState() => _BackupPageState();
}
class _BackupPageState extends State<BackupPage>
with TickerProviderStateMixin {
late TabController _tabController;
bool _autoBackupEnabled = true;
String _selectedFrequency = 'Quotidien';
String _selectedRetention = '30 jours';
final List<String> _frequencies = ['Horaire', 'Quotidien', 'Hebdomadaire'];
final List<String> _retentions = ['7 jours', '30 jours', '90 jours', '1 an'];
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF8F9FA),
body: Column(
children: [
_buildHeader(),
_buildTabBar(),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
_buildBackupsTab(),
_buildScheduleTab(),
_buildRestoreTab(),
],
),
),
],
),
);
}
/// Header harmonisé
Widget _buildHeader() {
return Container(
margin: const EdgeInsets.all(12),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF6C5CE7), Color(0xFF5A4FCF)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: const Color(0xFF6C5CE7).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
),
child: Column(
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
Icons.backup,
color: Colors.white,
size: 24,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Sauvegarde & Restauration',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'Gestion des sauvegardes système',
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(0.8),
),
),
],
),
),
Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
),
child: IconButton(
onPressed: () => _createBackupNow(),
icon: const Icon(
Icons.save,
color: Colors.white,
),
tooltip: 'Sauvegarde immédiate',
),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _buildStatCard('Dernière sauvegarde', '2h', Icons.schedule),
),
const SizedBox(width: 12),
Expanded(
child: _buildStatCard('Taille totale', '2.3 GB', Icons.storage),
),
const SizedBox(width: 12),
Expanded(
child: _buildStatCard('Statut', 'OK', Icons.check_circle),
),
],
),
],
),
);
}
/// Carte de statistique
Widget _buildStatCard(String label, String value, IconData icon) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Icon(icon, color: Colors.white, size: 20),
const SizedBox(height: 4),
Text(
value,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
label,
style: TextStyle(
fontSize: 10,
color: Colors.white.withOpacity(0.8),
),
textAlign: TextAlign.center,
),
],
),
);
}
/// Barre d'onglets
Widget _buildTabBar() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: TabBar(
controller: _tabController,
labelColor: const Color(0xFF6C5CE7),
unselectedLabelColor: Colors.grey[600],
indicatorColor: const Color(0xFF6C5CE7),
indicatorWeight: 3,
labelStyle: const TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
tabs: const [
Tab(icon: Icon(Icons.folder, size: 18), text: 'Sauvegardes'),
Tab(icon: Icon(Icons.schedule, size: 18), text: 'Planification'),
Tab(icon: Icon(Icons.restore, size: 18), text: 'Restauration'),
],
),
);
}
/// Onglet sauvegardes
Widget _buildBackupsTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
children: [
const SizedBox(height: 16),
_buildBackupsList(),
const SizedBox(height: 80),
],
),
);
}
/// Liste des sauvegardes
Widget _buildBackupsList() {
final backups = [
{'name': 'Sauvegarde automatique', 'date': '15/12/2024 02:00', 'size': '2.3 GB', 'type': 'Auto'},
{'name': 'Sauvegarde manuelle', 'date': '14/12/2024 14:30', 'size': '2.1 GB', 'type': 'Manuel'},
{'name': 'Sauvegarde automatique', 'date': '14/12/2024 02:00', 'size': '2.2 GB', 'type': 'Auto'},
];
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.folder, color: Color(0xFF6C5CE7), size: 20),
const SizedBox(width: 8),
Text(
'Sauvegardes disponibles',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.grey[800],
),
),
],
),
const SizedBox(height: 16),
...backups.map((backup) => _buildBackupItem(backup)),
],
),
);
}
/// Élément de sauvegarde
Widget _buildBackupItem(Map<String, String> backup) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Icon(
backup['type'] == 'Auto' ? Icons.schedule : Icons.touch_app,
color: backup['type'] == 'Auto' ? Colors.blue : Colors.green,
size: 20,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
backup['name']!,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF1F2937),
),
),
Text(
'${backup['date']}${backup['size']}',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
PopupMenuButton<String>(
onSelected: (action) => _handleBackupAction(backup, action),
itemBuilder: (context) => [
const PopupMenuItem(value: 'restore', child: Text('Restaurer')),
const PopupMenuItem(value: 'download', child: Text('Télécharger')),
const PopupMenuItem(value: 'delete', child: Text('Supprimer')),
],
child: const Icon(Icons.more_vert, color: Colors.grey),
),
],
),
);
}
/// Onglet planification
Widget _buildScheduleTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
children: [
const SizedBox(height: 16),
_buildScheduleSettings(),
const SizedBox(height: 80),
],
),
);
}
/// Paramètres de planification
Widget _buildScheduleSettings() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.schedule, color: Color(0xFF6C5CE7), size: 20),
const SizedBox(width: 8),
Text(
'Configuration automatique',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.grey[800],
),
),
],
),
const SizedBox(height: 16),
_buildSwitchSetting(
'Sauvegarde automatique',
'Activer les sauvegardes programmées',
_autoBackupEnabled,
(value) => setState(() => _autoBackupEnabled = value),
),
const SizedBox(height: 12),
_buildDropdownSetting(
'Fréquence',
_selectedFrequency,
_frequencies,
(value) => setState(() => _selectedFrequency = value!),
),
const SizedBox(height: 12),
_buildDropdownSetting(
'Rétention',
_selectedRetention,
_retentions,
(value) => setState(() => _selectedRetention = value!),
),
],
),
);
}
/// Onglet restauration
Widget _buildRestoreTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
children: [
const SizedBox(height: 16),
_buildRestoreOptions(),
const SizedBox(height: 80),
],
),
);
}
/// Options de restauration
Widget _buildRestoreOptions() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.restore, color: Color(0xFF6C5CE7), size: 20),
const SizedBox(width: 8),
Text(
'Options de restauration',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.grey[800],
),
),
],
),
const SizedBox(height: 16),
_buildActionButton(
'Restaurer depuis un fichier',
'Importer une sauvegarde externe',
Icons.file_upload,
const Color(0xFF0984E3),
() => _restoreFromFile(),
),
const SizedBox(height: 12),
_buildActionButton(
'Restauration sélective',
'Restaurer uniquement certaines données',
Icons.checklist,
const Color(0xFF00B894),
() => _selectiveRestore(),
),
const SizedBox(height: 12),
_buildActionButton(
'Point de restauration',
'Créer un point de restauration avant modification',
Icons.bookmark,
const Color(0xFFE17055),
() => _createRestorePoint(),
),
],
),
);
}
// Méthodes de construction des composants
Widget _buildSwitchSetting(String title, String subtitle, bool value, Function(bool) onChanged) {
return Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
Text(subtitle, style: TextStyle(fontSize: 12, color: Colors.grey[600])),
],
),
),
Switch(value: value, onChanged: onChanged, activeColor: const Color(0xFF6C5CE7)),
],
);
}
Widget _buildDropdownSetting(String title, String value, List<String> options, Function(String?) onChanged) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[300]!),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: value,
isExpanded: true,
onChanged: onChanged,
items: options.map((option) => DropdownMenuItem(value: option, child: Text(option))).toList(),
),
),
),
],
);
}
Widget _buildActionButton(String title, String subtitle, IconData icon, Color color, VoidCallback onTap) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withOpacity(0.05),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: color.withOpacity(0.1)),
),
child: Row(
children: [
Icon(icon, color: color, size: 20),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: color)),
Text(subtitle, style: TextStyle(fontSize: 12, color: Colors.grey[600])),
],
),
),
Icon(Icons.arrow_forward_ios, color: Colors.grey[400], size: 16),
],
),
),
);
}
// Méthodes d'action
void _createBackupNow() => _showSuccessSnackBar('Sauvegarde créée avec succès');
void _handleBackupAction(Map<String, String> backup, String action) => _showSuccessSnackBar('Action "$action" exécutée');
void _restoreFromFile() => _showSuccessSnackBar('Sélection de fichier de restauration');
void _selectiveRestore() => _showSuccessSnackBar('Mode de restauration sélective');
void _createRestorePoint() => _showSuccessSnackBar('Point de restauration créé');
void _showSuccessSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message), backgroundColor: const Color(0xFF00B894), behavior: SnackBarBehavior.floating),
);
}
}