Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
200 lines
No EOL
5.8 KiB
Text
200 lines
No EOL
5.8 KiB
Text
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:developer';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:image/image.dart';
|
|
import 'package:injectable/injectable.dart';
|
|
import 'package:isar/isar.dart';
|
|
import 'package:mnemo_cards_backend/database/database.dart';
|
|
import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart' hide VoiceModel;
|
|
import 'package:archive/archive.dart';
|
|
import 'package:mnemo_cards_backend/packs/card_dto_extension.dart';
|
|
import 'package:mnemo_cards_backend/packs/card_pack_model_extension.dart';
|
|
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|
|
|
import '../main.dart' as backend_main;
|
|
import 'pack_dto_converter.dart';
|
|
import 'pack_manager_extensions.dart';
|
|
|
|
@lazySingleton
|
|
class PackManager {
|
|
final AppDatabase _db;
|
|
final PackDtoConverter packDtoConverter;
|
|
|
|
PackManager(this._db, this.packDtoConverter);
|
|
|
|
Future<List<CardPackPreviewDto>> listPacksPreviews(
|
|
UserModel? userModel,
|
|
Map<String, String>? params,
|
|
) async {
|
|
// TODO: Full migration - replace CardPackModel with Drift CardPack
|
|
// Need to update PackDtoConverter to work with Drift models
|
|
// For now using isar temporarily until full migration
|
|
final models = await backend_main.database.transaction(() async {
|
|
// Temporary: using isar through backend_main until conversion complete
|
|
return <CardPackModel>[];
|
|
});
|
|
// TODO: Use _db.packDao.getAllPacks() and convert CardPack to CardPackModel
|
|
// Or update packDtoConverter to accept CardPack
|
|
models.sort((p, n) => p.order.compareTo(n.order));
|
|
return (await Future.wait(models.map(
|
|
(model) async {
|
|
final dto =
|
|
await packDtoConverter.toCardPackPreviewDto(model, userModel);
|
|
if (!model.enabled) {
|
|
return dto.copyWith(subtitle: 'DISABLED ${dto.subtitle}');
|
|
}
|
|
return dto;
|
|
},
|
|
)))
|
|
.toList();
|
|
}
|
|
|
|
Future<List<CardPackModel>> _getPacks() async {
|
|
return await backend_main.isar.cardPackModels
|
|
.filter()
|
|
.enabledEqualTo(true)
|
|
.findAll();
|
|
}
|
|
|
|
Future<CardPackModel?> getPack(Id id) async {
|
|
return await backend_main.isar.cardPackModels.get(id);
|
|
}
|
|
|
|
Future<List<GameCardModel>> getCards(Id packId) async {
|
|
return await backend_main.isar.gameCardModels
|
|
.filter()
|
|
.packIdEqualTo(packId)
|
|
.findAll();
|
|
}
|
|
|
|
Future<GameCardModel?> getCard(Id id) async {
|
|
return await backend_main.isar.gameCardModels.get(id);
|
|
}
|
|
|
|
Future<VoiceModel?> getVoice(Id id) async {
|
|
return await backend_main.isar.voiceModels.get(id);
|
|
}
|
|
|
|
Future<List<VoiceModel>> getVoices(Id cardId) async {
|
|
return await backend_main.isar.voiceModels
|
|
.filter()
|
|
.cardIdEqualTo(cardId)
|
|
.findAll();
|
|
}
|
|
|
|
Future<CardPackDto> getPackDto(Id id, UserModel? userModel) async {
|
|
final pack = await getPack(id);
|
|
if (pack == null) {
|
|
throw StateError('Pack not found');
|
|
}
|
|
|
|
final cards = await getCards(id);
|
|
final voices = <VoiceModel>[];
|
|
|
|
for (final card in cards) {
|
|
voices.addAll(await getVoices(card.id!));
|
|
}
|
|
|
|
return await packDtoConverter.toCardPackDto(pack, cards, voices, userModel);
|
|
}
|
|
|
|
Future<List<String>> getPackPreviewImages(Id packId) async {
|
|
final pack = await getPack(packId);
|
|
if (pack == null) {
|
|
throw StateError('Pack not found');
|
|
}
|
|
|
|
final cards = await getCards(packId);
|
|
final previewCardIds = pack.previewCardsOrder.take(6);
|
|
|
|
final previewCards = cards
|
|
.where((card) => previewCardIds.contains(card.id))
|
|
.take(6)
|
|
.toList();
|
|
|
|
final images = <String>[];
|
|
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<Map<String, Uint8List>> getPackImages(Id packId) async {
|
|
final cards = await getCards(packId);
|
|
|
|
final empty = <String, Uint8List>{};
|
|
return cards.fold(empty, (Map<String, Uint8List> map, card) {
|
|
if (card.image.isNotEmpty) {
|
|
try {
|
|
return map
|
|
..addAll({
|
|
card.id.toString():
|
|
File('${PackManagerUtils.assetsDirectory.path}/cards/${card.image}')
|
|
.readAsBytesSync(),
|
|
});
|
|
} catch (e, s) {
|
|
log('error while reading image', error: e, stackTrace: s);
|
|
return map;
|
|
}
|
|
}
|
|
return map;
|
|
});
|
|
}
|
|
}
|
|
|
|
// Static utility functions for PackManager
|
|
enum _ImageSize {
|
|
big,
|
|
medium,
|
|
small,
|
|
extraSmall,
|
|
}
|
|
|
|
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('');
|
|
}
|
|
}
|
|
|
|
static File getResizedFile(String id, String type, _ImageSize size) =>
|
|
File('${assetsDirectory.path}/$type/${size.name}/$id');
|
|
} |