Compare commits

...

10 Commits

29 changed files with 1246 additions and 346 deletions

View File

@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 30
compileSdkVersion 33
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@ -43,8 +43,8 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.tangocard_reader"
minSdkVersion 16
applicationId "xyz.h7x4.tangocard_reader"
minSdkVersion 26
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

View File

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tangocard_reader">
<application
android:label="tangocard_reader"
android:label="Tangocard Reader"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"

View File

@ -24,6 +24,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip

Binary file not shown.

@ -1 +1 @@
Subproject commit d8964efd9524859f97b416c97f9d7f1c6d809ae4
Subproject commit 00f37fddf6656c4cca07e1afd26d6ad431e8db94

View File

@ -1,7 +1,7 @@
import 'dart:math';
import 'package:tangocard_reader/models/yokutango_entry.dart';
import 'package:flutter/material.dart';
import 'package:tangocard_reader/models/data_entry.dart';
class Flashcard extends StatelessWidget {
final YokutangoEntry? card;
@ -104,7 +104,10 @@ class _FlashCardPaper extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
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(
fit: BoxFit.fitHeight,
child: DefaultTextStyle.merge(
style: const TextStyle(fontFamily: 'Heart Warming'),
style: const TextStyle(
fontFamily: 'Heart Warming',
color: Colors.black,
),
child: Column(
children: card.norwegian.map((n) {
final text = (n.hints == null)
? n.word
: "${n.word} (${n.hints?.join(', ')})";
return Text(text);
return Text(
text,
style: const TextStyle(color: Colors.black),
);
}).toList(),
),
),
@ -170,7 +179,10 @@ class _JapaneseContent extends StatelessWidget {
child: FittedBox(
fit: BoxFit.fitHeight,
child: DefaultTextStyle.merge(
style: const TextStyle(fontFamily: 'K Gothic'),
style: const TextStyle(
fontFamily: 'K Gothic',
color: Colors.black,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: card.japanese

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
class NavigationButtons extends StatelessWidget {
final String middleText;
final void Function() onNextCard;
final void Function() onPreviousCard;
final void Function()? onMiddlePressed;
const NavigationButtons({
Key? key,
required this.middleText,
required this.onNextCard,
required this.onPreviousCard,
this.onMiddlePressed,
}) : 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),
InkWell(
onTap: onMiddlePressed,
child: Padding(
padding: const EdgeInsets.all(10),
child: 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),
),
],
),
);
}

View File

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

View File

@ -0,0 +1,6 @@
part 'yokutango_entry.dart';
part 'kanji_entry.dart';
abstract class DataEntry {
const DataEntry();
}

View File

@ -0,0 +1,53 @@
part of 'data_entry.dart';
class KanjiEntry extends DataEntry {
final String kanji;
final List<WordConstruct> kana;
KanjiEntry.fromJson(Map<String, dynamic> json)
: kanji = json['kanji'] as String,
kana = [
for (final j in json['kana'] as List) WordConstruct.fromJson(j)
];
@override
String toString() {
return '$kanji - ${kana.join('')}';
}
}
class WordConstruct {
final List<WordPiece> pieces;
WordConstruct({required this.pieces});
WordConstruct.fromJson(dynamic json)
: pieces = (json is String)
? [WordPiece(word: json, isActive: true)]
: [for (final j in json as List) WordPiece.fromJson(j)];
@override
String toString() {
return pieces.map((p) => p.isActive ? p.word : '(${p.word})').join('');
}
}
class WordPiece {
final String? kana;
final String? romaji;
final String word;
final bool isActive;
const WordPiece({
required this.word,
this.kana,
this.romaji,
this.isActive = false,
});
WordPiece.fromJson(Map<String, dynamic> json)
: kana = json['kana'] as String?,
romaji = json['romaji'] as String?,
word = json['text'] as String,
isActive = json['active'] as bool? ?? false;
}

View File

@ -1,7 +1,7 @@
import 'package:tangocard_reader/models/yokutango_entry.dart';
import 'data_entry.dart';
class BenkyouArgs {
final List<YokutangoEntry> cards;
final List<DataEntry> cards;
final int? index;
const BenkyouArgs({required this.cards, this.index});

View File

@ -1,4 +1,6 @@
class YokutangoEntry {
part of 'data_entry.dart';
class YokutangoEntry extends DataEntry {
final List<JapaneseWord> japanese;
final List<NorwegianWord> norwegian;

View File

@ -1,10 +1,13 @@
import 'dart:io';
import 'package:tangocard_reader/models/data_entry.dart';
import 'package:tangocard_reader/models/router_args.dart';
import 'package:tangocard_reader/screens/flashcard.dart';
import 'package:tangocard_reader/screens/home.dart';
import 'package:tangocard_reader/screens/tango_list.dart';
import 'package:tangocard_reader/screens/pages/tango_list.dart';
import 'package:flutter/material.dart';
import 'package:tangocard_reader/screens/practise/practise.dart';
import 'screens/pages/kanji_list.dart';
class PageRouter {
static Route<dynamic> generateRoute(RouteSettings settings) {
@ -14,22 +17,41 @@ class PageRouter {
case '/':
return MaterialPageRoute(builder: (_) => const Home());
case '/tangolist':
case '/list/tango':
final file = args as File;
return MaterialPageRoute(builder: (_) => TangoList(file: file));
case '/benkyou':
case '/list/kanji':
final file = args as File;
return MaterialPageRoute(builder: (_) => KanjiList(file: file));
case '/benkyou/tango':
final benkyouArgs = args as BenkyouArgs;
return MaterialPageRoute(
builder: (_) => FlashcardView(
cards: benkyouArgs.cards,
index: benkyouArgs.index,
builder: (_) => PractiseView(
entries: benkyouArgs.cards as List<YokutangoEntry>,
index: benkyouArgs.index ?? 0,
isKanji: false,
),
);
case '/benkyou/kanji':
final benkyouArgs = args as BenkyouArgs;
return MaterialPageRoute(
builder: (_) => PractiseView(
entries: benkyouArgs.cards as List<KanjiEntry>,
index: benkyouArgs.index ?? 0,
isKanji: true,
),
);
default:
return MaterialPageRoute(
builder: (_) => const Text("ERROR: this route does not exist"));
builder: (_) => Scaffold(
appBar: AppBar(title: const Text('Error')),
body: Center(child: ErrorWidget('No such route...')),
),
);
}
}
}

View File

@ -1,168 +0,0 @@
import 'dart:math';
import 'package:tangocard_reader/components/flashcard.dart';
import 'package:tangocard_reader/models/yokutango_entry.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FlashcardView extends StatefulWidget {
final List<YokutangoEntry> cards;
final int? index;
const FlashcardView({
required this.cards,
this.index,
Key? key,
}) : super(key: key);
@override
_FlashcardViewState createState() => _FlashcardViewState();
}
const encouragingWords = [
'頑張れ〜!',
'できるぞ!',
'ヨッシャー!',
'いけいけいけー!',
];
class _FlashcardViewState extends State<FlashcardView> {
String title = '';
int currentCard = 0;
final List<bool> _isSelected = [false, false];
get isShuffleMode => _isSelected[0];
get isLanguageSwitchedMode => _isSelected[1];
get randomCard => Random().nextInt(widget.cards.length);
@override
void initState() {
title = encouragingWords[Random().nextInt(encouragingWords.length)];
currentCard = widget.index ?? 0;
final isPhone = MediaQueryData.fromWindow(WidgetsBinding.instance!.window)
.size
.shortestSide <
600;
if (isPhone) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
super.initState();
}
@override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitDown,
DeviceOrientation.portraitUp,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
super.dispose();
}
@override
Widget build(BuildContext context) {
return 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,
),
body: _FlashcardPage(
card: widget.cards[currentCard],
index: currentCard,
languageFlipped: isLanguageSwitchedMode,
onNextCard: () {
setState(() {
currentCard = isShuffleMode ? randomCard : currentCard + 1;
if (currentCard == widget.cards.length) currentCard = 0;
title = encouragingWords[Random().nextInt(encouragingWords.length)];
});
},
),
);
}
}
class _FlashcardPage extends StatefulWidget {
final YokutangoEntry card;
final Function() onNextCard;
final bool languageFlipped;
final int? index;
const _FlashcardPage({
required this.card,
required this.onNextCard,
this.languageFlipped = false,
this.index,
Key? key,
}) : super(key: key);
@override
_FlashcardPageState createState() => _FlashcardPageState();
}
class _FlashcardPageState extends State<_FlashcardPage> {
bool isPressed = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (isPressed) {
widget.onNextCard();
}
setState(() {
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,
),
],
),
),
);
}
}

View File

@ -1,81 +1,55 @@
import 'dart:convert';
import 'dart:io';
import 'package:tangocard_reader/models/yokutango_entry.dart';
import 'package:tangocard_reader/screens/error.dart';
import 'package:tangocard_reader/screens/loading.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tangocard_reader/service/tangocard_files.dart';
import 'package:tangocard_reader/service/theme_bloc.dart';
class Home extends StatelessWidget {
import 'pages/tango_set_list.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("よく単語"),
centerTitle: true,
),
body: const TangocardList());
}
State<Home> createState() => _HomeState();
}
class TangocardList extends StatelessWidget {
const TangocardList({Key? key}) : super(key: key);
class _HomeState extends State<Home> {
int page = 0;
Future<Map<File, List<YokutangoEntry>>> get tangocardFilePaths => rootBundle
.loadString('AssetManifest.json')
.then(
(json) => jsonDecode(json)
.keys
.where((String key) =>
key.contains('yokutango/json/') && key.contains('.json'))
.toList(),
)
.then(
(l) async => Map.fromIterables(
l.map<File>((f) => File(f)),
await Future.wait<List<YokutangoEntry>>(
l
.map<Future<List<YokutangoEntry>>>(
(String t) => rootBundle
.loadString(t)
.then<List<YokutangoEntry>>((s) => jsonDecode(s)
.map<YokutangoEntry>(
(e) => YokutangoEntry.fromJson(e))
.toList()),
)
),
),
);
final _pages = [
TangoSetList(
files: tangocardFilePaths,
route: '/list/tango',
),
TangoSetList(
files: kanjicardFilePaths,
route: '/list/kanji',
),
];
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: tangocardFilePaths,
builder: (context, snapshot) {
if (snapshot.hasError) {
debugPrint(snapshot.error.toString());
return const ErrorScreen();
} else if (!snapshot.hasData) {
return const LoadingScreen();
}
return ListView(
children: (snapshot.data as Map<File, List<YokutangoEntry>>)
.entries
.map(
(e) => ListTile(
title: Text(
"${e.key.uri.pathSegments.last} - ${e.value.length} cards"),
onTap: () => Navigator.pushNamed(context, '/tangolist',
arguments: e.key),
),
)
.toList(),
);
},
);
}
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
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,
),
body: _pages[page],
bottomNavigationBar: BottomNavigationBar(
onTap: (int index) => setState(() => page = index),
currentIndex: page,
items: const [
BottomNavigationBarItem(label: '単語', icon: Icon(Icons.style)),
BottomNavigationBarItem(label: '漢字', icon: Icon(Icons.translate)),
],
),
);
}

View File

@ -1,24 +1,23 @@
import 'dart:convert';
import 'dart:io';
import 'package:tangocard_reader/models/router_args.dart';
import 'package:tangocard_reader/models/yokutango_entry.dart';
import 'package:tangocard_reader/screens/error.dart';
import 'package:tangocard_reader/screens/loading.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tangocard_reader/models/data_entry.dart';
import 'package:tangocard_reader/models/router_args.dart';
import 'package:tangocard_reader/screens/misc/error.dart';
import 'package:tangocard_reader/screens/misc/loading.dart';
class TangoList extends StatelessWidget {
class KanjiList extends StatelessWidget {
final File file;
const TangoList({
required this.file,
const KanjiList({
Key? key,
required this.file,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(file.uri.pathSegments.last),
),
@ -33,7 +32,7 @@ class TangoList extends StatelessWidget {
}
final entries = (jsonSnapshot.data as List)
.map((e) => YokutangoEntry.fromJson(e))
.map((e) => KanjiEntry.fromJson(e))
.toList();
return ListView(
@ -44,7 +43,7 @@ class TangoList extends StatelessWidget {
i,
ListTile(
title: Text(e.toString()),
onTap: () => Navigator.pushNamed(context, '/benkyou',
onTap: () => Navigator.pushNamed(context, '/benkyou/kanji',
arguments: BenkyouArgs(cards: entries, index: i)),
),
),
@ -53,7 +52,7 @@ class TangoList extends StatelessWidget {
.toList(),
);
},
),
)
);
}
}

View File

@ -0,0 +1,61 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tangocard_reader/models/data_entry.dart';
import 'package:tangocard_reader/models/router_args.dart';
import 'package:tangocard_reader/screens/misc/error.dart';
import 'package:tangocard_reader/screens/misc/loading.dart';
class TangoList extends StatelessWidget {
final File file;
const TangoList({
required this.file,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(file.uri.pathSegments.last),
),
body: FutureBuilder(
future:
rootBundle.loadString(file.path).then((data) => jsonDecode(data)),
builder: (context, jsonSnapshot) {
if (jsonSnapshot.hasError) {
return const ErrorScreen();
} else if (!jsonSnapshot.hasData) {
return const LoadingScreen();
}
final entries = (jsonSnapshot.data as List)
.map((e) => YokutangoEntry.fromJson(e))
.toList();
return ListView(
children: entries
.asMap()
.map(
(i, e) => MapEntry(
i,
ListTile(
title: Text(e.toString()),
onTap: () => Navigator.pushNamed(
context,
'/benkyou/tango',
arguments: BenkyouArgs(cards: entries, index: i),
),
),
),
)
.values
.toList(),
);
},
));
}
}

View File

@ -0,0 +1,46 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:tangocard_reader/screens/misc/error.dart';
import 'package:tangocard_reader/screens/misc/loading.dart';
class TangoSetList extends StatelessWidget {
final String route;
final Future<Map<File, List>> files;
const TangoSetList({
Key? key,
required this.route,
required this.files,
}) : super(key: key);
@override
Widget build(BuildContext context) => FutureBuilder(
future: files,
builder: (context, snapshot) {
if (snapshot.hasError) {
debugPrint(snapshot.error.toString());
return const ErrorScreen();
} else if (!snapshot.hasData) {
return const LoadingScreen();
}
return ListView(
children: (snapshot.data as Map<File, List>)
.entries
.map(
(e) => ListTile(
title: Text(
"${e.key.uri.pathSegments.last} - ${e.value.length} cards"),
onTap: () => Navigator.pushNamed(
context,
route,
arguments: e.key,
),
),
)
.toList(),
);
},
);
}

View File

@ -0,0 +1,84 @@
import 'package:tangocard_reader/components/flashcard.dart';
import 'package:flutter/material.dart';
import 'package:tangocard_reader/models/data_entry.dart';
import 'package:tangocard_reader/components/navigation_buttons.dart';
class FlashcardPage extends StatefulWidget {
final YokutangoEntry card;
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,
}) : super(key: key);
@override
_FlashcardPageState createState() => _FlashcardPageState();
}
class _FlashcardPageState extends State<FlashcardPage> {
bool isPressed = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (isPressed) {
widget.onNextCard();
}
setState(() {
isPressed = !isPressed;
});
},
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()),
],
)
],
),
);
}
}

View File

@ -0,0 +1,151 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:signature/signature.dart';
import '../../models/data_entry.dart';
import '../../components/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);
@override
_KanjiPageState createState() => _KanjiPageState();
}
class _KanjiPageState extends State<KanjiPage> {
final focusNode = FocusNode();
bool isPressed = false;
late final controller = SignatureController(
penColor: Theme.of(context).textTheme.bodyText1?.color ?? Colors.black,
);
@override
void initState() {
focusNode.requestFocus();
super.initState();
}
@override
void dispose() {
focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RawKeyboardListener(
focusNode: focusNode,
onKey: (event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter) || event.isKeyPressed(LogicalKeyboardKey.space)) {
if (widget.showDrawingPanel) return;
if (isPressed) {
controller.clear();
widget.onNextCard();
}
setState(() => isPressed = !isPressed);
}
},
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (widget.showDrawingPanel) return;
if (isPressed) {
controller.clear();
widget.onNextCard();
}
setState(() => isPressed = !isPressed);
},
child: Stack(
alignment: Alignment.center,
fit: StackFit.expand,
children: [
if (widget.showDrawingPanel) ...[
const SizedBox(width: 20),
Signature(
controller: controller,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
)
],
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),
const SizedBox(width: 20),
Text(
widget.entry.kanji,
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),
if (widget.showDrawingPanel) ...[
const SizedBox(width: 20),
Row(
children: [
const Expanded(child: SizedBox()),
IconButton(
iconSize: 40,
onPressed: controller.clear,
icon: const Icon(Icons.delete),
)
],
)
]
],
),
Positioned(
bottom: 40,
child: NavigationButtons(
middleText:
widget.index == null ? 'N' : (widget.index! + 1).toString(),
onMiddlePressed: () {
if (isPressed) {
controller.clear();
widget.onNextCard();
}
setState(() => isPressed = !isPressed);
},
onNextCard: () => setState(() {
if (isPressed) {
controller.clear();
widget.onNextCard();
}
setState(() => isPressed = !isPressed);
}),
onPreviousCard: () => setState(() {
controller.clear();
isPressed = false;
widget.onPreviousCard();
}),
),
)
],
),
),
);
}
}

View File

@ -0,0 +1,194 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tangocard_reader/models/data_entry.dart';
import 'package:tangocard_reader/screens/practise/kanji.dart';
import 'flashcard.dart';
class PractiseView extends StatefulWidget {
final List<DataEntry> entries;
final bool isKanji;
final int index;
const PractiseView({
Key? key,
required this.entries,
required this.isKanji,
this.index = 0,
}) : super(key: key);
@override
State<PractiseView> createState() => _PractiseViewState();
}
const encouragingWords = [
'頑張れ〜!',
'できるぞ!',
'ヨッシャー!',
'いけいけー!',
];
class _PractiseViewState extends State<PractiseView> {
late int currentCard;
SharedPreferences get prefs => GetIt.instance.get<SharedPreferences>();
set isShuffleMode(b) => prefs.setBool('shuffleMode', b);
set isLanguageSwitchedMode(b) => prefs.setBool('languageSwitchedMode', b);
set isKanjiDrawingMode(b) => prefs.setBool('kanjiDrawingMode', b);
set isKanjiAnimationMode(b) => prefs.setBool('kanjiAnimationMode', b);
bool get isShuffleMode => prefs.getBool('shuffleMode') ?? false;
bool get isLanguageSwitchedMode =>
prefs.getBool('languageSwitchedMode') ?? false;
bool get isKanjiDrawingMode => prefs.getBool('kanjiDrawingMode') ?? false;
bool get isKanjiAnimationMode => prefs.getBool('kanjiAnimationMode') ?? false;
List<bool> get _flashcardToggles => [isShuffleMode, isLanguageSwitchedMode];
List<bool> get _kanjiToggles => [isKanjiDrawingMode, isKanjiAnimationMode];
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() {
currentCard = widget.index;
if (isPhone) {
if (widget.isKanji) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
} else {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
}
super.initState();
}
@override
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(
() {
if (index == 0) {
isShuffleMode = !_flashcardToggles[index];
} else if (index == 1) {
isLanguageSwitchedMode = !_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: _kanjiToggles,
onPressed: (int index) => setState(
() {
if (index == 0) {
isKanjiDrawingMode = !_kanjiToggles[index];
} else if (index == 1) {
isKanjiAnimationMode = !_kanjiToggles[index];
}
},
),
),
],
),
centerTitle: true,
);
@override
Widget build(BuildContext context) => Scaffold(
appBar: widget.isKanji ? kanjiAppBar : flashcardAppBar,
body: widget.isKanji
? 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;
}),
onPreviousCard: () => setState(() {
currentCard = isShuffleMode ? randomCard : currentCard - 1;
if (currentCard == -1) {
currentCard = widget.entries.length - 1;
}
}),
),
);
}

View File

@ -0,0 +1,50 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:tangocard_reader/models/data_entry.dart';
// TODO: merge
Future<Map<File, List<YokutangoEntry>>> get tangocardFilePaths => rootBundle
.loadString('AssetManifest.json')
.then(
(json) => jsonDecode(json)
.keys
.where((String key) =>
key.contains('yokutango/json/') && key.contains('.json'))
.toList(),
)
.then(
(l) async => Map.fromIterables(
l.map<File>((f) => File(f)),
await Future.wait<List<YokutangoEntry>>(
l.map<Future<List<YokutangoEntry>>>(
(String t) => rootBundle.loadString(t).then<List<YokutangoEntry>>(
(s) => jsonDecode(s)
.map<YokutangoEntry>((e) => YokutangoEntry.fromJson(e))
.toList()),
)),
),
);
Future<Map<File, List<KanjiEntry>>> get kanjicardFilePaths => rootBundle
.loadString('AssetManifest.json')
.then(
(json) => jsonDecode(json)
.keys
.where((String key) =>
key.contains(RegExp(r'yokutango/kanji/kanji_\d+.json')))
.toList(),
)
.then(
(l) async => Map.fromIterables(
l.map<File>((f) => File(f)),
await Future.wait<List<KanjiEntry>>(l.map<Future<List<KanjiEntry>>>(
(String t) => rootBundle.loadString(t).then<List<KanjiEntry>>((s) =>
jsonDecode(s)
.map<KanjiEntry>((e) => KanjiEntry.fromJson(e))
.toList()),
)),
),
);

View File

@ -0,0 +1,26 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.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> {
ThemeBloc({
required Brightness init,
}) : super(init) {
on<SetTheme>((event, emit) {
GetIt.instance
.get<SharedPreferences>()
.setBool('darkTheme', event.isDark);
emit(event.isDark ? Brightness.dark : Brightness.light);
});
}
}

View File

@ -5,6 +5,9 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@ -13,3 +16,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

View File

@ -1,121 +1,357 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
url: "https://pub.dev"
source: hosted
version: "3.4.10"
args:
dependency: transitive
description:
name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.4.2"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.8.2"
version: "2.11.0"
bloc:
dependency: transitive
description:
name: bloc
sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49"
url: "https://pub.dev"
source: hosted
version: "8.1.2"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.15.0"
cupertino_icons:
dependency: "direct main"
version: "1.18.0"
convert:
dependency: transitive
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
version: "3.1.1"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae
url: "https://pub.dev"
source: hosted
version: "8.1.3"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493
url: "https://pub.dev"
source: hosted
version: "1.0.4"
flutter_svg:
dependency: transitive
description:
name: flutter_svg
sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
url: "https://pub.dev"
source: hosted
version: "2.0.9"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
get_it:
dependency: "direct main"
description:
name: get_it
sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7
url: "https://pub.dev"
source: hosted
version: "7.6.7"
image:
dependency: transitive
description:
name: image
sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d"
url: "https://pub.dev"
source: hosted
version: "4.1.4"
js:
dependency: transitive
description:
name: js
sha256: "4186c61b32f99e60f011f7160e32c89a758ae9b1d0c6d28e2c02ef0382300e2b"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c
url: "https://pub.dev"
source: hosted
version: "1.0.1"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.11"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
version: "1.7.0"
version: "1.10.0"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.8.3"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
url: "https://pub.dev"
source: hosted
version: "1.0.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform:
dependency: transitive
description:
name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29"
url: "https://pub.dev"
source: hosted
version: "3.7.4"
provider:
dependency: "direct main"
dependency: transitive
description:
name: provider
url: "https://pub.dartlang.org"
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
version: "6.1.1"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
signature:
dependency: "direct main"
description:
name: signature
sha256: d072a766e9a40496296b7593c0d9dee2abded0bdcfb306d9962d0320a9763395
url: "https://pub.dev"
source: hosted
version: "5.4.1"
sky_engine:
dependency: transitive
description: flutter
@ -125,58 +361,122 @@ packages:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.8.1"
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.4.3"
version: "0.6.1"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.3.2"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "18f6690295af52d081f6808f2f7c69f0eed6d7e23a71539d75f4aeb8f0062172"
url: "https://pub.dev"
source: hosted
version: "1.1.9+2"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "531d20465c10dfac7f5cd90b60bbe4dd9921f1ec4ca54c83ebb176dbacb7bb2d"
url: "https://pub.dev"
source: hosted
version: "1.1.9+2"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "03012b0a33775c5530576b70240308080e1d5050f0faf000118c20e6463bc0ad"
url: "https://pub.dev"
source: hosted
version: "1.1.9+2"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.3.0"
win32:
dependency: transitive
description:
name: win32
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
url: "https://pub.dev"
source: hosted
version: "5.2.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.16.0"
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"

View File

@ -29,12 +29,10 @@ environment:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
provider: ^6.0.0
flutter_bloc: ^8.0.1
get_it: ^7.2.0
shared_preferences: ^2.0.12
signature: ^5.0.0
dev_dependencies:
flutter_test:
@ -69,10 +67,16 @@ flutter:
- family: K Gothic
fonts:
- asset: assets/fonts/K Gothic.ttf
- family: Heart Warming
fonts:
- asset: assets/fonts/Heart Warming.otf
- family: Noto Sans CJK
fonts:
- asset: assets/fonts/NotoSansCJK-Regular.ttc
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.