1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:kulinar_app/constants.dart';
import 'package:kulinar_app/util/notifications.dart';
import 'package:kulinar_app/widgets/toastbar_widget.dart';
import 'package:kulinar_app/models/data/recipe_data_class.dart';
import 'package:kulinar_app/models/data/settings_data_class.dart';
import 'package:file_picker/file_picker.dart';
import 'package:external_path/external_path.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
enum ExportType {
settings,
recipes,
recipe,
full,
}
/// Handles all the things related to file serialization / deserialization and other file interaction.
class FileHandler {
/// Serializes the given `data` into a json style File. Sends a confirmation Toast to the given `context` afterwards.
static Future<void> serializeFile(BuildContext context, Map<String, dynamic> data) async {
if (await Permission.storage.request().isGranted) {
try {
final _directory = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS);
final _file = File("$_directory/Export-${DateTime.now().toUtc().toString().split(" ")[0]}.kulinar");
await _file.writeAsString(jsonEncode(await encodeDataAsMap(ExportType.full, data)));
ToastBar.showToastBar(context, AppLocalizations.of(context)!.exportSuccess);
Notifications.notify(AppLocalizations.of(context)!.exportSuccess, AppLocalizations.of(context)!.tapHint, _file.path);
} catch (e) {
print(e);
ToastBar.showToastBar(context, AppLocalizations.of(context)!.exportError);
}
}
}
/// Deserializes the given `file` into the returned Map. Sends a confirmation Toast to the given `context` afterwards.
static Future<Map<String, String>> deserializeFile(BuildContext context, File file) async {
final dynamic _content = jsonDecode(await file.readAsString());
SettingsData.decode(_content["settings"]);
RecipeData.decode(_content["recipes"]);
ToastBar.showToastBar(context, AppLocalizations.of(context)!.importSuccess);
return _content;
}
/// Parses a given possible deserializable `file` for useful information and returns a map of it.
static Future<Map<String, String>> deserializeFileInformation(File file) async {
final Map<dynamic, dynamic> _content = jsonDecode(await file.readAsString());
Map<String, String> _map = Map<String, String>();
_map["version"] = _content["version"];
_map["type"] = _content["type"].split(".")[1];
_map["size"] = "${await file.length()} Bytes";
if (_content["type"] == ExportType.full.toString()) {
int a = jsonDecode(_content["recipes"]).length;
int b = jsonDecode(_content["settings"]).length;
_map["entries"] = (a + b).toString();
}
return _map;
}
/// Opens the native file picker and returns the picked `.kulinar` file.
static Future<File?> pickDeserializableFile(BuildContext context) async {
if (await Permission.storage.request().isGranted) {
try {
FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.custom, allowedExtensions: ["kulinar"]);
if (result != null) {
return File(result.files.single.path!);
}
} catch (e) {
print(e);
ToastBar.showToastBar(context, AppLocalizations.of(context)!.importError);
}
}
return null;
}
/// Encodes the given `data` together with some additional information into a serializable map.
static Future<Map<String, String>> encodeDataAsMap(ExportType type, Map<String, dynamic> data) async {
Map<String, String> _map = Map<String, String>();
_map["version"] = cVersion;
_map["type"] = type.toString();
// TODO: IMPLEMENT: Base64 Images and image count on export
// map["imageCount"] = getImageCount;
_map.addAll(data as Map<String, String>);
return _map;
}
/// Decodes the given `map` into
/// TODO: IMPLEMENT: decodeExportMap
// static Future<Map<String, String>> decodeMapToData(ExportType type) async {}
}
|