aboutsummaryrefslogtreecommitdiff
path: root/lib/util/file_handler.dart
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util/file_handler.dart')
-rw-r--r--lib/util/file_handler.dart109
1 files changed, 109 insertions, 0 deletions
diff --git a/lib/util/file_handler.dart b/lib/util/file_handler.dart
new file mode 100644
index 0000000..0344c60
--- /dev/null
+++ b/lib/util/file_handler.dart
@@ -0,0 +1,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 {}
+}