import 'dart:convert'; import 'dart:io'; import 'package:comunic/constants.dart'; import 'package:comunic/utils/flutter_utils.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; /// Base serialization helper /// /// @author Pierre Hubert abstract class SerializableElement extends Comparable { Map toJson(); } abstract class BaseSerializationHelper { /// List cache List _cache; /// The name of the type of data to serialise String get type; /// Parse an json entry into a [T] object T parse(Map m); /// Get the file where data should be stored Future _getFilePath() async { final dir = await getApplicationDocumentsDirectory(); final targetDir = Directory(path.join(dir.absolute.path, SERIALIZATION_DIRECTORY)); targetDir.create(recursive: true); return File(path.join(targetDir.absolute.path, type)); } /// Load the cache Future _loadCache() async { if (_cache != null) return; if (isWeb) { _cache = []; return; } try { final file = await _getFilePath(); if (!await file.exists()) return _cache = []; final List json = jsonDecode(await file.readAsString()); _cache = json.cast>().map(parse).toList(); _cache.sort(); } catch (e, s) { print("Failed to read serialized data! $e => $s"); _cache = []; } } /// Save the cache to the persistent memory Future _saveCache() async { if (isWeb) return; final file = await _getFilePath(); await file.writeAsString(jsonEncode( _cache.map((e) => e.toJson()).toList().cast>())); } /// Get the current list of elements Future> getList() async { await _loadCache(); return List.from(_cache); } /// Set a new list of conversations Future setList(List list) async { _cache = List.from(list); await _saveCache(); } /// Insert new element Future insert(T el) async { await _loadCache(); _cache.add(el); _cache.sort(); await _saveCache(); } /// Insert new element Future insertMany(List els) async { await _loadCache(); _cache.addAll(els); _cache.sort(); await _saveCache(); } /// Check if any entry in the last match the predicate Future any(bool isContained(T t)) async { await _loadCache(); return _cache.any((element) => isContained(element)); } Future has(T el) => any((t) => t == el); /// Check if any entry in the last match the predicate Future first(bool filter(T t)) async { await _loadCache(); return _cache.firstWhere((element) => filter(element)); } /// Replace an element with another one Future insertOrReplaceElement(bool isToReplace(T t), T newEl) async { await _loadCache(); // Insert or replace the element _cache = _cache.where((element) => !isToReplace(element)).toList(); _cache.add(newEl); _cache.sort(); await _saveCache(); } /// Insert or replace many elements Future insertOrReplaceElements(List list) async { await _loadCache(); _cache.removeWhere((element) => list.any((newEl) => element == newEl)); _cache.addAll(list); await _saveCache(); } /// Remove elements Future removeElement(bool isToRemove(T t)) async { await _loadCache(); _cache.removeWhere((element) => isToRemove(element)); await _saveCache(); } /// Remove all elements Future removeAll() async { _cache = []; await _saveCache(); } }