From 76d2b090f3e9f88d32644a07a83527db565f62e1 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Tue, 21 Jul 2020 23:29:02 +0200 Subject: [PATCH] JST 4 - Add kanji search suggestions (#3) * Add division package * Add base logic and widget * Finish layout * Fix kanji regex * Add bloc logic --- lib/bloc/kanji/kanji_bloc.dart | 5 ++ lib/bloc/kanji/kanji_event.dart | 10 ++-- lib/bloc/kanji/kanji_state.dart | 17 ++++--- lib/components/kanji/kanji_suggestions.dart | 55 +++++++++++++++++++++ lib/screens/kanji_search.dart | 4 ++ lib/services/kanji_suggestions.dart | 5 ++ pubspec.lock | 32 ++++++++---- pubspec.yaml | 39 +-------------- 8 files changed, 111 insertions(+), 56 deletions(-) create mode 100644 lib/components/kanji/kanji_suggestions.dart create mode 100644 lib/services/kanji_suggestions.dart diff --git a/lib/bloc/kanji/kanji_bloc.dart b/lib/bloc/kanji/kanji_bloc.dart index 593baf2..a8cfe7d 100644 --- a/lib/bloc/kanji/kanji_bloc.dart +++ b/lib/bloc/kanji/kanji_bloc.dart @@ -5,6 +5,7 @@ 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'; @@ -28,6 +29,10 @@ class KanjiBloc extends Bloc { } 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 index 6bbe8e5..7bb79b8 100644 --- a/lib/bloc/kanji/kanji_event.dart +++ b/lib/bloc/kanji/kanji_event.dart @@ -2,12 +2,16 @@ abstract class KanjiEvent { const KanjiEvent(); } +class GetKanjiSuggestions extends KanjiEvent { + final String searchString; + const GetKanjiSuggestions(this.searchString); +} + class GetKanji extends KanjiEvent { final String kanjiSearchString; - - GetKanji(this.kanjiSearchString); + const GetKanji(this.kanjiSearchString); } class ReturnToInitialState extends KanjiEvent { - ReturnToInitialState(); + const ReturnToInitialState(); } \ No newline at end of file diff --git a/lib/bloc/kanji/kanji_state.dart b/lib/bloc/kanji/kanji_state.dart index 7e5aff2..ad835db 100644 --- a/lib/bloc/kanji/kanji_state.dart +++ b/lib/bloc/kanji/kanji_state.dart @@ -5,18 +5,23 @@ abstract class KanjiState { } class KanjiSearchInitial extends KanjiState { - KanjiSearchInitial(); + const KanjiSearchInitial(); +} + +class KanjiSearchInput extends KanjiState { + final List kanjiSuggestions; + const KanjiSearchInput(this.kanjiSuggestions); } class KanjiSearchLoading extends KanjiState { - KanjiSearchLoading(); + const KanjiSearchLoading(); } class KanjiSearchFinished extends KanjiState { final KanjiResult kanji; final bool starred; - KanjiSearchFinished({ + const KanjiSearchFinished({ this.kanji, this.starred = false, }); @@ -25,7 +30,5 @@ class KanjiSearchFinished extends KanjiState { class KanjiSearchError extends KanjiState { final String message; - KanjiSearchError(this.message); -} - -class ReKanjiSearch extends KanjiState {} + const KanjiSearchError(this.message); +} \ 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..3c0a044 --- /dev/null +++ b/lib/components/kanji/kanji_suggestions.dart @@ -0,0 +1,55 @@ +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: () { + FocusScope.of(context).unfocus(); //Puts away the keyboard + 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/screens/kanji_search.dart b/lib/screens/kanji_search.dart index 03f9100..2a0fc7d 100644 --- a/lib/screens/kanji_search.dart +++ b/lib/screens/kanji_search.dart @@ -3,6 +3,7 @@ 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 { @@ -12,6 +13,8 @@ class KanjiView extends StatelessWidget { 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) @@ -42,6 +45,7 @@ class KanjiViewBar extends StatelessWidget { child: Container( padding: EdgeInsets.symmetric(vertical: 10.0), child: TextField( + onChanged: (text) => BlocProvider.of(context).add(GetKanjiSuggestions(text)), onSubmitted: (text) => BlocProvider.of(context).add(GetKanji(text)), decoration: new InputDecoration( 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 index 84e8413..c88cf25 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.4.2" bloc: dependency: transitive description: @@ -22,6 +22,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0-nullsafety" charcode: dependency: transitive description: @@ -42,7 +49,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.12" + version: "1.15.0-nullsafety" csslib: dependency: transitive description: @@ -57,6 +64,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + division: + dependency: "direct main" + description: + name: division + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.8" fake_async: dependency: transitive description: @@ -127,14 +141,14 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.9" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0-nullsafety" nested: dependency: transitive description: @@ -202,7 +216,7 @@ packages: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.9.5" stream_channel: dependency: transitive description: @@ -230,14 +244,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.16" + version: "0.2.18" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.0-nullsafety" unofficial_jisho_api: dependency: "direct main" description: @@ -286,7 +300,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0-nullsafety" sdks: - dart: ">=2.7.0 <3.0.0" + dart: ">=2.9.0-18.0 <2.9.0" flutter: ">=1.16.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7b108ef..7129eb3 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,45 +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.1.0 flutter_bloc: ^5.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: @@ -70,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