import 'dart:async'; import 'dart:developer'; import 'dart:io'; import 'dart:typed_data'; import 'package:injectable/injectable.dart'; import 'package:mnemo_cards_backend/database/database.dart'; import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart' hide VoiceModel; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'pack_dto_converter.dart'; import 'pack_manager_extensions.dart'; import 'card_pack_drift_extension.dart'; @lazySingleton class PackManager { final AppDatabase _db; final PackDtoConverter packDtoConverter; PackManager(this._db, this.packDtoConverter); Future> listPacksPreviews( UserModel? userModel, Map? params, ) async { // Get packs from Drift database final packs = await _db.packDao.getAllPacks( enabledOnly: true, orderByField: 'order', ); return (await Future.wait(packs.map( (pack) async { final dto = await pack.toPreviewDto(userModel); if (!pack.enabled) { return dto.copyWith(subtitle: 'DISABLED ${dto.subtitle}'); } return dto; }, ))) .toList(); } Future getPack(int id) async { return await _db.packDao.getPackById(id); } Future> getCards(int packId) async { return await _db.packDao.getPackCards(packId); } Future getCard(int id) async { return await _db.packDao.getCardById(id); } Future getVoice(int id) async { return await _db.packDao.getVoiceById(id); } Future> getVoices(int cardId) async { return await _db.packDao.getCardVoices(cardId); } Future getPackDto(int id, UserModel? userModel) async { final pack = await getPack(id); if (pack == null) { throw StateError('Pack not found'); } final cards = await getCards(id); final voices = []; for (final card in cards) { voices.addAll(await getVoices(card.id)); } return await pack.toDto(cards, voices, userModel); } Future> getPackPreviewImages(int packId) async { final pack = await getPack(packId); if (pack == null) { throw StateError('Pack not found'); } final previewCards = await _db.packDao.getPreviewCards(packId); final cards = previewCards.isNotEmpty ? previewCards : (await getCards(packId)).take(6).toList(); final images = []; for (final card in previewCards) { if (card.image.isNotEmpty) { try { final image = await card.image.base64Image; images.add(image); } catch (e, s) { log('error while reading image', error: e, stackTrace: s); } } } // If we don't have enough preview images, fill with empty strings while (images.length < 6) { images.add(''); } return images; } Future> getPackImages(int packId) async { final cards = await getCards(packId); final result = {}; for (final card in cards) { if (card.image.isNotEmpty) { try { result[card.id.toString()] = File('${PackManagerUtils.assetsDirectory.path}/cards/${card.image}') .readAsBytesSync(); } catch (e, s) { log('error while reading image', error: e, stackTrace: s); } } } return result; } } // Static utility functions for PackManager class PackManagerUtils { static Directory get assetsDirectory { String mainPath = Platform.resolvedExecutable; if ((Platform.isMacOS || Platform.isLinux) && !Platform.script.toString().contains('StudioProjects')) { mainPath = mainPath.substring(0, mainPath.lastIndexOf("/")); var dir = Directory("$mainPath/../data"); if (dir.existsSync()) { return dir; } dir = Directory("$mainPath/data"); if (dir.existsSync()) { return dir; } throw Exception('No asset dir! $mainPath'); } if (Platform.isMacOS) { mainPath = mainPath.substring(0, mainPath.lastIndexOf("/")); return Directory( '/Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards_backend/data'); } else if (Platform.isWindows) { mainPath = mainPath.substring(0, mainPath.lastIndexOf("\\")); return Directory("$mainPath/data/flutter_assets/data"); } else { return Directory(''); } } }