Add themes and drawing field for kanji

This commit is contained in:
Oystein Kristoffer Tveit 2022-02-04 04:22:35 +01:00
parent 4a98522973
commit fef9733ad7
10 changed files with 365 additions and 40 deletions

View File

@ -104,7 +104,10 @@ class _FlashCardPaper extends StatelessWidget {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text((cardIndex != null) ? (cardIndex! + 1).toString() : "?") Text(
(cardIndex != null) ? (cardIndex! + 1).toString() : "?",
style: const TextStyle(color: Colors.black),
)
], ],
), ),
), ),
@ -140,13 +143,19 @@ class _NorwegianContent extends StatelessWidget {
child: FittedBox( child: FittedBox(
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
child: DefaultTextStyle.merge( child: DefaultTextStyle.merge(
style: const TextStyle(fontFamily: 'Heart Warming'), style: const TextStyle(
fontFamily: 'Heart Warming',
color: Colors.black,
),
child: Column( child: Column(
children: card.norwegian.map((n) { children: card.norwegian.map((n) {
final text = (n.hints == null) final text = (n.hints == null)
? n.word ? n.word
: "${n.word} (${n.hints?.join(', ')})"; : "${n.word} (${n.hints?.join(', ')})";
return Text(text); return Text(
text,
style: const TextStyle(color: Colors.black),
);
}).toList(), }).toList(),
), ),
), ),
@ -170,7 +179,10 @@ class _JapaneseContent extends StatelessWidget {
child: FittedBox( child: FittedBox(
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
child: DefaultTextStyle.merge( child: DefaultTextStyle.merge(
style: const TextStyle(fontFamily: 'K Gothic'), style: const TextStyle(
fontFamily: 'K Gothic',
color: Colors.black,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: card.japanese children: card.japanese

View File

@ -4,12 +4,14 @@ class NavigationButtons extends StatelessWidget {
final String middleText; final String middleText;
final void Function() onNextCard; final void Function() onNextCard;
final void Function() onPreviousCard; final void Function() onPreviousCard;
final void Function()? onMiddlePressed;
const NavigationButtons({ const NavigationButtons({
Key? key, Key? key,
required this.middleText, required this.middleText,
required this.onNextCard, required this.onNextCard,
required this.onPreviousCard, required this.onPreviousCard,
this.onMiddlePressed,
}) : super(key: key); }) : super(key: key);
@override @override
@ -29,13 +31,19 @@ class NavigationButtons extends StatelessWidget {
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Text( InkWell(
onTap: onMiddlePressed,
child: Padding(
padding: const EdgeInsets.all(10),
child: Text(
middleText, middleText,
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.headline6! .headline6!
.merge(const TextStyle(color: Colors.white)), .merge(const TextStyle(color: Colors.white)),
), ),
),
),
const SizedBox(width: 10), const SizedBox(width: 10),
IconButton( IconButton(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),

View File

@ -1,21 +1,41 @@
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tangocard_reader/router.dart'; import 'package:tangocard_reader/router.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
void main() => runApp(const MyApp()); import 'service/theme_bloc.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
runApp(MyApp(prefs: prefs));
}
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key); final SharedPreferences prefs;
const MyApp({
Key? key,
required this.prefs,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => BlocProvider(
return MaterialApp( create: (context) => ThemeBloc(
prefs: prefs,
init: (prefs.getBool('darkTheme') ?? false)
? Brightness.dark
: Brightness.light),
child: BlocBuilder<ThemeBloc, Brightness>(
builder: (context, state) => MaterialApp(
title: 'Tangocard Reader', title: 'Tangocard Reader',
theme: ThemeData( theme: ThemeData(
fontFamily: 'Noto Sans CJK', fontFamily: 'Noto Sans CJK',
primarySwatch: Colors.blue, primarySwatch: Colors.blue,
brightness: state,
), ),
initialRoute: '/', initialRoute: '/',
onGenerateRoute: PageRouter.generateRoute, onGenerateRoute: PageRouter.generateRoute,
),
),
); );
} }
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tangocard_reader/service/tangocard_files.dart'; import 'package:tangocard_reader/service/tangocard_files.dart';
import 'package:tangocard_reader/service/theme_bloc.dart';
import 'pages/tango_set_list.dart'; import 'pages/tango_set_list.dart';
@ -14,14 +15,31 @@ class _HomeState extends State<Home> {
int page = 0; int page = 0;
final _pages = [ final _pages = [
TangoSetList(files: tangocardFilePaths, route: '/list/tango',), TangoSetList(
TangoSetList(files: kanjicardFilePaths, route: '/list/kanji',), files: tangocardFilePaths,
route: '/list/tango',
),
TangoSetList(
files: kanjicardFilePaths,
route: '/list/kanji',
),
]; ];
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("よく単語"), title: const Text("よく単語"),
actions: [
BlocBuilder<ThemeBloc, Brightness>(
builder: (context, state) {
return Switch(
value: state == Brightness.dark,
onChanged: (b) => BlocProvider.of<ThemeBloc>(context)
.add(SetTheme(state != Brightness.dark)),
);
},
)
],
centerTitle: true, centerTitle: true,
), ),
body: _pages[page], body: _pages[page],
@ -29,8 +47,8 @@ class _HomeState extends State<Home> {
onTap: (int index) => setState(() => page = index), onTap: (int index) => setState(() => page = index),
currentIndex: page, currentIndex: page,
items: const [ items: const [
BottomNavigationBarItem(label: 'Tango', icon: Icon(Icons.style)), BottomNavigationBarItem(label: '単語', icon: Icon(Icons.style)),
BottomNavigationBarItem(label: 'Kanji', icon: Text('漢字')), BottomNavigationBarItem(label: '漢字', icon: Icon(Icons.translate)),
], ],
), ),
); );

View File

@ -1,7 +1,7 @@
import 'package:tangocard_reader/components/flashcard.dart'; import 'package:tangocard_reader/components/flashcard.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tangocard_reader/models/data_entry.dart'; import 'package:tangocard_reader/models/data_entry.dart';
import 'package:tangocard_reader/screens/practise/navigation_buttons.dart'; import 'package:tangocard_reader/components/navigation_buttons.dart';
class FlashcardPage extends StatefulWidget { class FlashcardPage extends StatefulWidget {
final YokutangoEntry card; final YokutangoEntry card;

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:signature/signature.dart';
import '../../models/data_entry.dart'; import '../../models/data_entry.dart';
import 'navigation_buttons.dart'; import '../../components/navigation_buttons.dart';
class KanjiPage extends StatefulWidget { class KanjiPage extends StatefulWidget {
final KanjiEntry entry; final KanjiEntry entry;
@ -27,19 +28,33 @@ class KanjiPage extends StatefulWidget {
class _KanjiPageState extends State<KanjiPage> { class _KanjiPageState extends State<KanjiPage> {
bool isPressed = false; bool isPressed = false;
late final controller = SignatureController(
penColor: Theme.of(context).textTheme.bodyText1?.color ?? Colors.black,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
if (isPressed) widget.onNextCard(); if (widget.showDrawingPanel) return;
if (isPressed) {
controller.clear();
widget.onNextCard();
}
setState(() => isPressed = !isPressed); setState(() => isPressed = !isPressed);
}, },
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
if (widget.showDrawingPanel) ...[
const SizedBox(width: 20),
Signature(
controller: controller,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
)
],
Column( Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -49,13 +64,18 @@ class _KanjiPageState extends State<KanjiPage> {
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
const Divider(thickness: 5), const Divider(thickness: 5),
if (isPressed) ...[
const SizedBox(width: 20), const SizedBox(width: 20),
Text( Text(
widget.entry.kanji, widget.entry.kanji,
style: Theme.of(context).textTheme.headline1, style: isPressed
? Theme.of(context).textTheme.headline1
: Theme.of(context)
.textTheme
.headline1
?.merge(const TextStyle(color: Colors.transparent)),
), ),
], const SizedBox(width: 20),
const Divider(thickness: 5),
], ],
), ),
Positioned( Positioned(
@ -63,11 +83,20 @@ class _KanjiPageState extends State<KanjiPage> {
child: NavigationButtons( child: NavigationButtons(
middleText: middleText:
widget.index == null ? 'N' : (widget.index! + 1).toString(), widget.index == null ? 'N' : (widget.index! + 1).toString(),
onMiddlePressed: () {
if (isPressed) {
controller.clear();
widget.onNextCard();
}
setState(() => isPressed = !isPressed);
},
onNextCard: () => setState(() { onNextCard: () => setState(() {
controller.clear();
isPressed = false; isPressed = false;
widget.onNextCard(); widget.onNextCard();
}), }),
onPreviousCard: () => setState(() { onPreviousCard: () => setState(() {
controller.clear();
isPressed = false; isPressed = false;
widget.onPreviousCard(); widget.onPreviousCard();
}), }),

View File

@ -121,9 +121,9 @@ class _PractiseViewState extends State<PractiseView> {
Icon(Icons.edit), Icon(Icons.edit),
Icon(Icons.animation), Icon(Icons.animation),
], ],
isSelected: _flashcardToggles, isSelected: _kanjiToggles,
onPressed: (int index) => onPressed: (int index) =>
setState(() => _flashcardToggles[index] = !_flashcardToggles[index])), setState(() => _kanjiToggles[index] = !_kanjiToggles[index])),
], ],
), ),
centerTitle: true, centerTitle: true,

View File

@ -0,0 +1,26 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:shared_preferences/shared_preferences.dart';
export 'package:flutter_bloc/flutter_bloc.dart';
@immutable
class SetTheme {
final bool isDark;
const SetTheme(this.isDark);
}
class ThemeBloc extends Bloc<SetTheme, Brightness> {
final SharedPreferences prefs;
ThemeBloc({
required this.prefs,
required Brightness init,
}) : super(init) {
on<SetTheme>((event, emit) {
prefs.setBool('darkTheme', event.isDark);
emit(event.isDark ? Brightness.dark : Brightness.light);
});
}
}

View File

@ -1,6 +1,13 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.11"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -8,6 +15,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.8.2" version: "2.8.2"
bloc:
dependency: transitive
description:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.2"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -43,6 +57,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0" version: "1.15.0"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -50,11 +71,32 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.1"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -67,6 +109,25 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -88,6 +149,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.7.0" version: "1.7.0"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -95,6 +163,125 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0" version: "1.8.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.4"
provider:
dependency: transitive
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.2"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.12"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
signature:
dependency: "direct main"
description:
name: signature
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -156,5 +343,27 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.10"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "5.3.1"
sdks: sdks:
dart: ">=2.14.0 <3.0.0" dart: ">=2.15.0 <3.0.0"
flutter: ">=2.5.0"

View File

@ -29,6 +29,9 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_bloc: ^8.0.1
shared_preferences: ^2.0.12
signature: ^5.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: