1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 12:59:21 +00:00
comunicmobile/lib/helpers/serialization/base_serialization_helper.dart

160 lines
3.8 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:comunic/constants.dart';
import 'package:comunic/utils/flutter_utils.dart';
import 'package:comunic/utils/log_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<T> extends Comparable<T> {
Map<String, dynamic> toJson();
}
abstract class BaseSerializationHelper<T extends SerializableElement> {
/// List cache
List<T>? _cache;
/// The name of the type of data to serialise
String get type;
/// Parse an json entry into a [T] object
T parse(Map<String, dynamic> m);
/// Get the file where data should be stored
Future<File> _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<void> _loadCache() async {
if (_cache != null) return;
if (isWeb) {
_cache = [];
return;
}
try {
final file = await _getFilePath();
if (!await file.exists()) {
_cache = [];
return;
}
final List<dynamic> json = jsonDecode(await file.readAsString());
_cache = json.cast<Map<String, dynamic>>().map(parse).toList();
_cache!.sort();
} catch (e, s) {
logError(e, s);
print("Failed to read serialized data!");
_cache = [];
}
}
/// Save the cache to the persistent memory
Future<void> _saveCache() async {
if (isWeb) return;
try {
final file = await _getFilePath();
await file.writeAsString(jsonEncode(_cache!
.map((e) => e.toJson())
.toList()
.cast<Map<String, dynamic>>()));
} catch (e, s) {
print("Failed to write file!");
logError(e, s);
}
}
/// Get the current list of elements
Future<List<T>> getList() async {
await _loadCache();
return List.from(_cache!);
}
/// Set a new list of conversations
Future<void> setList(List<T> list) async {
_cache = List.from(list);
await _saveCache();
}
/// Insert new element
Future<void> insert(T el) async {
await _loadCache();
_cache!.add(el);
_cache!.sort();
await _saveCache();
}
/// Insert new element
Future<void> insertMany(List<T> els) async {
await _loadCache();
_cache!.addAll(els);
_cache!.sort();
await _saveCache();
}
/// Check if any entry in the last match the predicate
Future<bool> any(bool isContained(T t)) async {
await _loadCache();
return _cache!.any((element) => isContained(element));
}
Future<bool> has(T el) => any((t) => t == el);
/// Check if any entry in the last match the predicate
Future<T> first(bool filter(T t)) async {
await _loadCache();
return _cache!.firstWhere((element) => filter(element));
}
/// Replace an element with another one
Future<void> 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<void> insertOrReplaceElements(List<T> list) async {
await _loadCache();
_cache!.removeWhere((element) => list.any((newEl) => element == newEl));
_cache!.addAll(list);
await _saveCache();
}
/// Remove elements
Future<void> removeElement(bool isToRemove(T t)) async {
await _loadCache();
_cache!.removeWhere((element) => isToRemove(element));
await _saveCache();
}
/// Remove all elements
Future<void> removeAll() async {
_cache = [];
await _saveCache();
}
}