diff options
Diffstat (limited to 'lib/util')
-rw-r--r-- | lib/util/file_handler.dart | 109 | ||||
-rw-r--r-- | lib/util/notifications.dart | 32 | ||||
-rw-r--r-- | lib/util/storage_handler.dart | 20 |
3 files changed, 161 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 {} +} diff --git a/lib/util/notifications.dart b/lib/util/notifications.dart new file mode 100644 index 0000000..91280da --- /dev/null +++ b/lib/util/notifications.dart @@ -0,0 +1,32 @@ +import 'package:open_file/open_file.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +/// Handles all the notification related things. +class Notifications { + static FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + + /// Specifies the exact notification behavior on android. + static const AndroidNotificationDetails _androidSpecifics = AndroidNotificationDetails( + 'com.davidpenkowoj.kulinar', + 'Kulinar', + importance: Importance.defaultImportance, + priority: Priority.defaultPriority, + autoCancel: true, + playSound: false, + showWhen: false, + ); + + /// Is called when the notification is pressed. + static Future<dynamic> selectNotification(String? payload) async { + if (payload != null) { + OpenFile.open(payload, type: "*/*"); // TODO: FIXME: Still doesnt work (sometimes) + } + } + + /// Launches the notification + static Future<void> notify(String title, String description, String payload) async { + const NotificationDetails _platformChannelSpecifics = NotificationDetails(android: _androidSpecifics); + + await flutterLocalNotificationsPlugin.show(0, title, description, _platformChannelSpecifics, payload: payload); + } +} diff --git a/lib/util/storage_handler.dart b/lib/util/storage_handler.dart new file mode 100644 index 0000000..1e12ed7 --- /dev/null +++ b/lib/util/storage_handler.dart @@ -0,0 +1,20 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +/// Handles all persistance related app storage +class StorageHandler { + /// Stores the given `data` as a string with the `key`. + static Future<String> store(String key, String data) async { + final _prefs = await SharedPreferences.getInstance(); + + _prefs.setString(key, data); + + return data; + } + + /// Fetches the string related to the given `key`. + static Future<String?> fetch(String key) async { + final _prefs = await SharedPreferences.getInstance(); + + return _prefs.getString(key); + } +} |