feat(app): card tiles: the front, the tags, the options

A studyset's cards list as bordered rows of one height showing the
front, the card's tags above it and a badge when devices changed it
differently; tapping opens the composer, "…" offers editing and
deleting (after asking).

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 18:58:54 +02:00
commit 8cf7749ed6
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -4,6 +4,7 @@ import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.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/card/widget/card_tile.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
import 'package:material_ui/material_ui.dart' hide Card;
@ -87,7 +88,7 @@ void main() {
expect(find.text('No flashcards yet'), findsOneWidget);
});
testWidgets('lists the cards in order, front and back', (tester) async {
testWidgets('lists the cards in order, each by its front', (tester) async {
await cards.create('japanese', card('猫', 'cat'));
await cards.create('japanese', card('犬', 'dog'));
@ -97,7 +98,8 @@ void main() {
tester.getTopLeft(find.text('猫')).dy,
lessThan(tester.getTopLeft(find.text('犬')).dy),
);
expect(find.text('dog'), findsOneWidget);
// The back stays for the composer and studying.
expect(find.text('dog'), findsNothing);
});
testWidgets('marks a card changed on two devices', (tester) async {
@ -105,6 +107,29 @@ void main() {
await showList(tester);
expect(find.byTooltip('Changed on two devices'), findsOneWidget);
expect(find.text('Changed on two devices'), findsOneWidget);
});
testWidgets("a card's options delete it, after asking", (tester) async {
final id = await cards.create('japanese', card('猫', 'cat'));
await showList(tester);
await tester.tap(
find.descendant(
of: find.byType(CardTile),
matching: find.byTooltip('Options'),
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('Delete'));
// A menu item acts once the menu has closed, a frame later.
await tester.pump();
await tester.pump();
await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(FilledButton, 'Delete'));
await tester.pumpAndSettle();
expect(gateway.deletions, ['blank $id', 'delete $id']);
expect(find.text('No flashcards yet'), findsOneWidget);
});
}