diff --git a/assets/yokutango b/assets/yokutango index 4609ea5..00f37fd 160000 --- a/assets/yokutango +++ b/assets/yokutango @@ -1 +1 @@ -Subproject commit 4609ea5453fdc77d504999958222318495215d72 +Subproject commit 00f37fddf6656c4cca07e1afd26d6ad431e8db94 diff --git a/lib/screens/practise/flashcard.dart b/lib/screens/practise/flashcard.dart index a6cf223..2636d33 100644 --- a/lib/screens/practise/flashcard.dart +++ b/lib/screens/practise/flashcard.dart @@ -1,17 +1,19 @@ - import 'package:tangocard_reader/components/flashcard.dart'; import 'package:flutter/material.dart'; import 'package:tangocard_reader/models/data_entry.dart'; +import 'package:tangocard_reader/screens/practise/navigation_buttons.dart'; class FlashcardPage extends StatefulWidget { final YokutangoEntry card; - final Function() onNextCard; + final void Function() onNextCard; + final void Function() onPreviousCard; final bool languageFlipped; final int? index; const FlashcardPage({ required this.card, required this.onNextCard, + required this.onPreviousCard, this.languageFlipped = false, this.index, Key? key, @@ -36,24 +38,46 @@ class _FlashcardPageState extends State { isPressed = !isPressed; }); }, - child: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flashcard( - card: widget.card, - cardIndex: widget.index, - isLeftSide: true, - languageFlipped: widget.languageFlipped, - ), - const SizedBox(width: 40), - Flashcard( - card: isPressed ? widget.card : null, - cardIndex: widget.index, - languageFlipped: widget.languageFlipped, - ), - ], - ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flashcard( + card: widget.card, + cardIndex: widget.index, + isLeftSide: true, + languageFlipped: widget.languageFlipped, + ), + const SizedBox(width: 40), + Flashcard( + card: isPressed ? widget.card : null, + cardIndex: widget.index, + languageFlipped: widget.languageFlipped, + ), + ], + ), + Row( + children: [ + const Expanded(child: SizedBox()), + NavigationButtons( + middleText: + widget.index == null ? 'N' : (widget.index! + 1).toString(), + onNextCard: () => setState(() { + isPressed = false; + widget.onNextCard(); + }), + onPreviousCard: () => setState(() { + isPressed = false; + widget.onPreviousCard(); + }), + ), + const Expanded(child: SizedBox()), + ], + ) + ], ), ); } diff --git a/lib/screens/practise/kanji.dart b/lib/screens/practise/kanji.dart index 07b2925..632f5f5 100644 --- a/lib/screens/practise/kanji.dart +++ b/lib/screens/practise/kanji.dart @@ -1,15 +1,22 @@ import 'package:flutter/material.dart'; import '../../models/data_entry.dart'; +import 'navigation_buttons.dart'; class KanjiPage extends StatefulWidget { final KanjiEntry entry; final Function() onNextCard; + final Function() onPreviousCard; + final bool showDrawingPanel; + final bool showStrokeOrder; final int? index; const KanjiPage({ required this.entry, required this.onNextCard, + required this.onPreviousCard, + this.showDrawingPanel = false, + this.showStrokeOrder = false, this.index, Key? key, }) : super(key: key); @@ -24,19 +31,49 @@ class _KanjiPageState extends State { @override Widget build(BuildContext context) { return GestureDetector( + behavior: HitTestBehavior.opaque, onTap: () { if (isPressed) widget.onNextCard(); setState(() => isPressed = !isPressed); }, - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(widget.entry.kanji), - const SizedBox(width: 40), - Text(widget.entry.kana.toString()), - ], - ), + child: Stack( + alignment: Alignment.center, + fit: StackFit.expand, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + widget.entry.kana.join('\n'), + style: Theme.of(context).textTheme.headline3, + ), + const SizedBox(width: 20), + const Divider(thickness: 5), + if (isPressed) ...[ + const SizedBox(width: 20), + Text( + widget.entry.kanji, + style: Theme.of(context).textTheme.headline1, + ), + ], + ], + ), + Positioned( + bottom: 40, + child: NavigationButtons( + middleText: + widget.index == null ? 'N' : (widget.index! + 1).toString(), + onNextCard: () => setState(() { + isPressed = false; + widget.onNextCard(); + }), + onPreviousCard: () => setState(() { + isPressed = false; + widget.onPreviousCard(); + }), + ), + ) + ], ), ); } diff --git a/lib/screens/practise/navigation_buttons.dart b/lib/screens/practise/navigation_buttons.dart new file mode 100644 index 0000000..df27dfa --- /dev/null +++ b/lib/screens/practise/navigation_buttons.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +class NavigationButtons extends StatelessWidget { + final String middleText; + final void Function() onNextCard; + final void Function() onPreviousCard; + + const NavigationButtons({ + Key? key, + required this.middleText, + required this.onNextCard, + required this.onPreviousCard, + }) : super(key: key); + + @override + Widget build(BuildContext context) => + Container( + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(10), + ), + child: ButtonBar( + alignment: MainAxisAlignment.center, + children: [ + IconButton( + padding: const EdgeInsets.all(20), + color: Colors.white, + onPressed: onPreviousCard, + icon: const Icon(Icons.arrow_back), + ), + const SizedBox(width: 10), + Text( + middleText, + style: Theme.of(context) + .textTheme + .headline6! + .merge(const TextStyle(color: Colors.white)), + ), + const SizedBox(width: 10), + IconButton( + padding: const EdgeInsets.all(20), + color: Colors.white, + onPressed: onNextCard, + icon: const Icon(Icons.arrow_forward), + ), + ], + ), + ); +} diff --git a/lib/screens/practise/practise.dart b/lib/screens/practise/practise.dart index cbd7b4c..5802f77 100644 --- a/lib/screens/practise/practise.dart +++ b/lib/screens/practise/practise.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:tangocard_reader/models/data_entry.dart'; +import 'package:tangocard_reader/screens/practise/kanji.dart'; import 'flashcard.dart'; @@ -26,80 +27,142 @@ const encouragingWords = [ '頑張れ〜!', 'できるぞ!', 'ヨッシャー!', - 'いけいけいけー!', + 'いけいけー!', ]; class _PractiseViewState extends State { - String title = ''; late int currentCard; - final List _isSelected = [false, false]; + final List _flashcardToggles = [false, false]; + final List _kanjiToggles = [false, false]; - get isShuffleMode => _isSelected[0]; - get isLanguageSwitchedMode => _isSelected[1]; - get randomCard => Random().nextInt(widget.entries.length); + bool get isShuffleMode => _flashcardToggles[0]; + bool get isLanguageSwitchedMode => _flashcardToggles[1]; + bool get isKanjiDrawingMode => _kanjiToggles[0]; + bool get isKanjiAnimationMode => _kanjiToggles[1]; + + int get randomCard => Random().nextInt(widget.entries.length); + String get randomEncouragingWord => + encouragingWords[Random().nextInt(encouragingWords.length)]; + bool get isPhone => + MediaQueryData.fromWindow(WidgetsBinding.instance!.window) + .size + .shortestSide < + 600; @override void initState() { - title = encouragingWords[Random().nextInt(encouragingWords.length)]; currentCard = widget.index; - final isPhone = MediaQueryData.fromWindow(WidgetsBinding.instance!.window) - .size - .shortestSide < - 600; if (isPhone) { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.landscapeLeft, - DeviceOrientation.landscapeRight, - ]); + if (widget.isKanji) { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + } else { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); + } } super.initState(); } @override - Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: Row( - children: [ - Expanded(child: Container()), - Text(title), - Expanded(child: Container()), - IconButton( - onPressed: () => setState(() { - currentCard = 0; - }), - icon: const Icon(Icons.repeat), - ), - ToggleButtons( - children: const [ - Icon(Icons.shuffle), - Icon(Icons.translate), - ], - isSelected: _isSelected, - onPressed: (int index) { - setState(() { - _isSelected[index] = !_isSelected[index]; - }); - }) - ], - ), - centerTitle: true, + void dispose() { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.landscapeRight, + DeviceOrientation.landscapeLeft, + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + super.dispose(); + } + + AppBar get flashcardAppBar => AppBar( + title: Row( + children: [ + Expanded(child: Container()), + Text(randomEncouragingWord), + Expanded(child: Container()), + IconButton( + onPressed: () => setState(() => currentCard = 0), + icon: const Icon(Icons.repeat), + ), + ToggleButtons( + selectedColor: Colors.white, + children: const [ + Icon(Icons.shuffle), + Icon(Icons.translate), + ], + isSelected: _flashcardToggles, + onPressed: (int index) => + setState(() => _flashcardToggles[index] = !_flashcardToggles[index])), + ], ), + centerTitle: true, + ); + + AppBar get kanjiAppBar => AppBar( + title: Row( + children: [ + Expanded(child: Container()), + Text(randomEncouragingWord), + Expanded(child: Container()), + IconButton( + onPressed: () => setState(() => currentCard = 0), + icon: const Icon(Icons.repeat), + ), + ToggleButtons( + selectedColor: Colors.white, + children: const [ + Icon(Icons.edit), + Icon(Icons.animation), + ], + isSelected: _flashcardToggles, + onPressed: (int index) => + setState(() => _flashcardToggles[index] = !_flashcardToggles[index])), + ], + ), + centerTitle: true, + ); + + @override + Widget build(BuildContext context) => Scaffold( + appBar: widget.isKanji ? kanjiAppBar : flashcardAppBar, body: widget.isKanji - ? Container() + ? KanjiPage( + entry: widget.entries[currentCard] as KanjiEntry, + index: currentCard, + showDrawingPanel: isKanjiDrawingMode, + showStrokeOrder: isKanjiAnimationMode, + onNextCard: () => setState(() { + currentCard = isShuffleMode ? randomCard : currentCard + 1; + if (currentCard == widget.entries.length) currentCard = 0; + }), + onPreviousCard: () => setState(() { + currentCard = isShuffleMode ? randomCard : currentCard - 1; + if (currentCard == -1) { + currentCard = widget.entries.length - 1; + } + }), + ) : FlashcardPage( card: widget.entries[currentCard] as YokutangoEntry, index: currentCard, languageFlipped: isLanguageSwitchedMode, - onNextCard: () { - setState(() { - currentCard = isShuffleMode ? randomCard : currentCard + 1; - if (currentCard == widget.entries.length) currentCard = 0; - title = encouragingWords[ - Random().nextInt(encouragingWords.length)]; - }); - }, + onNextCard: () => setState(() { + currentCard = isShuffleMode ? randomCard : currentCard + 1; + if (currentCard == widget.entries.length) currentCard = 0; + }), + onPreviousCard: () => setState(() { + currentCard = isShuffleMode ? randomCard : currentCard - 1; + if (currentCard == -1) { + currentCard = widget.entries.length - 1; + } + }), ), ); }