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',
|
|
|
|
|
);
|
|
|
|
|
}
|