refactor(ajustes): split remaining Settings sections into pushed screens
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
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<void> _exportar(BuildContext context) async {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
try {
|
||||
final estado = context.read<EstadoRadio>();
|
||||
// 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<void> _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<EstadoRadio>().parsearConfigJson(contenido);
|
||||
if (json == null) {
|
||||
throw const FormatException('invalid backup file');
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
final confirmar = await showDialog<bool>(
|
||||
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<EstadoRadio>();
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user