238 lines
7.7 KiB
Dart
238 lines
7.7 KiB
Dart
|
|
import 'package:drift/drift.dart';
|
|||
|
|
import 'package:drift_postgres/drift_postgres.dart';
|
|||
|
|
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 'card_pack_drift_extension.dart';
|
|||
|
|
|
|||
|
|
/// Extension для конвертации GameCard (Drift) в GameCardModel
|
|||
|
|
extension GameCardToModel on GameCard {
|
|||
|
|
GameCardModel toModel() {
|
|||
|
|
return GameCardModel(
|
|||
|
|
id: id,
|
|||
|
|
image: image,
|
|||
|
|
mnemo: mnemo ?? '',
|
|||
|
|
original: original,
|
|||
|
|
translation: translation,
|
|||
|
|
transcription: transcription,
|
|||
|
|
transcriptionMnemo: transcriptionMnemo,
|
|||
|
|
imageBack: imageBack,
|
|||
|
|
back: back,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Repository для работы с паками
|
|||
|
|
/// Работает с доменными моделями (CardPackModel), использует DAO для доступа к БД
|
|||
|
|
@lazySingleton
|
|||
|
|
class PackRepository {
|
|||
|
|
final AppDatabase _db;
|
|||
|
|
|
|||
|
|
PackRepository(this._db);
|
|||
|
|
|
|||
|
|
/// Получить пак по ID
|
|||
|
|
/// [includeCards] - загружать ли связанные карточки
|
|||
|
|
/// [includePreviewCards] - загружать ли превью карточки
|
|||
|
|
Future<CardPackModel?> getPackById(
|
|||
|
|
String id, {
|
|||
|
|
bool includeCards = false,
|
|||
|
|
bool includePreviewCards = false,
|
|||
|
|
}) async {
|
|||
|
|
final pack = await _db.packDao.getPackById(id);
|
|||
|
|
if (pack == null) return null;
|
|||
|
|
|
|||
|
|
final packModel = await pack.toModel();
|
|||
|
|
|
|||
|
|
if (includeCards) {
|
|||
|
|
final cards = await _db.packDao.getPackCards(id);
|
|||
|
|
packModel.cards.addAll(cards.map((c) => c.toModel()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (includePreviewCards) {
|
|||
|
|
final previewCards = await _db.packDao.getPreviewCards(id);
|
|||
|
|
packModel.previewCards.addAll(previewCards.map((c) => c.toModel()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return packModel;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить все паки
|
|||
|
|
Future<List<CardPackModel>> getAllPacks({
|
|||
|
|
bool enabledOnly = false,
|
|||
|
|
String? orderByField,
|
|||
|
|
bool orderDesc = false,
|
|||
|
|
bool includeCards = false,
|
|||
|
|
bool includePreviewCards = false,
|
|||
|
|
}) async {
|
|||
|
|
final packs = await _db.packDao.getAllPacks(
|
|||
|
|
enabledOnly: enabledOnly,
|
|||
|
|
orderByField: orderByField,
|
|||
|
|
orderDesc: orderDesc,
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if (includeCards || includePreviewCards) {
|
|||
|
|
final packModels = <CardPackModel>[];
|
|||
|
|
for (final pack in packs) {
|
|||
|
|
final packModel = await pack.toModel();
|
|||
|
|
|
|||
|
|
if (includeCards) {
|
|||
|
|
final cards = await _db.packDao.getPackCards(pack.id);
|
|||
|
|
packModel.cards.addAll(cards.map((c) => c.toModel()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (includePreviewCards) {
|
|||
|
|
final previewCards = await _db.packDao.getPreviewCards(pack.id);
|
|||
|
|
packModel.previewCards.addAll(previewCards.map((c) => c.toModel()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
packModels.add(packModel);
|
|||
|
|
}
|
|||
|
|
return packModels;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return await Future.wait(packs.map((p) => p.toModel()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Создать пак
|
|||
|
|
Future<String> createPack(CardPackModel packModel) async {
|
|||
|
|
final companion = CardPacksCompanion.insert(
|
|||
|
|
title: packModel.title,
|
|||
|
|
subtitle: packModel.subtitle,
|
|||
|
|
size: packModel.size,
|
|||
|
|
color: Value(packModel.color),
|
|||
|
|
version: Value(packModel.version),
|
|||
|
|
cover: Value(packModel.cover),
|
|||
|
|
description: Value(packModel.description),
|
|||
|
|
googlePlayId: Value(packModel.googlePlayId),
|
|||
|
|
rustoreId: Value(packModel.rustoreId),
|
|||
|
|
appStoreId: Value(packModel.appStoreId),
|
|||
|
|
price: Value(packModel.price),
|
|||
|
|
currency: packModel.currency != null
|
|||
|
|
? Value(packModel.currency!)
|
|||
|
|
: const Value.absent(),
|
|||
|
|
enabled: Value(packModel.enabled),
|
|||
|
|
order: Value(packModel.order),
|
|||
|
|
cardsOrder: Value(packModel.cardsOrder),
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return await _db.packDao.createPack(companion);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Обновить пак
|
|||
|
|
Future<void> updatePack(CardPackModel packModel) async {
|
|||
|
|
if (packModel.id == null) {
|
|||
|
|
throw ArgumentError('Pack ID is required');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
await _db.packDao.updatePackPartial(
|
|||
|
|
CardPacksCompanion(
|
|||
|
|
id: Value(packModel.id!),
|
|||
|
|
title: Value(packModel.title),
|
|||
|
|
subtitle: Value(packModel.subtitle),
|
|||
|
|
size: Value(packModel.size),
|
|||
|
|
color: Value(packModel.color),
|
|||
|
|
version: Value(packModel.version),
|
|||
|
|
cover: Value(packModel.cover),
|
|||
|
|
description: Value(packModel.description),
|
|||
|
|
googlePlayId: Value(packModel.googlePlayId),
|
|||
|
|
rustoreId: Value(packModel.rustoreId),
|
|||
|
|
appStoreId: Value(packModel.appStoreId),
|
|||
|
|
price: Value(packModel.price),
|
|||
|
|
currency: packModel.currency != null
|
|||
|
|
? Value(packModel.currency!)
|
|||
|
|
: const Value.absent(),
|
|||
|
|
enabled: Value(packModel.enabled),
|
|||
|
|
order: Value(packModel.order),
|
|||
|
|
cardsOrder: Value(packModel.cardsOrder),
|
|||
|
|
updatedAt: Value(PgDateTime(DateTime.now())),
|
|||
|
|
),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Обновить пак частично
|
|||
|
|
Future<void> updatePackPartial(CardPacksCompanion updates) async {
|
|||
|
|
await _db.packDao.updatePackPartial(updates);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Удалить пак (soft delete)
|
|||
|
|
Future<void> softDeletePack(String packId) async {
|
|||
|
|
await _db.packDao.softDeletePack(packId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Подсчитать паки
|
|||
|
|
Future<int> countPacks({bool enabledOnly = false}) async {
|
|||
|
|
return await _db.packDao.countPacks(enabledOnly: enabledOnly);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить карточки пака
|
|||
|
|
Future<List<GameCardModel>> getPackCards(String packId) async {
|
|||
|
|
final cards = await _db.packDao.getPackCards(packId);
|
|||
|
|
return cards.map((c) => c.toModel()).toList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить превью карточки пака
|
|||
|
|
Future<List<GameCardModel>> getPreviewCards(String packId) async {
|
|||
|
|
final cards = await _db.packDao.getPreviewCards(packId);
|
|||
|
|
return cards.map((c) => c.toModel()).toList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить карточку по ID
|
|||
|
|
Future<GameCardModel?> getCardById(String id) async {
|
|||
|
|
final card = await _db.packDao.getCardById(id);
|
|||
|
|
return card?.toModel();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить паки для карточки
|
|||
|
|
Future<List<CardPackModel>> getPacksForCard(String cardId) async {
|
|||
|
|
final packs = await _db.packDao.getPacksForCard(cardId);
|
|||
|
|
return await Future.wait(packs.map((p) => p.toModel()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Добавить карточку в пак
|
|||
|
|
Future<void> addCardToPack({
|
|||
|
|
required String packId,
|
|||
|
|
required String cardId,
|
|||
|
|
int order = 0,
|
|||
|
|
}) async {
|
|||
|
|
await _db.packDao.addCardToPack(
|
|||
|
|
packId: packId,
|
|||
|
|
cardId: cardId,
|
|||
|
|
order: order,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Удалить карточку из пака
|
|||
|
|
Future<void> removeCardFromPack(String packId, String cardId) async {
|
|||
|
|
await _db.packDao.removeCardFromPack(packId, cardId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Обновить порядок карточек в паке
|
|||
|
|
Future<void> updatePackCardsOrder(String packId, List<String> cardIds) async {
|
|||
|
|
await _db.packDao.updatePackCardsOrder(packId, cardIds);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Установить preview карточки для пака
|
|||
|
|
Future<void> setPreviewCards(String packId, List<String> cardIds) async {
|
|||
|
|
await _db.packDao.setPreviewCards(packId, cardIds);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== VoiceModels ====================
|
|||
|
|
|
|||
|
|
/// Получить голосовые модели карточки
|
|||
|
|
Future<List<VoiceModel>> getCardVoices(String cardId) async {
|
|||
|
|
return await _db.packDao.getCardVoices(cardId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получить голосовую модель по ID
|
|||
|
|
Future<VoiceModel?> getVoiceById(String id) async {
|
|||
|
|
return await _db.packDao.getVoiceById(id);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Обновить путь/URL аудиофайла голосовой модели
|
|||
|
|
Future<void> updateVoiceUrl(String voiceId, String voiceUrl) async {
|
|||
|
|
await _db.packDao.updateVoiceUrl(voiceId, voiceUrl);
|
|||
|
|
}
|
|||
|
|
}
|