diff options
Diffstat (limited to 'lib/util/file_handler.dart')
-rw-r--r-- | lib/util/file_handler.dart | 109 |
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 {} +} |