mirror of
https://github.com/h7x4/Jisho-Study-Tool.git
synced 2024-12-21 13:37:29 +01:00
commit
5eaf220683
2
.gitignore
vendored
2
.gitignore
vendored
@ -35,3 +35,5 @@ lib/generated_plugin_registrant.dart
|
|||||||
|
|
||||||
# Exceptions to above rules.
|
# Exceptions to above rules.
|
||||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
|
||||||
|
pubspec.lock
|
24
README.md
24
README.md
@ -1,16 +1,20 @@
|
|||||||
# jisho_study_tool
|
# Jisho Study tool
|
||||||
|
|
||||||
A new Flutter project.
|
A japanese dictionary with features for making studying the language easier.
|
||||||
|
|
||||||
## Getting Started
|
## Search
|
||||||
|
|
||||||
This project is a starting point for a Flutter application.
|
Standard search using Jishos own API. This returns standard Jisho search results, including what you'd find if you searched for something through the standard jisho search bar without any #modifiers
|
||||||
|
|
||||||
A few resources to get you started if this is your first Flutter project:
|
## Kanji Search
|
||||||
|
|
||||||
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
|
Standard kanji search using the #kanji modifier. This will give you detailed information about things like drawing order, radicals, different kinds of ranks and statistics and some onyomi and kunyomi example words.
|
||||||
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
|
|
||||||
|
|
||||||
For help getting started with Flutter, view our
|
## Upcoming Features
|
||||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
|
||||||
samples, guidance on mobile development, and a full API reference.
|
* Different kinds of kanji input like radicals and grade based lists
|
||||||
|
* Favorites, history and custom lists
|
||||||
|
* Anki export
|
||||||
|
* Memo cards
|
||||||
|
* Cloud sync
|
||||||
|
* Dark theme
|
||||||
|
18
lib/bloc/history/bloc/history_bloc.dart
Normal file
18
lib/bloc/history/bloc/history_bloc.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
part 'history_event.dart';
|
||||||
|
part 'history_state.dart';
|
||||||
|
|
||||||
|
class HistoryBloc extends Bloc<HistoryEvent, HistoryState> {
|
||||||
|
HistoryBloc() : super(HistoryInitial());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<HistoryState> mapEventToState(
|
||||||
|
HistoryEvent event,
|
||||||
|
) async* {
|
||||||
|
// TODO: implement mapEventToState
|
||||||
|
}
|
||||||
|
}
|
4
lib/bloc/history/bloc/history_event.dart
Normal file
4
lib/bloc/history/bloc/history_event.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
part of 'history_bloc.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
abstract class HistoryEvent {}
|
6
lib/bloc/history/bloc/history_state.dart
Normal file
6
lib/bloc/history/bloc/history_state.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
part of 'history_bloc.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
abstract class HistoryState {}
|
||||||
|
|
||||||
|
class HistoryInitial extends HistoryState {}
|
41
lib/bloc/kanji/kanji_bloc.dart
Normal file
41
lib/bloc/kanji/kanji_bloc.dart
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import './kanji_event.dart';
|
||||||
|
import './kanji_state.dart';
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/services/kanji_search.dart';
|
||||||
|
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
||||||
|
|
||||||
|
export './kanji_event.dart';
|
||||||
|
export './kanji_state.dart';
|
||||||
|
|
||||||
|
class KanjiBloc extends Bloc<KanjiEvent, KanjiState> {
|
||||||
|
|
||||||
|
KanjiBloc() : super(KanjiSearchInitial());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<KanjiState> mapEventToState(
|
||||||
|
KanjiEvent event,
|
||||||
|
) async* {
|
||||||
|
if (event is GetKanji) {
|
||||||
|
|
||||||
|
yield KanjiSearchLoading();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final _kanji = await fetchKanji(event.kanjiSearchString);
|
||||||
|
if (_kanji.found) yield KanjiSearchFinished(kanji: _kanji);
|
||||||
|
else yield KanjiSearchError('Something went wrong');
|
||||||
|
} on Exception {
|
||||||
|
yield KanjiSearchError('Something went wrong');
|
||||||
|
}
|
||||||
|
} else if (event is GetKanjiSuggestions) {
|
||||||
|
|
||||||
|
final suggestions = kanjiSuggestions(event.searchString);
|
||||||
|
yield KanjiSearchInput(suggestions);
|
||||||
|
|
||||||
|
} else if (event is ReturnToInitialState) {
|
||||||
|
yield KanjiSearchInitial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
lib/bloc/kanji/kanji_event.dart
Normal file
17
lib/bloc/kanji/kanji_event.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
abstract class KanjiEvent {
|
||||||
|
const KanjiEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetKanjiSuggestions extends KanjiEvent {
|
||||||
|
final String searchString;
|
||||||
|
const GetKanjiSuggestions(this.searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetKanji extends KanjiEvent {
|
||||||
|
final String kanjiSearchString;
|
||||||
|
const GetKanji(this.kanjiSearchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReturnToInitialState extends KanjiEvent {
|
||||||
|
const ReturnToInitialState();
|
||||||
|
}
|
34
lib/bloc/kanji/kanji_state.dart
Normal file
34
lib/bloc/kanji/kanji_state.dart
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
abstract class KanjiState {
|
||||||
|
const KanjiState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class KanjiSearchInitial extends KanjiState {
|
||||||
|
const KanjiSearchInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class KanjiSearchInput extends KanjiState {
|
||||||
|
final List<String> kanjiSuggestions;
|
||||||
|
const KanjiSearchInput(this.kanjiSuggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
class KanjiSearchLoading extends KanjiState {
|
||||||
|
const KanjiSearchLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
class KanjiSearchFinished extends KanjiState {
|
||||||
|
final KanjiResult kanji;
|
||||||
|
final bool starred;
|
||||||
|
|
||||||
|
const KanjiSearchFinished({
|
||||||
|
this.kanji,
|
||||||
|
this.starred = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class KanjiSearchError extends KanjiState {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const KanjiSearchError(this.message);
|
||||||
|
}
|
34
lib/bloc/search/search_bloc.dart
Normal file
34
lib/bloc/search/search_bloc.dart
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
import 'package:jisho_study_tool/services/jisho_search.dart';
|
||||||
|
import 'package:unofficial_jisho_api/parser.dart';
|
||||||
|
|
||||||
|
part 'search_event.dart';
|
||||||
|
part 'search_state.dart';
|
||||||
|
|
||||||
|
class SearchBloc extends Bloc<SearchEvent, SearchState> {
|
||||||
|
SearchBloc() : super(SearchInitial());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<SearchState> mapEventToState(
|
||||||
|
SearchEvent event,
|
||||||
|
) async* {
|
||||||
|
if (event is GetSearchResults) {
|
||||||
|
yield SearchLoading();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final _searchResults = await fetchJishoResults(event.searchString);
|
||||||
|
if (_searchResults.meta.status == 200) yield SearchFinished(_searchResults.data);
|
||||||
|
} on Exception {
|
||||||
|
yield SearchError('Something went wrong');
|
||||||
|
}
|
||||||
|
} else if (event is ReturnToInitialState) {
|
||||||
|
yield SearchInitial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
lib/bloc/search/search_event.dart
Normal file
15
lib/bloc/search/search_event.dart
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
part of 'search_bloc.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
abstract class SearchEvent {
|
||||||
|
const SearchEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetSearchResults extends SearchEvent {
|
||||||
|
final String searchString;
|
||||||
|
const GetSearchResults(this.searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReturnToInitialState extends SearchEvent {
|
||||||
|
const ReturnToInitialState();
|
||||||
|
}
|
26
lib/bloc/search/search_state.dart
Normal file
26
lib/bloc/search/search_state.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
part of 'search_bloc.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
abstract class SearchState {
|
||||||
|
const SearchState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchInitial extends SearchState {
|
||||||
|
const SearchInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchLoading extends SearchState {
|
||||||
|
const SearchLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchFinished extends SearchState {
|
||||||
|
final List<JishoResult> results;
|
||||||
|
|
||||||
|
const SearchFinished(this.results);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchError extends SearchState {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const SearchError(this.message);
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
import 'parts/grade.dart';
|
||||||
|
import 'parts/header.dart';
|
||||||
|
import 'parts/jlpt_level.dart';
|
||||||
|
import 'parts/meaning.dart';
|
||||||
|
import 'parts/radical.dart';
|
||||||
|
import 'parts/rank.dart';
|
||||||
|
import 'parts/stroke_order_gif.dart';
|
||||||
|
import 'parts/onyomi.dart';
|
||||||
|
import 'parts/kunyomi.dart';
|
||||||
|
import 'parts/examples.dart';
|
||||||
|
|
||||||
|
class KanjiResultCard extends StatelessWidget {
|
||||||
|
final jisho.KanjiResult _result;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 30.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
flex: 1,
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Center(child: SizedBox()),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
flex: 1,
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Center(child: Header(_result.query)),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
flex: 1,
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Center(
|
||||||
|
child: Radical(_result.radical),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Meaning(_result.meaning),
|
||||||
|
_result.onyomi.length != 0 ? Onyomi(_result.onyomi) : SizedBox.shrink(),
|
||||||
|
_result.kunyomi.length != 0 ? Kunyomi(_result.kunyomi) : SizedBox.shrink(),
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
StrokeOrderGif(_result.strokeOrderGifUri),
|
||||||
|
Container(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text("JLPT: ", style: TextStyle(fontSize: 20.0)),
|
||||||
|
JlptLevel(_result.jlptLevel ?? "⨉"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text("Grade: ", style: TextStyle(fontSize: 20.0)),
|
||||||
|
Grade(_result.taughtIn ?? "⨉"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text("Rank: ", style: TextStyle(fontSize: 20.0)),
|
||||||
|
Rank(_result.newspaperFrequencyRank ?? -1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Examples(_result.onyomiExamples, _result.kunyomiExamples),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
KanjiResultCard(this._result);
|
||||||
|
}
|
126
lib/components/kanji/kanji__search_page/parts/examples.dart
Normal file
126
lib/components/kanji/kanji__search_page/parts/examples.dart
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
class Examples extends StatelessWidget {
|
||||||
|
final List<YomiExample> _onyomiExamples;
|
||||||
|
final List<YomiExample> _kunyomiExamples;
|
||||||
|
|
||||||
|
const Examples(
|
||||||
|
this._onyomiExamples,
|
||||||
|
this._kunyomiExamples,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ExpansionTile(
|
||||||
|
title: Center(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'Examples',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
_onyomiExamples
|
||||||
|
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
||||||
|
.toList(),
|
||||||
|
_kunyomiExamples
|
||||||
|
.map((kunyomiExample) =>
|
||||||
|
_Example(kunyomiExample, _KanaType.kunyomi))
|
||||||
|
.toList(),
|
||||||
|
].expand((list) => list).toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _KanaType { kunyomi, onyomi }
|
||||||
|
|
||||||
|
class _Example extends StatelessWidget {
|
||||||
|
final _KanaType _kanaType;
|
||||||
|
final YomiExample _yomiExample;
|
||||||
|
|
||||||
|
const _Example(this._yomiExample, this._kanaType);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0,
|
||||||
|
horizontal: 10.0,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey, borderRadius: BorderRadius.circular(10.0)),
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0,
|
||||||
|
horizontal: 10.0,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: (_kanaType == _KanaType.kunyomi)
|
||||||
|
? Colors.lightBlue
|
||||||
|
: Colors.orange,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10.0),
|
||||||
|
bottomLeft: Radius.circular(10.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
_yomiExample.reading,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 15.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 5.0,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
_yomiExample.example,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 15.0,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Wrap(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
_yomiExample.meaning,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
25
lib/components/kanji/kanji__search_page/parts/grade.dart
Normal file
25
lib/components/kanji/kanji__search_page/parts/grade.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Grade extends StatelessWidget {
|
||||||
|
final String _grade;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
child: Text(
|
||||||
|
_grade,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Grade(this._grade);
|
||||||
|
}
|
22
lib/components/kanji/kanji__search_page/parts/header.dart
Normal file
22
lib/components/kanji/kanji__search_page/parts/header.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Header extends StatelessWidget {
|
||||||
|
final String _kanji;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10.0), color: Colors.blue),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
child: Text(
|
||||||
|
_kanji,
|
||||||
|
style: TextStyle(fontSize: 80.0, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Header(this._kanji);
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class JlptLevel extends StatelessWidget {
|
||||||
|
final String _jlptLevel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
child: Text(
|
||||||
|
_jlptLevel,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
JlptLevel(this._jlptLevel);
|
||||||
|
}
|
77
lib/components/kanji/kanji__search_page/parts/kunyomi.dart
Normal file
77
lib/components/kanji/kanji__search_page/parts/kunyomi.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Kunyomi extends StatelessWidget {
|
||||||
|
final List<String> _kunyomi;
|
||||||
|
List<_KunyomiCard> _kunyomiCards;
|
||||||
|
bool _expandable;
|
||||||
|
|
||||||
|
Kunyomi(this._kunyomi) {
|
||||||
|
_kunyomiCards = _kunyomi.map((kunyomi) => _KunyomiCard(kunyomi)).toList();
|
||||||
|
_expandable = (_kunyomi.length > 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.0,
|
||||||
|
vertical: 5.0,
|
||||||
|
),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: _KunyomiWrapper(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _KunyomiWrapper(BuildContext context) {
|
||||||
|
if (_expandable) {
|
||||||
|
return ExpansionTile(
|
||||||
|
initiallyExpanded: false,
|
||||||
|
title: Center(child: _KunyomiCard('Kunyomi')),
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20.0,
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: _kunyomiCards,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 25.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: _kunyomiCards,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _KunyomiCard extends StatelessWidget {
|
||||||
|
final String _kunyomi;
|
||||||
|
const _KunyomiCard(this._kunyomi);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0,
|
||||||
|
horizontal: 10.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
_kunyomi,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.lightBlue,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
80
lib/components/kanji/kanji__search_page/parts/meaning.dart
Normal file
80
lib/components/kanji/kanji__search_page/parts/meaning.dart
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Meaning extends StatelessWidget {
|
||||||
|
List<String> _meanings;
|
||||||
|
List<_MeaningCard> _meaningCards;
|
||||||
|
bool _expandable;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.0,
|
||||||
|
vertical: 5.0,
|
||||||
|
),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: _MeaningWrapper(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _MeaningWrapper(BuildContext context) {
|
||||||
|
if (_expandable) {
|
||||||
|
return ExpansionTile(
|
||||||
|
initiallyExpanded: false,
|
||||||
|
title: Center(child: _MeaningCard('Meanings')),
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20.0,
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: _meaningCards,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 25.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: _meaningCards,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Meaning(_meaning) {
|
||||||
|
this._meanings = _meaning.split(', ');
|
||||||
|
this._meaningCards =
|
||||||
|
_meanings.map((meaning) => _MeaningCard(meaning)).toList();
|
||||||
|
this._expandable = (this._meanings.length > 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MeaningCard extends StatelessWidget {
|
||||||
|
final String _meaning;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.0,
|
||||||
|
vertical: 10.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
_meaning,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_MeaningCard(this._meaning);
|
||||||
|
}
|
77
lib/components/kanji/kanji__search_page/parts/onyomi.dart
Normal file
77
lib/components/kanji/kanji__search_page/parts/onyomi.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Onyomi extends StatelessWidget {
|
||||||
|
final List<String> _onyomi;
|
||||||
|
List<_OnyomiCard> _onyomiCards;
|
||||||
|
bool _expandable;
|
||||||
|
|
||||||
|
Onyomi(this._onyomi) {
|
||||||
|
_onyomiCards = _onyomi.map((onyomi) => _OnyomiCard(onyomi)).toList();
|
||||||
|
_expandable = (_onyomi.length > 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.0,
|
||||||
|
vertical: 5.0,
|
||||||
|
),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: _OnyomiWrapper(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _OnyomiWrapper(BuildContext context) {
|
||||||
|
if (_expandable) {
|
||||||
|
return ExpansionTile(
|
||||||
|
initiallyExpanded: false,
|
||||||
|
title: Center(child: _OnyomiCard('Onyomi')),
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20.0,
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: _onyomiCards,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 25.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: _onyomiCards,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OnyomiCard extends StatelessWidget {
|
||||||
|
final String _onyomi;
|
||||||
|
const _OnyomiCard(this._onyomi);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0,
|
||||||
|
horizontal: 10.0,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
_onyomi,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.orange,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
26
lib/components/kanji/kanji__search_page/parts/radical.dart
Normal file
26
lib/components/kanji/kanji__search_page/parts/radical.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
class Radical extends StatelessWidget {
|
||||||
|
final jisho.Radical _radical;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
child: Text(
|
||||||
|
_radical.symbol,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 40.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Radical(this._radical);
|
||||||
|
}
|
26
lib/components/kanji/kanji__search_page/parts/rank.dart
Normal file
26
lib/components/kanji/kanji__search_page/parts/rank.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Rank extends StatelessWidget {
|
||||||
|
final int _rank;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
child: Text(
|
||||||
|
'${_rank.toString()} / 2500',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rank(this._rank);
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class StrokeOrderGif extends StatelessWidget {
|
||||||
|
final String _uri;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 20.0),
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
child: ClipRRect(
|
||||||
|
child: Image.network(_uri),
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue,
|
||||||
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
StrokeOrderGif(this._uri);
|
||||||
|
}
|
11
lib/components/kanji/kanji_list/kanji_list.dart
Normal file
11
lib/components/kanji/kanji_list/kanji_list.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class KanjiGrid extends StatelessWidget {
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GridView.count(
|
||||||
|
crossAxisCount: 3,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
54
lib/components/kanji/kanji_suggestions.dart
Normal file
54
lib/components/kanji/kanji_suggestions.dart
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
|
|
||||||
|
class KanjiSuggestions extends StatelessWidget {
|
||||||
|
final List<String> _suggestions;
|
||||||
|
const KanjiSuggestions(this._suggestions);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 20.0,
|
||||||
|
horizontal: 40.0,
|
||||||
|
),
|
||||||
|
child: GridView.count(
|
||||||
|
crossAxisCount: 3,
|
||||||
|
mainAxisSpacing: 20.0,
|
||||||
|
crossAxisSpacing: 40.0,
|
||||||
|
children: _suggestions.map((kanji) => _Suggestion(kanji)).toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Suggestion extends StatelessWidget {
|
||||||
|
final String _kanji;
|
||||||
|
const _Suggestion(this._kanji);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
BlocProvider.of<KanjiBloc>(context).add(GetKanji(_kanji));
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.all(10.0),
|
||||||
|
child: FittedBox(
|
||||||
|
child: Text(
|
||||||
|
_kanji,
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
12
lib/components/loading.dart
Normal file
12
lib/components/loading.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class LoadingScreen extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
23
lib/components/search/parts/header.dart
Normal file
23
lib/components/search/parts/header.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
class JapaneseHeader extends StatelessWidget {
|
||||||
|
final JishoJapaneseWord _word;
|
||||||
|
const JapaneseHeader(this._word);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final hasFurigana = (_word.word != null);
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
padding: EdgeInsets.only(left: 10.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
(hasFurigana) ? Text(_word.reading) : Text(''),
|
||||||
|
(hasFurigana) ? Text(_word.word) : Text(_word.reading),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
59
lib/components/search/parts/other_forms.dart
Normal file
59
lib/components/search/parts/other_forms.dart
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
class OtherForms extends StatelessWidget {
|
||||||
|
final List<JishoJapaneseWord> _otherForms;
|
||||||
|
OtherForms(this._otherForms);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Other Forms',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: _otherForms.map((form) => _KanaBox(form)).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _KanaBox extends StatelessWidget {
|
||||||
|
final JishoJapaneseWord _word;
|
||||||
|
const _KanaBox(this._word);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final hasFurigana = (_word.word != null);
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
(hasFurigana) ? Text(_word.reading) : Text(''),
|
||||||
|
(hasFurigana) ? Text(_word.word) : Text(_word.reading),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 5.0,
|
||||||
|
vertical: 5.0,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
spreadRadius: 1,
|
||||||
|
blurRadius: 0.5,
|
||||||
|
offset: Offset(1, 1),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
42
lib/components/search/parts/senses.dart
Normal file
42
lib/components/search/parts/senses.dart
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/parser.dart';
|
||||||
|
|
||||||
|
class Senses extends StatelessWidget {
|
||||||
|
final List<JishoWordSense> _senses;
|
||||||
|
const Senses(this._senses);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final List<Widget> _senseWidgets =
|
||||||
|
_senses.map((sense) => _Sense(sense)).toList();
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
child: Column(
|
||||||
|
children: _senseWidgets,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Sense extends StatelessWidget {
|
||||||
|
final JishoWordSense _sense;
|
||||||
|
const _Sense(this._sense);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
_sense.parts_of_speech.join(', '),
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children:
|
||||||
|
_sense.english_definitions.map((def) => Text(def)).toList(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
29
lib/components/search/search_card.dart
Normal file
29
lib/components/search/search_card.dart
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
import 'parts/header.dart';
|
||||||
|
import 'parts/senses.dart';
|
||||||
|
import 'parts/other_forms.dart';
|
||||||
|
|
||||||
|
class SearchResultCard extends StatelessWidget {
|
||||||
|
final JishoResult _result;
|
||||||
|
JishoJapaneseWord _mainWord;
|
||||||
|
List<JishoJapaneseWord> _otherForms;
|
||||||
|
|
||||||
|
SearchResultCard(this._result) {
|
||||||
|
this._mainWord = _result.japanese[0];
|
||||||
|
this._otherForms = _result.japanese.sublist(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ExpansionTile(
|
||||||
|
title: JapaneseHeader(_mainWord),
|
||||||
|
children: [
|
||||||
|
Senses(_result.senses),
|
||||||
|
OtherForms(_otherForms),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
140
lib/main.dart
140
lib/main.dart
@ -1,4 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/screens/kanji_search.dart';
|
||||||
|
import 'package:jisho_study_tool/screens/history.dart';
|
||||||
|
import 'package:jisho_study_tool/screens/search.dart';
|
||||||
|
|
||||||
|
import 'bloc/search/search_bloc.dart';
|
||||||
|
|
||||||
void main() => runApp(MyApp());
|
void main() => runApp(MyApp());
|
||||||
|
|
||||||
@ -7,11 +14,17 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Flutter Demo',
|
title: 'Jisho Study Tool',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primarySwatch: Colors.blue,
|
primarySwatch: Colors.blue,
|
||||||
),
|
),
|
||||||
home: Home(),
|
home: MultiBlocProvider(
|
||||||
|
providers: [
|
||||||
|
BlocProvider(create: (context) => SearchBloc()),
|
||||||
|
BlocProvider(create: (context) => KanjiBloc()),
|
||||||
|
],
|
||||||
|
child: Home(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,55 +32,88 @@ class MyApp extends StatelessWidget {
|
|||||||
class Home extends StatefulWidget {
|
class Home extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
_HomeState createState() => _HomeState();
|
_HomeState createState() => _HomeState();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeState extends State<Home> {
|
class _HomeState extends State<Home> {
|
||||||
int _selectedPage = 0;
|
int _selectedPage = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Jisho Study Tool')
|
title: pages[_selectedPage].titleBar,
|
||||||
),
|
centerTitle: true,
|
||||||
body: Container(),
|
),
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
body: pages[_selectedPage].content,
|
||||||
currentIndex: _selectedPage,
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
onTap: (int index) {
|
currentIndex: _selectedPage,
|
||||||
setState(() {
|
onTap: (int index) {
|
||||||
_selectedPage = index;
|
setState(() {
|
||||||
});
|
_selectedPage = index;
|
||||||
},
|
});
|
||||||
items: [
|
},
|
||||||
BottomNavigationBarItem(
|
items: navBar,
|
||||||
title: Text('Search'),
|
showSelectedLabels: false,
|
||||||
icon: Icon(Icons.search)
|
showUnselectedLabels: false,
|
||||||
),
|
unselectedItemColor: Colors.blue,
|
||||||
BottomNavigationBarItem(
|
selectedItemColor: Colors.green,
|
||||||
title: Text('Kanji'),
|
),
|
||||||
icon: Text(
|
);
|
||||||
'漢',
|
}
|
||||||
style: TextStyle(
|
}
|
||||||
fontSize: 18
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
title: Text('Memorize'),
|
|
||||||
icon: Icon(Icons.book)
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
title: Text('Settings'),
|
|
||||||
icon: Icon(Icons.settings)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
showSelectedLabels: false,
|
|
||||||
showUnselectedLabels: false,
|
|
||||||
unselectedItemColor: Colors.blue,
|
|
||||||
selectedItemColor: Colors.green,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
final List<BottomNavigationBarItem> navBar = [
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
title: Text('Search'),
|
||||||
|
icon: Icon(Icons.search),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
title: Text('Kanji'),
|
||||||
|
icon: Text(
|
||||||
|
'漢',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
title: Text('History'),
|
||||||
|
icon: Icon(Icons.bookmark),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
title: Text('Memorize'),
|
||||||
|
icon: Icon(Icons.local_offer),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
title: Text('Settings'),
|
||||||
|
icon: Icon(Icons.settings),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
class Page {
|
||||||
|
Widget content;
|
||||||
|
Widget titleBar;
|
||||||
|
|
||||||
|
Page({
|
||||||
|
this.content,
|
||||||
|
this.titleBar,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Page> pages = [
|
||||||
|
Page(content: SearchView(), titleBar: Text('Search')),
|
||||||
|
Page(
|
||||||
|
content: KanjiView(),
|
||||||
|
titleBar: KanjiViewBar(),
|
||||||
|
),
|
||||||
|
Page(
|
||||||
|
content: HistoryView(),
|
||||||
|
titleBar: Text("History"),
|
||||||
|
),
|
||||||
|
Page(
|
||||||
|
content: Container(),
|
||||||
|
titleBar: Text("Memorization"),
|
||||||
|
),
|
||||||
|
Page(
|
||||||
|
content: Container(),
|
||||||
|
titleBar: Text("Settings"),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
10
lib/screens/history.dart
Normal file
10
lib/screens/history.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class HistoryView extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemBuilder: (context, index) => ListTile(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/components/kanji/kanji__search_page/kanji_search_page.dart';
|
||||||
|
import 'package:jisho_study_tool/components/kanji/kanji_suggestions.dart';
|
||||||
|
import 'package:jisho_study_tool/components/loading.dart';
|
||||||
|
|
||||||
|
class KanjiView extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocListener<KanjiBloc, KanjiState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state is KanjiSearchInitial) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
} else if (state is KanjiSearchLoading) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: BlocBuilder<KanjiBloc, KanjiState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is KanjiSearchInitial) return Container();
|
||||||
|
else if (state is KanjiSearchInput) return KanjiSuggestions(state.kanjiSuggestions);
|
||||||
|
else if (state is KanjiSearchLoading) return LoadingScreen();
|
||||||
|
else if (state is KanjiSearchFinished)
|
||||||
|
return WillPopScope(
|
||||||
|
child: KanjiResultCard(state.kanji),
|
||||||
|
onWillPop: () async {
|
||||||
|
BlocProvider.of<KanjiBloc>(context)
|
||||||
|
.add(ReturnToInitialState());
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
throw 'No such event found';
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KanjiViewBar extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.arrow_back),
|
||||||
|
onPressed: () =>
|
||||||
|
BlocProvider.of<KanjiBloc>(context).add(ReturnToInitialState()),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
child: _KanjiTextField(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.star_border),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _KanjiTextField extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_KanjiTextFieldState createState() => new _KanjiTextFieldState();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextFieldButton {clear, paste}
|
||||||
|
|
||||||
|
class _KanjiTextFieldState extends State<_KanjiTextField> {
|
||||||
|
FocusNode _focus = new FocusNode();
|
||||||
|
TextEditingController _textController = new TextEditingController();
|
||||||
|
TextFieldButton _button = TextFieldButton.paste;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_focus.addListener(_onFocusChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _getKanjiSuggestions(String text) =>
|
||||||
|
BlocProvider.of<KanjiBloc>(context).add(GetKanjiSuggestions(text));
|
||||||
|
|
||||||
|
void updateSuggestions() => _getKanjiSuggestions(_textController.text);
|
||||||
|
|
||||||
|
void _onFocusChange() {
|
||||||
|
debugPrint('TextField Focus Changed: ${_focus.hasFocus.toString()}');
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_button = _focus.hasFocus ? TextFieldButton.clear : TextFieldButton.paste;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_focus.hasFocus)
|
||||||
|
updateSuggestions();
|
||||||
|
else
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearText() {
|
||||||
|
_textController.text = '';
|
||||||
|
updateSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _pasteText() async {
|
||||||
|
ClipboardData clipboardData = await Clipboard.getData('text/plain');
|
||||||
|
_textController.text = clipboardData.text;
|
||||||
|
updateSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
IconButton _clearButton = IconButton(
|
||||||
|
icon: Icon(Icons.clear),
|
||||||
|
onPressed: () => _clearText(),
|
||||||
|
);
|
||||||
|
|
||||||
|
IconButton _pasteButton = IconButton(
|
||||||
|
icon: Icon(Icons.content_paste),
|
||||||
|
onPressed: () => _pasteText(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return TextField(
|
||||||
|
focusNode: _focus,
|
||||||
|
controller: _textController,
|
||||||
|
onChanged: (text) => _getKanjiSuggestions(text),
|
||||||
|
onSubmitted: (text) =>
|
||||||
|
BlocProvider.of<KanjiBloc>(context).add(GetKanji(text)),
|
||||||
|
decoration: new InputDecoration(
|
||||||
|
prefixIcon: Icon(Icons.search),
|
||||||
|
hintText: 'Search for kanji',
|
||||||
|
fillColor: Colors.white,
|
||||||
|
filled: true,
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(100.0),
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 10.0),
|
||||||
|
isDense: false,
|
||||||
|
suffixIcon: (_button == TextFieldButton.clear) ? _clearButton : _pasteButton,
|
||||||
|
),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/components/loading.dart';
|
||||||
|
import 'package:jisho_study_tool/components/search/search_card.dart';
|
||||||
|
|
||||||
|
class SearchView extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocListener<SearchBloc, SearchState>(
|
||||||
|
listener: (context, state) {},
|
||||||
|
child: BlocBuilder<SearchBloc, SearchState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is SearchInitial)
|
||||||
|
return _InitialView();
|
||||||
|
else if (state is SearchLoading)
|
||||||
|
return LoadingScreen();
|
||||||
|
else if (state is SearchFinished) {
|
||||||
|
return WillPopScope(
|
||||||
|
child: ListView(
|
||||||
|
children: state.results
|
||||||
|
.map((result) => SearchResultCard(result))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
onWillPop: () async {
|
||||||
|
BlocProvider.of<SearchBloc>(context)
|
||||||
|
.add(ReturnToInitialState());
|
||||||
|
print('Popped');
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw 'No such event found';
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InitialView extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
|
SearchBar(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LanguageOption extends StatelessWidget {
|
||||||
|
final String _language;
|
||||||
|
final Color _color;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Expanded(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||||
|
child: Center(child: Text(_language)),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.black,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
color: _color),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_LanguageOption(this._language, this._color);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchBar extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
onSubmitted: (text) => BlocProvider.of<SearchBloc>(context)
|
||||||
|
.add(GetSearchResults(text)),
|
||||||
|
controller: TextEditingController(),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Search',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.0,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
_LanguageOption('Auto', Colors.white),
|
||||||
|
_LanguageOption('English', Colors.white),
|
||||||
|
_LanguageOption('Japanese', Colors.blue),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
Future<jisho.JishoAPIResult> fetchJishoResults(searchTerm) async {
|
||||||
|
return await jisho.searchForPhrase(searchTerm);
|
||||||
|
}
|
23
lib/services/kanji_search.dart
Normal file
23
lib/services/kanji_search.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
String _convertGrade(String grade) {
|
||||||
|
const _conversionTable = {
|
||||||
|
"grade 1": "小1",
|
||||||
|
"grade 2": "小2",
|
||||||
|
"grade 3": "小3",
|
||||||
|
"grade 4": "小4",
|
||||||
|
"grade 5": "小5",
|
||||||
|
"grade 6": "小6",
|
||||||
|
"junior high": "中"
|
||||||
|
};
|
||||||
|
|
||||||
|
print('conversion run: $grade -> ${_conversionTable[grade]}');
|
||||||
|
|
||||||
|
return _conversionTable[grade];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<jisho.KanjiResult> fetchKanji(String kanji) async {
|
||||||
|
final result = await jisho.searchForKanji(kanji);
|
||||||
|
result.taughtIn = _convertGrade(result.taughtIn);
|
||||||
|
return result;
|
||||||
|
}
|
5
lib/services/kanji_suggestions.dart
Normal file
5
lib/services/kanji_suggestions.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
final kanjiPattern = RegExp(r'[\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A]');
|
||||||
|
|
||||||
|
List<String> kanjiSuggestions(String string) {
|
||||||
|
return kanjiPattern.allMatches(string).map((match) => match.group(0)).toList();
|
||||||
|
}
|
237
pubspec.lock
237
pubspec.lock
@ -1,237 +0,0 @@
|
|||||||
# Generated by pub
|
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
|
||||||
packages:
|
|
||||||
archive:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: archive
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.11"
|
|
||||||
args:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: args
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.5.2"
|
|
||||||
async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: async
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.5"
|
|
||||||
charcode:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: charcode
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.2"
|
|
||||||
collection:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: collection
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.14.11"
|
|
||||||
convert:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: convert
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.1"
|
|
||||||
crypto:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: crypto
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
csslib:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: csslib
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.16.1"
|
|
||||||
cupertino_icons:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.3"
|
|
||||||
flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_test:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
html:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: html
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.14.0+3"
|
|
||||||
html_unescape:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: html_unescape
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.1+3"
|
|
||||||
http:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.1"
|
|
||||||
http_parser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http_parser
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.4"
|
|
||||||
image:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: image
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.4"
|
|
||||||
matcher:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: matcher
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.6"
|
|
||||||
meta:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: meta
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.8"
|
|
||||||
path:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.6.4"
|
|
||||||
pedantic:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: pedantic
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.0+1"
|
|
||||||
petitparser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: petitparser
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
quiver:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: quiver
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.5"
|
|
||||||
sky_engine:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.99"
|
|
||||||
source_span:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_span
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.5.5"
|
|
||||||
stack_trace:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stack_trace
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.9.3"
|
|
||||||
stream_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_channel
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.0"
|
|
||||||
string_scanner:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: string_scanner
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.5"
|
|
||||||
term_glyph:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: term_glyph
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.11"
|
|
||||||
typed_data:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: typed_data
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.6"
|
|
||||||
unofficial_jisho_api:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: unofficial_jisho_api
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.2"
|
|
||||||
vector_math:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_math
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.8"
|
|
||||||
xml:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: xml
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.5.0"
|
|
||||||
sdks:
|
|
||||||
dart: ">=2.7.0 <3.0.0"
|
|
45
pubspec.yaml
45
pubspec.yaml
@ -1,16 +1,5 @@
|
|||||||
name: jisho_study_tool
|
name: jisho_study_tool
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
|
||||||
# A version number is three numbers separated by dots, like 1.2.43
|
|
||||||
# followed by an optional build number separated by a +.
|
|
||||||
# Both the version and the builder number may be overridden in flutter
|
|
||||||
# build by specifying --build-name and --build-number, respectively.
|
|
||||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
|
||||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
|
||||||
# Read more about iOS versioning at
|
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@ -20,43 +9,24 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# cupertino_icons: ^0.1.2
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
unofficial_jisho_api: ^1.1.0
|
||||||
cupertino_icons: ^0.1.2
|
flutter_bloc: ^6.0.1
|
||||||
unofficial_jisho_api: ^1.0.2
|
url_launcher: ^5.5.0
|
||||||
|
division: ^0.8.8
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
|
||||||
|
|
||||||
# The following section is specific to Flutter.
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|
||||||
# The following line ensures that the Material Icons font is
|
|
||||||
# included with your application, so that you can use the icons in
|
|
||||||
# the material Icons class.
|
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
|
||||||
# assets:
|
# assets:
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
|
||||||
|
|
||||||
# For details regarding adding assets from package dependencies, see
|
|
||||||
# https://flutter.dev/assets-and-images/#from-packages
|
|
||||||
|
|
||||||
# To add custom fonts to your application, add a fonts section here,
|
|
||||||
# in this "flutter" section. Each entry in this list should have a
|
|
||||||
# "family" key with the font family name, and a "fonts" key with a
|
|
||||||
# list giving the asset and other descriptors for the font. For
|
|
||||||
# example:
|
|
||||||
# fonts:
|
# fonts:
|
||||||
# - family: Schyler
|
# - family: Schyler
|
||||||
# fonts:
|
# fonts:
|
||||||
@ -68,6 +38,3 @@ flutter:
|
|||||||
# - asset: fonts/TrajanPro.ttf
|
# - asset: fonts/TrajanPro.ttf
|
||||||
# - asset: fonts/TrajanPro_Bold.ttf
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
# weight: 700
|
# weight: 700
|
||||||
#
|
|
||||||
# For details regarding fonts from package dependencies,
|
|
||||||
# see https://flutter.dev/custom-fonts/#from-packages
|
|
||||||
|
Loading…
Reference in New Issue
Block a user