feat(app): reset a studyset's progress, with an undo

The studyset's options offer Reset progress: after asking, every card
in it and in the studysets inside it starts afresh as new (a 'reset'
entry each), its history kept; an undo for a few seconds deletes those
entries again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-01 19:34:44 +02:00
commit f922fceb47
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -3,6 +3,7 @@ import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
import 'package:halkyon_learn_flutter/src/feature/study/data/review_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/study/model/rating.dart';
import 'package:halkyon_learn_flutter/src/feature/study/model/study_progress.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/bloc/studyset_list_bloc.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_deletions.dart';
@ -21,6 +22,7 @@ void main() {
late FakeCardGateway cardGateway;
late CardRepository cards;
late StudysetDeletions deletions;
late ReviewRepository reviews;
late StudysetListBloc bloc;
setUp(() {
@ -28,6 +30,7 @@ void main() {
studysets = StudysetRepository(gateway);
cardGateway = FakeCardGateway();
cards = CardRepository(cardGateway);
reviews = ReviewRepository(FakeReviewGateway());
});
tearDown(() async {
await bloc.close();
@ -45,7 +48,7 @@ void main() {
bloc = StudysetListBloc(
studysets,
cards,
ReviewRepository(FakeReviewGateway()),
reviews,
deletions,
parentId: parentId,
)..add(const StudysetListEventStarted());
@ -337,4 +340,33 @@ void main() {
await listing(['Kanji', 'Kana']);
});
});
test('resetting starts the progress of a studyset and what is inside it '
'afresh; an undo takes it back', () async {
final japanese = await studysets.create(StudysetContent.titled('Japanese'));
final kanji = await studysets.create(
StudysetContent.titled('Kanji'),
parentId: japanese,
);
for (final studyset in [japanese, kanji]) {
final id = await cards.create(studyset, newCard());
await reviews.record(
cardId: id,
rating: Rating.easy,
reviewedAt: DateTime.now().toUtc(),
duration: Duration.zero,
);
}
start();
Future<int> dueIn(String id) async => (await bloc.stream.firstWhere(
(s) => s is StudysetListStateLoaded && s.progress.containsKey(id),
) as StudysetListStateLoaded).progress[id]!.due;
await listing(['Japanese']);
bloc.add(StudysetListEventResetRequested(japanese));
expect(await dueIn(japanese), 2);
bloc.add(const StudysetListEventResetUndone());
expect(await dueIn(japanese), 0);
});
}