diff --git a/.gitignore b/.gitignore index ae1f183..ec2d65d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ lib/generated_plugin_registrant.dart # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +pubspec.lock \ No newline at end of file diff --git a/README.md b/README.md index e66db82..7827e81 100644 --- a/README.md +++ b/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) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +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. -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Upcoming Features + +* Different kinds of kanji input like radicals and grade based lists +* Favorites, history and custom lists +* Anki export +* Memo cards +* Cloud sync +* Dark theme diff --git a/lib/bloc/history/bloc/history_bloc.dart b/lib/bloc/history/bloc/history_bloc.dart new file mode 100644 index 0000000..9396c8c --- /dev/null +++ b/lib/bloc/history/bloc/history_bloc.dart @@ -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 { + HistoryBloc() : super(HistoryInitial()); + + @override + Stream mapEventToState( + HistoryEvent event, + ) async* { + // TODO: implement mapEventToState + } +} diff --git a/lib/bloc/history/bloc/history_event.dart b/lib/bloc/history/bloc/history_event.dart new file mode 100644 index 0000000..40ede67 --- /dev/null +++ b/lib/bloc/history/bloc/history_event.dart @@ -0,0 +1,4 @@ +part of 'history_bloc.dart'; + +@immutable +abstract class HistoryEvent {} diff --git a/lib/bloc/history/bloc/history_state.dart b/lib/bloc/history/bloc/history_state.dart new file mode 100644 index 0000000..57b69b2 --- /dev/null +++ b/lib/bloc/history/bloc/history_state.dart @@ -0,0 +1,6 @@ +part of 'history_bloc.dart'; + +@immutable +abstract class HistoryState {} + +class HistoryInitial extends HistoryState {} diff --git a/lib/bloc/kanji/kanji_bloc.dart b/lib/bloc/kanji/kanji_bloc.dart new file mode 100644 index 0000000..a8cfe7d --- /dev/null +++ b/lib/bloc/kanji/kanji_bloc.dart @@ -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 { + + KanjiBloc() : super(KanjiSearchInitial()); + + @override + Stream 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(); + } + } +} diff --git a/lib/bloc/kanji/kanji_event.dart b/lib/bloc/kanji/kanji_event.dart new file mode 100644 index 0000000..7bb79b8 --- /dev/null +++ b/lib/bloc/kanji/kanji_event.dart @@ -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(); +} \ No newline at end of file diff --git a/lib/bloc/kanji/kanji_state.dart b/lib/bloc/kanji/kanji_state.dart new file mode 100644 index 0000000..ad835db --- /dev/null +++ b/lib/bloc/kanji/kanji_state.dart @@ -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 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); +} \ No newline at end of file diff --git a/lib/bloc/search/search_bloc.dart b/lib/bloc/search/search_bloc.dart new file mode 100644 index 0000000..357dee1 --- /dev/null +++ b/lib/bloc/search/search_bloc.dart @@ -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 { + SearchBloc() : super(SearchInitial()); + + @override + Stream 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(); + } + } +} diff --git a/lib/bloc/search/search_event.dart b/lib/bloc/search/search_event.dart new file mode 100644 index 0000000..9b5d3f2 --- /dev/null +++ b/lib/bloc/search/search_event.dart @@ -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(); +} \ No newline at end of file diff --git a/lib/bloc/search/search_state.dart b/lib/bloc/search/search_state.dart new file mode 100644 index 0000000..4f934ee --- /dev/null +++ b/lib/bloc/search/search_state.dart @@ -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 results; + + const SearchFinished(this.results); +} + +class SearchError extends SearchState { + final String message; + + const SearchError(this.message); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji__search_page/kanji_search_page.dart b/lib/components/kanji/kanji__search_page/kanji_search_page.dart new file mode 100644 index 0000000..889a48f --- /dev/null +++ b/lib/components/kanji/kanji__search_page/kanji_search_page.dart @@ -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); +} diff --git a/lib/components/kanji/kanji__search_page/parts/examples.dart b/lib/components/kanji/kanji__search_page/parts/examples.dart new file mode 100644 index 0000000..f90911a --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/examples.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; +import 'package:unofficial_jisho_api/api.dart'; + +class Examples extends StatelessWidget { + final List _onyomiExamples; + final List _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, + ), + ), + ) + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/components/kanji/kanji__search_page/parts/grade.dart b/lib/components/kanji/kanji__search_page/parts/grade.dart new file mode 100644 index 0000000..c7422ea --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/grade.dart @@ -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); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji__search_page/parts/header.dart b/lib/components/kanji/kanji__search_page/parts/header.dart new file mode 100644 index 0000000..08d2211 --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/header.dart @@ -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); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji__search_page/parts/jlpt_level.dart b/lib/components/kanji/kanji__search_page/parts/jlpt_level.dart new file mode 100644 index 0000000..4f67fd3 --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/jlpt_level.dart @@ -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); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji__search_page/parts/kunyomi.dart b/lib/components/kanji/kanji__search_page/parts/kunyomi.dart new file mode 100644 index 0000000..2168303 --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/kunyomi.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; + +class Kunyomi extends StatelessWidget { + final List _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), + ), + ); + } +} diff --git a/lib/components/kanji/kanji__search_page/parts/meaning.dart b/lib/components/kanji/kanji__search_page/parts/meaning.dart new file mode 100644 index 0000000..daa9d8e --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/meaning.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +class Meaning extends StatelessWidget { + List _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); +} diff --git a/lib/components/kanji/kanji__search_page/parts/onyomi.dart b/lib/components/kanji/kanji__search_page/parts/onyomi.dart new file mode 100644 index 0000000..3d76434 --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/onyomi.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; + +class Onyomi extends StatelessWidget { + final List _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), + ), + ); + } +} diff --git a/lib/components/kanji/kanji__search_page/parts/radical.dart b/lib/components/kanji/kanji__search_page/parts/radical.dart new file mode 100644 index 0000000..fcc952e --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/radical.dart @@ -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); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji__search_page/parts/rank.dart b/lib/components/kanji/kanji__search_page/parts/rank.dart new file mode 100644 index 0000000..4202398 --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/rank.dart @@ -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); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji__search_page/parts/stroke_order_gif.dart b/lib/components/kanji/kanji__search_page/parts/stroke_order_gif.dart new file mode 100644 index 0000000..e99b7da --- /dev/null +++ b/lib/components/kanji/kanji__search_page/parts/stroke_order_gif.dart @@ -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); +} \ No newline at end of file diff --git a/lib/components/kanji/kanji_list/kanji_list.dart b/lib/components/kanji/kanji_list/kanji_list.dart new file mode 100644 index 0000000..b0f49fb --- /dev/null +++ b/lib/components/kanji/kanji_list/kanji_list.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +class KanjiGrid extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return GridView.count( + crossAxisCount: 3, + ); + } +} \ No newline at end of file diff --git a/lib/components/kanji/kanji_suggestions.dart b/lib/components/kanji/kanji_suggestions.dart new file mode 100644 index 0000000..ade96cb --- /dev/null +++ b/lib/components/kanji/kanji_suggestions.dart @@ -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 _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(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), + ), + ), + ), + ), + ); + } +} diff --git a/lib/components/kanji_search_card.dart b/lib/components/kanji_search_card.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/components/loading.dart b/lib/components/loading.dart new file mode 100644 index 0000000..327c44c --- /dev/null +++ b/lib/components/loading.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class LoadingScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: Center( + child: CircularProgressIndicator(), + ), + ); + } +} diff --git a/lib/components/search/parts/header.dart b/lib/components/search/parts/header.dart new file mode 100644 index 0000000..6b75b6a --- /dev/null +++ b/lib/components/search/parts/header.dart @@ -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), + ], + ), + ); + } +} diff --git a/lib/components/search/parts/other_forms.dart b/lib/components/search/parts/other_forms.dart new file mode 100644 index 0000000..ca83901 --- /dev/null +++ b/lib/components/search/parts/other_forms.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:unofficial_jisho_api/api.dart'; + +class OtherForms extends StatelessWidget { + final List _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), + ), + ], + ), + ); + } +} diff --git a/lib/components/search/parts/senses.dart b/lib/components/search/parts/senses.dart new file mode 100644 index 0000000..3d3771d --- /dev/null +++ b/lib/components/search/parts/senses.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:unofficial_jisho_api/parser.dart'; + +class Senses extends StatelessWidget { + final List _senses; + const Senses(this._senses); + + @override + Widget build(BuildContext context) { + final List _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(), + ) + ], + ), + ); + } +} diff --git a/lib/components/search/search_card.dart b/lib/components/search/search_card.dart new file mode 100644 index 0000000..20b2032 --- /dev/null +++ b/lib/components/search/search_card.dart @@ -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 _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), + ], + ); + } +} diff --git a/lib/components/wikipedia_attribute.dart b/lib/components/search/wikipedia_attribute.dart similarity index 100% rename from lib/components/wikipedia_attribute.dart rename to lib/components/search/wikipedia_attribute.dart diff --git a/lib/components/search_card.dart b/lib/components/search_card.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/components/yomi_card.dart b/lib/components/yomi_card.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/main.dart b/lib/main.dart index 2c1c9e8..7e91207 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,11 @@ 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()); @@ -7,11 +14,17 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'Jisho Study Tool', theme: ThemeData( 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 { @override _HomeState createState() => _HomeState(); - } class _HomeState extends State { int _selectedPage = 0; @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Jisho Study Tool') - ), - body: Container(), - bottomNavigationBar: BottomNavigationBar( - currentIndex: _selectedPage, - onTap: (int index) { - setState(() { - _selectedPage = index; - }); - }, - items: [ - BottomNavigationBarItem( - title: Text('Search'), - icon: Icon(Icons.search) - ), - BottomNavigationBarItem( - 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, - ), - ); - } + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: pages[_selectedPage].titleBar, + centerTitle: true, + ), + body: pages[_selectedPage].content, + bottomNavigationBar: BottomNavigationBar( + currentIndex: _selectedPage, + onTap: (int index) { + setState(() { + _selectedPage = index; + }); + }, + items: navBar, + showSelectedLabels: false, + showUnselectedLabels: false, + unselectedItemColor: Colors.blue, + selectedItemColor: Colors.green, + ), + ); + } +} -} \ No newline at end of file +final List 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 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"), + ), +]; diff --git a/lib/screens/history.dart b/lib/screens/history.dart new file mode 100644 index 0000000..0b16214 --- /dev/null +++ b/lib/screens/history.dart @@ -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(), + ); + } +} diff --git a/lib/screens/kanji_search.dart b/lib/screens/kanji_search.dart index e69de29..617423b 100644 --- a/lib/screens/kanji_search.dart +++ b/lib/screens/kanji_search.dart @@ -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( + listener: (context, state) { + if (state is KanjiSearchInitial) { + FocusScope.of(context).unfocus(); + } else if (state is KanjiSearchLoading) { + FocusScope.of(context).unfocus(); + } + }, + child: BlocBuilder( + 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(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(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(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(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, + ), + ); + } +} diff --git a/lib/screens/search.dart b/lib/screens/search.dart index e69de29..5dd8541 100644 --- a/lib/screens/search.dart +++ b/lib/screens/search.dart @@ -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( + listener: (context, state) {}, + child: BlocBuilder( + 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(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(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), + ], + ), + ], + ), + ); + } +} diff --git a/lib/services/jisho_search.dart b/lib/services/jisho_search.dart index e69de29..eb1e379 100644 --- a/lib/services/jisho_search.dart +++ b/lib/services/jisho_search.dart @@ -0,0 +1,5 @@ +import 'package:unofficial_jisho_api/api.dart' as jisho; + +Future fetchJishoResults(searchTerm) async { + return await jisho.searchForPhrase(searchTerm); +} \ No newline at end of file diff --git a/lib/services/kanji_search.dart b/lib/services/kanji_search.dart new file mode 100644 index 0000000..ff4b460 --- /dev/null +++ b/lib/services/kanji_search.dart @@ -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 fetchKanji(String kanji) async { + final result = await jisho.searchForKanji(kanji); + result.taughtIn = _convertGrade(result.taughtIn); + return result; +} \ No newline at end of file diff --git a/lib/services/kanji_suggestions.dart b/lib/services/kanji_suggestions.dart new file mode 100644 index 0000000..a2adfc2 --- /dev/null +++ b/lib/services/kanji_suggestions.dart @@ -0,0 +1,5 @@ +final kanjiPattern = RegExp(r'[\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A]'); + +List kanjiSuggestions(String string) { + return kanjiPattern.allMatches(string).map((match) => match.group(0)).toList(); +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 3b7e3ae..0000000 --- a/pubspec.lock +++ /dev/null @@ -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" diff --git a/pubspec.yaml b/pubspec.yaml index aa80cfc..ece49e4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,16 +1,5 @@ name: jisho_study_tool 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 environment: @@ -20,43 +9,24 @@ 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: ^0.1.2 - unofficial_jisho_api: ^1.0.2 + # cupertino_icons: ^0.1.2 + unofficial_jisho_api: ^1.1.0 + flutter_bloc: ^6.0.1 + url_launcher: ^5.5.0 + division: ^0.8.8 dev_dependencies: flutter_test: 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: - - # 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 - - # To add assets to your application, add an assets section, like this: + # assets: # - images/a_dot_burr.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: # - family: Schyler # fonts: @@ -68,6 +38,3 @@ flutter: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages