Merge pull request #618 from Whiskas101/fix/statistics-synchronous-load

fix: updated statistics to use async fetch from db
This commit is contained in:
Moustapha Kodjo Amadou 2025-12-05 10:19:01 +01:00 committed by GitHub
commit 0789f4c85a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 106 additions and 69 deletions

View file

@ -6,37 +6,68 @@ import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'statistics_provider.g.dart';
class StatisticsData {
final int totalItems;
final int totalChapters;
final int readChapters;
final int completedItems;
final int downloadedItems;
const StatisticsData({
required this.totalItems,
required this.totalChapters,
required this.readChapters,
required this.completedItems,
required this.downloadedItems,
});
}
@riverpod
class StatisticsState extends _$StatisticsState {
@override
void build(ItemType itemType) {}
final items = isar.mangas
.filter()
.idIsNotNull()
.favoriteEqualTo(true)
.findAllSync();
final chapters = isar.chapters
.filter()
.idIsNotNull()
.manga((q) => q.favoriteEqualTo(true))
.findAllSync();
int get totalItems => items.where((i) => i.itemType == itemType).length;
int get totalChapters =>
chapters.where((i) => i.manga.value!.itemType == itemType).length;
int get readChapters => chapters
.where((i) => i.manga.value!.itemType == itemType && (i.isRead ?? false))
.length;
int get completedItems => items
.where((i) => i.itemType == itemType && (i.status == Status.completed))
.where((e) => e.chapters.every((element) => element.isRead ?? false))
.length;
Future<StatisticsData> build(ItemType itemType) async {
final items = await isar.mangas
.filter()
.idIsNotNull()
.favoriteEqualTo(true)
.itemTypeEqualTo(itemType)
.findAll();
int get downloadedItems => isar.downloads
.filter()
.idIsNotNull()
.chapter((q) => q.manga((m) => m.itemTypeEqualTo(itemType)))
.chapter((q) => q.manga((m) => m.favoriteEqualTo(true)))
.isDownloadEqualTo(true)
.findAllSync()
.length;
final chapters = await isar.chapters
.filter()
.idIsNotNull()
.manga((q) => q.favoriteEqualTo(true).itemTypeEqualTo(itemType))
.findAll();
final downloadedCount = await isar.downloads
.filter()
.idIsNotNull()
.chapter((q) => q.manga((m) => m.itemTypeEqualTo(itemType)))
.chapter((q) => q.manga((m) => m.favoriteEqualTo(true)))
.isDownloadEqualTo(true)
.count();
final totalItems = items.length;
final totalChapters = chapters.length;
final readChapters = chapters.where((c) => c.isRead ?? false).length;
int completedItems = 0;
for (var item in items) {
if (item.status == Status.completed) {
final itemChapters = item.chapters.toList();
if (itemChapters.isNotEmpty &&
itemChapters.every((element) => element.isRead ?? false)) {
completedItems++;
}
}
}
return StatisticsData(
totalItems: totalItems,
totalChapters: totalChapters,
readChapters: readChapters,
completedItems: completedItems,
downloadedItems: downloadedCount,
);
}
}

View file

@ -75,7 +75,8 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
Widget _buildStatisticsTab({required ItemType itemType}) {
final l10n = context.l10n;
final stats = ref.watch(statisticsStateProvider(itemType).notifier);
// final stats = ref.watch(statisticsStateProvider(itemType).notifier);
final stats = ref.watch(statisticsStateProvider(itemType));
final title = switch (itemType) {
ItemType.manga => l10n.manga,
@ -94,47 +95,52 @@ class _StatisticsScreenState extends ConsumerState<StatisticsScreen>
_ => l10n.unread,
};
final totalItems = stats.totalItems;
final totalChapters = stats.totalChapters;
final readChapters = stats.readChapters;
final unreadChapters = totalChapters - readChapters;
final completedItems = stats.completedItems;
final downloadedItems = stats.downloadedItems;
return stats.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, stack) => Center(child: Text("Err: $err")),
data: (stats) {
final totalItems = stats.totalItems;
final totalChapters = stats.totalChapters;
final readChapters = stats.readChapters;
final unreadChapters = totalChapters - readChapters;
final completedItems = stats.completedItems;
final downloadedItems = stats.downloadedItems;
final averageChapters = totalItems > 0 ? totalChapters / totalItems : 0;
final readPercentage = totalChapters > 0
? (readChapters / totalChapters) * 100
: 0;
final completedPercentage = totalItems > 0
? (completedItems / totalItems) * 100
: 0;
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildSectionHeader('Entries'),
_buildEntriesCard(
totalItems: totalItems,
completedItems: completedItems,
completedPercentage: completedPercentage.toDouble(),
final averageChapters = totalItems > 0 ? totalChapters / totalItems : 0;
final readPercentage = totalChapters > 0
? (readChapters / totalChapters) * 100
: 0;
final completedPercentage = totalItems > 0
? (completedItems / totalItems) * 100
: 0;
return SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildSectionHeader('Entries'),
_buildEntriesCard(
totalItems: totalItems,
completedItems: completedItems,
completedPercentage: completedPercentage.toDouble(),
),
const SizedBox(height: 10),
_buildSectionHeader(chapterLabel),
_buildChaptersCard(
totalChapters: totalChapters,
readChapters: readChapters,
unreadChapters: unreadChapters,
downloadedItems: downloadedItems,
averageChapters: averageChapters.toDouble(),
readPercentage: readPercentage.toDouble(),
title: title,
context: context,
unreadLabel: unreadLabel,
),
],
),
const SizedBox(height: 10),
_buildSectionHeader(chapterLabel),
_buildChaptersCard(
totalChapters: totalChapters,
readChapters: readChapters,
unreadChapters: unreadChapters,
downloadedItems: downloadedItems,
averageChapters: averageChapters.toDouble(),
readPercentage: readPercentage.toDouble(),
title: title,
context: context,
unreadLabel: unreadLabel,
),
],
),
);
},
);
}