chore: Halkyon Learn moves into apps/learn

Its server, client, app and curator, and the tools that write its
assets (maps, Anki fixtures, icons), as they are; paths are fixed in
the commits that follow.

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-19 20:08:06 +02:00
commit 649499be23
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,130 @@
import 'package:flutter_test/flutter_test.dart';
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/settings/data/settings_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/study/bloc/study_settings_bloc.dart';
import 'package:halkyon_learn_flutter/src/feature/study/model/study_options.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart';
import '../../../support/fake_card_gateway.dart';
import '../../../support/fake_settings_gateway.dart';
import '../../../support/fake_studyset_gateway.dart';
import '../../../support/fake_tag_gateway.dart';
void main() {
late StudysetRepository studysets;
late CardRepository cards;
late TagRepository tags;
late SettingsRepository settings;
late StudySettingsBloc bloc;
CardContent card(String front) =>
CardContent(front: RichContent.empty(), back: RichContent.empty());
setUp(() async {
studysets = StudysetRepository(
FakeStudysetGateway()
..receiveRemoteChange(
'japanese',
encodeStudysetPayload(StudysetContent.titled('Japanese')),
)
..receiveRemoteChange(
'kanji',
encodeStudysetPayload(StudysetContent.titled('Kanji')),
parentId: 'japanese',
)
..receiveRemoteChange(
'german',
encodeStudysetPayload(StudysetContent.titled('German')),
),
);
cards = CardRepository(FakeCardGateway());
tags = TagRepository(FakeTagGateway());
settings = SettingsRepository(FakeSettingsGateway());
final neko = await cards.create('japanese', card('猫'));
final kanji = await cards.create('kanji', card('日'));
final hund = await cards.create('german', card('Hund'));
await tags.setTagsOf(neko, {await tags.create('noun')});
await tags.setTagsOf(kanji, {await tags.create('kanji')});
await tags.setTagsOf(hund, {await tags.create('german noun')});
await tags.create('unused');
bloc = StudySettingsBloc(studysets, cards, tags, settings, 'japanese')
..add(const StudySettingsEventStarted());
});
tearDown(() async {
await bloc.close();
await studysets.dispose();
await cards.dispose();
await tags.dispose();
await settings.dispose();
});
Future<StudySettingsStateLoaded> loaded() async =>
await bloc.stream.firstWhere((s) => s is StudySettingsStateLoaded)
as StudySettingsStateLoaded;
test('offers the tags the studied cards have, those inside included, '
'none chosen at first', () async {
final state = await loaded();
expect(state.tags.map((tag) => tag.name), ['kanji', 'noun']);
expect(state.chosen, isEmpty);
expect(state.canSave, isFalse);
});
test('saves the tags chosen into the settings, by id and name', () async {
final noun = (await loaded()).tags.last;
bloc
..add(StudySettingsEventTagToggled(noun.id))
..add(const StudySettingsEventSaveRequested());
await bloc.stream.firstWhere(
(s) => s is StudySettingsStateLoaded && s.isDone,
);
expect((await settings.read()).studyTagsOf('japanese'), [noun.ref]);
});
test('a reset chooses none, and saving that studies every card '
'again', () async {
final noun = (await loaded()).tags.last;
await settings.update((s) => s.withStudyTags('japanese', [noun.ref]));
await bloc.close();
bloc = StudySettingsBloc(studysets, cards, tags, settings, 'japanese')
..add(const StudySettingsEventStarted());
expect((await loaded()).chosen, {noun.id});
bloc
..add(const StudySettingsEventResetRequested())
..add(const StudySettingsEventSaveRequested());
await bloc.stream.firstWhere(
(s) => s is StudySettingsStateLoaded && s.isDone,
);
expect((await settings.read()).studyTags, isEmpty);
});
test('saves the study options chosen, with the tags', () async {
await loaded();
bloc
..add(
const StudySettingsEventOptionsChanged(
StudyOptions(mode: LearnMode.cram, cardsPerRound: 10),
),
)
..add(const StudySettingsEventSaveRequested());
await bloc.stream.firstWhere(
(s) => s is StudySettingsStateLoaded && s.isDone,
);
expect(
(await settings.read()).study,
const StudyOptions(mode: LearnMode.cram, cardsPerRound: 10),
);
});
}