mnemo_cards/lib/features/packs/pack_cache_manager.dart

182 lines
5.2 KiB
Dart
Raw Normal View History

2024-05-22 20:48:44 +00:00
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
2024-06-21 19:12:29 +00:00
import 'package:flutter/foundation.dart';
2024-05-22 20:48:44 +00:00
import 'package:flutter/widgets.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
2024-06-12 23:00:13 +00:00
2024-05-22 20:48:44 +00:00
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../di/locator.dart';
2024-06-08 23:34:38 +00:00
import '../analytics/analytics.dart';
2024-05-22 20:48:44 +00:00
// persist
class PackCacheManager {
late final SharedPreferences _sharedPreferences;
PackCacheManager();
Future<void> init() async {
_sharedPreferences = await SharedPreferences.getInstance();
}
2024-06-08 23:34:38 +00:00
Future<void> markPackForUpdate(String packId) async {
try {
final dir = await _packDirectory(packId);
final file = File('${dir.path}/pack.json');
if (file.existsSync()) {
2024-06-12 23:00:13 +00:00
final json = (await file.readAsString()).decode<Map>();
2024-06-08 23:34:38 +00:00
json['id'] = '0';
await file.writeAsString(jsonEncode(json));
}
} catch (e, s) {
2024-08-03 22:37:10 +00:00
log('Cant mark pack for update', error: e, stackTrace: s);
2024-06-08 23:34:38 +00:00
Analytics.crashlyticsError(
e: e,
s: s,
message: 'Cant mark pack for update',
);
}
}
2024-05-22 20:48:44 +00:00
Future<CardPackDto> loadPackFromCache(
String packId, {
bool withCardImages = true,
}) async {
log('Loading from cache ${packId}');
try {
final packDir = await _packDirectory(packId);
final packFile = File('${packDir.path}/pack.json');
if (!packFile.existsSync()) {
log('Pack file not exist');
return throw Exception('Pack file not exist');
}
2024-06-12 23:00:13 +00:00
var pack = packFile.readAsStringSync().decode(CardPackDto.fromJson);
2024-05-22 20:48:44 +00:00
if (withCardImages) {
Map<String, MemoryImage> images = {};
log('Cards ${packId}: ${pack.cards.length}');
if (pack.cards.isNotEmpty) {
log('Loading cards ${packId}');
2024-06-08 23:34:38 +00:00
await Future.wait(
pack.cards.map((dto) async {
final file = File('${packDir.path}/images/${dto.id}');
if (await file.exists()) {
try {
images[dto.id.toString()] =
MemoryImage(await file.readAsBytes());
} catch (e) {
markPackForUpdate(packId);
throw Exception('Cant read file $packId $e');
}
} else {
log('Cant load card ${dto.id} from $packId, skiping');
2024-05-22 20:48:44 +00:00
}
2024-06-08 23:34:38 +00:00
}),
);
2024-05-22 20:48:44 +00:00
}
log('Pack loaded ${packId}');
2024-06-08 23:34:38 +00:00
locator.imagesHolder.setPackImages(images, packId);
2024-05-22 20:48:44 +00:00
}
return pack;
} catch (e, s) {
log('Cant load from cache ${packId} ${e} ${s}');
deletePack(packId);
rethrow;
}
}
Future<List<String>> _updateSavedPacks() async {
2024-06-21 19:12:29 +00:00
if (kIsWeb) {
return [];
}
2024-05-22 20:48:44 +00:00
final packsDir =
Directory('${(await getApplicationDocumentsDirectory()).path}/packs');
List<String> savedPackIds = [];
if (packsDir.existsSync()) {
for (final packDir in packsDir.listSync()) {
if (File('${packDir.path}/pack.json').existsSync()) {
savedPackIds.add(packDir.path.split('/').last);
}
}
}
_sharedPreferences.setStringList('packs', savedPackIds);
return savedPackIds;
}
Future<List<CardPackDto>> loadAllPacks() async {
final ids = await _updateSavedPacks();
final List<CardPackDto> packs = [];
for (final id in ids) {
try {
final pack = await loadPackFromCache(id, withCardImages: false);
packs.add(pack);
} catch (e) {
log('Pack $id doesnt exist anymore');
}
}
return packs;
}
Future<void> deletePack(String packId) async {
try {
final dir = await _packDirectory(packId);
dir.deleteSync(recursive: true);
} catch (e) {
log('Deletion failed $e');
}
_updateSavedPacks();
}
Future<Uint8List?> loadPackFile(String packId, String path) async {
final bytes =
File('${(await _packDirectory(packId)).path}/$path').readAsBytesSync();
return bytes;
}
Future<void> clearCache() async {
final saved = await _updateSavedPacks();
for (final p in saved) {
await deletePack(p);
}
await _sharedPreferences.remove('packs');
}
2024-05-28 21:25:51 +00:00
Future<void> savePack(
CardPackDto dto, {
Map<String, MemoryImage>? images,
}) async {
2024-05-22 20:48:44 +00:00
log('Saving pack ${dto.id}');
final dir = await _packDirectory(dto.id);
2024-06-12 23:00:13 +00:00
final json = dto.encode();
2024-05-22 20:48:44 +00:00
log('Saving dto ${dto.id}');
File('${dir.path}/pack.json')
..createSync(recursive: true)
..writeAsStringSync(json);
if (images != null) {
log('Saving card images ${dto.id}');
final imageDir = Directory('${dir.path}/images');
if (imageDir.existsSync()) {
imageDir.deleteSync(recursive: true);
}
for (final card in dto.cards) {
final bytes = images[card.id.toString()]?.bytes;
if (bytes != null) {
File('${imageDir.path}/${card.id}')
..createSync(recursive: true)
..writeAsBytesSync(bytes);
}
}
}
log('Saved ${dto.id}');
}
2024-06-21 19:12:29 +00:00
Future<Directory> _packDirectory(String id) async => kIsWeb ? Directory.current : Directory(
2024-05-22 20:48:44 +00:00
'${(await getApplicationDocumentsDirectory()).path}/packs/$id',
);
}