import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart' show Share, XFile; import '../../estado/estado_radio.dart'; import '../../l10n/gen/app_localizations.dart'; import '../../widgets/pluri_glass_surface.dart'; import '../../widgets/pluri_layout.dart'; import '../../widgets/pluri_push_scaffold.dart'; /// APLICACIÓN group · "Copia de seguridad" (design ADR-3). Body moved /// verbatim from the former `_SeccionBackup` in `pantalla_ajustes.dart` — /// only the panel header's icon and title were removed (the pushed screen's /// title now carries them); every method below is unchanged. class PantallaAjustesBackup extends StatelessWidget { const PantallaAjustesBackup({super.key}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); return PluriPushScaffold( title: l10n.backupSectionTitle, body: ListView( padding: PluriLayout.pageContentPadding, children: const [_CuerpoBackup()], ), ); } } class _CuerpoBackup extends StatelessWidget { const _CuerpoBackup(); Future _exportar(BuildContext context) async { final l10n = AppLocalizations.of(context); try { final estado = context.read(); // JSON serialization is owned by ServicioExportImport (S4-R4). final json = await estado.exportarConfigJson(); final dir = await getTemporaryDirectory(); final file = File('${dir.path}/pluriwave-backup.json'); await file.writeAsString(json); await Share.shareXFiles( [XFile(file.path)], subject: l10n.backupShareSubject, text: l10n.backupShareText(DateTime.now().toLocal()), ); } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.backupExportError(e.toString()))), ); } } } Future _importar(BuildContext context) async { final l10n = AppLocalizations.of(context); try { final result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['json'], ); if (result == null || result.files.single.path == null) return; final file = File(result.files.single.path!); final contenido = await file.readAsString(); if (!context.mounted) return; // Parsing is owned by ServicioExportImport (S4-R4): null = malformed. final json = context.read().parsearConfigJson(contenido); if (json == null) { throw const FormatException('invalid backup file'); } if (context.mounted) { final confirmar = await showDialog( context: context, builder: (ctx) => AlertDialog( title: Text(AppLocalizations.of(ctx).backupImportTitle), content: Text( AppLocalizations.of(ctx).backupImportConfirmMessage, ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: Text(AppLocalizations.of(ctx).cancelAction), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), child: Text(AppLocalizations.of(ctx).backupImportTitle), ), ], ), ); if (confirmar != true) return; if (context.mounted) { final estado = context.read(); final messenger = ScaffoldMessenger.of(context); await estado.importarConfig(json); messenger.showSnackBar( SnackBar(content: Text(l10n.backupImportSuccess)), ); } } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.backupImportError(e.toString()))), ); } } } @override Widget build(BuildContext context) { return PluriGlassSurface( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( contentPadding: EdgeInsets.zero, leading: const Icon(Icons.upload_outlined), title: Text(AppLocalizations.of(context).backupExportTitle), subtitle: Text(AppLocalizations.of(context).backupExportSubtitle), onTap: () => _exportar(context), ), ListTile( contentPadding: EdgeInsets.zero, leading: const Icon(Icons.download_outlined), title: Text(AppLocalizations.of(context).backupImportTitle), subtitle: Text(AppLocalizations.of(context).backupImportSubtitle), onTap: () => _importar(context), ), ], ), ); } }