107 lines
3.7 KiB
Dart
107 lines
3.7 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.gesamtpreis != null && !_nonNegative(item.gesamtpreis!)) ||
|
|
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;
|
|
}
|