add import export and items

This commit is contained in:
atseirjo
2026-10-28 08:10:55 +01:00
parent 07a1bb02fd
commit 4a1731f986
22 changed files with 1118 additions and 106 deletions
+117
View File
@@ -0,0 +1,117 @@
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();
}
}