569 lines
17 KiB
Dart
569 lines
17 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../../../shared/design_system/tokens/color_tokens.dart';
|
|
import '../../../../shared/design_system/tokens/spacing_tokens.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: ColorTokens.background,
|
|
body: Column(
|
|
children: [
|
|
_buildHeader(),
|
|
_buildTabBar(),
|
|
Expanded(
|
|
child: TabBarView(
|
|
controller: _tabController,
|
|
children: [
|
|
_buildBackupsTab(),
|
|
_buildScheduleTab(),
|
|
_buildRestoreTab(),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Header harmonisé
|
|
Widget _buildHeader() {
|
|
return Container(
|
|
margin: const EdgeInsets.all(SpacingTokens.lg),
|
|
padding: const EdgeInsets.all(SpacingTokens.xl),
|
|
decoration: BoxDecoration(
|
|
gradient: const LinearGradient(
|
|
colors: ColorTokens.primaryGradient,
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
),
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusXl),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: ColorTokens.primary.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),
|
|
);
|
|
}
|
|
}
|