commit
4bf863c16b
|
@ -30,8 +30,6 @@
|
||||||
.pub/
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
|
|
||||||
objectbox.g.dart
|
|
||||||
|
|
||||||
# Web related
|
# Web related
|
||||||
lib/generated_plugin_registrant.dart
|
lib/generated_plugin_registrant.dart
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
analyzer:
|
||||||
|
exclude:
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
# these rules are documented on and in the same order as
|
||||||
|
# the Dart Lint rules page to make maintenance easier
|
||||||
|
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||||
|
- always_declare_return_types
|
||||||
|
# - always_put_control_body_on_new_line # Allow return statements on same line as ifs
|
||||||
|
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
|
||||||
|
- always_require_non_null_named_parameters
|
||||||
|
# - always_specify_types
|
||||||
|
# - always_use_package_imports # we do this commonly
|
||||||
|
- annotate_overrides
|
||||||
|
- avoid_bool_literals_in_conditional_expressions
|
||||||
|
- avoid_classes_with_only_static_members
|
||||||
|
- avoid_double_and_int_checks
|
||||||
|
- avoid_dynamic_calls
|
||||||
|
- avoid_empty_else
|
||||||
|
- avoid_equals_and_hash_code_on_mutable_classes
|
||||||
|
- avoid_escaping_inner_quotes
|
||||||
|
- avoid_field_initializers_in_const_classes
|
||||||
|
- avoid_function_literals_in_foreach_calls
|
||||||
|
- avoid_implementing_value_types
|
||||||
|
- avoid_init_to_null
|
||||||
|
- avoid_js_rounded_ints
|
||||||
|
- avoid_multiple_declarations_per_line
|
||||||
|
- avoid_null_checks_in_equality_operators
|
||||||
|
- avoid_positional_boolean_parameters
|
||||||
|
- avoid_print
|
||||||
|
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
|
||||||
|
- avoid_redundant_argument_values
|
||||||
|
- avoid_relative_lib_imports
|
||||||
|
- avoid_renaming_method_parameters
|
||||||
|
- avoid_return_types_on_setters
|
||||||
|
- avoid_returning_null
|
||||||
|
- avoid_returning_null_for_future
|
||||||
|
- avoid_returning_null_for_void
|
||||||
|
- avoid_setters_without_getters
|
||||||
|
- avoid_shadowing_type_parameters
|
||||||
|
- avoid_single_cascade_in_expression_statements
|
||||||
|
- avoid_slow_async_io
|
||||||
|
- avoid_type_to_string
|
||||||
|
- avoid_types_as_parameter_names
|
||||||
|
- avoid_types_on_closure_parameters
|
||||||
|
- avoid_unnecessary_containers
|
||||||
|
- avoid_unused_constructor_parameters
|
||||||
|
- avoid_void_async
|
||||||
|
- await_only_futures
|
||||||
|
- camel_case_extensions
|
||||||
|
- camel_case_types
|
||||||
|
- cancel_subscriptions
|
||||||
|
- cast_nullable_to_non_nullable
|
||||||
|
- control_flow_in_finally
|
||||||
|
# - curly_braces_in_flow_control_structures
|
||||||
|
- depend_on_referenced_packages
|
||||||
|
- deprecated_consistency
|
||||||
|
- directives_ordering
|
||||||
|
- do_not_use_environment
|
||||||
|
- empty_catches
|
||||||
|
- empty_constructor_bodies
|
||||||
|
- empty_statements
|
||||||
|
- eol_at_end_of_file
|
||||||
|
- exhaustive_cases
|
||||||
|
- file_names
|
||||||
|
# - flutter_style_todos # This is mostly a single person project for the time being
|
||||||
|
- hash_and_equals
|
||||||
|
- implementation_imports
|
||||||
|
- iterable_contains_unrelated_type
|
||||||
|
- join_return_with_assignment
|
||||||
|
- leading_newlines_in_multiline_strings
|
||||||
|
- library_names
|
||||||
|
- library_prefixes
|
||||||
|
- library_private_types_in_public_api
|
||||||
|
# - lines_longer_than_80_chars
|
||||||
|
- list_remove_unrelated_type
|
||||||
|
- missing_whitespace_between_adjacent_strings
|
||||||
|
- no_adjacent_strings_in_list
|
||||||
|
- no_default_cases
|
||||||
|
- no_duplicate_case_values
|
||||||
|
- no_logic_in_create_state
|
||||||
|
# - non_constant_identifier_names # use API names for several variables
|
||||||
|
- noop_primitive_operations
|
||||||
|
- null_check_on_nullable_type_parameter
|
||||||
|
- null_closures
|
||||||
|
- only_throw_errors
|
||||||
|
- overridden_fields
|
||||||
|
- package_api_docs
|
||||||
|
- package_names
|
||||||
|
- package_prefixed_library_names
|
||||||
|
- prefer_adjacent_string_concatenation
|
||||||
|
- prefer_asserts_in_initializer_lists
|
||||||
|
- prefer_collection_literals
|
||||||
|
- prefer_conditional_assignment
|
||||||
|
- prefer_const_constructors
|
||||||
|
- prefer_const_constructors_in_immutables
|
||||||
|
- prefer_const_declarations
|
||||||
|
- prefer_const_literals_to_create_immutables
|
||||||
|
- prefer_contains
|
||||||
|
- prefer_equal_for_default_values
|
||||||
|
- prefer_final_fields
|
||||||
|
- prefer_final_in_for_each
|
||||||
|
- prefer_final_locals
|
||||||
|
# - prefer_final_parameters
|
||||||
|
- prefer_for_elements_to_map_fromIterable
|
||||||
|
- prefer_foreach
|
||||||
|
- prefer_function_declarations_over_variables
|
||||||
|
- prefer_generic_function_type_aliases
|
||||||
|
# - prefer_if_elements_to_conditional_expressions
|
||||||
|
- prefer_if_null_operators
|
||||||
|
- prefer_initializing_formals
|
||||||
|
- prefer_inlined_adds
|
||||||
|
- prefer_interpolation_to_compose_strings
|
||||||
|
- prefer_is_empty
|
||||||
|
- prefer_is_not_empty
|
||||||
|
- prefer_is_not_operator
|
||||||
|
- prefer_iterable_whereType
|
||||||
|
- prefer_null_aware_operators
|
||||||
|
- prefer_relative_imports
|
||||||
|
- prefer_single_quotes
|
||||||
|
- prefer_spread_collections
|
||||||
|
- prefer_typing_uninitialized_variables
|
||||||
|
- prefer_void_to_null
|
||||||
|
- provide_deprecation_message
|
||||||
|
- recursive_getters
|
||||||
|
- require_trailing_commas
|
||||||
|
- sized_box_for_whitespace
|
||||||
|
- slash_for_doc_comments
|
||||||
|
- sort_child_properties_last
|
||||||
|
# - sort_constructors_first
|
||||||
|
- sort_unnamed_constructors_first
|
||||||
|
- test_types_in_equals
|
||||||
|
- throw_in_finally
|
||||||
|
- tighten_type_of_initializing_formals
|
||||||
|
- type_init_formals
|
||||||
|
- unnecessary_await_in_return
|
||||||
|
- unnecessary_brace_in_string_interps
|
||||||
|
- unnecessary_const
|
||||||
|
- unnecessary_getters_setters
|
||||||
|
- unnecessary_new
|
||||||
|
- unnecessary_null_aware_assignments
|
||||||
|
- unnecessary_null_checks
|
||||||
|
- unnecessary_null_in_if_null_operators
|
||||||
|
- unnecessary_nullable_for_final_variable_declarations
|
||||||
|
- unnecessary_overrides
|
||||||
|
- unnecessary_parenthesis
|
||||||
|
- unnecessary_statements
|
||||||
|
- unnecessary_string_escapes
|
||||||
|
- unnecessary_string_interpolations
|
||||||
|
- unnecessary_this
|
||||||
|
- unrelated_type_equality_checks
|
||||||
|
- unsafe_html
|
||||||
|
- use_build_context_synchronously
|
||||||
|
- use_full_hex_values_for_flutter_colors
|
||||||
|
- use_function_type_syntax_for_parameters
|
||||||
|
- use_is_even_rather_than_modulo
|
||||||
|
- use_key_in_widget_constructors
|
||||||
|
- use_late_for_private_fields_and_variables
|
||||||
|
- use_named_constants
|
||||||
|
- use_raw_strings
|
||||||
|
- use_rethrow_when_possible
|
||||||
|
- use_setters_to_change_properties
|
||||||
|
- use_test_throws_matchers
|
||||||
|
- valid_regexps
|
||||||
|
- void_checks
|
||||||
|
|
|
@ -27,4 +27,5 @@
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.50'
|
ext.kotlin_version = '1.5.0'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
|
|
||||||
import './database_event.dart';
|
|
||||||
import './database_state.dart';
|
|
||||||
|
|
||||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
export './database_event.dart';
|
|
||||||
export './database_state.dart';
|
|
||||||
export './database_not_connected_exception.dart';
|
|
||||||
|
|
||||||
class DatabaseBloc extends Bloc<DatabaseEvent, DatabaseState> {
|
|
||||||
|
|
||||||
DatabaseBloc() : super(DatabaseDisconnected());
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<DatabaseState> mapEventToState(DatabaseEvent event)
|
|
||||||
async* {
|
|
||||||
if (event is ConnectedToDatabase) {
|
|
||||||
yield DatabaseConnected(event.database);
|
|
||||||
} else {
|
|
||||||
yield DatabaseDisconnected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import 'package:objectbox/objectbox.dart';
|
|
||||||
|
|
||||||
abstract class DatabaseEvent {
|
|
||||||
const DatabaseEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConnectedToDatabase extends DatabaseEvent {
|
|
||||||
final Store database;
|
|
||||||
const ConnectedToDatabase(this.database);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisconnectedFromDatabase extends DatabaseEvent {
|
|
||||||
const DisconnectedFromDatabase();
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
class DatabaseNotConnectedException implements Exception {}
|
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
import 'package:objectbox/objectbox.dart';
|
|
||||||
|
|
||||||
abstract class DatabaseState {
|
|
||||||
const DatabaseState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class DatabaseConnected extends DatabaseState {
|
|
||||||
final Store database;
|
|
||||||
const DatabaseConnected(this.database);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DatabaseDisconnected extends DatabaseState {
|
|
||||||
const DatabaseDisconnected();
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
part 'history_event.dart';
|
|
||||||
part 'history_state.dart';
|
|
||||||
|
|
||||||
class HistoryBloc extends Bloc<HistoryEvent, HistoryState> {
|
|
||||||
HistoryBloc() : super(HistoryInitial());
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<HistoryState> mapEventToState(
|
|
||||||
HistoryEvent event,
|
|
||||||
) async* {
|
|
||||||
// TODO: implement mapEventToState
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
part of 'history_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class HistoryEvent {}
|
|
|
@ -1,6 +0,0 @@
|
||||||
part of 'history_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class HistoryState {}
|
|
||||||
|
|
||||||
class HistoryInitial extends HistoryState {}
|
|
|
@ -1,59 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/models/history/kanji_query.dart';
|
|
||||||
import 'package:jisho_study_tool/models/history/search.dart';
|
|
||||||
|
|
||||||
import './kanji_event.dart';
|
|
||||||
import './kanji_state.dart';
|
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/services/jisho_api/kanji_search.dart';
|
|
||||||
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
|
||||||
|
|
||||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
export './kanji_event.dart';
|
|
||||||
export './kanji_state.dart';
|
|
||||||
|
|
||||||
class KanjiBloc extends Bloc<KanjiEvent, KanjiState> {
|
|
||||||
DatabaseBloc _databaseBloc;
|
|
||||||
|
|
||||||
KanjiBloc(this._databaseBloc) : super(KanjiSearch(KanjiSearchType.Initial));
|
|
||||||
|
|
||||||
void addSearchToDB(kanji) {
|
|
||||||
if (_databaseBloc.state is DatabaseDisconnected)
|
|
||||||
throw DatabaseNotConnectedException;
|
|
||||||
|
|
||||||
(_databaseBloc.state as DatabaseConnected)
|
|
||||||
.database
|
|
||||||
.box<Search>()
|
|
||||||
.put(Search(timestamp: DateTime.now())
|
|
||||||
..kanjiQuery.target = KanjiQuery(
|
|
||||||
kanji: kanji,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<KanjiState> mapEventToState(KanjiEvent event) async* {
|
|
||||||
if (event is GetKanji) {
|
|
||||||
yield KanjiSearchLoading();
|
|
||||||
|
|
||||||
try {
|
|
||||||
addSearchToDB(event.kanjiSearchString);
|
|
||||||
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 KanjiSearchKeyboard(KanjiSearchType.Keyboard, suggestions);
|
|
||||||
} else if (event is ReturnToInitialState) {
|
|
||||||
yield KanjiSearch(KanjiSearchType.Initial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
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();
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
import 'package:unofficial_jisho_api/api.dart';
|
|
||||||
|
|
||||||
abstract class KanjiState {
|
|
||||||
const KanjiState();
|
|
||||||
}
|
|
||||||
|
|
||||||
enum KanjiSearchType {
|
|
||||||
Initial,
|
|
||||||
Keyboard,
|
|
||||||
Drawing,
|
|
||||||
Radical,
|
|
||||||
Grade
|
|
||||||
}
|
|
||||||
|
|
||||||
class KanjiSearch extends KanjiState {
|
|
||||||
final KanjiSearchType type;
|
|
||||||
const KanjiSearch(this.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
class KanjiSearchKeyboard extends KanjiSearch {
|
|
||||||
final List<String> kanjiSuggestions;
|
|
||||||
const KanjiSearchKeyboard(KanjiSearchType type, this.kanjiSuggestions) : super(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
class KanjiSearchLoading extends KanjiState {
|
|
||||||
const KanjiSearchLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
class KanjiSearchFinished extends KanjiState {
|
|
||||||
final KanjiResult kanji;
|
|
||||||
final bool starred;
|
|
||||||
|
|
||||||
const KanjiSearchFinished({
|
|
||||||
required this.kanji,
|
|
||||||
this.starred = false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class KanjiSearchError extends KanjiState {
|
|
||||||
final String message;
|
|
||||||
|
|
||||||
const KanjiSearchError(this.message);
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
|
|
||||||
import './navigation_event.dart';
|
|
||||||
import './navigation_state.dart';
|
|
||||||
|
|
||||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
export './navigation_event.dart';
|
|
||||||
export './navigation_state.dart';
|
|
||||||
|
|
||||||
class NavigationBloc extends Bloc<NavigationEvent, NavigationState> {
|
|
||||||
|
|
||||||
NavigationBloc() : super(NavigationPage(0));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<NavigationState> mapEventToState(NavigationEvent event) async* {
|
|
||||||
if (event is ChangePage)
|
|
||||||
yield NavigationPage(event.pageNum);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
abstract class NavigationEvent {
|
|
||||||
const NavigationEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChangePage extends NavigationEvent {
|
|
||||||
final int pageNum;
|
|
||||||
const ChangePage(this.pageNum);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
abstract class NavigationState {
|
|
||||||
const NavigationState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class NavigationPage extends NavigationState {
|
|
||||||
final int pageNum;
|
|
||||||
const NavigationPage(this.pageNum);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/models/history/search.dart';
|
|
||||||
import 'package:jisho_study_tool/models/history/word_query.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/services/jisho_api/jisho_search.dart';
|
|
||||||
import 'package:unofficial_jisho_api/parser.dart';
|
|
||||||
|
|
||||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
part 'search_event.dart';
|
|
||||||
part 'search_state.dart';
|
|
||||||
|
|
||||||
class SearchBloc extends Bloc<SearchEvent, SearchState> {
|
|
||||||
DatabaseBloc _databaseBloc;
|
|
||||||
|
|
||||||
SearchBloc(this._databaseBloc) : super(SearchInitial());
|
|
||||||
|
|
||||||
void addSearchToDB(searchString) {
|
|
||||||
if (_databaseBloc.state is DatabaseDisconnected)
|
|
||||||
throw DatabaseNotConnectedException;
|
|
||||||
|
|
||||||
(_databaseBloc.state as DatabaseConnected)
|
|
||||||
.database
|
|
||||||
.box<Search>()
|
|
||||||
.put(Search(timestamp: DateTime.now())
|
|
||||||
..wordQuery.target = WordQuery(
|
|
||||||
query: searchString,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<SearchState> mapEventToState(
|
|
||||||
SearchEvent event,
|
|
||||||
) async* {
|
|
||||||
if (event is GetSearchResults) {
|
|
||||||
yield SearchLoading();
|
|
||||||
|
|
||||||
try {
|
|
||||||
addSearchToDB(event.searchString);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
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();
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
part of 'search_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class SearchState {
|
|
||||||
const SearchState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchInitial extends SearchState {
|
|
||||||
const SearchInitial();
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchLoading extends SearchState {
|
|
||||||
const SearchLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchFinished extends SearchState {
|
|
||||||
final List<JishoResult> results;
|
|
||||||
|
|
||||||
const SearchFinished(this.results);
|
|
||||||
}
|
|
||||||
|
|
||||||
class SearchError extends SearchState {
|
|
||||||
final String message;
|
|
||||||
|
|
||||||
const SearchError(this.message);
|
|
||||||
}
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:async';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../../models/themes/theme.dart';
|
||||||
|
|
||||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
export 'package:jisho_study_tool/models/themes/theme.dart';
|
export 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
|
|
||||||
|
@ -12,24 +12,20 @@ part 'theme_event.dart';
|
||||||
part 'theme_state.dart';
|
part 'theme_state.dart';
|
||||||
|
|
||||||
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
|
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
|
||||||
bool prefsAreLoaded = false;
|
ThemeBloc() : super(const LightThemeState()) {
|
||||||
|
on<SetTheme>(
|
||||||
|
(event, emit) => emit(
|
||||||
|
event.themeIsDark ? const DarkThemeState() : const LightThemeState(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
ThemeBloc() : super(LightThemeState()) {
|
add(
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
SetTheme(
|
||||||
this.prefsAreLoaded = true;
|
themeIsDark: GetIt.instance
|
||||||
this.add(
|
.get<SharedPreferences>()
|
||||||
SetTheme(
|
.getBool('darkThemeEnabled') ??
|
||||||
themeIsDark: prefs.getBool('darkThemeEnabled') ?? false,
|
false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<ThemeState> mapEventToState(ThemeEvent event) async* {
|
|
||||||
if (event is SetTheme)
|
|
||||||
yield event.themeIsDark
|
|
||||||
? DarkThemeState(prefsAreLoaded: prefsAreLoaded)
|
|
||||||
: LightThemeState(prefsAreLoaded: prefsAreLoaded);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,25 +2,21 @@ part of 'theme_bloc.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
abstract class ThemeState {
|
abstract class ThemeState {
|
||||||
final bool prefsAreLoaded;
|
const ThemeState();
|
||||||
|
|
||||||
const ThemeState(this.prefsAreLoaded);
|
|
||||||
|
|
||||||
AppTheme get theme;
|
AppTheme get theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
class LightThemeState extends ThemeState {
|
class LightThemeState extends ThemeState {
|
||||||
final bool prefsAreLoaded;
|
const LightThemeState();
|
||||||
|
|
||||||
const LightThemeState({this.prefsAreLoaded = false}) : super(prefsAreLoaded);
|
|
||||||
|
|
||||||
|
@override
|
||||||
AppTheme get theme => LightTheme();
|
AppTheme get theme => LightTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
class DarkThemeState extends ThemeState {
|
class DarkThemeState extends ThemeState {
|
||||||
final bool prefsAreLoaded;
|
const DarkThemeState();
|
||||||
|
|
||||||
const DarkThemeState({this.prefsAreLoaded = false}) : super(prefsAreLoaded);
|
|
||||||
|
|
||||||
|
@override
|
||||||
AppTheme get theme => DarkTheme();
|
AppTheme get theme => DarkTheme();
|
||||||
}
|
}
|
||||||
|
|
193
lib/main.dart
193
lib/main.dart
|
@ -1,180 +1,57 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:jisho_study_tool/view/screens/splash.dart';
|
|
||||||
import 'package:mdi/mdi.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:sembast/sembast.dart';
|
||||||
|
import 'package:sembast/sembast_io.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/objectbox.g.dart';
|
import 'bloc/theme/theme_bloc.dart';
|
||||||
|
import 'router.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
Future<void> setupDatabase() async {
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
final Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
if (!appDocDir.existsSync()) appDocDir.createSync(recursive: true);
|
||||||
import 'package:jisho_study_tool/bloc/navigation/navigation_bloc.dart';
|
final Database database =
|
||||||
|
await databaseFactoryIo.openDatabase(join(appDocDir.path, 'sembast.db'));
|
||||||
import 'package:jisho_study_tool/view/screens/kanji/view.dart';
|
GetIt.instance.registerSingleton<Database>(database);
|
||||||
import 'package:jisho_study_tool/view/screens/history.dart';
|
|
||||||
import 'package:jisho_study_tool/view/screens/search/view.dart';
|
|
||||||
import 'package:jisho_study_tool/view/screens/settings.dart';
|
|
||||||
|
|
||||||
import 'models/themes/theme.dart';
|
|
||||||
|
|
||||||
void main() => runApp(MyApp());
|
|
||||||
|
|
||||||
DatabaseBloc _databaseBloc = DatabaseBloc();
|
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_MyAppState createState() => _MyAppState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
Future<void> setupSharedPreferences() async {
|
||||||
late final Store _store;
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
bool dbConnected = false;
|
GetIt.instance.registerSingleton<SharedPreferences>(prefs);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
Future<void> main() async {
|
||||||
void initState() {
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
super.initState();
|
|
||||||
|
|
||||||
getApplicationDocumentsDirectory().then((dir) {
|
await Future.wait([
|
||||||
_store = Store(
|
setupDatabase(),
|
||||||
getObjectBoxModel(),
|
setupSharedPreferences(),
|
||||||
directory: join(dir.path, 'objectbox'),
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
_databaseBloc.add(ConnectedToDatabase(_store));
|
runApp(const MyApp());
|
||||||
setState(() {
|
}
|
||||||
dbConnected = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
class MyApp extends StatelessWidget {
|
||||||
void dispose() {
|
const MyApp({Key? key}) : super(key: key);
|
||||||
_store.close();
|
|
||||||
_databaseBloc.add(DisconnectedFromDatabase());
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(create: (context) => SearchBloc(_databaseBloc)),
|
|
||||||
BlocProvider(create: (context) => KanjiBloc(_databaseBloc)),
|
|
||||||
BlocProvider(create: (context) => _databaseBloc),
|
|
||||||
BlocProvider(create: (context) => NavigationBloc()),
|
|
||||||
BlocProvider(create: (context) => ThemeBloc()),
|
BlocProvider(create: (context) => ThemeBloc()),
|
||||||
],
|
],
|
||||||
child: BlocBuilder<ThemeBloc, ThemeState>(
|
child: BlocBuilder<ThemeBloc, ThemeState>(
|
||||||
builder: (context, themeState) {
|
builder: (context, themeState) => MaterialApp(
|
||||||
return MaterialApp(
|
title: 'Jisho Study Tool',
|
||||||
title: 'Jisho Study Tool',
|
theme: themeState.theme.getMaterialTheme(),
|
||||||
theme: themeState.theme.getMaterialTheme(),
|
initialRoute: '/',
|
||||||
home: dbConnected && themeState.prefsAreLoaded
|
onGenerateRoute: generateRoute,
|
||||||
? Home()
|
),
|
||||||
: SplashScreen(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Home extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<NavigationBloc, NavigationState>(
|
|
||||||
builder: (context, navigationState) {
|
|
||||||
int selectedPage = (navigationState as NavigationPage).pageNum;
|
|
||||||
return BlocBuilder<ThemeBloc, ThemeState>(
|
|
||||||
builder: (context, themeState) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: pages[selectedPage].titleBar,
|
|
||||||
centerTitle: true,
|
|
||||||
backgroundColor: AppTheme.jishoGreen.background,
|
|
||||||
foregroundColor: AppTheme.jishoGreen.foreground,
|
|
||||||
),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Positioned(
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/denshi_jisho_background_overlay.png'),
|
|
||||||
right: 30,
|
|
||||||
left: 100,
|
|
||||||
bottom: 30,
|
|
||||||
),
|
|
||||||
pages[selectedPage].content,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
|
||||||
fixedColor: AppTheme.jishoGreen.background,
|
|
||||||
currentIndex: selectedPage,
|
|
||||||
onTap: (int index) => BlocProvider.of<NavigationBloc>(context)
|
|
||||||
.add(ChangePage(index)),
|
|
||||||
items: pages.map((p) => p.item).toList(),
|
|
||||||
showSelectedLabels: false,
|
|
||||||
showUnselectedLabels: false,
|
|
||||||
unselectedItemColor: themeState.theme.menuGreyDark.background,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Page {
|
|
||||||
final Widget content;
|
|
||||||
final Widget titleBar;
|
|
||||||
final BottomNavigationBarItem item;
|
|
||||||
|
|
||||||
const _Page({
|
|
||||||
required this.content,
|
|
||||||
required this.titleBar,
|
|
||||||
required this.item,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<_Page> pages = [
|
|
||||||
_Page(
|
|
||||||
content: SearchView(),
|
|
||||||
titleBar: Text('Search'),
|
|
||||||
item: BottomNavigationBarItem(
|
|
||||||
label: 'Search',
|
|
||||||
icon: Icon(Icons.search),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_Page(
|
|
||||||
content: KanjiView(),
|
|
||||||
titleBar: KanjiViewBar(),
|
|
||||||
item: BottomNavigationBarItem(
|
|
||||||
label: 'Kanji', icon: Icon(Mdi.ideogramCjk, size: 30)),
|
|
||||||
),
|
|
||||||
_Page(
|
|
||||||
content: HistoryView(),
|
|
||||||
titleBar: Text("History"),
|
|
||||||
item: BottomNavigationBarItem(
|
|
||||||
label: 'History',
|
|
||||||
icon: Icon(Icons.history),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_Page(
|
|
||||||
content: Container(),
|
|
||||||
titleBar: Text("Saved"),
|
|
||||||
item: BottomNavigationBarItem(
|
|
||||||
label: 'Saved',
|
|
||||||
icon: Icon(Icons.bookmark),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_Page(
|
|
||||||
content: SettingsView(),
|
|
||||||
titleBar: Text("Settings"),
|
|
||||||
item: BottomNavigationBarItem(
|
|
||||||
label: 'Settings',
|
|
||||||
icon: Icon(Icons.settings),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import 'package:objectbox/objectbox.dart';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class KanjiQuery {
|
class KanjiQuery {
|
||||||
int id;
|
final String kanji;
|
||||||
|
|
||||||
String kanji;
|
|
||||||
|
|
||||||
KanjiQuery({
|
KanjiQuery({
|
||||||
this.id = 0,
|
|
||||||
required this.kanji,
|
required this.kanji,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Map<String, Object?> toJson() => {'kanji': kanji};
|
||||||
|
|
||||||
|
factory KanjiQuery.fromJson(Map<String, dynamic> json) =>
|
||||||
|
KanjiQuery(kanji: json['kanji'] as String);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,42 @@
|
||||||
import 'package:objectbox/objectbox.dart';
|
import 'package:sembast/sembast.dart';
|
||||||
|
|
||||||
import './kanji_query.dart';
|
import './kanji_query.dart';
|
||||||
import './word_query.dart';
|
import './word_query.dart';
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class Search {
|
class Search {
|
||||||
int id;
|
final DateTime timestamp;
|
||||||
|
final WordQuery? wordQuery;
|
||||||
|
final KanjiQuery? kanjiQuery;
|
||||||
|
|
||||||
@Property(type: PropertyType.date)
|
Search.fromKanjiQuery({
|
||||||
late final DateTime timestamp;
|
required this.timestamp,
|
||||||
|
required KanjiQuery this.kanjiQuery,
|
||||||
|
}) : wordQuery = null;
|
||||||
|
|
||||||
final wordQuery = ToOne<WordQuery>();
|
Search.fromWordQuery({
|
||||||
|
required this.timestamp,
|
||||||
|
required WordQuery this.wordQuery,
|
||||||
|
}) : kanjiQuery = null;
|
||||||
|
|
||||||
final kanjiQuery = ToOne<KanjiQuery>();
|
bool get isKanji => wordQuery == null;
|
||||||
|
|
||||||
Search({
|
Map<String, Object?> toJson() => {
|
||||||
this.id = 0,
|
'timestamp': timestamp.millisecondsSinceEpoch,
|
||||||
required this.timestamp
|
'wordQuery': wordQuery?.toJson(),
|
||||||
}); // {
|
'kanjiQuery': kanjiQuery?.toJson(),
|
||||||
|
};
|
||||||
|
|
||||||
bool isKanji() {
|
factory Search.fromJson(Map<String, dynamic> json) =>
|
||||||
// // TODO: better error message
|
json['wordQuery'] != null
|
||||||
if (this.wordQuery.target == null && this.kanjiQuery.target == null)
|
? Search.fromWordQuery(
|
||||||
throw Exception();
|
timestamp:
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int),
|
||||||
return this.wordQuery.target == null;
|
wordQuery: WordQuery.fromJson(json['wordQuery']),
|
||||||
}
|
)
|
||||||
|
: Search.fromKanjiQuery(
|
||||||
|
timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int),
|
||||||
|
kanjiQuery: KanjiQuery.fromJson(json['kanjiQuery']),
|
||||||
|
);
|
||||||
|
|
||||||
}
|
static StoreRef<int, Object?> get store => intMapStoreFactory.store('search');
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import 'package:objectbox/objectbox.dart';
|
|
||||||
|
|
||||||
import './word_result.dart';
|
import './word_result.dart';
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class WordQuery {
|
class WordQuery {
|
||||||
int id;
|
final String query;
|
||||||
|
|
||||||
String query;
|
|
||||||
|
|
||||||
// TODO: Link query with results that the user clicks onto.
|
// TODO: Link query with results that the user clicks onto.
|
||||||
@Backlink()
|
// final List<WordResult> chosenResults;
|
||||||
final chosenResults = ToMany<WordResult>();
|
|
||||||
|
|
||||||
WordQuery({
|
WordQuery({
|
||||||
this.id = 0,
|
|
||||||
required this.query,
|
required this.query,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
Map<String, Object?> toJson() => {'query': query};
|
||||||
|
|
||||||
|
factory WordQuery.fromJson(Map<String, dynamic> json) =>
|
||||||
|
WordQuery(query: json['query'] as String);
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
import 'package:objectbox/objectbox.dart';
|
import 'word_query.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/models/history/word_query.dart';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class WordResult {
|
class WordResult {
|
||||||
int id;
|
final DateTime timestamp;
|
||||||
|
final String word;
|
||||||
@Property(type: PropertyType.date)
|
final WordQuery searchString;
|
||||||
DateTime timestamp;
|
|
||||||
|
|
||||||
String word;
|
|
||||||
|
|
||||||
final searchString = ToOne<WordQuery>();
|
|
||||||
|
|
||||||
WordResult({
|
WordResult({
|
||||||
this.id = 0,
|
|
||||||
required this.timestamp,
|
required this.timestamp,
|
||||||
required this.word,
|
required this.word,
|
||||||
|
required this.searchString,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
// import 'package:objectbox/objectbox.dart';
|
||||||
|
// import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
// TODO: Rewrite for sembast
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class ExampleSentencePiece {
|
||||||
|
// int id;
|
||||||
|
// String? lifted;
|
||||||
|
// String unlifted;
|
||||||
|
|
||||||
|
// ExampleSentencePiece({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.lifted,
|
||||||
|
// required this.unlifted,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// ExampleSentencePiece.fromJishoObject(jisho.ExampleSentencePiece object)
|
||||||
|
// : id = 0,
|
||||||
|
// lifted = object.lifted,
|
||||||
|
// unlifted = object.unlifted;
|
||||||
|
// }
|
|
@ -0,0 +1,58 @@
|
||||||
|
// import 'package:objectbox/objectbox.dart';
|
||||||
|
// import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
// import 'common.dart';
|
||||||
|
|
||||||
|
// TODO: Rewrite for sembast
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class ExampleResultData {
|
||||||
|
// int id;
|
||||||
|
// String kanji;
|
||||||
|
// String kana;
|
||||||
|
// String english;
|
||||||
|
// List<ExampleSentencePiece> pieces;
|
||||||
|
|
||||||
|
// ExampleResultData({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.kanji,
|
||||||
|
// required this.kana,
|
||||||
|
// required this.english,
|
||||||
|
// required this.pieces,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// ExampleResultData.fromJishoObject(jisho.ExampleResultData object)
|
||||||
|
// : id = 0,
|
||||||
|
// kanji = object.kanji,
|
||||||
|
// kana = object.kana,
|
||||||
|
// english = object.english,
|
||||||
|
// pieces = object.pieces
|
||||||
|
// .map((p) => ExampleSentencePiece.fromJishoObject(p))
|
||||||
|
// .toList();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class ExampleResults {
|
||||||
|
// int id;
|
||||||
|
// String query;
|
||||||
|
// bool found;
|
||||||
|
// String uri;
|
||||||
|
// List<ExampleResultData> results;
|
||||||
|
|
||||||
|
// ExampleResults({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.query,
|
||||||
|
// required this.found,
|
||||||
|
// required this.uri,
|
||||||
|
// required this.results,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// ExampleResults.fromJishoObject(jisho.ExampleResults object)
|
||||||
|
// : id = 0,
|
||||||
|
// query = object.query,
|
||||||
|
// found = object.found,
|
||||||
|
// uri = object.uri,
|
||||||
|
// results = object.results
|
||||||
|
// .map((r) => ExampleResultData.fromJishoObject(r))
|
||||||
|
// .toList();
|
||||||
|
// }
|
|
@ -0,0 +1,129 @@
|
||||||
|
// import 'package:objectbox/objectbox.dart';
|
||||||
|
// import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
// TODO: Rewrite for sembast
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class YomiExample {
|
||||||
|
// int id;
|
||||||
|
// String example;
|
||||||
|
// String reading;
|
||||||
|
// String meaning;
|
||||||
|
|
||||||
|
// YomiExample({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.example,
|
||||||
|
// required this.reading,
|
||||||
|
// required this.meaning,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// YomiExample.fromJishoObject(jisho.YomiExample object)
|
||||||
|
// : id = 0,
|
||||||
|
// example = object.example,
|
||||||
|
// reading = object.reading,
|
||||||
|
// meaning = object.meaning;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class Radical {
|
||||||
|
// int id = 0;
|
||||||
|
// String symbol;
|
||||||
|
// List<String> forms;
|
||||||
|
// String meaning;
|
||||||
|
|
||||||
|
// Radical({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.symbol,
|
||||||
|
// required this.forms,
|
||||||
|
// required this.meaning,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Radical.fromJishoObject(jisho.Radical object)
|
||||||
|
// : symbol = object.symbol,
|
||||||
|
// forms = object.forms,
|
||||||
|
// meaning = object.meaning;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class KanjiResult {
|
||||||
|
// int id = 0;
|
||||||
|
// String query;
|
||||||
|
// bool found;
|
||||||
|
// KanjiResultData? data;
|
||||||
|
|
||||||
|
// KanjiResult({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.query,
|
||||||
|
// required this.found,
|
||||||
|
// required this.data,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// KanjiResult.fromJishoObject(jisho.KanjiResult object)
|
||||||
|
// : query = object.query,
|
||||||
|
// found = object.found,
|
||||||
|
// data = (object.data == null)
|
||||||
|
// ? null
|
||||||
|
// : KanjiResultData.fromJishoObject(object.data!);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class KanjiResultData {
|
||||||
|
// int id = 0;
|
||||||
|
// String? taughtIn;
|
||||||
|
// String? jlptLevel;
|
||||||
|
// int? newspaperFrequencyRank;
|
||||||
|
// int strokeCount;
|
||||||
|
// String meaning;
|
||||||
|
// List<String> kunyomi;
|
||||||
|
// List<String> onyomi;
|
||||||
|
// List<YomiExample> kunyomiExamples;
|
||||||
|
// List<YomiExample> onyomiExamples;
|
||||||
|
// Radical? radical;
|
||||||
|
// List<String> parts;
|
||||||
|
// String strokeOrderDiagramUri;
|
||||||
|
// String strokeOrderSvgUri;
|
||||||
|
// String strokeOrderGifUri;
|
||||||
|
// String uri;
|
||||||
|
|
||||||
|
// KanjiResultData({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.taughtIn,
|
||||||
|
// required this.jlptLevel,
|
||||||
|
// required this.newspaperFrequencyRank,
|
||||||
|
// required this.strokeCount,
|
||||||
|
// required this.meaning,
|
||||||
|
// required this.kunyomi,
|
||||||
|
// required this.onyomi,
|
||||||
|
// required this.kunyomiExamples,
|
||||||
|
// required this.onyomiExamples,
|
||||||
|
// required this.radical,
|
||||||
|
// required this.parts,
|
||||||
|
// required this.strokeOrderDiagramUri,
|
||||||
|
// required this.strokeOrderSvgUri,
|
||||||
|
// required this.strokeOrderGifUri,
|
||||||
|
// required this.uri,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// KanjiResultData.fromJishoObject(jisho.KanjiResultData object)
|
||||||
|
// : taughtIn = object.taughtIn,
|
||||||
|
// jlptLevel = object.jlptLevel,
|
||||||
|
// newspaperFrequencyRank = object.newspaperFrequencyRank,
|
||||||
|
// strokeCount = object.strokeCount,
|
||||||
|
// meaning = object.meaning,
|
||||||
|
// kunyomi = object.kunyomi,
|
||||||
|
// onyomi = object.onyomi,
|
||||||
|
// kunyomiExamples = object.kunyomiExamples
|
||||||
|
// .map((k) => YomiExample.fromJishoObject(k))
|
||||||
|
// .toList(),
|
||||||
|
// onyomiExamples = object.onyomiExamples
|
||||||
|
// .map((o) => YomiExample.fromJishoObject(o))
|
||||||
|
// .toList(),
|
||||||
|
// radical = (object.radical == null)
|
||||||
|
// ? null
|
||||||
|
// : Radical.fromJishoObject(object.radical!),
|
||||||
|
// parts = object.parts,
|
||||||
|
// strokeOrderDiagramUri = object.strokeOrderDiagramUri,
|
||||||
|
// strokeOrderSvgUri = object.strokeOrderSvgUri,
|
||||||
|
// strokeOrderGifUri = object.strokeOrderGifUri,
|
||||||
|
// uri = object.uri;
|
||||||
|
// }
|
|
@ -0,0 +1,155 @@
|
||||||
|
// import 'package:objectbox/objectbox.dart';
|
||||||
|
// import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
// import 'common.dart';
|
||||||
|
|
||||||
|
// TODO: Rewrite for sembast
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class PhraseScrapeSentence {
|
||||||
|
// int id;
|
||||||
|
// String english;
|
||||||
|
// String japanese;
|
||||||
|
// List<ExampleSentencePiece> pieces;
|
||||||
|
|
||||||
|
// PhraseScrapeSentence({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.english,
|
||||||
|
// required this.japanese,
|
||||||
|
// required this.pieces,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// PhraseScrapeSentence.fromJishoObject(jisho.PhraseScrapeSentence object)
|
||||||
|
// : id = 0,
|
||||||
|
// english = object.english,
|
||||||
|
// japanese = object.japanese,
|
||||||
|
// pieces = object.pieces
|
||||||
|
// .map((p) => ExampleSentencePiece.fromJishoObject(p))
|
||||||
|
// .toList();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class PhraseScrapeMeaning {
|
||||||
|
// int id;
|
||||||
|
// List<String> seeAlsoTerms;
|
||||||
|
// List<PhraseScrapeSentence> sentences;
|
||||||
|
// String definition;
|
||||||
|
// List<String> supplemental;
|
||||||
|
// String? definitionAbstract;
|
||||||
|
// List<String> tags;
|
||||||
|
|
||||||
|
// PhraseScrapeMeaning({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.seeAlsoTerms,
|
||||||
|
// required this.sentences,
|
||||||
|
// required this.definition,
|
||||||
|
// required this.supplemental,
|
||||||
|
// required this.definitionAbstract,
|
||||||
|
// required this.tags,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// PhraseScrapeMeaning.fromJishoObject(jisho.PhraseScrapeMeaning object)
|
||||||
|
// : id = 0,
|
||||||
|
// seeAlsoTerms = object.seeAlsoTerms,
|
||||||
|
// sentences = object.sentences
|
||||||
|
// .map((s) => PhraseScrapeSentence.fromJishoObject(s))
|
||||||
|
// .toList(),
|
||||||
|
// definition = object.definition,
|
||||||
|
// supplemental = object.supplemental,
|
||||||
|
// definitionAbstract = object.definitionAbstract,
|
||||||
|
// tags = object.tags;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class KanjiKanaPair {
|
||||||
|
// int id;
|
||||||
|
// String kanji;
|
||||||
|
// String? kana;
|
||||||
|
|
||||||
|
// KanjiKanaPair({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.kanji,
|
||||||
|
// required this.kana,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// KanjiKanaPair.fromJishoObject(jisho.KanjiKanaPair object)
|
||||||
|
// : id = 0,
|
||||||
|
// kanji = object.kanji,
|
||||||
|
// kana = object.kana;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class PhrasePageScrapeResult {
|
||||||
|
// int id;
|
||||||
|
// bool found;
|
||||||
|
// String query;
|
||||||
|
// PhrasePageScrapeResultData? data;
|
||||||
|
|
||||||
|
// PhrasePageScrapeResult({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.found,
|
||||||
|
// required this.query,
|
||||||
|
// required this.data,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// PhrasePageScrapeResult.fromJishoObject(jisho.PhrasePageScrapeResult object)
|
||||||
|
// : id = 0,
|
||||||
|
// found = object.found,
|
||||||
|
// query = object.query,
|
||||||
|
// data = (object.data == null)
|
||||||
|
// ? null
|
||||||
|
// : PhrasePageScrapeResultData.fromJishoObject(object.data!);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class AudioFile {
|
||||||
|
// int id;
|
||||||
|
// String uri;
|
||||||
|
// String mimetype;
|
||||||
|
|
||||||
|
// AudioFile({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.uri,
|
||||||
|
// required this.mimetype,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// AudioFile.fromJishoObject(jisho.AudioFile object)
|
||||||
|
// : id = 0,
|
||||||
|
// uri = object.uri,
|
||||||
|
// mimetype = object.mimetype;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class PhrasePageScrapeResultData {
|
||||||
|
// int id;
|
||||||
|
// String uri;
|
||||||
|
// List<String> tags;
|
||||||
|
// List<PhraseScrapeMeaning> meanings;
|
||||||
|
// List<KanjiKanaPair> otherForms;
|
||||||
|
// List<AudioFile> audio;
|
||||||
|
// List<String> notes;
|
||||||
|
|
||||||
|
// PhrasePageScrapeResultData({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.uri,
|
||||||
|
// required this.tags,
|
||||||
|
// required this.meanings,
|
||||||
|
// required this.otherForms,
|
||||||
|
// required this.audio,
|
||||||
|
// required this.notes,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// PhrasePageScrapeResultData.fromJishoObject(
|
||||||
|
// jisho.PhrasePageScrapeResultData object,
|
||||||
|
// ) : id = 0,
|
||||||
|
// uri = object.uri,
|
||||||
|
// tags = object.tags,
|
||||||
|
// meanings = object.meanings
|
||||||
|
// .map((m) => PhraseScrapeMeaning.fromJishoObject(m))
|
||||||
|
// .toList(),
|
||||||
|
// otherForms = object.otherForms
|
||||||
|
// .map((f) => KanjiKanaPair.fromJishoObject(f))
|
||||||
|
// .toList(),
|
||||||
|
// audio = object.audio.map((a) => AudioFile.fromJishoObject(a)).toList(),
|
||||||
|
// notes = object.notes;
|
||||||
|
// }
|
|
@ -1,72 +1,195 @@
|
||||||
// import 'package:objectbox/objectbox.dart';
|
// import 'package:objectbox/objectbox.dart';
|
||||||
// import 'package:unofficial_jisho_api/api.dart' as jisho;
|
// import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
// TODO: Rewrite for sembast
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class SearchResult {
|
// class SearchResult {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// final meta = ToOne<JishoResultMeta>();
|
// final JishoResultMeta meta;
|
||||||
// final data = ToMany<JishoResult>();
|
// final ToMany<JishoResult> data;
|
||||||
|
|
||||||
// // SearchResult(JishoAPIResult result) {
|
// SearchResult({
|
||||||
// // this.data = result.data;
|
// this.id = 0,
|
||||||
// // this.meta = result.meta;
|
// required this.meta,
|
||||||
// // }
|
// required this.data,
|
||||||
|
// });
|
||||||
|
|
||||||
// // JishoAPIResult toJishoAPIResult() {
|
// SearchResult.fromJishoObject(final jisho.JishoAPIResult object)
|
||||||
// // return JishoAPIResult(meta: this.meta, data: this.data);
|
// : id = 0,
|
||||||
// // }
|
// meta = JishoResultMeta.fromJishoObject(object.meta),
|
||||||
|
// data = ToMany<JishoResult>()
|
||||||
|
// ..addAll(
|
||||||
|
// object.data?.map((r) => JishoResult.fromJishoObject(r)) ??
|
||||||
|
// <JishoResult>[],
|
||||||
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class JishoResultMeta {
|
// class JishoResultMeta {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// int status;
|
// int status;
|
||||||
|
|
||||||
|
// JishoResultMeta({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.status,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoResultMeta.fromJishoObject(final jisho.JishoResultMeta object)
|
||||||
|
// : id = 0,
|
||||||
|
// status = object.status;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class JishoResult {
|
// class JishoResult {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// final attribution = ToOne<JishoAttribution>();
|
// JishoAttribution attribution;
|
||||||
// bool is_common;
|
// bool? is_common;
|
||||||
// final japanese = ToMany<JishoJapaneseWord>();
|
// List<JishoJapaneseWord> japanese;
|
||||||
// List<String> jlpt;
|
// List<String> jlpt;
|
||||||
// final senses = ToMany<JishoWordSense>();
|
// List<JishoWordSense> senses;
|
||||||
// String slug;
|
// String slug;
|
||||||
// List<String> tags;
|
// List<String> tags;
|
||||||
|
|
||||||
|
// JishoResult({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.attribution,
|
||||||
|
// required this.is_common,
|
||||||
|
// required this.japanese,
|
||||||
|
// required this.jlpt,
|
||||||
|
// required this.senses,
|
||||||
|
// required this.slug,
|
||||||
|
// required this.tags,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoResult.fromJishoObject(final jisho.JishoResult object)
|
||||||
|
// : id = 0,
|
||||||
|
// attribution = JishoAttribution.fromJishoObject(object.attribution),
|
||||||
|
// is_common = object.isCommon,
|
||||||
|
// japanese = object.japanese
|
||||||
|
// .map((j) => JishoJapaneseWord.fromJishoObject(j))
|
||||||
|
// .toList(),
|
||||||
|
// jlpt = object.jlpt,
|
||||||
|
// senses = object.senses
|
||||||
|
// .map((s) => JishoWordSense.fromJishoObject(s))
|
||||||
|
// .toList(),
|
||||||
|
// slug = object.slug,
|
||||||
|
// tags = object.tags;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class JishoAttribution {
|
// class JishoAttribution {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// String dbpedia;
|
// String? dbpedia;
|
||||||
// String jmdict;
|
// bool jmdict;
|
||||||
// bool jmnedict;
|
// bool jmnedict;
|
||||||
|
|
||||||
|
// JishoAttribution({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.dbpedia,
|
||||||
|
// required this.jmdict,
|
||||||
|
// required this.jmnedict,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoAttribution.fromJishoObject(final jisho.JishoAttribution object)
|
||||||
|
// : id = 0,
|
||||||
|
// dbpedia = object.dbpedia,
|
||||||
|
// jmdict = object.jmdict,
|
||||||
|
// jmnedict = object.jmnedict;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class JishoJapaneseWord {
|
// class JishoJapaneseWord {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// String reading;
|
// String? reading;
|
||||||
// String word;
|
// String? word;
|
||||||
|
|
||||||
|
// JishoJapaneseWord({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.reading,
|
||||||
|
// required this.word,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoJapaneseWord.fromJishoObject(final jisho.JishoJapaneseWord object)
|
||||||
|
// : id = 0,
|
||||||
|
// reading = object.reading,
|
||||||
|
// word = object.word;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class JishoWordSense {
|
// class JishoWordSense {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// List<String> antonyms;
|
// List<String> antonyms;
|
||||||
// List<String> english_definitions;
|
// List<String> english_definitions;
|
||||||
// List<String> info;
|
// List<String> info;
|
||||||
// final links = ToMany<JishoSenseLink>();
|
// List<JishoSenseLink> links;
|
||||||
// List<String> parts_of_speech;
|
// List<String> parts_of_speech;
|
||||||
// List<String> restrictions;
|
// List<String> restrictions;
|
||||||
// List<String> see_also;
|
// List<String> see_also;
|
||||||
// List<dynamic> source;
|
// List<JishoWordSource> source;
|
||||||
// List<String> tags;
|
// List<String> tags;
|
||||||
|
|
||||||
|
// JishoWordSense({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.antonyms,
|
||||||
|
// required this.english_definitions,
|
||||||
|
// required this.info,
|
||||||
|
// required this.links,
|
||||||
|
// required this.parts_of_speech,
|
||||||
|
// required this.restrictions,
|
||||||
|
// required this.see_also,
|
||||||
|
// required this.source,
|
||||||
|
// required this.tags,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoWordSense.fromJishoObject(final jisho.JishoWordSense object)
|
||||||
|
// : id = 0,
|
||||||
|
// antonyms = object.antonyms,
|
||||||
|
// english_definitions = object.englishDefinitions,
|
||||||
|
// info = object.info,
|
||||||
|
// links =
|
||||||
|
// object.links.map((l) => JishoSenseLink.fromJishoObject(l)).toList(),
|
||||||
|
// parts_of_speech = object.partsOfSpeech,
|
||||||
|
// restrictions = object.restrictions,
|
||||||
|
// see_also = object.seeAlso,
|
||||||
|
// source = object.source
|
||||||
|
// .map((s) => JishoWordSource.fromJishoObject(s))
|
||||||
|
// .toList(),
|
||||||
|
// tags = object.tags;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Entity()
|
||||||
|
// class JishoWordSource {
|
||||||
|
// int id;
|
||||||
|
// String language;
|
||||||
|
// String? word;
|
||||||
|
|
||||||
|
// JishoWordSource({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.language,
|
||||||
|
// required this.word,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoWordSource.fromJishoObject(final jisho.JishoWordSource object)
|
||||||
|
// : id = 0,
|
||||||
|
// language = object.language,
|
||||||
|
// word = object.word;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Entity()
|
// @Entity()
|
||||||
// class JishoSenseLink {
|
// class JishoSenseLink {
|
||||||
// int id = 0;
|
// int id;
|
||||||
// String text;
|
// String text;
|
||||||
// String url;
|
// String url;
|
||||||
|
|
||||||
|
// JishoSenseLink({
|
||||||
|
// this.id = 0,
|
||||||
|
// required this.text,
|
||||||
|
// required this.url,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// JishoSenseLink.fromJishoObject(final jisho.JishoSenseLink object)
|
||||||
|
// : id = 0,
|
||||||
|
// text = object.text,
|
||||||
|
// url = object.url;
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -1,34 +1,42 @@
|
||||||
part of './theme.dart';
|
part of './theme.dart';
|
||||||
|
|
||||||
class DarkTheme extends AppTheme {
|
class DarkTheme extends AppTheme {
|
||||||
|
@override
|
||||||
ColorSet get kanjiResultColor => const ColorSet(
|
ColorSet get kanjiResultColor => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.green,
|
background: Colors.green,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get onyomiColor => const ColorSet(
|
ColorSet get onyomiColor => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.orange,
|
background: Colors.orange,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get kunyomiColor => const ColorSet(
|
ColorSet get kunyomiColor => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.lightBlue,
|
background: Colors.lightBlue,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
Color get foreground => Colors.black;
|
Color get foreground => Colors.black;
|
||||||
|
@override
|
||||||
Color get background => Colors.white;
|
Color get background => Colors.white;
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get menuGreyLight => ColorSet(
|
ColorSet get menuGreyLight => ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.grey.shade700,
|
background: Colors.grey.shade700,
|
||||||
);
|
);
|
||||||
|
|
||||||
ColorSet get menuGreyNormal => ColorSet(
|
@override
|
||||||
|
ColorSet get menuGreyNormal => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.grey,
|
background: Colors.grey,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get menuGreyDark => ColorSet(
|
ColorSet get menuGreyDark => ColorSet(
|
||||||
foreground: Colors.black,
|
foreground: Colors.black,
|
||||||
background: Colors.grey.shade300,
|
background: Colors.grey.shade300,
|
||||||
|
|
|
@ -1,33 +1,41 @@
|
||||||
part of './theme.dart';
|
part of './theme.dart';
|
||||||
|
|
||||||
class LightTheme extends AppTheme {
|
class LightTheme extends AppTheme {
|
||||||
|
@override
|
||||||
ColorSet get kanjiResultColor => const ColorSet(
|
ColorSet get kanjiResultColor => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.blue,
|
background: Colors.blue,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get onyomiColor => const ColorSet(
|
ColorSet get onyomiColor => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.orange,
|
background: Colors.orange,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get kunyomiColor => const ColorSet(
|
ColorSet get kunyomiColor => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.lightBlue,
|
background: Colors.lightBlue,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
Color get foreground => Colors.black;
|
Color get foreground => Colors.black;
|
||||||
|
@override
|
||||||
Color get background => Colors.white;
|
Color get background => Colors.white;
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get menuGreyLight => ColorSet(
|
ColorSet get menuGreyLight => ColorSet(
|
||||||
foreground: Colors.black,
|
foreground: Colors.black,
|
||||||
background: Colors.grey.shade300,
|
background: Colors.grey.shade300,
|
||||||
);
|
);
|
||||||
ColorSet get menuGreyNormal => ColorSet(
|
@override
|
||||||
|
ColorSet get menuGreyNormal => const ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.grey,
|
background: Colors.grey,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
ColorSet get menuGreyDark => ColorSet(
|
ColorSet get menuGreyDark => ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Colors.grey.shade700,
|
background: Colors.grey.shade700,
|
||||||
|
|
|
@ -4,7 +4,6 @@ part 'light.dart';
|
||||||
part 'dark.dart';
|
part 'dark.dart';
|
||||||
|
|
||||||
abstract class AppTheme {
|
abstract class AppTheme {
|
||||||
|
|
||||||
static const ColorSet jishoGreen = ColorSet(
|
static const ColorSet jishoGreen = ColorSet(
|
||||||
foreground: Colors.white,
|
foreground: Colors.white,
|
||||||
background: Color(0xFF3EDD00),
|
background: Color(0xFF3EDD00),
|
||||||
|
@ -49,14 +48,17 @@ class ColorSet {
|
||||||
|
|
||||||
/// Source: https://blog.usejournal.com/creating-a-custom-color-swatch-in-flutter-554bcdcb27f3
|
/// Source: https://blog.usejournal.com/creating-a-custom-color-swatch-in-flutter-554bcdcb27f3
|
||||||
MaterialColor createMaterialColor(Color color) {
|
MaterialColor createMaterialColor(Color color) {
|
||||||
List strengths = <double>[.05];
|
final List<double> strengths = [.05];
|
||||||
final swatch = <int, Color>{};
|
final swatch = <int, Color>{};
|
||||||
final int r = color.red, g = color.green, b = color.blue;
|
final int r = color.red;
|
||||||
|
final int g = color.green;
|
||||||
|
final int b = color.blue;
|
||||||
|
|
||||||
for (int i = 1; i < 10; i++) {
|
for (int i = 1; i < 10; i++) {
|
||||||
strengths.add(0.1 * i);
|
strengths.add(0.1 * i);
|
||||||
}
|
}
|
||||||
strengths.forEach((strength) {
|
|
||||||
|
for (final strength in strengths) {
|
||||||
final double ds = 0.5 - strength;
|
final double ds = 0.5 - strength;
|
||||||
swatch[(strength * 1000).round()] = Color.fromRGBO(
|
swatch[(strength * 1000).round()] = Color.fromRGBO(
|
||||||
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
|
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
|
||||||
|
@ -64,6 +66,6 @@ MaterialColor createMaterialColor(Color color) {
|
||||||
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
|
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
return MaterialColor(color.value, swatch);
|
return MaterialColor(color.value, swatch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
{
|
|
||||||
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
|
|
||||||
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
|
|
||||||
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"id": "3:8314315977756262774",
|
|
||||||
"lastPropertyId": "4:7972948456299367594",
|
|
||||||
"name": "WordResult",
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": "1:8286440150679521496",
|
|
||||||
"name": "id",
|
|
||||||
"type": 6,
|
|
||||||
"flags": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2:2698026687178480112",
|
|
||||||
"name": "timestamp",
|
|
||||||
"type": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "3:8750782874894963158",
|
|
||||||
"name": "word",
|
|
||||||
"type": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "4:7972948456299367594",
|
|
||||||
"name": "searchStringId",
|
|
||||||
"type": 11,
|
|
||||||
"flags": 520,
|
|
||||||
"indexId": "1:6146948198859733323",
|
|
||||||
"relationTarget": "WordQuery"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"relations": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "4:4256390943850643278",
|
|
||||||
"lastPropertyId": "3:1496429060084558178",
|
|
||||||
"name": "KanjiQuery",
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": "1:2966275213904862677",
|
|
||||||
"name": "id",
|
|
||||||
"type": 6,
|
|
||||||
"flags": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2:3733952844232949036",
|
|
||||||
"name": "kanji",
|
|
||||||
"type": 9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"relations": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "5:3499538826755540666",
|
|
||||||
"lastPropertyId": "3:1154921921492752045",
|
|
||||||
"name": "WordQuery",
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": "1:2582448470002735577",
|
|
||||||
"name": "id",
|
|
||||||
"type": 6,
|
|
||||||
"flags": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2:6622038022626247037",
|
|
||||||
"name": "query",
|
|
||||||
"type": 9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"relations": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "6:8118874861016646859",
|
|
||||||
"lastPropertyId": "5:818915488505962903",
|
|
||||||
"name": "Search",
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": "1:3233720904924970047",
|
|
||||||
"name": "id",
|
|
||||||
"type": 6,
|
|
||||||
"flags": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2:7793044338609887616",
|
|
||||||
"name": "timestamp",
|
|
||||||
"type": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "4:5737790291742758071",
|
|
||||||
"name": "wordQueryId",
|
|
||||||
"type": 11,
|
|
||||||
"flags": 520,
|
|
||||||
"indexId": "4:4174896839978600983",
|
|
||||||
"relationTarget": "WordQuery"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "5:818915488505962903",
|
|
||||||
"name": "kanjiQueryId",
|
|
||||||
"type": 11,
|
|
||||||
"flags": 520,
|
|
||||||
"indexId": "5:5394995618034342416",
|
|
||||||
"relationTarget": "KanjiQuery"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"relations": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lastEntityId": "6:8118874861016646859",
|
|
||||||
"lastIndexId": "5:5394995618034342416",
|
|
||||||
"lastRelationId": "1:2624712325077938293",
|
|
||||||
"lastSequenceId": "0:0",
|
|
||||||
"modelVersion": 5,
|
|
||||||
"modelVersionParserMinimum": 5,
|
|
||||||
"retiredEntityUids": [
|
|
||||||
8135239166970424087,
|
|
||||||
461492167249325765
|
|
||||||
],
|
|
||||||
"retiredIndexUids": [
|
|
||||||
2344626140411525437,
|
|
||||||
1957456749938325194
|
|
||||||
],
|
|
||||||
"retiredPropertyUids": [
|
|
||||||
2681934095975267680,
|
|
||||||
4514526257378540330,
|
|
||||||
1930470268740402049,
|
|
||||||
4297905889790758495,
|
|
||||||
4157902147911002923,
|
|
||||||
7573103520245228403,
|
|
||||||
1496429060084558178,
|
|
||||||
1154921921492752045,
|
|
||||||
2254834401134912797
|
|
||||||
],
|
|
||||||
"retiredRelationUids": [
|
|
||||||
2624712325077938293
|
|
||||||
],
|
|
||||||
"version": 1
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'view/home.dart';
|
||||||
|
import 'view/screens/search/kanji_result_page.dart';
|
||||||
|
import 'view/screens/search/search_results_page.dart';
|
||||||
|
|
||||||
|
Route<Widget> generateRoute(RouteSettings settings) {
|
||||||
|
final args = settings.arguments;
|
||||||
|
|
||||||
|
switch (settings.name) {
|
||||||
|
case '/':
|
||||||
|
return MaterialPageRoute(builder: (_) => const Home());
|
||||||
|
|
||||||
|
case '/search':
|
||||||
|
final searchTerm = args! as String;
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => SearchResultsPage(searchTerm: searchTerm),
|
||||||
|
);
|
||||||
|
|
||||||
|
case '/kanjiSearch':
|
||||||
|
final searchTerm = args! as String;
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => KanjiResultPage(kanjiSearchTerm: searchTerm),
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => const Text('ERROR: this route does not exist'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
export 'package:unofficial_jisho_api/api.dart' show JishoAPIResult;
|
||||||
|
|
||||||
Future<jisho.JishoAPIResult> fetchJishoResults(searchTerm) async {
|
Future<jisho.JishoAPIResult> fetchJishoResults(searchTerm) async {
|
||||||
return await jisho.searchForPhrase(searchTerm);
|
return jisho.searchForPhrase(searchTerm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
export 'package:unofficial_jisho_api/api.dart' show KanjiResult;
|
||||||
|
|
||||||
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',
|
||||||
"grade 4": "小4",
|
'grade 4': '小4',
|
||||||
"grade 5": "小5",
|
'grade 5': '小5',
|
||||||
"grade 6": "小6",
|
'grade 6': '小6',
|
||||||
"junior high": "中"
|
'junior high': '中'
|
||||||
};
|
};
|
||||||
|
|
||||||
print('conversion run: $grade -> ${conversionTable[grade]}');
|
debugPrint('conversion run: $grade -> ${conversionTable[grade]}');
|
||||||
|
|
||||||
return conversionTable[grade];
|
return conversionTable[grade];
|
||||||
}
|
}
|
||||||
|
@ -23,4 +25,4 @@ Future<jisho.KanjiResult> fetchKanji(String kanji) async {
|
||||||
if (result.data != null && result.data?.taughtIn != null)
|
if (result.data != null && result.data?.taughtIn != null)
|
||||||
result.data!.taughtIn = _convertGrade(result.data!.taughtIn!);
|
result.data!.taughtIn = _convertGrade(result.data!.taughtIn!);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class LoadingScreen extends StatelessWidget {
|
class LoadingScreen extends StatelessWidget {
|
||||||
|
const LoadingScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return const Center(
|
||||||
child: Center(
|
child: CircularProgressIndicator(),
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
|
||||||
|
import '../../../models/themes/theme.dart';
|
||||||
|
|
||||||
class SplashScreen extends StatelessWidget {
|
class SplashScreen extends StatelessWidget {
|
||||||
const SplashScreen({Key? key}) : super(key: key);
|
const SplashScreen({Key? key}) : super(key: key);
|
||||||
|
@ -8,9 +9,11 @@ class SplashScreen extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(color: AppTheme.jishoGreen.background),
|
decoration: BoxDecoration(color: AppTheme.jishoGreen.background),
|
||||||
child: Center(
|
child: const Center(
|
||||||
child: Image.asset('assets/images/logo/logo_icon_transparent.png'),
|
child: Image(
|
||||||
|
image: AssetImage('assets/images/logo/logo_icon_transparent.png'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
import '../../../bloc/theme/theme_bloc.dart';
|
||||||
|
import '../../../models/themes/theme.dart';
|
||||||
|
|
||||||
class DateDivider extends StatelessWidget {
|
class DateDivider extends StatelessWidget {
|
||||||
final String? text;
|
final String? text;
|
||||||
|
@ -33,31 +34,31 @@ class DateDivider extends StatelessWidget {
|
||||||
final int day = date.day;
|
final int day = date.day;
|
||||||
final String month = monthTable[date.month]!;
|
final String month = monthTable[date.month]!;
|
||||||
final int year = date.year;
|
final int year = date.year;
|
||||||
return "$day. $month $year";
|
return '$day. $month $year';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Widget header = (this.text != null)
|
final Widget header = (text != null)
|
||||||
? Text(this.text!)
|
? Text(text!)
|
||||||
: (this.date != null)
|
: (date != null)
|
||||||
? Text(getHumanReadableDate(this.date!))
|
? Text(getHumanReadableDate(date!))
|
||||||
: SizedBox.shrink();
|
: const SizedBox.shrink();
|
||||||
|
|
||||||
final ColorSet _menuColors =
|
final ColorSet _menuColors =
|
||||||
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyNormal;
|
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyNormal;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
|
decoration: BoxDecoration(color: _menuColors.background),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 5,
|
||||||
|
horizontal: 10,
|
||||||
|
),
|
||||||
|
margin: margin,
|
||||||
child: DefaultTextStyle.merge(
|
child: DefaultTextStyle.merge(
|
||||||
child: header,
|
child: header,
|
||||||
style: TextStyle(color: _menuColors.foreground),
|
style: TextStyle(color: _menuColors.foreground),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(color: _menuColors.background),
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 5,
|
|
||||||
horizontal: 10,
|
|
||||||
),
|
|
||||||
margin: this.margin,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/navigation/navigation_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/models/history/kanji_query.dart';
|
|
||||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
|
||||||
|
|
||||||
import './search_item.dart';
|
import './search_item.dart';
|
||||||
|
import '../../../bloc/theme/theme_bloc.dart';
|
||||||
|
import '../../../models/history/kanji_query.dart';
|
||||||
|
import '../../../models/themes/theme.dart';
|
||||||
|
|
||||||
class _KanjiBox extends StatelessWidget {
|
class _KanjiBox extends StatelessWidget {
|
||||||
final String kanji;
|
final String kanji;
|
||||||
|
@ -15,13 +13,14 @@ class _KanjiBox extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ColorSet _menuColors = BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
|
final ColorSet _menuColors =
|
||||||
|
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
|
||||||
|
|
||||||
return IntrinsicHeight(
|
return IntrinsicHeight(
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(5),
|
padding: const EdgeInsets.all(5),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _menuColors.background,
|
color: _menuColors.background,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
@ -56,27 +55,30 @@ class KanjiSearchItem extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Slidable(
|
return Slidable(
|
||||||
|
endActionPane: ActionPane(
|
||||||
|
motion: const ScrollMotion(),
|
||||||
|
children: [
|
||||||
|
SlidableAction(
|
||||||
|
label: 'Favourite',
|
||||||
|
backgroundColor: Colors.yellow,
|
||||||
|
icon: Icons.star,
|
||||||
|
onPressed: (_) {},
|
||||||
|
),
|
||||||
|
SlidableAction(
|
||||||
|
label: 'Delete',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
icon: Icons.delete,
|
||||||
|
onPressed: (_) {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
child: SearchItem(
|
child: SearchItem(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
BlocProvider.of<NavigationBloc>(context).add(ChangePage(1));
|
Navigator.pushNamed(context, '/kanjiSearch', arguments: result.kanji);
|
||||||
BlocProvider.of<KanjiBloc>(context).add(GetKanji(this.result.kanji));
|
|
||||||
},
|
},
|
||||||
time: timestamp,
|
time: timestamp,
|
||||||
search: _KanjiBox(result.kanji),
|
search: _KanjiBox(result.kanji),
|
||||||
),
|
),
|
||||||
actionPane: SlidableScrollActionPane(),
|
|
||||||
secondaryActions: [
|
|
||||||
IconSlideAction(
|
|
||||||
caption: "Favourite",
|
|
||||||
color: Colors.yellow,
|
|
||||||
icon: Icons.star,
|
|
||||||
),
|
|
||||||
IconSlideAction(
|
|
||||||
caption: "Delete",
|
|
||||||
color: Colors.red,
|
|
||||||
icon: Icons.delete,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
import 'package:jisho_study_tool/bloc/navigation/navigation_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/models/history/word_query.dart';
|
|
||||||
|
|
||||||
import './search_item.dart';
|
import './search_item.dart';
|
||||||
|
import '../../../models/history/word_query.dart';
|
||||||
|
|
||||||
class PhraseSearchItem extends StatelessWidget {
|
class PhraseSearchItem extends StatelessWidget {
|
||||||
final WordQuery search;
|
final WordQuery search;
|
||||||
|
@ -19,16 +17,25 @@ class PhraseSearchItem extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Slidable(
|
return Slidable(
|
||||||
actionPane: SlidableScrollActionPane(),
|
endActionPane: ActionPane(
|
||||||
secondaryActions: [
|
motion: const ScrollMotion(),
|
||||||
IconSlideAction(
|
children: [
|
||||||
caption: "Delete", color: Colors.red, icon: Icons.delete)
|
|
||||||
],
|
SlidableAction(
|
||||||
|
label: 'Delete',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
icon: Icons.delete,
|
||||||
|
onPressed: (_) {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
),
|
||||||
child: SearchItem(
|
child: SearchItem(
|
||||||
onTap: () {
|
onTap: () => Navigator.pushNamed(
|
||||||
BlocProvider.of<NavigationBloc>(context).add(ChangePage(0));
|
context,
|
||||||
BlocProvider.of<SearchBloc>(context).add(GetSearchResults(this.search.query));
|
'/search',
|
||||||
},
|
arguments: search.query,
|
||||||
|
),
|
||||||
time: timestamp,
|
time: timestamp,
|
||||||
search: Text(search.query),
|
search: Text(search.query),
|
||||||
),
|
),
|
||||||
|
|
|
@ -13,26 +13,24 @@ class SearchItem extends StatelessWidget {
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
String getTime() {
|
String getTime() {
|
||||||
final hours = this.time.hour.toString().padLeft(2, '0');
|
final hours = time.hour.toString().padLeft(2, '0');
|
||||||
final mins = this.time.minute.toString().padLeft(2, '0');
|
final mins = time.minute.toString().padLeft(2, '0');
|
||||||
return "$hours:$mins";
|
return '$hours:$mins';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return ListTile(
|
||||||
child: ListTile(
|
onTap: onTap,
|
||||||
onTap: onTap,
|
contentPadding: EdgeInsets.zero,
|
||||||
contentPadding: EdgeInsets.zero,
|
title: Row(
|
||||||
title: Row(
|
children: [
|
||||||
children: [
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
child: Text(getTime()),
|
||||||
child: Text(getTime()),
|
),
|
||||||
),
|
search,
|
||||||
search,
|
],
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
import './kanji_result_body/examples.dart';
|
||||||
|
import './kanji_result_body/grade.dart';
|
||||||
|
import './kanji_result_body/header.dart';
|
||||||
|
import './kanji_result_body/jlpt_level.dart';
|
||||||
|
import './kanji_result_body/radical.dart';
|
||||||
|
import './kanji_result_body/rank.dart';
|
||||||
|
import './kanji_result_body/stroke_order_gif.dart';
|
||||||
|
import './kanji_result_body/yomi_chips.dart';
|
||||||
|
|
||||||
|
class KanjiResultBody extends StatelessWidget {
|
||||||
|
late final String query;
|
||||||
|
late final jisho.KanjiResultData resultData;
|
||||||
|
|
||||||
|
KanjiResultBody({required jisho.KanjiResult result, Key? key})
|
||||||
|
: super(key: key) {
|
||||||
|
query = result.query;
|
||||||
|
|
||||||
|
// TODO: Handle this kind of exception before widget is initialized
|
||||||
|
if (result.data == null) throw Exception();
|
||||||
|
|
||||||
|
resultData = result.data!;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 30.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
const Flexible(
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Center(child: SizedBox()),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Center(child: Header(kanji: query)),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Center(
|
||||||
|
child: (resultData.radical != null)
|
||||||
|
? Radical(radical: resultData.radical!)
|
||||||
|
: const SizedBox(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
YomiChips(yomi: resultData.meaning.split(', '), type: YomiType.meaning),
|
||||||
|
(resultData.onyomi.isNotEmpty)
|
||||||
|
? YomiChips(yomi: resultData.onyomi, type: YomiType.onyomi)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
(resultData.kunyomi.isNotEmpty)
|
||||||
|
? YomiChips(yomi: resultData.kunyomi, type: YomiType.kunyomi)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
StrokeOrderGif(uri: resultData.strokeOrderGifUri),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text('JLPT: ', style: TextStyle(fontSize: 20.0)),
|
||||||
|
JlptLevel(jlptLevel: resultData.jlptLevel ?? '⨉'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text('Grade: ', style: TextStyle(fontSize: 20.0)),
|
||||||
|
Grade(grade: resultData.taughtIn ?? '⨉'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text('Rank: ', style: TextStyle(fontSize: 20.0)),
|
||||||
|
Rank(rank: resultData.newspaperFrequencyRank ?? -1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Examples(
|
||||||
|
onyomi: resultData.onyomiExamples,
|
||||||
|
kunyomi: resultData.kunyomiExamples,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,17 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
class Examples extends StatelessWidget {
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
final List<YomiExample> onyomiExamples;
|
|
||||||
final List<YomiExample> kunyomiExamples;
|
|
||||||
|
|
||||||
const Examples(
|
class Examples extends StatelessWidget {
|
||||||
this.onyomiExamples,
|
final List<YomiExample> onyomi;
|
||||||
this.kunyomiExamples,
|
final List<YomiExample> kunyomi;
|
||||||
);
|
|
||||||
|
const Examples({
|
||||||
|
required this.onyomi,
|
||||||
|
required this.kunyomi,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -17,20 +19,21 @@ class Examples extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
[
|
[
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 10),
|
margin: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: const Text(
|
||||||
'Examples:',
|
'Examples:',
|
||||||
style: TextStyle(fontSize: 20),
|
style: TextStyle(fontSize: 20),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
onyomiExamples
|
onyomi
|
||||||
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
||||||
.toList(),
|
.toList(),
|
||||||
kunyomiExamples
|
kunyomi
|
||||||
.map(
|
.map(
|
||||||
(kunyomiExample) => _Example(kunyomiExample, _KanaType.kunyomi))
|
(kunyomiExample) => _Example(kunyomiExample, _KanaType.kunyomi),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
].expand((list) => list).toList(),
|
].expand((list) => list).toList(),
|
||||||
);
|
);
|
||||||
|
@ -48,68 +51,66 @@ class _Example extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _themeData = BlocProvider.of<ThemeBloc>(context).state.theme;
|
final _themeData = BlocProvider.of<ThemeBloc>(context).state.theme;
|
||||||
final _kanaColors = kanaType == _KanaType.kunyomi ? _themeData.kunyomiColor : _themeData.onyomiColor;
|
final _kanaColors = kanaType == _KanaType.kunyomi
|
||||||
|
? _themeData.kunyomiColor
|
||||||
|
: _themeData.onyomiColor;
|
||||||
final _menuColors = _themeData.menuGreyNormal;
|
final _menuColors = _themeData.menuGreyNormal;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(
|
margin: const EdgeInsets.symmetric(
|
||||||
vertical: 5.0,
|
vertical: 5.0,
|
||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _menuColors.background, borderRadius: BorderRadius.circular(10.0)),
|
color: _menuColors.background,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 10.0,
|
vertical: 10.0,
|
||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _kanaColors.background,
|
color: _kanaColors.background,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(10.0),
|
topLeft: Radius.circular(10.0),
|
||||||
bottomLeft: Radius.circular(10.0),
|
bottomLeft: Radius.circular(10.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Text(
|
||||||
child: Text(
|
yomiExample.reading,
|
||||||
yomiExample.reading,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: _kanaColors.foreground,
|
||||||
color: _kanaColors.foreground,
|
fontSize: 15.0,
|
||||||
fontSize: 15.0,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 5.0,
|
height: 5.0,
|
||||||
),
|
),
|
||||||
Container(
|
Text(
|
||||||
child: Text(
|
yomiExample.example,
|
||||||
yomiExample.example,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: _kanaColors.foreground,
|
||||||
color: _kanaColors.foreground,
|
fontSize: 20.0,
|
||||||
fontSize: 20.0,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
width: 15.0,
|
width: 15.0,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Text(
|
||||||
child: Text(
|
yomiExample.meaning,
|
||||||
yomiExample.meaning,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: _menuColors.foreground,
|
||||||
color: _menuColors.foreground,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
|
@ -1,17 +1,22 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Grade extends StatelessWidget {
|
class Grade extends StatelessWidget {
|
||||||
final String grade;
|
final String grade;
|
||||||
|
|
||||||
const Grade(this.grade);
|
const Grade({required this.grade, Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _kanjiColors.background,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
grade,
|
grade,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -19,10 +24,6 @@ class Grade extends StatelessWidget {
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: _kanjiColors.background,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Header extends StatelessWidget {
|
class Header extends StatelessWidget {
|
||||||
final String kanji;
|
final String kanji;
|
||||||
|
|
||||||
const Header(this.kanji);
|
const Header({
|
||||||
|
required this.kanji,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
final _kanjiColors =
|
||||||
|
BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return AspectRatio(
|
return AspectRatio(
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
|
@ -1,18 +1,26 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class JlptLevel extends StatelessWidget {
|
class JlptLevel extends StatelessWidget {
|
||||||
final String jlptLevel;
|
final String jlptLevel;
|
||||||
|
|
||||||
const JlptLevel(this.jlptLevel);
|
const JlptLevel({
|
||||||
|
required this.jlptLevel,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
final _kanjiColors =
|
||||||
|
BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: _kanjiColors.background,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
jlptLevel,
|
jlptLevel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -20,10 +28,6 @@ class JlptLevel extends StatelessWidget {
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: _kanjiColors.background,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,24 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Radical extends StatelessWidget {
|
class Radical extends StatelessWidget {
|
||||||
final jisho.Radical radical;
|
final jisho.Radical radical;
|
||||||
|
|
||||||
const Radical(this.radical);
|
const Radical({required this.radical, Key? key,}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: _kanjiColors.background,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
radical.symbol,
|
radical.symbol,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -20,10 +26,6 @@ class Radical extends StatelessWidget {
|
||||||
fontSize: 40.0,
|
fontSize: 40.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: _kanjiColors.background,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,23 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Rank extends StatelessWidget {
|
class Rank extends StatelessWidget {
|
||||||
final int rank;
|
final int rank;
|
||||||
|
|
||||||
const Rank(this.rank);
|
const Rank({required this.rank, Key? key,}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
color: _kanjiColors.background,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${rank.toString()} / 2500',
|
'${rank.toString()} / 2500',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -20,10 +25,6 @@ class Rank extends StatelessWidget {
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
color: _kanjiColors.background,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,26 +1,28 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class StrokeOrderGif extends StatelessWidget {
|
class StrokeOrderGif extends StatelessWidget {
|
||||||
final String uri;
|
final String uri;
|
||||||
|
|
||||||
const StrokeOrderGif(this.uri);
|
const StrokeOrderGif({required this.uri, Key? key,}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(vertical: 20.0),
|
margin: const EdgeInsets.symmetric(vertical: 20.0),
|
||||||
padding: EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: ClipRRect(
|
|
||||||
child: Image.network(uri),
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _kanjiColors.background,
|
color: _kanjiColors.background,
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
),
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
child: Image.network(uri),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
|
enum YomiType {
|
||||||
|
onyomi,
|
||||||
|
kunyomi,
|
||||||
|
meaning,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on YomiType {
|
||||||
|
String get title {
|
||||||
|
switch (this) {
|
||||||
|
case YomiType.onyomi:
|
||||||
|
return 'Onyomi';
|
||||||
|
case YomiType.kunyomi:
|
||||||
|
return 'Kunyomi';
|
||||||
|
case YomiType.meaning:
|
||||||
|
return 'Meanings';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorSet getColors(BuildContext context) {
|
||||||
|
final theme = BlocProvider.of<ThemeBloc>(context).state.theme;
|
||||||
|
|
||||||
|
switch (this) {
|
||||||
|
case YomiType.onyomi:
|
||||||
|
return theme.onyomiColor;
|
||||||
|
case YomiType.kunyomi:
|
||||||
|
return theme.kunyomiColor;
|
||||||
|
case YomiType.meaning:
|
||||||
|
return theme.menuGreyNormal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class YomiChips extends StatelessWidget {
|
||||||
|
final List<String> yomi;
|
||||||
|
final YomiType type;
|
||||||
|
|
||||||
|
const YomiChips({
|
||||||
|
required this.yomi,
|
||||||
|
required this.type,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
bool get isExpandable => yomi.length > 6;
|
||||||
|
|
||||||
|
Widget yomiCard({
|
||||||
|
required BuildContext context,
|
||||||
|
required String yomi,
|
||||||
|
required ColorSet colors,
|
||||||
|
}) =>
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0,
|
||||||
|
horizontal: 10.0,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: type.getColors(context).background,
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
yomi,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.0,
|
||||||
|
color: colors.foreground,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget yomiWrapper(BuildContext context) {
|
||||||
|
final yomiCards = yomi
|
||||||
|
.map(
|
||||||
|
(y) => yomiCard(
|
||||||
|
context: context,
|
||||||
|
yomi: y,
|
||||||
|
colors: type.getColors(context),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (!isExpandable)
|
||||||
|
return Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: yomiCards,
|
||||||
|
);
|
||||||
|
else
|
||||||
|
return ExpansionTile(
|
||||||
|
// initiallyExpanded: false,
|
||||||
|
title: Center(
|
||||||
|
child: yomiCard(
|
||||||
|
context: context,
|
||||||
|
yomi: type.title,
|
||||||
|
colors: type.getColors(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 20.0,
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 10.0,
|
||||||
|
children: yomiCards,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 25.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.0,
|
||||||
|
vertical: 5.0,
|
||||||
|
),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: yomiWrapper(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,71 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
|
||||||
|
|
||||||
class KanjiSearchBar extends StatefulWidget {
|
|
||||||
|
|
||||||
const KanjiSearchBar();
|
|
||||||
|
|
||||||
@override
|
|
||||||
_KanjiSearchBarState createState() => new _KanjiSearchBarState();
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TextFieldButton {clear, paste}
|
|
||||||
|
|
||||||
class _KanjiSearchBarState extends State<KanjiSearchBar> {
|
|
||||||
final TextEditingController textController = new TextEditingController();
|
|
||||||
TextFieldButton button = TextFieldButton.paste;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _getKanjiSuggestions(String text) =>
|
|
||||||
BlocProvider.of<KanjiBloc>(context).add(GetKanjiSuggestions(text));
|
|
||||||
|
|
||||||
void updateSuggestions() => _getKanjiSuggestions(textController.text);
|
|
||||||
|
|
||||||
void _clearText() {
|
|
||||||
textController.text = '';
|
|
||||||
updateSuggestions();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _pasteText() async {
|
|
||||||
ClipboardData? clipboardData = await Clipboard.getData('text/plain');
|
|
||||||
if (clipboardData != null && clipboardData.text != null) {
|
|
||||||
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(
|
|
||||||
controller: textController,
|
|
||||||
onChanged: (text) => _getKanjiSuggestions(text),
|
|
||||||
onSubmitted: (_) => {},
|
|
||||||
decoration: new InputDecoration(
|
|
||||||
prefixIcon: Icon(Icons.search),
|
|
||||||
hintText: 'Search',
|
|
||||||
// fillColor: Colors.white,
|
|
||||||
// filled: true,
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
isDense: false,
|
|
||||||
suffixIcon: (button == TextFieldButton.clear) ? clearButton : pasteButton,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
import 'package:animated_size_and_fade/animated_size_and_fade.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../services/kanji_suggestions.dart';
|
||||||
|
import 'kanji_search_body/kanji_grid.dart';
|
||||||
|
import 'kanji_search_body/kanji_search_bar.dart';
|
||||||
|
import 'kanji_search_body/kanji_search_options_bar.dart';
|
||||||
|
|
||||||
|
class KanjiSearchBody extends StatefulWidget {
|
||||||
|
const KanjiSearchBody({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_KanjiSearchBodyState createState() => _KanjiSearchBodyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _KanjiSearchBodyState extends State<KanjiSearchBody>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late final AnimationController _controller;
|
||||||
|
late final Animation _searchbarMovementAnimation;
|
||||||
|
final FocusNode focus = FocusNode();
|
||||||
|
final GlobalKey<KanjiSearchBarState> _kanjiSearchBarState =
|
||||||
|
GlobalKey<KanjiSearchBarState>();
|
||||||
|
List<String> suggestions = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_controller = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
);
|
||||||
|
|
||||||
|
_searchbarMovementAnimation = AlignmentTween(
|
||||||
|
begin: Alignment.center,
|
||||||
|
end: Alignment.topCenter,
|
||||||
|
).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () async {
|
||||||
|
if (_controller.value == 1) {
|
||||||
|
focus.unfocus();
|
||||||
|
_kanjiSearchBarState.currentState!.clearText();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: _searchbarMovementAnimation,
|
||||||
|
builder: (context, _) {
|
||||||
|
return Container(
|
||||||
|
alignment: _searchbarMovementAnimation.value,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Focus(
|
||||||
|
focusNode: focus,
|
||||||
|
onFocusChange: (hasFocus) {
|
||||||
|
if (hasFocus)
|
||||||
|
_controller.forward();
|
||||||
|
else
|
||||||
|
_controller.reverse();
|
||||||
|
},
|
||||||
|
child: KanjiSearchBar(
|
||||||
|
key: _kanjiSearchBarState,
|
||||||
|
onChanged: (text) => setState(() {
|
||||||
|
suggestions = kanjiSuggestions(text);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AnimatedSizeAndFade(
|
||||||
|
fadeDuration: const Duration(milliseconds: 200),
|
||||||
|
sizeDuration: const Duration(milliseconds: 300),
|
||||||
|
child: _controller.value == 1
|
||||||
|
? KanjiGrid(suggestions: suggestions)
|
||||||
|
: const KanjiSearchOptionsBar(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import '../../../../bloc/theme/theme_bloc.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
|
||||||
class KanjiGrid extends StatelessWidget {
|
class KanjiGrid extends StatelessWidget {
|
||||||
final List<String> suggestions;
|
final List<String> suggestions;
|
||||||
const KanjiGrid(this.suggestions);
|
|
||||||
|
const KanjiGrid({required this.suggestions, Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 20.0,
|
vertical: 20.0,
|
||||||
horizontal: 40.0,
|
horizontal: 40.0,
|
||||||
),
|
),
|
||||||
|
@ -33,29 +33,28 @@ class _GridItem extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
BlocProvider.of<KanjiBloc>(context).add(GetKanji(kanji));
|
Navigator.pushNamed(context, '/kanjiSearch', arguments: kanji);
|
||||||
},
|
},
|
||||||
child: BlocBuilder<ThemeBloc, ThemeState>(
|
child: BlocBuilder<ThemeBloc, ThemeState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final _menuColors = state.theme.menuGreyLight;
|
final _menuColors = state.theme.menuGreyLight;
|
||||||
return
|
return Container(
|
||||||
Container(
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: _menuColors.background,
|
||||||
color: _menuColors.background,
|
borderRadius: BorderRadius.circular(20.0),
|
||||||
borderRadius: BorderRadius.circular(20.0),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.all(10.0),
|
|
||||||
child: FittedBox(
|
|
||||||
child: Text(
|
|
||||||
kanji,
|
|
||||||
style: TextStyle(color: _menuColors.foreground),
|
|
||||||
),
|
),
|
||||||
),
|
child: Container(
|
||||||
),
|
margin: const EdgeInsets.all(10.0),
|
||||||
);
|
child: FittedBox(
|
||||||
|
child: Text(
|
||||||
|
kanji,
|
||||||
|
style: TextStyle(color: _menuColors.foreground),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class KanjiSearchBar extends StatefulWidget {
|
||||||
|
final Function(String)? onChanged;
|
||||||
|
|
||||||
|
const KanjiSearchBar({this.onChanged, Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
KanjiSearchBarState createState() => KanjiSearchBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextFieldButton { clear, paste }
|
||||||
|
|
||||||
|
class KanjiSearchBarState extends State<KanjiSearchBar> {
|
||||||
|
final TextEditingController textController = TextEditingController();
|
||||||
|
TextFieldButton button = TextFieldButton.paste;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void runOnChanged() {
|
||||||
|
if (widget.onChanged != null) widget.onChanged!(textController.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearText() {
|
||||||
|
textController.text = '';
|
||||||
|
runOnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pasteText() async {
|
||||||
|
final ClipboardData? clipboardData = await Clipboard.getData('text/plain');
|
||||||
|
if (clipboardData != null && clipboardData.text != null) {
|
||||||
|
textController.text = clipboardData.text!;
|
||||||
|
runOnChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final IconButton clearButton = IconButton(
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
onPressed: () => clearText(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final IconButton pasteButton = IconButton(
|
||||||
|
icon: const Icon(Icons.content_paste),
|
||||||
|
onPressed: () => pasteText(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return TextField(
|
||||||
|
controller: textController,
|
||||||
|
onChanged: (text) {
|
||||||
|
if (widget.onChanged != null) widget.onChanged!(text);
|
||||||
|
},
|
||||||
|
onSubmitted: (_) => {},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.search),
|
||||||
|
hintText: 'Search',
|
||||||
|
// fillColor: Colors.white,
|
||||||
|
// filled: true,
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
),
|
||||||
|
isDense: false,
|
||||||
|
suffixIcon:
|
||||||
|
(button == TextFieldButton.clear) ? clearButton : pasteButton,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
|
||||||
|
|
||||||
//TODO: Make buttons have an effect
|
//TODO: Make buttons have an effect
|
||||||
|
|
||||||
|
@ -13,25 +12,22 @@ class KanjiSearchOptionsBar extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
_IconButton(
|
_IconButton(
|
||||||
icon: Text(
|
icon: const Text(
|
||||||
"部",
|
'部',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed: () {},
|
||||||
BlocProvider.of<KanjiBloc>(context).add(ReturnToInitialState()),
|
|
||||||
),
|
),
|
||||||
_IconButton(
|
_IconButton(
|
||||||
icon: Icon(Icons.category),
|
icon: const Icon(Icons.category),
|
||||||
onPressed: () =>
|
onPressed: () {},
|
||||||
BlocProvider.of<KanjiBloc>(context).add(ReturnToInitialState()),
|
|
||||||
),
|
),
|
||||||
_IconButton(
|
_IconButton(
|
||||||
icon: Icon(Icons.mode),
|
icon: const Icon(Icons.mode),
|
||||||
onPressed: () =>
|
onPressed: () {},
|
||||||
BlocProvider.of<KanjiBloc>(context).add(ReturnToInitialState()),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
|
@ -1,122 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
|
|
||||||
enum YomiType {
|
|
||||||
onyomi,
|
|
||||||
kunyomi,
|
|
||||||
meaning,
|
|
||||||
}
|
|
||||||
|
|
||||||
extension on YomiType {
|
|
||||||
String get title {
|
|
||||||
switch (this) {
|
|
||||||
case YomiType.onyomi:
|
|
||||||
return 'Onyomi';
|
|
||||||
case YomiType.kunyomi:
|
|
||||||
return 'Kunyomi';
|
|
||||||
case YomiType.meaning:
|
|
||||||
return 'Meanings';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorSet getColors(BuildContext context) {
|
|
||||||
final theme = BlocProvider.of<ThemeBloc>(context).state.theme;
|
|
||||||
|
|
||||||
switch (this) {
|
|
||||||
case YomiType.onyomi:
|
|
||||||
return theme.onyomiColor;
|
|
||||||
case YomiType.kunyomi:
|
|
||||||
return theme.kunyomiColor;
|
|
||||||
case YomiType.meaning:
|
|
||||||
return theme.menuGreyNormal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class YomiChips extends StatelessWidget {
|
|
||||||
final List<String> yomi;
|
|
||||||
final YomiType type;
|
|
||||||
|
|
||||||
const YomiChips(this.yomi, this.type);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 10.0,
|
|
||||||
vertical: 5.0,
|
|
||||||
),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: _yomiWrapper(context),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isExpandable() => yomi.length > 6;
|
|
||||||
|
|
||||||
Widget _yomiWrapper(BuildContext context) {
|
|
||||||
final yomiCards = this
|
|
||||||
.yomi
|
|
||||||
.map((yomi) => _YomiCard(
|
|
||||||
yomi: yomi,
|
|
||||||
colors: this.type.getColors(context),
|
|
||||||
))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (!this.isExpandable())
|
|
||||||
return Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: yomiCards,
|
|
||||||
);
|
|
||||||
|
|
||||||
return ExpansionTile(
|
|
||||||
initiallyExpanded: false,
|
|
||||||
title: Center(
|
|
||||||
child: _YomiCard(
|
|
||||||
yomi: this.type.title,
|
|
||||||
colors: this.type.getColors(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 20.0,
|
|
||||||
),
|
|
||||||
Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: yomiCards,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 25.0,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _YomiCard extends StatelessWidget {
|
|
||||||
final String yomi;
|
|
||||||
final ColorSet colors;
|
|
||||||
|
|
||||||
const _YomiCard({required this.yomi, required this.colors});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 10.0,
|
|
||||||
horizontal: 10.0,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
this.yomi,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20.0,
|
|
||||||
color: colors.foreground,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: colors.background,
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,7 @@ class OpaqueBox extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor),
|
decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor),
|
||||||
child: this.child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,55 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../../../models/themes/theme.dart';
|
||||||
|
|
||||||
class LanguageSelector extends StatefulWidget {
|
class LanguageSelector extends StatefulWidget {
|
||||||
const LanguageSelector();
|
const LanguageSelector({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LanguageSelectorState createState() => new _LanguageSelectorState();
|
_LanguageSelectorState createState() => _LanguageSelectorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LanguageSelectorState extends State<LanguageSelector> {
|
class _LanguageSelectorState extends State<LanguageSelector> {
|
||||||
late final SharedPreferences prefs;
|
final SharedPreferences prefs = GetIt.instance.get<SharedPreferences>();
|
||||||
late List<bool> isSelected;
|
late List<bool> isSelected;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
isSelected = [false, false, false];
|
isSelected = _getSelectedStatus() ?? [false, false, false];
|
||||||
|
|
||||||
SharedPreferences.getInstance()
|
|
||||||
.then((prefs) {
|
|
||||||
this.prefs = prefs;
|
|
||||||
setState(() {
|
|
||||||
isSelected = _getSelectedStatus() ?? isSelected;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateSelectedStatus() async {
|
Future<void> _updateSelectedStatus() async => prefs.setStringList(
|
||||||
await prefs.setStringList('languageSelectorStatus',
|
'languageSelectorStatus',
|
||||||
isSelected
|
isSelected.map((b) => b ? '1' : '0').toList(),
|
||||||
.map((b) => b ? '1' : '0')
|
);
|
||||||
.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<bool>? _getSelectedStatus() {
|
List<bool>? _getSelectedStatus() => prefs
|
||||||
return prefs
|
|
||||||
.getStringList('languageSelectorStatus')
|
.getStringList('languageSelectorStatus')
|
||||||
?.map((s) => s == '1')
|
?.map((s) => s == '1')
|
||||||
.toList();
|
.toList();
|
||||||
}
|
|
||||||
|
Widget _languageOption(String language) =>
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||||
|
child: Center(child: Text(language)),
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ToggleButtons(
|
return ToggleButtons(
|
||||||
selectedColor: AppTheme.jishoGreen.background,
|
selectedColor: AppTheme.jishoGreen.background,
|
||||||
isSelected: isSelected,
|
isSelected: isSelected,
|
||||||
children: <Widget> [
|
children: <Widget>[
|
||||||
_LanguageOption("Auto"),
|
_languageOption('Auto'),
|
||||||
_LanguageOption("日本語"),
|
_languageOption('日本語'),
|
||||||
_LanguageOption("English")
|
_languageOption('English')
|
||||||
],
|
],
|
||||||
onPressed: (int buttonIndex) {
|
onPressed: (buttonIndex) {
|
||||||
setState(() {
|
setState(() {
|
||||||
for (var i in Iterable.generate(isSelected.length)) {
|
for (final int i in Iterable.generate(isSelected.length)) {
|
||||||
isSelected[i] = i == buttonIndex;
|
isSelected[i] = i == buttonIndex;
|
||||||
}
|
}
|
||||||
_updateSelectedStatus();
|
_updateSelectedStatus();
|
||||||
|
@ -61,19 +57,4 @@ class _LanguageSelectorState extends State<LanguageSelector> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LanguageOption extends StatelessWidget {
|
|
||||||
final String language;
|
|
||||||
|
|
||||||
const _LanguageOption(this.language);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
|
||||||
child: Center(child: Text(language)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/language_selector.dart';
|
import 'language_selector.dart';
|
||||||
|
|
||||||
class SearchBar extends StatelessWidget {
|
class SearchBar extends StatelessWidget {
|
||||||
|
const SearchBar({Key? key}) : super(key: key);
|
||||||
const SearchBar();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
TextField(
|
TextField(
|
||||||
onSubmitted: (text) {
|
onSubmitted: (text) =>
|
||||||
BlocProvider.of<SearchBloc>(context)
|
Navigator.pushNamed(context, '/search', arguments: text),
|
||||||
.add(GetSearchResults(text));
|
|
||||||
},
|
|
||||||
controller: TextEditingController(),
|
controller: TextEditingController(),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Search',
|
labelText: 'Search',
|
||||||
|
@ -25,12 +22,10 @@ class SearchBar extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(height: 10.0),
|
||||||
height: 10.0,
|
const LanguageSelector()
|
||||||
),
|
|
||||||
LanguageSelector()
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
import 'search_results_body/search_card.dart';
|
||||||
|
|
||||||
|
class SearchResultsBody extends StatelessWidget {
|
||||||
|
final List<JishoResult> results;
|
||||||
|
|
||||||
|
const SearchResultsBody({
|
||||||
|
required this.results,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView(
|
||||||
|
children: results.map((result) => SearchResultCard(result: result)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/parts/badge.dart';
|
|
||||||
|
|
||||||
class CommonBadge extends StatelessWidget {
|
|
||||||
final bool isCommon;
|
|
||||||
|
|
||||||
const CommonBadge(this.isCommon);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Badge(
|
|
||||||
Text(
|
|
||||||
"C",
|
|
||||||
style: TextStyle(color: this.isCommon ? Colors.white : Colors.transparent)
|
|
||||||
),
|
|
||||||
this.isCommon ? Colors.green : Colors.transparent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/parts/badge.dart';
|
|
||||||
|
|
||||||
class JLPTBadge extends StatelessWidget {
|
|
||||||
final String jlptLevel;
|
|
||||||
|
|
||||||
const JLPTBadge(this.jlptLevel);
|
|
||||||
|
|
||||||
String _extractJlptLevel(String jlptRaw) {
|
|
||||||
return jlptRaw.isNotEmpty ? jlptRaw.substring(5).toUpperCase() : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Badge(
|
|
||||||
Text(
|
|
||||||
_extractJlptLevel(this.jlptLevel),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white
|
|
||||||
),
|
|
||||||
),
|
|
||||||
this.jlptLevel.isNotEmpty ? Colors.blue : Colors.transparent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:unofficial_jisho_api/parser.dart';
|
|
||||||
|
|
||||||
class Senses extends StatelessWidget {
|
|
||||||
final List<JishoWordSense> senses;
|
|
||||||
|
|
||||||
const Senses(this.senses);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final List<Widget> senseWidgets =
|
|
||||||
senses.asMap().entries.map((e) => _Sense(e.key, e.value)).toList();
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
child: Column(
|
|
||||||
children: senseWidgets,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Sense extends StatelessWidget {
|
|
||||||
final int index;
|
|
||||||
final JishoWordSense sense;
|
|
||||||
|
|
||||||
const _Sense(this.index, this.sense);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
(index + 1).toString() + '. ',
|
|
||||||
style: TextStyle(color: Colors.grey),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
sense.partsOfSpeech.join(', '),
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
child: Row(
|
|
||||||
children:[
|
|
||||||
Column(
|
|
||||||
children:
|
|
||||||
sense.englishDefinitions.map((def) => Text(def)).toList(),
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
margin: EdgeInsets.fromLTRB(0, 5, 0, 15),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/parts/badge.dart';
|
|
||||||
|
|
||||||
class WKBadge extends StatelessWidget {
|
|
||||||
final String wkLevel;
|
|
||||||
|
|
||||||
const WKBadge(this.wkLevel);
|
|
||||||
|
|
||||||
String _extractWkLevel(String wkRaw) {
|
|
||||||
// return jlptRaw.isNotEmpty ? jlptRaw.substring(5).toUpperCase() : '';
|
|
||||||
return wkRaw.isNotEmpty ? 'W' + wkRaw.substring(8) : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Badge(
|
|
||||||
Text(
|
|
||||||
_extractWkLevel(this.wkLevel),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
this.wkLevel.isNotEmpty ? Colors.red : Colors.transparent
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,27 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Badge extends StatelessWidget {
|
class Badge extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget? child;
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
const Badge(this.child, this.color);
|
const Badge({this.child, required this.color, Key? key,}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
child: FittedBox(
|
padding: const EdgeInsets.all(5),
|
||||||
child: Center(
|
|
||||||
child: this.child
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.all(5),
|
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
margin: EdgeInsets.symmetric(horizontal: 2),
|
margin: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: color
|
color: color,
|
||||||
|
),
|
||||||
|
child: FittedBox(
|
||||||
|
child: Center(
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
); }
|
); }
|
||||||
|
}
|
||||||
}
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import './badge.dart';
|
||||||
|
|
||||||
|
class CommonBadge extends StatelessWidget {
|
||||||
|
final bool isCommon;
|
||||||
|
|
||||||
|
const CommonBadge({
|
||||||
|
required this.isCommon,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Badge(
|
||||||
|
color: isCommon ? Colors.green : Colors.transparent,
|
||||||
|
child: Text(
|
||||||
|
'C',
|
||||||
|
style: TextStyle(
|
||||||
|
color: isCommon ? Colors.white : Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,21 +3,24 @@ 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({
|
||||||
|
required this.word,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
bool get hasFurigana => word.word != null && word.reading != null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
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: const EdgeInsets.only(left: 10.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// TODO: take a look at this logic
|
// TODO: take a look at this logic
|
||||||
(hasFurigana) ? Text(word.reading!) : Text(''),
|
hasFurigana ? Text(word.reading!) : const Text(''),
|
||||||
(hasFurigana) ? Text(word.word!) : Text(word.reading ?? word.word!),
|
hasFurigana ? Text(word.word!) : Text(word.reading ?? word.word!),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import './badge.dart';
|
||||||
|
|
||||||
|
class JLPTBadge extends StatelessWidget {
|
||||||
|
final String jlptLevel;
|
||||||
|
|
||||||
|
const JLPTBadge({
|
||||||
|
required this.jlptLevel,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
String get formattedJlptLevel =>
|
||||||
|
jlptLevel.isNotEmpty ? jlptLevel.substring(5).toUpperCase() : '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Badge(
|
||||||
|
color: jlptLevel.isNotEmpty ? Colors.blue : Colors.transparent,
|
||||||
|
child: Text(
|
||||||
|
formattedJlptLevel,
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,28 +1,27 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
|
||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
class OtherForms extends StatelessWidget {
|
import '../../../../../bloc/theme/theme_bloc.dart';
|
||||||
final List<JishoJapaneseWord> otherForms;
|
|
||||||
|
|
||||||
const OtherForms(this.otherForms);
|
class OtherForms extends StatelessWidget {
|
||||||
|
final List<JishoJapaneseWord> forms;
|
||||||
|
|
||||||
|
const OtherForms({required this.forms, Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Column(
|
||||||
child: Column(
|
children: forms.isNotEmpty
|
||||||
children: this.otherForms.isNotEmpty
|
? [
|
||||||
? [
|
const Text(
|
||||||
Text(
|
'Other Forms',
|
||||||
'Other Forms',
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
),
|
||||||
),
|
Row(
|
||||||
Row(
|
children: forms.map((form) => _KanaBox(form)).toList(),
|
||||||
children: otherForms.map((form) => _KanaBox(form)).toList(),
|
),
|
||||||
),
|
]
|
||||||
]
|
: [],
|
||||||
: [],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,28 +31,19 @@ class _KanaBox extends StatelessWidget {
|
||||||
|
|
||||||
const _KanaBox(this.word);
|
const _KanaBox(this.word);
|
||||||
|
|
||||||
|
bool get hasFurigana => word.word != null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final hasFurigana = (word.word != null);
|
|
||||||
final _menuColors =
|
final _menuColors =
|
||||||
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
|
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: DefaultTextStyle.merge(
|
margin: const EdgeInsets.symmetric(
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
// TODO: take a look at this logic
|
|
||||||
(hasFurigana) ? Text(word.reading ?? '') : Text(''),
|
|
||||||
(hasFurigana) ? Text(word.word!) : Text(word.reading ?? ''),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
style: TextStyle(color: _menuColors.foreground),
|
|
||||||
),
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 5.0,
|
horizontal: 5.0,
|
||||||
vertical: 5.0,
|
vertical: 5.0,
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _menuColors.background,
|
color: _menuColors.background,
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
|
@ -61,10 +51,20 @@ class _KanaBox extends StatelessWidget {
|
||||||
color: Colors.grey.withOpacity(0.5),
|
color: Colors.grey.withOpacity(0.5),
|
||||||
spreadRadius: 1,
|
spreadRadius: 1,
|
||||||
blurRadius: 0.5,
|
blurRadius: 0.5,
|
||||||
offset: Offset(1, 1),
|
offset: const Offset(1, 1),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
child: DefaultTextStyle.merge(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// TODO: take a look at this logic
|
||||||
|
hasFurigana ? Text(word.reading ?? '') : const Text(''),
|
||||||
|
hasFurigana ? Text(word.word!) : Text(word.reading ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: TextStyle(color: _menuColors.foreground),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:unofficial_jisho_api/parser.dart';
|
||||||
|
|
||||||
|
class Senses extends StatelessWidget {
|
||||||
|
final List<JishoWordSense> senses;
|
||||||
|
|
||||||
|
const Senses({
|
||||||
|
required this.senses,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final List<Widget> senseWidgets =
|
||||||
|
senses.asMap().entries.map((e) => _Sense(e.key, e.value)).toList();
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: senseWidgets,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Sense extends StatelessWidget {
|
||||||
|
final int index;
|
||||||
|
final JishoWordSense sense;
|
||||||
|
|
||||||
|
const _Sense(this.index, this.sense);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${index + 1}. ',
|
||||||
|
style: const TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
sense.partsOfSpeech.join(', '),
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 5, 0, 15),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children:
|
||||||
|
sense.englishDefinitions.map((def) => Text(def)).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import './badge.dart';
|
||||||
|
|
||||||
|
class WKBadge extends StatelessWidget {
|
||||||
|
final String level;
|
||||||
|
|
||||||
|
const WKBadge({
|
||||||
|
required this.level,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
String _extractWkLevel(String wkRaw) {
|
||||||
|
return wkRaw.isNotEmpty ? 'W${wkRaw.substring(8)}' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Badge(
|
||||||
|
color: level.isNotEmpty ? Colors.red : Colors.transparent,
|
||||||
|
child: Text(
|
||||||
|
_extractWkLevel(level),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +1,24 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/parts/common_badge.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/parts/jlpt_badge.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/parts/wanikani_badge.dart';
|
|
||||||
|
|
||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
|
import './parts/common_badge.dart';
|
||||||
import './parts/header.dart';
|
import './parts/header.dart';
|
||||||
import './parts/senses.dart';
|
import './parts/jlpt_badge.dart';
|
||||||
import './parts/other_forms.dart';
|
import './parts/other_forms.dart';
|
||||||
|
import './parts/senses.dart';
|
||||||
|
import './parts/wanikani_badge.dart';
|
||||||
|
|
||||||
class SearchResultCard extends StatelessWidget {
|
class SearchResultCard extends StatelessWidget {
|
||||||
final JishoResult result;
|
final JishoResult result;
|
||||||
late final JishoJapaneseWord mainWord;
|
late final JishoJapaneseWord mainWord;
|
||||||
late final List<JishoJapaneseWord> otherForms;
|
late final List<JishoJapaneseWord> otherForms;
|
||||||
|
|
||||||
SearchResultCard(this.result) {
|
SearchResultCard({
|
||||||
this.mainWord = result.japanese[0];
|
required this.result,
|
||||||
this.otherForms = result.japanese.sublist(1);
|
Key? key,
|
||||||
}
|
}) : mainWord = result.japanese[0],
|
||||||
|
otherForms = result.japanese.sublist(1),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -25,34 +26,40 @@ class SearchResultCard extends StatelessWidget {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
collapsedBackgroundColor: backgroundColor,
|
collapsedBackgroundColor: backgroundColor,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
title:
|
title: IntrinsicWidth(
|
||||||
IntrinsicWidth(
|
|
||||||
child: Row(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
JapaneseHeader(mainWord),
|
JapaneseHeader(word: mainWord),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
WKBadge(result.tags.firstWhere((tag) => tag.contains("wanikani"), orElse: () => '')),
|
WKBadge(
|
||||||
JLPTBadge(result.jlpt.isNotEmpty ? result.jlpt[0] : ''),
|
level: result.tags.firstWhere(
|
||||||
CommonBadge(result.isCommon ?? false)
|
(tag) => tag.contains('wanikani'),
|
||||||
|
orElse: () => '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
JLPTBadge(
|
||||||
|
jlptLevel: result.jlpt.isNotEmpty ? result.jlpt[0] : '',
|
||||||
|
),
|
||||||
|
CommonBadge(isCommon: result.isCommon ?? false)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Senses(result.senses),
|
Senses(senses: result.senses),
|
||||||
OtherForms(otherForms),
|
OtherForms(forms: otherForms),
|
||||||
// Text(result.toJson().toString()),
|
// Text(result.toJson().toString()),
|
||||||
// Text(result.attribution.toJson().toString()),
|
// Text(result.attribution.toJson().toString()),
|
||||||
// Text(result.japanese.map((e) => e.toJson().toString()).toList().toString()),
|
// Text(result.japanese.map((e) => e.toJson().toString()).toList().toString()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 30),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
|
@ -0,0 +1,114 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mdi/mdi.dart';
|
||||||
|
|
||||||
|
import '../bloc/theme/theme_bloc.dart';
|
||||||
|
import 'screens/history.dart';
|
||||||
|
import 'screens/search/kanji_view.dart';
|
||||||
|
import 'screens/search/search_view.dart';
|
||||||
|
import 'screens/settings.dart';
|
||||||
|
|
||||||
|
class Home extends StatefulWidget {
|
||||||
|
const Home({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _HomeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeState extends State<Home> {
|
||||||
|
int pageNum = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<ThemeBloc, ThemeState>(
|
||||||
|
builder: (context, themeState) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: pages[pageNum].titleBar,
|
||||||
|
centerTitle: true,
|
||||||
|
backgroundColor: AppTheme.jishoGreen.background,
|
||||||
|
foregroundColor: AppTheme.jishoGreen.foreground,
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
right: 30,
|
||||||
|
left: 100,
|
||||||
|
bottom: 30,
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/denshi_jisho_background_overlay.png',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pages[pageNum].content,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
fixedColor: AppTheme.jishoGreen.background,
|
||||||
|
currentIndex: pageNum,
|
||||||
|
onTap: (index) => setState(() {
|
||||||
|
pageNum = index;
|
||||||
|
}),
|
||||||
|
items: pages.map((p) => p.item).toList(),
|
||||||
|
showSelectedLabels: false,
|
||||||
|
showUnselectedLabels: false,
|
||||||
|
unselectedItemColor: themeState.theme.menuGreyDark.background,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<_Page> get pages => [
|
||||||
|
const _Page(
|
||||||
|
content: SearchView(),
|
||||||
|
titleBar: Text('Search'),
|
||||||
|
item: BottomNavigationBarItem(
|
||||||
|
label: 'Search',
|
||||||
|
icon: Icon(Icons.search),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const _Page(
|
||||||
|
content: KanjiView(),
|
||||||
|
titleBar: Text('Kanji'),
|
||||||
|
item: BottomNavigationBarItem(
|
||||||
|
label: 'Kanji',
|
||||||
|
icon: Icon(Mdi.ideogramCjk, size: 30),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const _Page(
|
||||||
|
content: HistoryView(),
|
||||||
|
titleBar: Text('History'),
|
||||||
|
item: BottomNavigationBarItem(
|
||||||
|
label: 'History',
|
||||||
|
icon: Icon(Icons.history),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_Page(
|
||||||
|
content: Container(),
|
||||||
|
titleBar: const Text('Saved'),
|
||||||
|
item: const BottomNavigationBarItem(
|
||||||
|
label: 'Saved',
|
||||||
|
icon: Icon(Icons.bookmark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const _Page(
|
||||||
|
content: SettingsView(),
|
||||||
|
titleBar: Text('Settings'),
|
||||||
|
item: BottomNavigationBarItem(
|
||||||
|
label: 'Settings',
|
||||||
|
icon: Icon(Icons.settings),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Page {
|
||||||
|
final Widget content;
|
||||||
|
final Widget titleBar;
|
||||||
|
final BottomNavigationBarItem item;
|
||||||
|
|
||||||
|
const _Page({
|
||||||
|
required this.content,
|
||||||
|
required this.titleBar,
|
||||||
|
required this.item,
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,80 +1,113 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:jisho_study_tool/models/history/search.dart';
|
import 'package:jisho_study_tool/view/components/common/loading.dart';
|
||||||
import 'package:jisho_study_tool/view/components/history/kanji_search_item.dart';
|
import 'package:sembast/sembast.dart';
|
||||||
import 'package:jisho_study_tool/view/components/history/phrase_search_item.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/history/date_divider.dart';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/objectbox.g.dart';
|
import '../../models/history/search.dart';
|
||||||
import 'package:jisho_study_tool/view/components/opaque_box.dart';
|
import '../components/history/date_divider.dart';
|
||||||
|
import '../components/history/kanji_search_item.dart';
|
||||||
|
import '../components/history/phrase_search_item.dart';
|
||||||
|
import '../components/opaque_box.dart';
|
||||||
|
|
||||||
class HistoryView extends StatelessWidget {
|
class HistoryView extends StatelessWidget {
|
||||||
|
const HistoryView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
Database get _db => GetIt.instance.get<Database>();
|
||||||
|
|
||||||
|
Stream<List<Search>> get searchStream => Search.store
|
||||||
|
.query(
|
||||||
|
finder: Finder(
|
||||||
|
sortOrders: [SortOrder('timestamp', false)],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.onSnapshots(_db)
|
||||||
|
.map((snapshot) {
|
||||||
|
return snapshot
|
||||||
|
.map<Search?>(
|
||||||
|
(snap) => (snap.value != null)
|
||||||
|
? Search.fromJson(snap.value! as Map<String, Object?>)
|
||||||
|
: null,
|
||||||
|
)
|
||||||
|
.where((s) => s != null)
|
||||||
|
.map<Search>((s) => s!)
|
||||||
|
.toList();
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<DatabaseBloc, DatabaseState>(
|
return StreamBuilder<List<Search>>(
|
||||||
builder: (context, state) {
|
stream: searchStream,
|
||||||
if (state is DatabaseDisconnected)
|
builder: (context, snapshot) {
|
||||||
throw DatabaseNotConnectedException();
|
if (!snapshot.hasData) return const LoadingScreen();
|
||||||
|
|
||||||
return StreamBuilder(
|
final List<Search> data = snapshot.data!;
|
||||||
stream: ((state as DatabaseConnected).database.box<Search>().query()
|
if (data.isEmpty)
|
||||||
..order(Search_.timestamp, flags: Order.descending))
|
return const Center(
|
||||||
.watch(triggerImmediately: true)
|
child: Text('The history is empty.\nTry searching for something!'),
|
||||||
.map((query) => query.find()),
|
);
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
|
||||||
if (!snapshot.hasData) return Container();
|
|
||||||
return OpaqueBox(
|
|
||||||
child: ListView.separated(
|
|
||||||
itemCount: snapshot.data.length + 1,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
if (index == 0) return Container();
|
|
||||||
Search search = snapshot.data[index - 1];
|
|
||||||
if (search.isKanji()) {
|
|
||||||
return KanjiSearchItem(
|
|
||||||
result: search.kanjiQuery.target!,
|
|
||||||
timestamp: search.timestamp,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return PhraseSearchItem(
|
|
||||||
search: search.wordQuery.target!,
|
|
||||||
timestamp: search.timestamp,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (context, index) {
|
|
||||||
Function roundToDay = (DateTime date) =>
|
|
||||||
DateTime(date.year, date.month, date.day);
|
|
||||||
|
|
||||||
Search search = snapshot.data[index];
|
return OpaqueBox(
|
||||||
DateTime searchDate = roundToDay(search.timestamp);
|
child: ListView.separated(
|
||||||
|
itemCount: data.length + 1,
|
||||||
bool newDate = true;
|
itemBuilder: historyEntryWithData(data),
|
||||||
|
separatorBuilder: historyEntrySeparatorWithData(data),
|
||||||
EdgeInsets? margin;
|
),
|
||||||
if (index != 0) {
|
|
||||||
Search prevSearch = snapshot.data[index - 1];
|
|
||||||
|
|
||||||
DateTime prevSearchDate = roundToDay(prevSearch.timestamp);
|
|
||||||
newDate = prevSearchDate != searchDate;
|
|
||||||
margin = EdgeInsets.only(bottom: 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newDate) {
|
|
||||||
if (searchDate == roundToDay(DateTime.now()))
|
|
||||||
return DateDivider(text: "Today", margin: margin);
|
|
||||||
else if (searchDate ==
|
|
||||||
roundToDay(
|
|
||||||
DateTime.now().subtract(const Duration(days: 1))))
|
|
||||||
return DateDivider(text: "Yesterday", margin: margin);
|
|
||||||
return DateDivider(date: searchDate, margin: margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Divider();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget Function(BuildContext, int) historyEntryWithData(List<Search> data) =>
|
||||||
|
(context, index) {
|
||||||
|
if (index == 0) return Container();
|
||||||
|
|
||||||
|
final Search search = data[index - 1];
|
||||||
|
|
||||||
|
return (search.isKanji)
|
||||||
|
? KanjiSearchItem(
|
||||||
|
result: search.kanjiQuery!,
|
||||||
|
timestamp: search.timestamp,
|
||||||
|
)
|
||||||
|
: PhraseSearchItem(
|
||||||
|
search: search.wordQuery!,
|
||||||
|
timestamp: search.timestamp,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
DateTime roundToDay(DateTime date) =>
|
||||||
|
DateTime(date.year, date.month, date.day);
|
||||||
|
|
||||||
|
bool dateChangedFromLastSearch(Search prevSearch, DateTime searchDate) {
|
||||||
|
final DateTime prevSearchDate = roundToDay(prevSearch.timestamp);
|
||||||
|
return prevSearchDate != searchDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime get today => roundToDay(DateTime.now());
|
||||||
|
DateTime get yesterday =>
|
||||||
|
roundToDay(DateTime.now().subtract(const Duration(days: 1)));
|
||||||
|
|
||||||
|
Widget Function(BuildContext, int) historyEntrySeparatorWithData(
|
||||||
|
List<Search> data,
|
||||||
|
) =>
|
||||||
|
(context, index) {
|
||||||
|
final Search search = data[index];
|
||||||
|
final DateTime searchDate = roundToDay(search.timestamp);
|
||||||
|
|
||||||
|
EdgeInsets? margin;
|
||||||
|
if (index != 0) {
|
||||||
|
margin = const EdgeInsets.only(bottom: 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0 ||
|
||||||
|
dateChangedFromLastSearch(data[index - 1], searchDate)) {
|
||||||
|
if (searchDate == today)
|
||||||
|
return DateDivider(text: 'Today', margin: margin);
|
||||||
|
else if (searchDate == yesterday)
|
||||||
|
return DateDivider(text: 'Yesterday', margin: margin);
|
||||||
|
else
|
||||||
|
return DateDivider(date: searchDate, margin: margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return const Divider();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/examples.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/grade.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/header.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/jlpt_level.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/radical.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/rank.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/stroke_order_gif.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/yomi_chips.dart';
|
|
||||||
|
|
||||||
class KanjiResultCard extends StatelessWidget {
|
|
||||||
late final String query;
|
|
||||||
late final jisho.KanjiResultData resultData;
|
|
||||||
|
|
||||||
KanjiResultCard({required jisho.KanjiResult result}) {
|
|
||||||
|
|
||||||
query = result.query;
|
|
||||||
|
|
||||||
// TODO: Handle this kind of exception before widget is initialized
|
|
||||||
if (result.data == null)
|
|
||||||
throw Exception();
|
|
||||||
|
|
||||||
resultData = result.data!;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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(query)),
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
flex: 1,
|
|
||||||
fit: FlexFit.tight,
|
|
||||||
child: Center(
|
|
||||||
child: (resultData.radical != null) ? Radical(resultData.radical!) : SizedBox(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
YomiChips(resultData.meaning.split(', '), YomiType.meaning),
|
|
||||||
resultData.onyomi.length != 0 ? YomiChips(resultData.onyomi, YomiType.onyomi) : SizedBox.shrink(),
|
|
||||||
resultData.kunyomi.length != 0 ? YomiChips(resultData.kunyomi, YomiType.kunyomi) : SizedBox.shrink(),
|
|
||||||
IntrinsicHeight(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
StrokeOrderGif(resultData.strokeOrderGifUri),
|
|
||||||
Container(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text("JLPT: ", style: TextStyle(fontSize: 20.0)),
|
|
||||||
JlptLevel(resultData.jlptLevel ?? "⨉"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text("Grade: ", style: TextStyle(fontSize: 20.0)),
|
|
||||||
Grade(resultData.taughtIn ?? "⨉"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text("Rank: ", style: TextStyle(fontSize: 20.0)),
|
|
||||||
Rank(resultData.newspaperFrequencyRank ?? -1),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Examples(resultData.onyomiExamples, resultData.kunyomiExamples),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
|
||||||
import 'package:animated_size_and_fade/animated_size_and_fade.dart';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/kanji_grid.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_bar.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_options_bar.dart';
|
|
||||||
|
|
||||||
class SearchScreen extends StatefulWidget {
|
|
||||||
SearchScreen({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
_SearchScreenState createState() => _SearchScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SearchScreenState extends State<SearchScreen>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late final AnimationController _controller;
|
|
||||||
late final Animation _searchbarMovementAnimation;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
_controller = AnimationController(
|
|
||||||
vsync: this,
|
|
||||||
duration: Duration(milliseconds: 200),
|
|
||||||
);
|
|
||||||
|
|
||||||
_searchbarMovementAnimation = AlignmentTween(
|
|
||||||
begin: Alignment.center,
|
|
||||||
end: Alignment.topCenter,
|
|
||||||
).animate(CurvedAnimation(
|
|
||||||
parent: _controller,
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () => FocusScope.of(context).unfocus(),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
child: AnimatedBuilder(
|
|
||||||
animation: _searchbarMovementAnimation,
|
|
||||||
builder: (BuildContext context, _) {
|
|
||||||
return Container(
|
|
||||||
alignment: _searchbarMovementAnimation.value,
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Focus(
|
|
||||||
onFocusChange: (hasFocus) {
|
|
||||||
if (hasFocus)
|
|
||||||
_controller.forward();
|
|
||||||
else
|
|
||||||
_controller.reverse();
|
|
||||||
},
|
|
||||||
child: KanjiSearchBar(),
|
|
||||||
),
|
|
||||||
BlocBuilder<KanjiBloc, KanjiState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return AnimatedSizeAndFade(
|
|
||||||
vsync: this,
|
|
||||||
child: _controller.value == 1
|
|
||||||
? KanjiGrid((state is KanjiSearchKeyboard)
|
|
||||||
? state.kanjiSuggestions
|
|
||||||
: [])
|
|
||||||
// ? Container()
|
|
||||||
: KanjiSearchOptionsBar(),
|
|
||||||
fadeDuration: const Duration(milliseconds: 200),
|
|
||||||
sizeDuration: const Duration(milliseconds: 300),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/kanji_grid.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_bar.dart';
|
|
||||||
|
|
||||||
class SearchGrid extends StatelessWidget {
|
|
||||||
final List<String> suggestions;
|
|
||||||
const SearchGrid(this.suggestions);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(height: 10),
|
|
||||||
KanjiSearchBar(),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
Expanded(
|
|
||||||
child: KanjiGrid(suggestions)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
const List<List<String>> radicals = [[]];
|
|
|
@ -1,71 +0,0 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/view/screens/loading.dart';
|
|
||||||
|
|
||||||
import 'search.dart';
|
|
||||||
import 'result.dart';
|
|
||||||
|
|
||||||
class KanjiView extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocListener<KanjiBloc, KanjiState>(
|
|
||||||
listener: (context, state) {
|
|
||||||
if (state is KanjiSearch && state.type == KanjiSearchType.Initial) {
|
|
||||||
FocusScope.of(context).unfocus();
|
|
||||||
} else if (state is KanjiSearchLoading) {
|
|
||||||
FocusScope.of(context).unfocus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: BlocBuilder<KanjiBloc, KanjiState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state is KanjiSearch) {
|
|
||||||
if (state.type == KanjiSearchType.Initial) return SearchScreen();
|
|
||||||
else if (state is KanjiSearchKeyboard) return SearchScreen();
|
|
||||||
}
|
|
||||||
else if (state is KanjiSearchLoading) return LoadingScreen();
|
|
||||||
else if (state is KanjiSearchFinished)
|
|
||||||
return WillPopScope(
|
|
||||||
child: KanjiResultCard(result: 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,
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:sembast/sembast.dart';
|
||||||
|
|
||||||
|
import '../../../models/history/kanji_query.dart';
|
||||||
|
import '../../../models/history/search.dart';
|
||||||
|
import '../../../services/jisho_api/kanji_search.dart';
|
||||||
|
import '../../components/common/loading.dart';
|
||||||
|
import '../../components/kanji/kanji_result_body.dart';
|
||||||
|
|
||||||
|
class KanjiResultPage extends StatelessWidget {
|
||||||
|
final String kanjiSearchTerm;
|
||||||
|
bool addedToDatabase = false;
|
||||||
|
|
||||||
|
KanjiResultPage({required this.kanjiSearchTerm, Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: FutureBuilder<KanjiResult>(
|
||||||
|
future: fetchKanji(kanjiSearchTerm),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) return const LoadingScreen();
|
||||||
|
if (snapshot.hasError) return ErrorWidget(snapshot.error!);
|
||||||
|
|
||||||
|
if (!addedToDatabase) {
|
||||||
|
Search.store.add(
|
||||||
|
GetIt.instance.get<Database>(),
|
||||||
|
Search.fromKanjiQuery(
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
kanjiQuery: KanjiQuery(kanji: kanjiSearchTerm),
|
||||||
|
).toJson(),
|
||||||
|
);
|
||||||
|
addedToDatabase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KanjiResultBody(result: snapshot.data!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../components/kanji/kanji_search_body.dart';
|
||||||
|
|
||||||
|
class KanjiView extends StatelessWidget {
|
||||||
|
const KanjiView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const KanjiSearchBody();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/search_card.dart';
|
|
||||||
import 'package:unofficial_jisho_api/api.dart';
|
|
||||||
|
|
||||||
class SearchResults extends StatelessWidget {
|
|
||||||
final List<JishoResult> results;
|
|
||||||
|
|
||||||
const SearchResults({
|
|
||||||
required this.results,
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return WillPopScope(
|
|
||||||
child: ListView(
|
|
||||||
children: results.map((result) => SearchResultCard(result)).toList(),
|
|
||||||
),
|
|
||||||
onWillPop: () async {
|
|
||||||
BlocProvider.of<SearchBloc>(context).add(ReturnToInitialState());
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../components/kanji/kanji_search_body/kanji_grid.dart';
|
||||||
|
import '../../../components/kanji/kanji_search_body/kanji_search_bar.dart';
|
||||||
|
|
||||||
|
class SearchGrid extends StatelessWidget {
|
||||||
|
final List<String> suggestions;
|
||||||
|
|
||||||
|
const SearchGrid({
|
||||||
|
required this.suggestions,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
const KanjiSearchBar(),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Expanded(child: KanjiGrid(suggestions: suggestions))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
const List<List<String>> radicals = [[]];
|
|
@ -0,0 +1,49 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:sembast/sembast.dart';
|
||||||
|
|
||||||
|
import '../../../models/history/search.dart';
|
||||||
|
import '../../../models/history/word_query.dart';
|
||||||
|
import '../../../services/jisho_api/jisho_search.dart';
|
||||||
|
import '../../components/common/loading.dart';
|
||||||
|
import '../../components/search/search_result_body.dart';
|
||||||
|
|
||||||
|
class SearchResultsPage extends StatelessWidget {
|
||||||
|
final String searchTerm;
|
||||||
|
final Future<JishoAPIResult> results;
|
||||||
|
bool addedToDatabase = false;
|
||||||
|
|
||||||
|
SearchResultsPage({required this.searchTerm, Key? key})
|
||||||
|
: results = fetchJishoResults(searchTerm),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: FutureBuilder<JishoAPIResult>(
|
||||||
|
future: results,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) return const LoadingScreen();
|
||||||
|
if (snapshot.hasError || snapshot.data!.data == null)
|
||||||
|
return ErrorWidget(snapshot.error!);
|
||||||
|
|
||||||
|
if (!addedToDatabase) {
|
||||||
|
Search.store.add(
|
||||||
|
GetIt.instance.get<Database>(),
|
||||||
|
Search.fromWordQuery(
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
wordQuery: WordQuery(query: searchTerm),
|
||||||
|
).toJson(),
|
||||||
|
);
|
||||||
|
addedToDatabase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchResultsBody(
|
||||||
|
results: snapshot.data!.data!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../components/search/search_bar.dart';
|
||||||
|
|
||||||
|
class SearchView extends StatelessWidget {
|
||||||
|
const SearchView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: const <Widget>[
|
||||||
|
SearchBar(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
import 'package:flutter/material.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/screens/search/results.dart';
|
|
||||||
|
|
||||||
class SearchView extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocConsumer<SearchBloc, SearchState>(
|
|
||||||
listener: (context, state) {},
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state is SearchInitial)
|
|
||||||
return _InitialView();
|
|
||||||
else if (state is SearchLoading)
|
|
||||||
return LoadingScreen();
|
|
||||||
else if (state is SearchFinished) {
|
|
||||||
return SearchResults(results: state.results);
|
|
||||||
}
|
|
||||||
throw 'No such event found';
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _InitialView extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
|
||||||
SearchBar(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +1,23 @@
|
||||||
import 'package:confirm_dialog/confirm_dialog.dart';
|
import 'package:confirm_dialog/confirm_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
import 'package:sembast/sembast.dart';
|
||||||
import 'package:jisho_study_tool/models/history/search.dart';
|
|
||||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
|
||||||
import 'package:jisho_study_tool/objectbox.g.dart';
|
|
||||||
import 'package:settings_ui/settings_ui.dart';
|
import 'package:settings_ui/settings_ui.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../../bloc/theme/theme_bloc.dart';
|
||||||
|
import '../../models/history/search.dart';
|
||||||
|
import '../../models/themes/theme.dart';
|
||||||
|
|
||||||
class SettingsView extends StatefulWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
SettingsView({Key? key}) : super(key: key);
|
const SettingsView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SettingsViewState createState() => _SettingsViewState();
|
_SettingsViewState createState() => _SettingsViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsViewState extends State<SettingsView> {
|
class _SettingsViewState extends State<SettingsView> {
|
||||||
late final SharedPreferences prefs;
|
final SharedPreferences prefs = GetIt.instance.get<SharedPreferences>();
|
||||||
|
|
||||||
bool darkThemeEnabled = false;
|
bool darkThemeEnabled = false;
|
||||||
bool autoThemeEnabled = false;
|
bool autoThemeEnabled = false;
|
||||||
|
@ -24,41 +25,41 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
darkThemeEnabled = prefs.getBool('darkThemeEnabled') ?? darkThemeEnabled;
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
autoThemeEnabled = prefs.getBool('autoThemeEnabled') ?? autoThemeEnabled;
|
||||||
this.prefs = prefs;
|
|
||||||
_getPrefs();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get stored preferences and set setting page state accordingly
|
|
||||||
void _getPrefs() {
|
|
||||||
setState(() {
|
|
||||||
darkThemeEnabled = prefs.getBool('darkThemeEnabled') ?? darkThemeEnabled;
|
|
||||||
autoThemeEnabled = prefs.getBool('autoThemeEnabled') ?? autoThemeEnabled;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update stored preferences with values from setting page state
|
/// Update stored preferences with values from setting page state
|
||||||
void _updatePrefs() async {
|
Future<void> _updatePrefs() async {
|
||||||
await prefs.setBool('darkThemeEnabled', darkThemeEnabled);
|
prefs.setBool('darkThemeEnabled', darkThemeEnabled);
|
||||||
await prefs.setBool('autoThemeEnabled', autoThemeEnabled);
|
prefs.setBool('autoThemeEnabled', autoThemeEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> clearHistory(context) async {
|
||||||
|
final bool userIsSure = await confirm(context);
|
||||||
|
|
||||||
|
if (userIsSure) {
|
||||||
|
final Database db = GetIt.instance.get<Database>();
|
||||||
|
await Search.store.delete(db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TextStyle _titleTextStyle = TextStyle(
|
final TextStyle _titleTextStyle = TextStyle(
|
||||||
color: BlocProvider.of<ThemeBloc>(context).state is DarkThemeState
|
color: BlocProvider.of<ThemeBloc>(context).state is DarkThemeState
|
||||||
? AppTheme.jishoGreen.background
|
? AppTheme.jishoGreen.background
|
||||||
: null);
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
return SettingsList(
|
return SettingsList(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 10),
|
contentPadding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
sections: [
|
sections: <SettingsSection>[
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Theme',
|
title: 'Theme',
|
||||||
titleTextStyle: _titleTextStyle,
|
titleTextStyle: _titleTextStyle,
|
||||||
tiles: [
|
tiles: <SettingsTile>[
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Automatically determine theme',
|
title: 'Automatically determine theme',
|
||||||
onToggle: (b) {
|
onToggle: (b) {
|
||||||
|
@ -74,7 +75,8 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Dark Theme',
|
title: 'Dark Theme',
|
||||||
onToggle: (b) {
|
onToggle: (b) {
|
||||||
BlocProvider.of<ThemeBloc>(context).add(SetTheme(themeIsDark: b));
|
BlocProvider.of<ThemeBloc>(context)
|
||||||
|
.add(SetTheme(themeIsDark: b));
|
||||||
setState(() {
|
setState(() {
|
||||||
darkThemeEnabled = b;
|
darkThemeEnabled = b;
|
||||||
});
|
});
|
||||||
|
@ -89,7 +91,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Cache',
|
title: 'Cache',
|
||||||
titleTextStyle: _titleTextStyle,
|
titleTextStyle: _titleTextStyle,
|
||||||
tiles: [
|
tiles: <SettingsTile>[
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Cache grade 1-7 kanji',
|
title: 'Cache grade 1-7 kanji',
|
||||||
switchValue: false,
|
switchValue: false,
|
||||||
|
@ -123,24 +125,23 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Data',
|
title: 'Data',
|
||||||
titleTextStyle: _titleTextStyle,
|
titleTextStyle: _titleTextStyle,
|
||||||
tiles: [
|
tiles: <SettingsTile>[
|
||||||
SettingsTile(
|
const SettingsTile(
|
||||||
leading: Icon(Icons.file_download),
|
leading: Icon(Icons.file_download),
|
||||||
title: 'Export Data',
|
title: 'Export Data',
|
||||||
enabled: false,
|
enabled: false,
|
||||||
),
|
),
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: Icon(Icons.delete),
|
leading: const Icon(Icons.delete),
|
||||||
title: 'Clear History',
|
title: 'Clear History',
|
||||||
onPressed: _clearHistory,
|
onPressed: clearHistory,
|
||||||
titleTextStyle: TextStyle(color: Colors.red),
|
titleTextStyle: const TextStyle(color: Colors.red),
|
||||||
enabled: false,
|
|
||||||
),
|
),
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: Icon(Icons.delete),
|
leading: const Icon(Icons.delete),
|
||||||
title: 'Clear Favourites',
|
title: 'Clear Favourites',
|
||||||
onPressed: (c) {},
|
onPressed: (c) {},
|
||||||
titleTextStyle: TextStyle(color: Colors.red),
|
titleTextStyle: const TextStyle(color: Colors.red),
|
||||||
enabled: false,
|
enabled: false,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -149,13 +150,3 @@ class _SettingsViewState extends State<SettingsView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearHistory(context) async {
|
|
||||||
if (await confirm(context)) {
|
|
||||||
Store db =
|
|
||||||
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected)
|
|
||||||
.database;
|
|
||||||
// db.box<Search>().query().build().find()
|
|
||||||
db.box<Search>().removeAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
302
pubspec.lock
302
pubspec.lock
|
@ -7,35 +7,49 @@ packages:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "22.0.0"
|
version: "31.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.7.2"
|
version: "2.8.0"
|
||||||
|
animated_size_and_fade:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: animated_size_and_fade
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
archive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: archive
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.6"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.3.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.0"
|
version: "2.8.1"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: bloc
|
name: bloc
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "8.0.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -49,56 +63,56 @@ packages:
|
||||||
name: build
|
name: build
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.1.1"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_config
|
name: build_config
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.7"
|
version: "1.0.0"
|
||||||
build_daemon:
|
build_daemon:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_daemon
|
name: build_daemon
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.10"
|
version: "3.0.1"
|
||||||
build_resolvers:
|
build_resolvers:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_resolvers
|
name: build_resolvers
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.0.5"
|
||||||
build_runner:
|
build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.2"
|
version: "2.1.5"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.12"
|
version: "7.2.2"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_collection
|
name: built_collection
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.0"
|
version: "5.1.1"
|
||||||
built_value:
|
built_value:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.1.1"
|
version: "8.1.3"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -112,7 +126,7 @@ packages:
|
||||||
name: charcode
|
name: charcode
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.3.1"
|
||||||
checked_yaml:
|
checked_yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -126,7 +140,7 @@ packages:
|
||||||
name: cli_util
|
name: cli_util
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.3"
|
version: "0.3.5"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -140,7 +154,7 @@ packages:
|
||||||
name: code_builder
|
name: code_builder
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.7.0"
|
version: "4.1.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -148,6 +162,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.15.0"
|
||||||
|
confirm_dialog:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: confirm_dialog
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -168,21 +189,21 @@ packages:
|
||||||
name: csslib
|
name: csslib
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.16.2"
|
version: "0.17.1"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.2.0"
|
||||||
division:
|
division:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: division
|
name: division
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.8"
|
version: "0.9.0"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -196,14 +217,14 @@ packages:
|
||||||
name: ffi
|
name: ffi
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.2"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file
|
name: file
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
version: "6.1.2"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -222,7 +243,28 @@ packages:
|
||||||
name: flutter_bloc
|
name: flutter_bloc
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "8.0.0"
|
||||||
|
flutter_launcher_icons:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: flutter_launcher_icons
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.2"
|
||||||
|
flutter_native_splash:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: flutter_native_splash
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
|
flutter_slidable:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_slidable
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -233,41 +275,55 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
get_it:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: get_it
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "7.2.0"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: glob
|
name: glob
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: graphs
|
name: graphs
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "2.1.0"
|
||||||
html:
|
html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: html
|
name: html
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.14.0+4"
|
version: "0.15.0"
|
||||||
html_unescape:
|
html_unescape:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: html_unescape
|
name: html_unescape
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "2.0.0"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.2"
|
version: "0.13.4"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -281,7 +337,14 @@ packages:
|
||||||
name: http_parser
|
name: http_parser
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.4"
|
version: "4.0.0"
|
||||||
|
image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -302,14 +365,14 @@ packages:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.4.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logging
|
name: logging
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -323,21 +386,21 @@ packages:
|
||||||
name: mdi
|
name: mdi
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "5.0.0-nullsafety.0"
|
||||||
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.4.0"
|
version: "1.7.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -345,36 +408,15 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
objectbox:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: objectbox
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
objectbox_flutter_libs:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: objectbox_flutter_libs
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
objectbox_generator:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: objectbox_generator
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_config
|
name: package_config
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
|
@ -386,56 +428,70 @@ packages:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.7"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.9"
|
||||||
|
path_provider_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_ios
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.7"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_linux
|
name: path_provider_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.1.2"
|
||||||
path_provider_macos:
|
path_provider_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_macos
|
name: path_provider_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.4"
|
||||||
path_provider_platform_interface:
|
path_provider_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_platform_interface
|
name: path_provider_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.1"
|
||||||
path_provider_windows:
|
path_provider_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.4"
|
||||||
pedantic:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pedantic
|
name: petitparser
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "4.4.0"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.1.0"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.3"
|
version: "2.0.2"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -449,27 +505,41 @@ packages:
|
||||||
name: process
|
name: process
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.1"
|
version: "4.2.4"
|
||||||
provider:
|
provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "6.0.1"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.1.0"
|
||||||
pubspec_parse:
|
pubspec_parse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pubspec_parse
|
name: pubspec_parse
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
sembast:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sembast
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
|
settings_ui:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: settings_ui
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
|
@ -477,21 +547,35 @@ packages:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.0.9"
|
||||||
|
shared_preferences_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_android
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.9"
|
||||||
|
shared_preferences_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_ios
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.8"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_linux
|
name: shared_preferences_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.3"
|
||||||
shared_preferences_macos:
|
shared_preferences_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_macos
|
name: shared_preferences_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
shared_preferences_platform_interface:
|
shared_preferences_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -505,40 +589,33 @@ packages:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_windows
|
name: shared_preferences_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.3"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf
|
name: shelf
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.9"
|
version: "1.2.0"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_web_socket
|
name: shelf_web_socket
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.4+1"
|
version: "1.0.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
source_gen:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_gen
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.3"
|
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -574,6 +651,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
synchronized:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: synchronized
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -587,7 +671,7 @@ packages:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.0"
|
version: "0.4.2"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -602,55 +686,76 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
universal_io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_io
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.4"
|
||||||
unofficial_jisho_api:
|
unofficial_jisho_api:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: unofficial_jisho_api
|
name: unofficial_jisho_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "2.0.3"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.3"
|
version: "6.0.17"
|
||||||
|
url_launcher_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_android
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.13"
|
||||||
|
url_launcher_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_ios
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.13"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_linux
|
name: url_launcher_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
url_launcher_macos:
|
url_launcher_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_macos
|
name: url_launcher_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
url_launcher_platform_interface:
|
url_launcher_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.4"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.5"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -664,7 +769,7 @@ packages:
|
||||||
name: watcher
|
name: watcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -678,7 +783,7 @@ packages:
|
||||||
name: win32
|
name: win32
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.3.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -686,6 +791,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.2.0"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.3.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -694,5 +806,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.12.0 <3.0.0"
|
dart: ">=2.14.0 <3.0.0"
|
||||||
flutter: ">=2.0.0"
|
flutter: ">=2.5.0"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue