yokutango-mobile-reader/lib/components/flashcard.dart

191 lines
4.5 KiB
Dart

import 'dart:math';
import 'package:tangocard_reader/models/yokutango_entry.dart';
import 'package:flutter/material.dart';
class Flashcard extends StatelessWidget {
final YokutangoEntry? card;
final int? cardIndex;
final bool isLeftSide;
final bool languageFlipped;
final int amountOfCardsOnStack;
final double rotationAmount;
const Flashcard({
this.card,
this.cardIndex,
this.isLeftSide = false,
this.languageFlipped = false,
this.amountOfCardsOnStack = 10,
this.rotationAmount = pi / 18,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final stackItems = <Widget>[];
final rng = Random();
for (int i = 0; i < amountOfCardsOnStack; i++) {
stackItems.add(
makeBlankCard(
offset: (isLeftSide ? -1 : 1) * (amountOfCardsOnStack - i) * 2,
rotationOrigin: isLeftSide ? 0.9 : 0.1,
angle: rng.nextDouble() * rotationAmount - rotationAmount / 2,
),
);
}
Widget? content;
if (card != null) {
if (isLeftSide && !languageFlipped || !isLeftSide && languageFlipped) {
content = _NorwegianContent(card: card!);
} else {
content = _JapaneseContent(card: card!);
}
}
stackItems.add(_FlashCardPaper(
child: content,
cardIndex: cardIndex,
));
return Center(
child: SizedBox(
width: MediaQuery.of(context).size.width / 2 - 60,
child: Stack(
children: stackItems,
),
),
);
}
Widget makeBlankCard({
required double offset,
required double rotationOrigin,
required double angle,
}) =>
Transform.translate(
offset: Offset(
offset,
0,
),
child: Transform.rotate(
angle: angle,
alignment: FractionalOffset(
rotationOrigin,
0.5,
),
child: const _FlashCardPaper()),
);
}
class _FlashCardPaper extends StatelessWidget {
final Widget? child;
final int? cardIndex;
const _FlashCardPaper({
this.child,
this.cardIndex,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Widget? content;
if (child != null) {
content = Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(child: Container()),
child!,
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text((cardIndex != null) ? (cardIndex! + 1).toString() : "?")
],
),
),
],
);
}
return AspectRatio(
aspectRatio: 5 / 2,
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(),
),
child: content,
),
);
}
}
class _NorwegianContent extends StatelessWidget {
final YokutangoEntry card;
const _NorwegianContent({
required this.card,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
child: FittedBox(
fit: BoxFit.fitHeight,
child: DefaultTextStyle.merge(
style: const TextStyle(fontFamily: 'Heart Warming'),
child: Column(
children: card.norwegian.map((n) {
final text = (n.hints == null)
? n.word
: "${n.word} (${n.hints?.join(', ')})";
return Text(text);
}).toList(),
),
),
),
);
}
}
class _JapaneseContent extends StatelessWidget {
final YokutangoEntry card;
const _JapaneseContent({
required this.card,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Expanded(
flex: 3,
child: FittedBox(
fit: BoxFit.fitHeight,
child: DefaultTextStyle.merge(
style: const TextStyle(fontFamily: 'K Gothic'),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: card.japanese
.map((e) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(e.word),
const Divider(),
Text(e.romaji ?? ""),
]))
.toList(),
),
),
),
);
}
}