mirror of
https://github.com/h7x4/Jisho-Study-Tool.git
synced 2025-02-08 17:20:49 +01:00
Merge pull request #6 from h7x4ABk3g/refactor-1
Refactor, update bits and pieces, and clean up the code
This commit is contained in:
commit
8e11db856d
16
README.md
16
README.md
@ -4,17 +4,17 @@ A japanese dictionary with features for making studying the language easier.
|
|||||||
|
|
||||||
## Search
|
## Search
|
||||||
|
|
||||||
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
|
Standard search using Jishos API. This returns standard Jisho search results, including what you'd find if you searched through the search bar without any modifiers
|
||||||
|
|
||||||
## Kanji Search
|
## Kanji Search
|
||||||
|
|
||||||
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.
|
Jisho kanji search just like using the #kanji modifier in the jisho search bar. 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.
|
||||||
|
|
||||||
## Upcoming Features
|
## Upcoming Features
|
||||||
|
|
||||||
* Different kinds of kanji input like radicals and grade based lists
|
- [ ] Different kinds of kanji input like radicals and grade based lists
|
||||||
* Favorites, history and custom lists
|
- [ ] Favorites, history and custom lists
|
||||||
* Anki export
|
- [ ] Anki export
|
||||||
* Memo cards
|
- [ ] Memo cards
|
||||||
* Cloud sync
|
- [ ] Cloud sync
|
||||||
* Dark theme
|
- [ ] Dark theme
|
||||||
|
@ -4,7 +4,7 @@ import './kanji_event.dart';
|
|||||||
import './kanji_state.dart';
|
import './kanji_state.dart';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:jisho_study_tool/services/kanji_search.dart';
|
import 'package:jisho_study_tool/services/jisho_api/kanji_search.dart';
|
||||||
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
||||||
|
|
||||||
export './kanji_event.dart';
|
export './kanji_event.dart';
|
||||||
@ -15,16 +15,15 @@ class KanjiBloc extends Bloc<KanjiEvent, KanjiState> {
|
|||||||
KanjiBloc() : super(KanjiSearchInitial());
|
KanjiBloc() : super(KanjiSearchInitial());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<KanjiState> mapEventToState(
|
Stream<KanjiState> mapEventToState(KanjiEvent event)
|
||||||
KanjiEvent event,
|
async* {
|
||||||
) async* {
|
|
||||||
if (event is GetKanji) {
|
if (event is GetKanji) {
|
||||||
|
|
||||||
yield KanjiSearchLoading();
|
yield KanjiSearchLoading();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final _kanji = await fetchKanji(event.kanjiSearchString);
|
final kanji = await fetchKanji(event.kanjiSearchString);
|
||||||
if (_kanji.found) yield KanjiSearchFinished(kanji: _kanji);
|
if (kanji.found) yield KanjiSearchFinished(kanji: kanji);
|
||||||
else yield KanjiSearchError('Something went wrong');
|
else yield KanjiSearchError('Something went wrong');
|
||||||
} on Exception {
|
} on Exception {
|
||||||
yield KanjiSearchError('Something went wrong');
|
yield KanjiSearchError('Something went wrong');
|
||||||
|
@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/services/jisho_search.dart';
|
import 'package:jisho_study_tool/services/jisho_api/jisho_search.dart';
|
||||||
import 'package:unofficial_jisho_api/parser.dart';
|
import 'package:unofficial_jisho_api/parser.dart';
|
||||||
|
|
||||||
part 'search_event.dart';
|
part 'search_event.dart';
|
||||||
@ -22,8 +22,8 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {
|
|||||||
yield SearchLoading();
|
yield SearchLoading();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final _searchResults = await fetchJishoResults(event.searchString);
|
final searchResults = await fetchJishoResults(event.searchString);
|
||||||
if (_searchResults.meta.status == 200) yield SearchFinished(_searchResults.data);
|
if (searchResults.meta.status == 200) yield SearchFinished(searchResults.data);
|
||||||
} on Exception {
|
} on Exception {
|
||||||
yield SearchError('Something went wrong');
|
yield SearchError('Something went wrong');
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
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),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:mdi/mdi.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_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/view/screens/kanji_search.dart';
|
||||||
import 'package:jisho_study_tool/screens/history.dart';
|
import 'package:jisho_study_tool/view/screens/history.dart';
|
||||||
import 'package:jisho_study_tool/screens/search.dart';
|
import 'package:jisho_study_tool/view/screens/search.dart';
|
||||||
|
|
||||||
import 'bloc/search/search_bloc.dart';
|
import 'bloc/search/search_bloc.dart';
|
||||||
|
|
||||||
void main() => runApp(MyApp());
|
void main() => runApp(MyApp());
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
// This widget is the root of your application.
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
@ -35,21 +36,21 @@ class Home extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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: pages[_selectedPage].titleBar,
|
title: pages[selectedPage].titleBar,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
body: pages[_selectedPage].content,
|
body: pages[selectedPage].content,
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
currentIndex: _selectedPage,
|
currentIndex: selectedPage,
|
||||||
onTap: (int index) {
|
onTap: (int index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedPage = index;
|
selectedPage = index;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: navBar,
|
items: navBar,
|
||||||
@ -64,55 +65,55 @@ class _HomeState extends State<Home> {
|
|||||||
|
|
||||||
final List<BottomNavigationBarItem> navBar = [
|
final List<BottomNavigationBarItem> navBar = [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
title: Text('Search'),
|
label: 'Search',
|
||||||
icon: Icon(Icons.search),
|
icon: Icon(Icons.search),
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
title: Text('Kanji'),
|
label: 'Kanji',
|
||||||
icon: Text(
|
icon: Icon(Mdi.ideogramCjk, size: 30,)
|
||||||
'漢',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
title: Text('History'),
|
label: 'History',
|
||||||
icon: Icon(Icons.bookmark),
|
icon: Icon(Icons.bookmark),
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
title: Text('Memorize'),
|
label: 'Memorize',
|
||||||
icon: Icon(Icons.local_offer),
|
icon: Icon(Icons.local_offer),
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
title: Text('Settings'),
|
label: 'Settings',
|
||||||
icon: Icon(Icons.settings),
|
icon: Icon(Icons.settings),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
class Page {
|
class _Page {
|
||||||
Widget content;
|
Widget content;
|
||||||
Widget titleBar;
|
Widget titleBar;
|
||||||
|
|
||||||
Page({
|
_Page({
|
||||||
this.content,
|
this.content,
|
||||||
this.titleBar,
|
this.titleBar,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Page> pages = [
|
final List<_Page> pages = [
|
||||||
Page(content: SearchView(), titleBar: Text('Search')),
|
_Page(
|
||||||
Page(
|
content: SearchView(),
|
||||||
|
titleBar: Text('Search'),
|
||||||
|
),
|
||||||
|
_Page(
|
||||||
content: KanjiView(),
|
content: KanjiView(),
|
||||||
titleBar: KanjiViewBar(),
|
titleBar: KanjiViewBar(),
|
||||||
),
|
),
|
||||||
Page(
|
_Page(
|
||||||
content: HistoryView(),
|
content: HistoryView(),
|
||||||
titleBar: Text("History"),
|
titleBar: Text("History"),
|
||||||
),
|
),
|
||||||
Page(
|
_Page(
|
||||||
content: Container(),
|
content: Container(),
|
||||||
titleBar: Text("Memorization"),
|
titleBar: Text("Memorization"),
|
||||||
),
|
),
|
||||||
Page(
|
_Page(
|
||||||
content: Container(),
|
content: Container(),
|
||||||
titleBar: Text("Settings"),
|
titleBar: Text("Settings"),
|
||||||
),
|
),
|
||||||
|
@ -1,153 +0,0 @@
|
|||||||
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,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
String _convertGrade(String grade) {
|
String _convertGrade(String grade) {
|
||||||
const _conversionTable = {
|
const conversionTable = {
|
||||||
"grade 1": "小1",
|
"grade 1": "小1",
|
||||||
"grade 2": "小2",
|
"grade 2": "小2",
|
||||||
"grade 3": "小3",
|
"grade 3": "小3",
|
||||||
@ -11,9 +11,9 @@ String _convertGrade(String grade) {
|
|||||||
"junior high": "中"
|
"junior high": "中"
|
||||||
};
|
};
|
||||||
|
|
||||||
print('conversion run: $grade -> ${_conversionTable[grade]}');
|
print('conversion run: $grade -> ${conversionTable[grade]}');
|
||||||
|
|
||||||
return _conversionTable[grade];
|
return conversionTable[grade];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<jisho.KanjiResult> fetchKanji(String kanji) async {
|
Future<jisho.KanjiResult> fetchKanji(String kanji) async {
|
88
lib/view/components/kanji/kanji_search_bar.dart
Normal file
88
lib/view/components/kanji/kanji_search_bar.dart
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
class KanjiSearchBar extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_KanjiSearchBarState createState() => new _KanjiSearchBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextFieldButton {clear, paste}
|
||||||
|
|
||||||
|
class _KanjiSearchBarState extends State<KanjiSearchBar> {
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ import 'parts/kunyomi.dart';
|
|||||||
import 'parts/examples.dart';
|
import 'parts/examples.dart';
|
||||||
|
|
||||||
class KanjiResultCard extends StatelessWidget {
|
class KanjiResultCard extends StatelessWidget {
|
||||||
final jisho.KanjiResult _result;
|
final jisho.KanjiResult result;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -33,26 +33,26 @@ class KanjiResultCard extends StatelessWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
fit: FlexFit.tight,
|
fit: FlexFit.tight,
|
||||||
child: Center(child: Header(_result.query)),
|
child: Center(child: Header(result.query)),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
fit: FlexFit.tight,
|
fit: FlexFit.tight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Radical(_result.radical),
|
child: Radical(result.radical),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Meaning(_result.meaning),
|
Meaning(result.meaning),
|
||||||
_result.onyomi.length != 0 ? Onyomi(_result.onyomi) : SizedBox.shrink(),
|
result.onyomi.length != 0 ? Onyomi(result.onyomi) : SizedBox.shrink(),
|
||||||
_result.kunyomi.length != 0 ? Kunyomi(_result.kunyomi) : SizedBox.shrink(),
|
result.kunyomi.length != 0 ? Kunyomi(result.kunyomi) : SizedBox.shrink(),
|
||||||
IntrinsicHeight(
|
IntrinsicHeight(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
StrokeOrderGif(_result.strokeOrderGifUri),
|
StrokeOrderGif(result.strokeOrderGifUri),
|
||||||
Container(
|
Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
@ -61,19 +61,19 @@ class KanjiResultCard extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text("JLPT: ", style: TextStyle(fontSize: 20.0)),
|
Text("JLPT: ", style: TextStyle(fontSize: 20.0)),
|
||||||
JlptLevel(_result.jlptLevel ?? "⨉"),
|
JlptLevel(result.jlptLevel ?? "⨉"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text("Grade: ", style: TextStyle(fontSize: 20.0)),
|
Text("Grade: ", style: TextStyle(fontSize: 20.0)),
|
||||||
Grade(_result.taughtIn ?? "⨉"),
|
Grade(result.taughtIn ?? "⨉"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text("Rank: ", style: TextStyle(fontSize: 20.0)),
|
Text("Rank: ", style: TextStyle(fontSize: 20.0)),
|
||||||
Rank(_result.newspaperFrequencyRank ?? -1),
|
Rank(result.newspaperFrequencyRank ?? -1),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -82,10 +82,10 @@ class KanjiResultCard extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Examples(_result.onyomiExamples, _result.kunyomiExamples),
|
Examples(result.onyomiExamples, result.kunyomiExamples),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
KanjiResultCard(this._result);
|
KanjiResultCard(this.result);
|
||||||
}
|
}
|
@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
class Examples extends StatelessWidget {
|
class Examples extends StatelessWidget {
|
||||||
final List<YomiExample> _onyomiExamples;
|
final List<YomiExample> onyomiExamples;
|
||||||
final List<YomiExample> _kunyomiExamples;
|
final List<YomiExample> kunyomiExamples;
|
||||||
|
|
||||||
const Examples(
|
const Examples(
|
||||||
this._onyomiExamples,
|
this.onyomiExamples,
|
||||||
this._kunyomiExamples,
|
this.kunyomiExamples,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -30,10 +30,10 @@ class Examples extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
_onyomiExamples
|
onyomiExamples
|
||||||
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
||||||
.toList(),
|
.toList(),
|
||||||
_kunyomiExamples
|
kunyomiExamples
|
||||||
.map((kunyomiExample) =>
|
.map((kunyomiExample) =>
|
||||||
_Example(kunyomiExample, _KanaType.kunyomi))
|
_Example(kunyomiExample, _KanaType.kunyomi))
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -44,10 +44,10 @@ class Examples extends StatelessWidget {
|
|||||||
enum _KanaType { kunyomi, onyomi }
|
enum _KanaType { kunyomi, onyomi }
|
||||||
|
|
||||||
class _Example extends StatelessWidget {
|
class _Example extends StatelessWidget {
|
||||||
final _KanaType _kanaType;
|
final _KanaType kanaType;
|
||||||
final YomiExample _yomiExample;
|
final YomiExample yomiExample;
|
||||||
|
|
||||||
const _Example(this._yomiExample, this._kanaType);
|
const _Example(this.yomiExample, this.kanaType);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -67,7 +67,7 @@ class _Example extends StatelessWidget {
|
|||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: (_kanaType == _KanaType.kunyomi)
|
color: (kanaType == _KanaType.kunyomi)
|
||||||
? Colors.lightBlue
|
? Colors.lightBlue
|
||||||
: Colors.orange,
|
: Colors.orange,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
@ -79,7 +79,7 @@ class _Example extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
child: Text(
|
child: Text(
|
||||||
_yomiExample.reading,
|
yomiExample.reading,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 15.0,
|
fontSize: 15.0,
|
||||||
@ -91,7 +91,7 @@ class _Example extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
child: Text(
|
child: Text(
|
||||||
_yomiExample.example,
|
yomiExample.example,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
@ -109,7 +109,7 @@ class _Example extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
child: Text(
|
child: Text(
|
||||||
_yomiExample.meaning,
|
yomiExample.meaning,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
@ -1,14 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Grade extends StatelessWidget {
|
class Grade extends StatelessWidget {
|
||||||
final String _grade;
|
final String grade;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
_grade,
|
grade,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
@ -21,5 +21,5 @@ class Grade extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grade(this._grade);
|
Grade(this.grade);
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Header extends StatelessWidget {
|
class Header extends StatelessWidget {
|
||||||
final String _kanji;
|
final String kanji;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -11,12 +11,12 @@ class Header extends StatelessWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
_kanji,
|
kanji,
|
||||||
style: TextStyle(fontSize: 80.0, color: Colors.white),
|
style: TextStyle(fontSize: 80.0, color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Header(this._kanji);
|
Header(this.kanji);
|
||||||
}
|
}
|
@ -2,14 +2,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class JlptLevel extends StatelessWidget {
|
class JlptLevel extends StatelessWidget {
|
||||||
final String _jlptLevel;
|
final String jlptLevel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
_jlptLevel,
|
jlptLevel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
@ -22,5 +22,5 @@ class JlptLevel extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
JlptLevel(this._jlptLevel);
|
JlptLevel(this.jlptLevel);
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Kunyomi extends StatelessWidget {
|
class Kunyomi extends StatelessWidget {
|
||||||
final List<String> _kunyomi;
|
final List<String> kunyomi;
|
||||||
List<_KunyomiCard> _kunyomiCards;
|
List<_KunyomiCard> kunyomiCards;
|
||||||
bool _expandable;
|
bool expandable;
|
||||||
|
|
||||||
Kunyomi(this._kunyomi) {
|
Kunyomi(this.kunyomi) {
|
||||||
_kunyomiCards = _kunyomi.map((kunyomi) => _KunyomiCard(kunyomi)).toList();
|
kunyomiCards = kunyomi.map((kunyomi) => _KunyomiCard(kunyomi)).toList();
|
||||||
_expandable = (_kunyomi.length > 6);
|
expandable = (kunyomi.length > 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -23,7 +23,7 @@ class Kunyomi extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _KunyomiWrapper(BuildContext context) {
|
Widget _KunyomiWrapper(BuildContext context) {
|
||||||
if (_expandable) {
|
if (expandable) {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
initiallyExpanded: false,
|
initiallyExpanded: false,
|
||||||
title: Center(child: _KunyomiCard('Kunyomi')),
|
title: Center(child: _KunyomiCard('Kunyomi')),
|
||||||
@ -33,7 +33,7 @@ class Kunyomi extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Wrap(
|
Wrap(
|
||||||
runSpacing: 10.0,
|
runSpacing: 10.0,
|
||||||
children: _kunyomiCards,
|
children: kunyomiCards,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 25.0,
|
height: 25.0,
|
||||||
@ -43,15 +43,15 @@ class Kunyomi extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
return Wrap(
|
return Wrap(
|
||||||
runSpacing: 10.0,
|
runSpacing: 10.0,
|
||||||
children: _kunyomiCards,
|
children: kunyomiCards,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _KunyomiCard extends StatelessWidget {
|
class _KunyomiCard extends StatelessWidget {
|
||||||
final String _kunyomi;
|
final String kunyomi;
|
||||||
const _KunyomiCard(this._kunyomi);
|
const _KunyomiCard(this.kunyomi);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -62,7 +62,7 @@ class _KunyomiCard extends StatelessWidget {
|
|||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_kunyomi,
|
kunyomi,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Meaning extends StatelessWidget {
|
class Meaning extends StatelessWidget {
|
||||||
List<String> _meanings;
|
List<String> meanings;
|
||||||
List<_MeaningCard> _meaningCards;
|
List<_MeaningCard> meaningCards;
|
||||||
bool _expandable;
|
bool expandable;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -18,7 +18,7 @@ class Meaning extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _MeaningWrapper(BuildContext context) {
|
Widget _MeaningWrapper(BuildContext context) {
|
||||||
if (_expandable) {
|
if (expandable) {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
initiallyExpanded: false,
|
initiallyExpanded: false,
|
||||||
title: Center(child: _MeaningCard('Meanings')),
|
title: Center(child: _MeaningCard('Meanings')),
|
||||||
@ -28,7 +28,7 @@ class Meaning extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Wrap(
|
Wrap(
|
||||||
runSpacing: 10.0,
|
runSpacing: 10.0,
|
||||||
children: _meaningCards,
|
children: meaningCards,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 25.0,
|
height: 25.0,
|
||||||
@ -38,21 +38,21 @@ class Meaning extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
return Wrap(
|
return Wrap(
|
||||||
runSpacing: 10.0,
|
runSpacing: 10.0,
|
||||||
children: _meaningCards,
|
children: meaningCards,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Meaning(_meaning) {
|
Meaning(meaning) {
|
||||||
this._meanings = _meaning.split(', ');
|
this.meanings = meaning.split(', ');
|
||||||
this._meaningCards =
|
this.meaningCards =
|
||||||
_meanings.map((meaning) => _MeaningCard(meaning)).toList();
|
meanings.map((m) => _MeaningCard(m)).toList();
|
||||||
this._expandable = (this._meanings.length > 6);
|
this.expandable = (this.meanings.length > 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MeaningCard extends StatelessWidget {
|
class _MeaningCard extends StatelessWidget {
|
||||||
final String _meaning;
|
final String meaning;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -63,7 +63,7 @@ class _MeaningCard extends StatelessWidget {
|
|||||||
vertical: 10.0,
|
vertical: 10.0,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_meaning,
|
meaning,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@ -76,5 +76,5 @@ class _MeaningCard extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_MeaningCard(this._meaning);
|
_MeaningCard(this.meaning);
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Onyomi extends StatelessWidget {
|
class Onyomi extends StatelessWidget {
|
||||||
final List<String> _onyomi;
|
final List<String> onyomi;
|
||||||
List<_OnyomiCard> _onyomiCards;
|
List<_OnyomiCard> onyomiCards;
|
||||||
bool _expandable;
|
bool expandable;
|
||||||
|
|
||||||
Onyomi(this._onyomi) {
|
Onyomi(this.onyomi) {
|
||||||
_onyomiCards = _onyomi.map((onyomi) => _OnyomiCard(onyomi)).toList();
|
onyomiCards = onyomi.map((onyomi) => _OnyomiCard(onyomi)).toList();
|
||||||
_expandable = (_onyomi.length > 6);
|
expandable = (onyomi.length > 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -23,7 +23,7 @@ class Onyomi extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _OnyomiWrapper(BuildContext context) {
|
Widget _OnyomiWrapper(BuildContext context) {
|
||||||
if (_expandable) {
|
if (expandable) {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
initiallyExpanded: false,
|
initiallyExpanded: false,
|
||||||
title: Center(child: _OnyomiCard('Onyomi')),
|
title: Center(child: _OnyomiCard('Onyomi')),
|
||||||
@ -33,7 +33,7 @@ class Onyomi extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Wrap(
|
Wrap(
|
||||||
runSpacing: 10.0,
|
runSpacing: 10.0,
|
||||||
children: _onyomiCards,
|
children: onyomiCards,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 25.0,
|
height: 25.0,
|
||||||
@ -43,15 +43,15 @@ class Onyomi extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
return Wrap(
|
return Wrap(
|
||||||
runSpacing: 10.0,
|
runSpacing: 10.0,
|
||||||
children: _onyomiCards,
|
children: onyomiCards,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OnyomiCard extends StatelessWidget {
|
class _OnyomiCard extends StatelessWidget {
|
||||||
final String _onyomi;
|
final String onyomi;
|
||||||
const _OnyomiCard(this._onyomi);
|
const _OnyomiCard(this.onyomi);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -62,7 +62,7 @@ class _OnyomiCard extends StatelessWidget {
|
|||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_onyomi,
|
onyomi,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
class Radical extends StatelessWidget {
|
class Radical extends StatelessWidget {
|
||||||
final jisho.Radical _radical;
|
final jisho.Radical radical;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
_radical.symbol,
|
radical.symbol,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 40.0,
|
fontSize: 40.0,
|
||||||
@ -22,5 +22,5 @@ class Radical extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Radical(this._radical);
|
Radical(this.radical);
|
||||||
}
|
}
|
@ -2,14 +2,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Rank extends StatelessWidget {
|
class Rank extends StatelessWidget {
|
||||||
final int _rank;
|
final int rank;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${_rank.toString()} / 2500',
|
'${rank.toString()} / 2500',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
@ -22,5 +22,5 @@ class Rank extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rank(this._rank);
|
Rank(this.rank);
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StrokeOrderGif extends StatelessWidget {
|
class StrokeOrderGif extends StatelessWidget {
|
||||||
final String _uri;
|
final String uri;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -9,7 +9,7 @@ class StrokeOrderGif extends StatelessWidget {
|
|||||||
margin: EdgeInsets.symmetric(vertical: 20.0),
|
margin: EdgeInsets.symmetric(vertical: 20.0),
|
||||||
padding: EdgeInsets.all(5.0),
|
padding: EdgeInsets.all(5.0),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
child: Image.network(_uri),
|
child: Image.network(uri),
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -19,5 +19,5 @@ class StrokeOrderGif extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
StrokeOrderGif(this._uri);
|
StrokeOrderGif(this.uri);
|
||||||
}
|
}
|
@ -3,8 +3,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
|
|
||||||
class KanjiSuggestions extends StatelessWidget {
|
class KanjiSuggestions extends StatelessWidget {
|
||||||
final List<String> _suggestions;
|
final List<String> suggestions;
|
||||||
const KanjiSuggestions(this._suggestions);
|
const KanjiSuggestions(this.suggestions);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -18,21 +18,21 @@ class KanjiSuggestions extends StatelessWidget {
|
|||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
crossAxisSpacing: 40.0,
|
crossAxisSpacing: 40.0,
|
||||||
children: _suggestions.map((kanji) => _Suggestion(kanji)).toList(),
|
children: suggestions.map((kanji) => _Suggestion(kanji)).toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Suggestion extends StatelessWidget {
|
class _Suggestion extends StatelessWidget {
|
||||||
final String _kanji;
|
final String kanji;
|
||||||
const _Suggestion(this._kanji);
|
const _Suggestion(this.kanji);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
BlocProvider.of<KanjiBloc>(context).add(GetKanji(_kanji));
|
BlocProvider.of<KanjiBloc>(context).add(GetKanji(kanji));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -43,7 +43,7 @@ class _Suggestion extends StatelessWidget {
|
|||||||
margin: EdgeInsets.all(10.0),
|
margin: EdgeInsets.all(10.0),
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
child: Text(
|
child: Text(
|
||||||
_kanji,
|
kanji,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
76
lib/view/components/search/LanguageSelector.dart
Normal file
76
lib/view/components/search/LanguageSelector.dart
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class LanguageSelector extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_LanguageSelectorState createState() => new _LanguageSelectorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LanguageSelectorState extends State<LanguageSelector> {
|
||||||
|
SharedPreferences prefs;
|
||||||
|
List<bool> isSelected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
isSelected = [false, false, false];
|
||||||
|
|
||||||
|
SharedPreferences.getInstance()
|
||||||
|
.then((prefs) {
|
||||||
|
this.prefs = prefs;
|
||||||
|
setState(() {
|
||||||
|
isSelected = _getSelectedStatus() ?? isSelected;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateSelectedStatus() async {
|
||||||
|
await prefs.setStringList('languageSelectorStatus',
|
||||||
|
isSelected
|
||||||
|
.map((b) => b ? '1' : '0')
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<bool> _getSelectedStatus() {
|
||||||
|
return prefs
|
||||||
|
.getStringList('languageSelectorStatus')
|
||||||
|
?.map((s) => s == '1')
|
||||||
|
?.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ToggleButtons(
|
||||||
|
isSelected: isSelected,
|
||||||
|
children: <Widget> [
|
||||||
|
_LanguageOption("Auto"),
|
||||||
|
_LanguageOption("Japanese"),
|
||||||
|
_LanguageOption("English")
|
||||||
|
],
|
||||||
|
selectedColor: Colors.blue,
|
||||||
|
onPressed: (int buttonIndex) {
|
||||||
|
setState(() {
|
||||||
|
for (var i in Iterable.generate(isSelected.length)) {
|
||||||
|
isSelected[i] = i == buttonIndex;
|
||||||
|
}
|
||||||
|
_updateSelectedStatus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LanguageOption extends StatelessWidget {
|
||||||
|
final String language;
|
||||||
|
|
||||||
|
_LanguageOption(this.language);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||||
|
child: Center(child: Text(language)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
32
lib/view/components/search/search_bar.dart
Normal file
32
lib/view/components/search/search_bar.dart
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
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/view/components/search/LanguageSelector.dart';
|
||||||
|
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
LanguageSelector()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,20 +2,20 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
class JapaneseHeader extends StatelessWidget {
|
class JapaneseHeader extends StatelessWidget {
|
||||||
final JishoJapaneseWord _word;
|
final JishoJapaneseWord word;
|
||||||
const JapaneseHeader(this._word);
|
const JapaneseHeader(this.word);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final hasFurigana = (_word.word != null);
|
final hasFurigana = (word.word != null && word.reading != null);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
padding: EdgeInsets.only(left: 10.0),
|
padding: EdgeInsets.only(left: 10.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
(hasFurigana) ? Text(_word.reading) : Text(''),
|
(hasFurigana) ? Text(word.reading) : Text(''),
|
||||||
(hasFurigana) ? Text(_word.word) : Text(_word.reading),
|
(hasFurigana) ? Text(word.word) : Text(word.reading ?? word.word),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
class OtherForms extends StatelessWidget {
|
class OtherForms extends StatelessWidget {
|
||||||
final List<JishoJapaneseWord> _otherForms;
|
final List<JishoJapaneseWord> otherForms;
|
||||||
OtherForms(this._otherForms);
|
OtherForms(this.otherForms);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -15,7 +15,7 @@ class OtherForms extends StatelessWidget {
|
|||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: _otherForms.map((form) => _KanaBox(form)).toList(),
|
children: otherForms.map((form) => _KanaBox(form)).toList(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -24,18 +24,18 @@ class OtherForms extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _KanaBox extends StatelessWidget {
|
class _KanaBox extends StatelessWidget {
|
||||||
final JishoJapaneseWord _word;
|
final JishoJapaneseWord word;
|
||||||
const _KanaBox(this._word);
|
const _KanaBox(this.word);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final hasFurigana = (_word.word != null);
|
final hasFurigana = (word.word != null);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
(hasFurigana) ? Text(_word.reading) : Text(''),
|
(hasFurigana) ? Text(word.reading) : Text(''),
|
||||||
(hasFurigana) ? Text(_word.word) : Text(_word.reading),
|
(hasFurigana) ? Text(word.word) : Text(word.reading),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
margin: EdgeInsets.symmetric(
|
margin: EdgeInsets.symmetric(
|
@ -2,24 +2,24 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:unofficial_jisho_api/parser.dart';
|
import 'package:unofficial_jisho_api/parser.dart';
|
||||||
|
|
||||||
class Senses extends StatelessWidget {
|
class Senses extends StatelessWidget {
|
||||||
final List<JishoWordSense> _senses;
|
final List<JishoWordSense> senses;
|
||||||
const Senses(this._senses);
|
const Senses(this.senses);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<Widget> _senseWidgets =
|
final List<Widget> senseWidgets =
|
||||||
_senses.map((sense) => _Sense(sense)).toList();
|
senses.map((sense) => _Sense(sense)).toList();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: _senseWidgets,
|
children: senseWidgets,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Sense extends StatelessWidget {
|
class _Sense extends StatelessWidget {
|
||||||
final JishoWordSense _sense;
|
final JishoWordSense sense;
|
||||||
const _Sense(this._sense);
|
const _Sense(this.sense);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -27,13 +27,13 @@ class _Sense extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
_sense.parts_of_speech.join(', '),
|
sense.parts_of_speech.join(', '),
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children:
|
children:
|
||||||
_sense.english_definitions.map((def) => Text(def)).toList(),
|
sense.english_definitions.map((def) => Text(def)).toList(),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
@ -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),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
69
lib/view/screens/kanji_search.dart
Normal file
69
lib/view/screens/kanji_search.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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/view/components/kanji/kanji_search_bar.dart';
|
||||||
|
import 'package:jisho_study_tool/view/components/kanji/kanji_search_result_page/kanji_search_result_page.dart';
|
||||||
|
import 'package:jisho_study_tool/view/components/kanji/kanji_search_suggestion_list/kanji_search_suggestion_list.dart';
|
||||||
|
import 'package:jisho_study_tool/view/screens/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: KanjiSearchBar(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.star_border),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
47
lib/view/screens/search.dart
Normal file
47
lib/view/screens/search.dart
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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/view/components/search/search_bar.dart';
|
||||||
|
import 'package:jisho_study_tool/view/screens/loading.dart';
|
||||||
|
import 'package:jisho_study_tool/view/components/search/search_result_page/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(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -9,9 +9,12 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
shared_preferences: "^2.0.3"
|
||||||
|
|
||||||
# cupertino_icons: ^0.1.2
|
# cupertino_icons: ^0.1.2
|
||||||
|
mdi: ^3.0.0
|
||||||
unofficial_jisho_api: ^1.1.0
|
unofficial_jisho_api: ^1.1.0
|
||||||
flutter_bloc: ^6.0.1
|
flutter_bloc: ^6.1.0
|
||||||
url_launcher: ^5.5.0
|
url_launcher: ^5.5.0
|
||||||
division: ^0.8.8
|
division: ^0.8.8
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user