118 lines
5.0 KiB
Dart
118 lines
5.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
import '../controller/export_controller.dart';
|
|
import '../helper/storage_keys.dart';
|
|
import '../widgets/entry_panel.dart';
|
|
|
|
class ExportView extends GetView<ExportController> {
|
|
static const routeName = '/export-view';
|
|
const ExportView({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) => Scaffold(
|
|
appBar: AppBar(title: const Text('Datensicherung')),
|
|
body: SafeArea(
|
|
child: Align(
|
|
alignment: Alignment.topCenter,
|
|
child: ConstrainedBox(
|
|
constraints: const BoxConstraints(maxWidth: 760),
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Obx(() {
|
|
final busy = controller.isBusy.value;
|
|
final backup = controller.pendingBackup.value;
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
EntryPanel(
|
|
title: 'Daten exportieren',
|
|
subtitle: 'Sichere Filamente, Verarbeitungsprofile, Bauteile inklusive Fotos und Verbrauch sowie deine Materialarten in einer JSON-Datei.\n\nSpeichere die Datei außerhalb der App, zum Beispiel in Dokumente oder in deiner Cloud. So kannst du sie nach einer Neuinstallation wieder importieren.',
|
|
child: FilledButton.icon(
|
|
onPressed: busy ? null : controller.exportData,
|
|
icon: const Icon(Icons.file_download_outlined),
|
|
label: const Text('Als JSON exportieren'),
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
EntryPanel(
|
|
title: 'Daten importieren',
|
|
subtitle: 'Wähle eine JSON-Datensicherung dieser App. Beim Import werden alle aktuell gespeicherten Daten durch den Inhalt der Datei ersetzt. Exportiere bei Bedarf vorher deinen aktuellen Bestand.',
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
OutlinedButton.icon(
|
|
onPressed: busy ? null : controller.selectImport,
|
|
icon: const Icon(Icons.file_upload_outlined),
|
|
label: const Text('JSON-Datei auswählen'),
|
|
),
|
|
if (backup != null) ...[
|
|
const SizedBox(height: 16),
|
|
const Text('Geprüfte Datensicherung:'),
|
|
Text(
|
|
'${backup.data[StorageKeys.filamente]!.length} Filamente',
|
|
),
|
|
Text(
|
|
'${backup.data[StorageKeys.anwendungen]!.length} Profile',
|
|
),
|
|
Text(
|
|
'${backup.data[StorageKeys.bauteile]!.length} Bauteile',
|
|
),
|
|
Text(
|
|
backup.data[StorageKeys.materialien]!.isEmpty
|
|
? 'Materialarten: Standardliste'
|
|
: '${(backup.data[StorageKeys.materialien]!.single['werte'] as List).length} Materialarten',
|
|
),
|
|
const SizedBox(height: 16),
|
|
FilledButton.icon(
|
|
onPressed: busy
|
|
? null
|
|
: () => _confirmImport(context),
|
|
icon: const Icon(Icons.restore),
|
|
label: const Text('Daten ersetzen und importieren'),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
if (busy) ...[
|
|
const SizedBox(height: 20),
|
|
const LinearProgressIndicator(),
|
|
],
|
|
EntryMessage(
|
|
message: controller.message.value,
|
|
hasError: controller.hasError.value,
|
|
),
|
|
],
|
|
);
|
|
}),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Future<void> _confirmImport(BuildContext context) async {
|
|
final confirmed = await showDialog<bool>(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('Alle Daten ersetzen?'),
|
|
content: const Text(
|
|
'Der aktuelle Bestand wird vollständig durch die ausgewählte Datensicherung ersetzt. Auch eine leere Sicherung ersetzt den Bestand.',
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context, false),
|
|
child: const Text('Abbrechen'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () => Navigator.pop(context, true),
|
|
child: const Text('Daten ersetzen'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
if (confirmed == true) await controller.importData();
|
|
}
|
|
}
|