Files
ertl_filament_verwaltung/lib/models/backup_model.dart
T
2026-10-28 08:10:55 +01:00

106 lines
3.6 KiB
Dart

import 'dart:convert';
import '../helper/storage_keys.dart';
import 'anwendung_model.dart';
import 'bauteil_model.dart';
import 'kauf_filament_model.dart';
class BackupModel {
static const keys = [
StorageKeys.filamente,
StorageKeys.anwendungen,
StorageKeys.bauteile,
StorageKeys.materialien,
];
final Map<String, List<Map<String, dynamic>>> data;
const BackupModel(this.data);
String encode() => const JsonEncoder.withIndent(' ').convert({
'format': 'ertl_filament_verwaltung',
'version': 1,
'exportiertAm': DateTime.now().toUtc().toIso8601String(),
'daten': data,
});
factory BackupModel.decode(String source) {
try {
final json =
jsonDecode(source.replaceFirst(RegExp(r'^\uFEFF'), '')) as Map;
if (json['format'] != 'ertl_filament_verwaltung' ||
json['version'] != 1) {
throw const FormatException();
}
final raw = json['daten'] as Map;
final data = <String, List<Map<String, dynamic>>>{
for (final key in keys)
key: (raw[key] as List)
.map((item) => Map<String, dynamic>.from(item as Map))
.toList(),
};
final filamentIds = <String>{};
for (final json in data[StorageKeys.filamente]!) {
final item = KaufFilamentModel.fromJson(json);
if (item.filamentId.isEmpty ||
!filamentIds.add(item.filamentId) ||
item.material.trim().isEmpty ||
!_positive(item.gewichtGramm) ||
!_nonNegative(item.preis)) {
throw const FormatException();
}
}
final profileIds = <String>{};
for (final json in data[StorageKeys.anwendungen]!) {
final item = AnwendungModel.fromJson(json);
if (item.anwendungId.isEmpty ||
!profileIds.add(item.anwendungId) ||
item.filamentId.isEmpty ||
!_positive(item.druckTemperatur) ||
!_nonNegative(item.druckbettTemperatur) ||
(item.bauraumTemperatur != null &&
!_nonNegative(item.bauraumTemperatur!))) {
throw const FormatException();
}
}
final partIds = <String>{};
for (final json in data[StorageKeys.bauteile]!) {
final item = BauteilModel.fromJson(json);
if (item.bauteilId.isEmpty ||
!partIds.add(item.bauteilId) ||
item.name.trim().isEmpty ||
item.druckdauerMinuten <= 0 ||
!_positive(item.gewichtGramm) ||
!_nonNegative(item.abfallGramm) ||
item.filamente.isEmpty ||
item.filamente.any(
(entry) =>
entry.filamentId.isEmpty ||
!_nonNegative(entry.verbrauchGramm),
)) {
throw const FormatException();
}
if (item.fotoBase64 != null) base64Decode(item.fotoBase64!);
}
final materials = data[StorageKeys.materialien]!;
if (materials.isNotEmpty) {
if (materials.length != 1) throw const FormatException();
final values = (materials.single['werte'] as List).cast<String>();
if (values.any((value) => value.trim().isEmpty) ||
values.map((value) => value.toLowerCase()).toSet().length !=
values.length) {
throw const FormatException();
}
}
return BackupModel(data);
} catch (_) {
throw const FormatException(
'Ungültige oder nicht unterstützte Datensicherung. Bitte eine vollständige JSON-Datei dieser App auswählen.',
);
}
}
static bool _nonNegative(num value) => value.isFinite && value >= 0;
static bool _positive(num? value) =>
value != null && value.isFinite && value > 0;
}