JST 4 - Add kanji search suggestions (#3)

* Add division package

* Add base logic and widget

* Finish layout

* Fix kanji regex

* Add bloc logic
This commit is contained in:
Oystein Kristoffer Tveit 2020-07-21 23:29:02 +02:00 committed by GitHub
parent 2f63c202fc
commit 76d2b090f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 111 additions and 56 deletions

View File

@ -5,6 +5,7 @@ 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/kanji_search.dart';
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
export './kanji_event.dart'; export './kanji_event.dart';
export './kanji_state.dart'; export './kanji_state.dart';
@ -28,6 +29,10 @@ class KanjiBloc extends Bloc<KanjiEvent, KanjiState> {
} on Exception { } on Exception {
yield KanjiSearchError('Something went wrong'); yield KanjiSearchError('Something went wrong');
} }
} else if (event is GetKanjiSuggestions) {
final suggestions = kanjiSuggestions(event.searchString);
yield KanjiSearchInput(suggestions);
} else if (event is ReturnToInitialState) { } else if (event is ReturnToInitialState) {
yield KanjiSearchInitial(); yield KanjiSearchInitial();

View File

@ -2,12 +2,16 @@ abstract class KanjiEvent {
const KanjiEvent(); const KanjiEvent();
} }
class GetKanjiSuggestions extends KanjiEvent {
final String searchString;
const GetKanjiSuggestions(this.searchString);
}
class GetKanji extends KanjiEvent { class GetKanji extends KanjiEvent {
final String kanjiSearchString; final String kanjiSearchString;
const GetKanji(this.kanjiSearchString);
GetKanji(this.kanjiSearchString);
} }
class ReturnToInitialState extends KanjiEvent { class ReturnToInitialState extends KanjiEvent {
ReturnToInitialState(); const ReturnToInitialState();
} }

View File

@ -5,18 +5,23 @@ abstract class KanjiState {
} }
class KanjiSearchInitial extends KanjiState { class KanjiSearchInitial extends KanjiState {
KanjiSearchInitial(); const KanjiSearchInitial();
}
class KanjiSearchInput extends KanjiState {
final List<String> kanjiSuggestions;
const KanjiSearchInput(this.kanjiSuggestions);
} }
class KanjiSearchLoading extends KanjiState { class KanjiSearchLoading extends KanjiState {
KanjiSearchLoading(); const KanjiSearchLoading();
} }
class KanjiSearchFinished extends KanjiState { class KanjiSearchFinished extends KanjiState {
final KanjiResult kanji; final KanjiResult kanji;
final bool starred; final bool starred;
KanjiSearchFinished({ const KanjiSearchFinished({
this.kanji, this.kanji,
this.starred = false, this.starred = false,
}); });
@ -25,7 +30,5 @@ class KanjiSearchFinished extends KanjiState {
class KanjiSearchError extends KanjiState { class KanjiSearchError extends KanjiState {
final String message; final String message;
KanjiSearchError(this.message); const KanjiSearchError(this.message);
} }
class ReKanjiSearch extends KanjiState {}

View File

@ -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<String> _suggestions;
const KanjiSuggestions(this._suggestions);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.grey[300],
padding: EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 40.0,
),
child: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 20.0,
crossAxisSpacing: 40.0,
children: _suggestions.map((kanji) => _Suggestion(kanji)).toList(),
),
);
}
}
class _Suggestion extends StatelessWidget {
final String _kanji;
const _Suggestion(this._kanji);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
FocusScope.of(context).unfocus(); //Puts away the keyboard
BlocProvider.of<KanjiBloc>(context).add(GetKanji(_kanji));
},
child: Container(
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(10.0),
),
child: Container(
margin: EdgeInsets.all(10.0),
child: FittedBox(
child: Text(
_kanji,
style: TextStyle(color: Colors.white),
),
),
),
),
);
}
}

View File

@ -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/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__search_page/kanji_search_page.dart';
import 'package:jisho_study_tool/components/kanji/kanji_suggestions.dart';
import 'package:jisho_study_tool/components/loading.dart'; import 'package:jisho_study_tool/components/loading.dart';
class KanjiView extends StatelessWidget { class KanjiView extends StatelessWidget {
@ -12,6 +13,8 @@ class KanjiView extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
if (state is KanjiSearchInitial) if (state is KanjiSearchInitial)
return Container(); return Container();
else if (state is KanjiSearchInput)
return KanjiSuggestions(state.kanjiSuggestions);
else if (state is KanjiSearchLoading) else if (state is KanjiSearchLoading)
return LoadingScreen(); return LoadingScreen();
else if (state is KanjiSearchFinished) else if (state is KanjiSearchFinished)
@ -42,6 +45,7 @@ class KanjiViewBar extends StatelessWidget {
child: Container( child: Container(
padding: EdgeInsets.symmetric(vertical: 10.0), padding: EdgeInsets.symmetric(vertical: 10.0),
child: TextField( child: TextField(
onChanged: (text) => BlocProvider.of<KanjiBloc>(context).add(GetKanjiSuggestions(text)),
onSubmitted: (text) => onSubmitted: (text) =>
BlocProvider.of<KanjiBloc>(context).add(GetKanji(text)), BlocProvider.of<KanjiBloc>(context).add(GetKanji(text)),
decoration: new InputDecoration( decoration: new InputDecoration(

View File

@ -0,0 +1,5 @@
final kanjiPattern = RegExp(r'[\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A]');
List<String> kanjiSuggestions(String string) {
return kanjiPattern.allMatches(string).map((match) => match.group(0)).toList();
}

View File

@ -7,7 +7,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
bloc: bloc:
dependency: transitive dependency: transitive
description: description:
@ -22,6 +22,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -42,7 +49,7 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.12" version: "1.15.0-nullsafety"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
@ -57,6 +64,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.1.2"
division:
dependency: "direct main"
description:
name: division
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.8"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -127,14 +141,14 @@ packages:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.6" version: "0.12.9"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.8" version: "1.3.0-nullsafety"
nested: nested:
dependency: transitive dependency: transitive
description: description:
@ -202,7 +216,7 @@ packages:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" version: "1.9.5"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -230,14 +244,14 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.16" version: "0.2.18"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.6" version: "1.3.0-nullsafety"
unofficial_jisho_api: unofficial_jisho_api:
dependency: "direct main" dependency: "direct main"
description: description:
@ -286,7 +300,7 @@ packages:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.8" version: "2.1.0-nullsafety"
sdks: sdks:
dart: ">=2.7.0 <3.0.0" dart: ">=2.9.0-18.0 <2.9.0"
flutter: ">=1.16.0 <2.0.0" flutter: ">=1.16.0 <2.0.0"

View File

@ -1,16 +1,5 @@
name: jisho_study_tool name: jisho_study_tool
description: A new Flutter project. description: A new Flutter project.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
@ -20,45 +9,24 @@ dependencies:
flutter: flutter:
sdk: 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 # cupertino_icons: ^0.1.2
unofficial_jisho_api: ^1.1.0 unofficial_jisho_api: ^1.1.0
flutter_bloc: ^5.0.1 flutter_bloc: ^5.0.1
url_launcher: ^5.5.0 url_launcher: ^5.5.0
division: ^0.8.8
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter: flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets: # assets:
# - images/a_dot_burr.jpeg # - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts: # fonts:
# - family: Schyler # - family: Schyler
# fonts: # fonts:
@ -70,6 +38,3 @@ flutter:
# - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf # - asset: fonts/TrajanPro_Bold.ttf
# weight: 700 # weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages