Update code style
This commit is contained in:
parent
9d8c7b8ebb
commit
8811cef864
|
@ -0,0 +1,169 @@
|
|||
analyzer:
|
||||
exclude:
|
||||
- "lib/objectbox.g.dart"
|
||||
|
||||
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_constructor_name
|
||||
- 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
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import './database_event.dart';
|
||||
import './database_state.dart';
|
||||
|
@ -7,12 +7,12 @@ 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';
|
||||
export './database_state.dart';
|
||||
|
||||
class DatabaseBloc extends Bloc<DatabaseEvent, DatabaseState> {
|
||||
|
||||
DatabaseBloc() : super(DatabaseDisconnected());
|
||||
DatabaseBloc() : super(const DatabaseDisconnected());
|
||||
|
||||
@override
|
||||
Stream<DatabaseState> mapEventToState(DatabaseEvent event)
|
||||
|
@ -20,8 +20,8 @@ class DatabaseBloc extends Bloc<DatabaseEvent, DatabaseState> {
|
|||
if (event is ConnectedToDatabase) {
|
||||
yield DatabaseConnected(event.database);
|
||||
} else {
|
||||
yield DatabaseDisconnected();
|
||||
yield const DatabaseDisconnected();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,4 +11,4 @@ class ConnectedToDatabase extends DatabaseEvent {
|
|||
|
||||
class DisconnectedFromDatabase extends DatabaseEvent {
|
||||
const DisconnectedFromDatabase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
class DatabaseNotConnectedException implements Exception {}
|
||||
class DatabaseNotConnectedException implements Exception {}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import 'package:objectbox/objectbox.dart';
|
||||
|
||||
abstract class DatabaseState {
|
||||
|
@ -12,4 +11,4 @@ class DatabaseConnected extends DatabaseState {
|
|||
|
||||
class DatabaseDisconnected extends DatabaseState {
|
||||
const DatabaseDisconnected();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../models/themes/theme.dart';
|
||||
|
||||
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||
export 'package:jisho_study_tool/models/themes/theme.dart';
|
||||
|
||||
|
@ -14,10 +15,10 @@ part 'theme_state.dart';
|
|||
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
|
||||
bool prefsAreLoaded = false;
|
||||
|
||||
ThemeBloc() : super(LightThemeState()) {
|
||||
ThemeBloc() : super(const LightThemeState()) {
|
||||
SharedPreferences.getInstance().then((prefs) {
|
||||
this.prefsAreLoaded = true;
|
||||
this.add(
|
||||
prefsAreLoaded = true;
|
||||
add(
|
||||
SetTheme(
|
||||
themeIsDark: prefs.getBool('darkThemeEnabled') ?? false,
|
||||
),
|
||||
|
|
|
@ -14,6 +14,7 @@ class LightThemeState extends ThemeState {
|
|||
|
||||
const LightThemeState({this.prefsAreLoaded = false}) : super(prefsAreLoaded);
|
||||
|
||||
@override
|
||||
AppTheme get theme => LightTheme();
|
||||
}
|
||||
|
||||
|
@ -22,5 +23,6 @@ class DarkThemeState extends ThemeState {
|
|||
|
||||
const DarkThemeState({this.prefsAreLoaded = false}) : super(prefsAreLoaded);
|
||||
|
||||
@override
|
||||
AppTheme get theme => DarkTheme();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||
import 'package:jisho_study_tool/router.dart';
|
||||
import 'package:jisho_study_tool/view/components/common/splash.dart';
|
||||
import 'package:mdi/mdi.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'package:jisho_study_tool/objectbox.g.dart';
|
||||
|
||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
||||
|
||||
import 'package:jisho_study_tool/view/screens/search/kanji_view.dart';
|
||||
import 'package:jisho_study_tool/view/screens/history.dart';
|
||||
import 'package:jisho_study_tool/view/screens/search/search_view.dart';
|
||||
import 'package:jisho_study_tool/view/screens/settings.dart';
|
||||
|
||||
import 'bloc/database/database_bloc.dart';
|
||||
import 'bloc/theme/theme_bloc.dart';
|
||||
import 'models/themes/theme.dart';
|
||||
import 'objectbox.g.dart';
|
||||
import 'router.dart';
|
||||
import 'view/components/common/splash.dart';
|
||||
import 'view/screens/history.dart';
|
||||
import 'view/screens/search/kanji_view.dart';
|
||||
import 'view/screens/search/search_view.dart';
|
||||
import 'view/screens/settings.dart';
|
||||
|
||||
void main() => runApp(MyApp());
|
||||
void main() => runApp(const MyApp());
|
||||
|
||||
DatabaseBloc _databaseBloc = DatabaseBloc();
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_MyAppState createState() => _MyAppState();
|
||||
}
|
||||
|
@ -50,7 +49,7 @@ class _MyAppState extends State<MyApp> {
|
|||
@override
|
||||
void dispose() {
|
||||
_store.close();
|
||||
_databaseBloc.add(DisconnectedFromDatabase());
|
||||
_databaseBloc.add(const DisconnectedFromDatabase());
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -64,13 +63,13 @@ class _MyAppState extends State<MyApp> {
|
|||
child: BlocBuilder<ThemeBloc, ThemeState>(
|
||||
builder: (context, themeState) {
|
||||
if (!(dbConnected && themeState.prefsAreLoaded))
|
||||
return SplashScreen();
|
||||
return const SplashScreen();
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Jisho Study Tool',
|
||||
theme: themeState.theme.getMaterialTheme(),
|
||||
initialRoute: '/',
|
||||
onGenerateRoute: PageRouter.generateRoute,
|
||||
onGenerateRoute: generateRoute,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -79,6 +78,8 @@ class _MyAppState extends State<MyApp> {
|
|||
}
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
const Home({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _HomeState();
|
||||
}
|
||||
|
@ -100,11 +101,12 @@ class _HomeState extends State<Home> {
|
|||
body: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
child: Image.asset(
|
||||
'assets/images/denshi_jisho_background_overlay.png'),
|
||||
right: 30,
|
||||
left: 100,
|
||||
bottom: 30,
|
||||
child: Image.asset(
|
||||
'assets/images/denshi_jisho_background_overlay.png',
|
||||
),
|
||||
),
|
||||
pages[pageNum].content,
|
||||
],
|
||||
|
@ -112,8 +114,8 @@ class _HomeState extends State<Home> {
|
|||
bottomNavigationBar: BottomNavigationBar(
|
||||
fixedColor: AppTheme.jishoGreen.background,
|
||||
currentIndex: pageNum,
|
||||
onTap: (int index) => setState(() {
|
||||
this.pageNum = index;
|
||||
onTap: (index) => setState(() {
|
||||
pageNum = index;
|
||||
}),
|
||||
items: pages.map((p) => p.item).toList(),
|
||||
showSelectedLabels: false,
|
||||
|
@ -139,7 +141,7 @@ class _Page {
|
|||
}
|
||||
|
||||
final List<_Page> pages = [
|
||||
_Page(
|
||||
const _Page(
|
||||
content: SearchView(),
|
||||
titleBar: Text('Search'),
|
||||
item: BottomNavigationBarItem(
|
||||
|
@ -147,15 +149,17 @@ final List<_Page> pages = [
|
|||
icon: Icon(Icons.search),
|
||||
),
|
||||
),
|
||||
_Page(
|
||||
const _Page(
|
||||
content: KanjiView(),
|
||||
titleBar: Text('Kanji'),
|
||||
item: BottomNavigationBarItem(
|
||||
label: 'Kanji', icon: Icon(Mdi.ideogramCjk, size: 30)),
|
||||
label: 'Kanji',
|
||||
icon: Icon(Mdi.ideogramCjk, size: 30),
|
||||
),
|
||||
),
|
||||
_Page(
|
||||
const _Page(
|
||||
content: HistoryView(),
|
||||
titleBar: Text("History"),
|
||||
titleBar: Text('History'),
|
||||
item: BottomNavigationBarItem(
|
||||
label: 'History',
|
||||
icon: Icon(Icons.history),
|
||||
|
@ -163,15 +167,15 @@ final List<_Page> pages = [
|
|||
),
|
||||
_Page(
|
||||
content: Container(),
|
||||
titleBar: Text("Saved"),
|
||||
item: BottomNavigationBarItem(
|
||||
titleBar: const Text('Saved'),
|
||||
item: const BottomNavigationBarItem(
|
||||
label: 'Saved',
|
||||
icon: Icon(Icons.bookmark),
|
||||
),
|
||||
),
|
||||
_Page(
|
||||
const _Page(
|
||||
content: SettingsView(),
|
||||
titleBar: Text("Settings"),
|
||||
titleBar: Text('Settings'),
|
||||
item: BottomNavigationBarItem(
|
||||
label: 'Settings',
|
||||
icon: Icon(Icons.settings),
|
||||
|
|
|
@ -16,15 +16,15 @@ class Search {
|
|||
|
||||
Search({
|
||||
this.id = 0,
|
||||
required this.timestamp
|
||||
}); // {
|
||||
required this.timestamp,
|
||||
});
|
||||
|
||||
bool isKanji() {
|
||||
// // TODO: better error message
|
||||
if (this.wordQuery.target == null && this.kanjiQuery.target == null)
|
||||
if (wordQuery.target == null && kanjiQuery.target == null)
|
||||
throw Exception();
|
||||
|
||||
return this.wordQuery.target == null;
|
||||
return wordQuery.target == null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,4 @@ class WordQuery {
|
|||
this.id = 0,
|
||||
required this.query,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:objectbox/objectbox.dart';
|
||||
|
||||
import 'package:jisho_study_tool/models/history/word_query.dart';
|
||||
import 'word_query.dart';
|
||||
|
||||
@Entity()
|
||||
class WordResult {
|
||||
|
@ -18,4 +18,4 @@ class WordResult {
|
|||
required this.timestamp,
|
||||
required this.word,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,42 @@
|
|||
part of './theme.dart';
|
||||
|
||||
class DarkTheme extends AppTheme {
|
||||
@override
|
||||
ColorSet get kanjiResultColor => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.green,
|
||||
);
|
||||
|
||||
@override
|
||||
ColorSet get onyomiColor => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.orange,
|
||||
);
|
||||
|
||||
@override
|
||||
ColorSet get kunyomiColor => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.lightBlue,
|
||||
);
|
||||
|
||||
@override
|
||||
Color get foreground => Colors.black;
|
||||
@override
|
||||
Color get background => Colors.white;
|
||||
|
||||
@override
|
||||
ColorSet get menuGreyLight => ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.grey.shade700,
|
||||
);
|
||||
|
||||
ColorSet get menuGreyNormal => ColorSet(
|
||||
@override
|
||||
ColorSet get menuGreyNormal => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.grey,
|
||||
);
|
||||
|
||||
@override
|
||||
ColorSet get menuGreyDark => ColorSet(
|
||||
foreground: Colors.black,
|
||||
background: Colors.grey.shade300,
|
||||
|
|
|
@ -1,33 +1,41 @@
|
|||
part of './theme.dart';
|
||||
|
||||
class LightTheme extends AppTheme {
|
||||
@override
|
||||
ColorSet get kanjiResultColor => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.blue,
|
||||
);
|
||||
|
||||
@override
|
||||
ColorSet get onyomiColor => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.orange,
|
||||
);
|
||||
|
||||
@override
|
||||
ColorSet get kunyomiColor => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.lightBlue,
|
||||
);
|
||||
|
||||
@override
|
||||
Color get foreground => Colors.black;
|
||||
@override
|
||||
Color get background => Colors.white;
|
||||
|
||||
@override
|
||||
ColorSet get menuGreyLight => ColorSet(
|
||||
foreground: Colors.black,
|
||||
background: Colors.grey.shade300,
|
||||
);
|
||||
ColorSet get menuGreyNormal => ColorSet(
|
||||
@override
|
||||
ColorSet get menuGreyNormal => const ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.grey,
|
||||
);
|
||||
|
||||
@override
|
||||
ColorSet get menuGreyDark => ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Colors.grey.shade700,
|
||||
|
|
|
@ -4,7 +4,6 @@ part 'light.dart';
|
|||
part 'dark.dart';
|
||||
|
||||
abstract class AppTheme {
|
||||
|
||||
static const ColorSet jishoGreen = ColorSet(
|
||||
foreground: Colors.white,
|
||||
background: Color(0xFF3EDD00),
|
||||
|
@ -49,14 +48,15 @@ class ColorSet {
|
|||
|
||||
/// Source: https://blog.usejournal.com/creating-a-custom-color-swatch-in-flutter-554bcdcb27f3
|
||||
MaterialColor createMaterialColor(Color color) {
|
||||
List strengths = <double>[.05];
|
||||
final List<double> strengths = [.05];
|
||||
final swatch = <int, Color>{};
|
||||
final int r = color.red, g = color.green, b = color.blue;
|
||||
|
||||
for (int i = 1; i < 10; i++) {
|
||||
strengths.add(0.1 * i);
|
||||
}
|
||||
strengths.forEach((strength) {
|
||||
|
||||
for (final strength in strengths) {
|
||||
final double ds = 0.5 - strength;
|
||||
swatch[(strength * 1000).round()] = Color.fromRGBO(
|
||||
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
|
||||
|
@ -64,6 +64,6 @@ MaterialColor createMaterialColor(Color color) {
|
|||
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
|
||||
1,
|
||||
);
|
||||
});
|
||||
}
|
||||
return MaterialColor(color.value, swatch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/view/screens/search/kanji_result_page.dart';
|
||||
import 'package:jisho_study_tool/view/screens/search/search_results_page.dart';
|
||||
|
||||
import 'main.dart';
|
||||
import 'view/screens/search/kanji_result_page.dart';
|
||||
import 'view/screens/search/search_results_page.dart';
|
||||
|
||||
class PageRouter {
|
||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||
final args = settings.arguments;
|
||||
Route<dynamic> generateRoute(RouteSettings settings) {
|
||||
final args = settings.arguments;
|
||||
|
||||
switch (settings.name) {
|
||||
case '/':
|
||||
return MaterialPageRoute(builder: (_) => Home());
|
||||
switch (settings.name) {
|
||||
case '/':
|
||||
return MaterialPageRoute(builder: (_) => const Home());
|
||||
|
||||
case '/search':
|
||||
final searchTerm = args as String;
|
||||
return MaterialPageRoute(builder: (_) => SearchResultsPage(searchTerm: searchTerm));
|
||||
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));
|
||||
case '/kanjiSearch':
|
||||
final searchTerm = args as String;
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => KanjiResultPage(kanjiSearchTerm: searchTerm),
|
||||
);
|
||||
|
||||
default:
|
||||
return MaterialPageRoute(builder: (_) => Text("ERROR: this route does not exist"));
|
||||
}
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => const Text('ERROR: this route does not exist'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,5 +2,5 @@ import 'package:unofficial_jisho_api/api.dart' as jisho;
|
|||
export 'package:unofficial_jisho_api/api.dart' show JishoAPIResult;
|
||||
|
||||
Future<jisho.JishoAPIResult> fetchJishoResults(searchTerm) async {
|
||||
return await jisho.searchForPhrase(searchTerm);
|
||||
}
|
||||
return jisho.searchForPhrase(searchTerm);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||
export 'package:unofficial_jisho_api/api.dart' show KanjiResult;
|
||||
|
||||
String? _convertGrade(String grade) {
|
||||
const conversionTable = {
|
||||
"grade 1": "小1",
|
||||
"grade 2": "小2",
|
||||
"grade 3": "小3",
|
||||
"grade 4": "小4",
|
||||
"grade 5": "小5",
|
||||
"grade 6": "小6",
|
||||
"junior high": "中"
|
||||
'grade 1': '小1',
|
||||
'grade 2': '小2',
|
||||
'grade 3': '小3',
|
||||
'grade 4': '小4',
|
||||
'grade 5': '小5',
|
||||
'grade 6': '小6',
|
||||
'junior high': '中'
|
||||
};
|
||||
|
||||
print('conversion run: $grade -> ${conversionTable[grade]}');
|
||||
debugPrint('conversion run: $grade -> ${conversionTable[grade]}');
|
||||
|
||||
return conversionTable[grade];
|
||||
}
|
||||
|
@ -24,4 +25,4 @@ Future<jisho.KanjiResult> fetchKanji(String kanji) async {
|
|||
if (result.data != null && result.data?.taughtIn != null)
|
||||
result.data!.taughtIn = _convertGrade(result.data!.taughtIn!);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoadingScreen extends StatelessWidget {
|
||||
const LoadingScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||
|
||||
import '../../../models/themes/theme.dart';
|
||||
|
||||
class SplashScreen extends StatelessWidget {
|
||||
const SplashScreen({Key? key}) : super(key: key);
|
||||
|
@ -8,9 +9,11 @@ class SplashScreen extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: AppTheme.jishoGreen.background),
|
||||
child: Center(
|
||||
child: Image(image: AssetImage('assets/images/logo/logo_icon_transparent.png'),)
|
||||
child: const Center(
|
||||
child: Image(
|
||||
image: AssetImage('assets/images/logo/logo_icon_transparent.png'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
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 {
|
||||
final String? text;
|
||||
|
@ -33,31 +34,31 @@ class DateDivider extends StatelessWidget {
|
|||
final int day = date.day;
|
||||
final String month = monthTable[date.month]!;
|
||||
final int year = date.year;
|
||||
return "$day. $month $year";
|
||||
return '$day. $month $year';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Widget header = (this.text != null)
|
||||
? Text(this.text!)
|
||||
: (this.date != null)
|
||||
? Text(getHumanReadableDate(this.date!))
|
||||
: SizedBox.shrink();
|
||||
final Widget header = (text != null)
|
||||
? Text(text!)
|
||||
: (date != null)
|
||||
? Text(getHumanReadableDate(date!))
|
||||
: const SizedBox.shrink();
|
||||
|
||||
final ColorSet _menuColors =
|
||||
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyNormal;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: _menuColors.background),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 5,
|
||||
horizontal: 10,
|
||||
),
|
||||
margin: margin,
|
||||
child: DefaultTextStyle.merge(
|
||||
child: header,
|
||||
style: TextStyle(color: _menuColors.foreground),
|
||||
),
|
||||
decoration: BoxDecoration(color: _menuColors.background),
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 5,
|
||||
horizontal: 10,
|
||||
),
|
||||
margin: this.margin,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.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 '../../../bloc/theme/theme_bloc.dart';
|
||||
import '../../../models/history/kanji_query.dart';
|
||||
import '../../../models/themes/theme.dart';
|
||||
|
||||
class _KanjiBox extends StatelessWidget {
|
||||
final String kanji;
|
||||
|
@ -19,7 +19,7 @@ class _KanjiBox extends StatelessWidget {
|
|||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
color: _menuColors.background,
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:jisho_study_tool/models/history/word_query.dart';
|
||||
|
||||
import './search_item.dart';
|
||||
import '../../../models/history/word_query.dart';
|
||||
|
||||
class PhraseSearchItem extends StatelessWidget {
|
||||
final WordQuery search;
|
||||
|
@ -17,15 +17,20 @@ class PhraseSearchItem extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Slidable(
|
||||
actionPane: SlidableScrollActionPane(),
|
||||
secondaryActions: [
|
||||
actionPane: const SlidableScrollActionPane(),
|
||||
secondaryActions: const [
|
||||
IconSlideAction(
|
||||
caption: "Delete", color: Colors.red, icon: Icons.delete)
|
||||
caption: 'Delete',
|
||||
color: Colors.red,
|
||||
icon: Icons.delete,
|
||||
),
|
||||
],
|
||||
child: SearchItem(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, '/search', arguments: this.search.query);
|
||||
},
|
||||
onTap: () => Navigator.pushNamed(
|
||||
context,
|
||||
'/search',
|
||||
arguments: search.query,
|
||||
),
|
||||
time: timestamp,
|
||||
search: Text(search.query),
|
||||
),
|
||||
|
|
|
@ -13,26 +13,24 @@ class SearchItem extends StatelessWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
String getTime() {
|
||||
final hours = this.time.hour.toString().padLeft(2, '0');
|
||||
final mins = this.time.minute.toString().padLeft(2, '0');
|
||||
return "$hours:$mins";
|
||||
final hours = time.hour.toString().padLeft(2, '0');
|
||||
final mins = time.minute.toString().padLeft(2, '0');
|
||||
return '$hours:$mins';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: ListTile(
|
||||
onTap: onTap,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text(getTime()),
|
||||
),
|
||||
search,
|
||||
],
|
||||
),
|
||||
return ListTile(
|
||||
onTap: onTap,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text(getTime()),
|
||||
),
|
||||
search,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,14 +14,13 @@ class KanjiResultBody extends StatelessWidget {
|
|||
late final String query;
|
||||
late final jisho.KanjiResultData resultData;
|
||||
|
||||
KanjiResultBody({required jisho.KanjiResult result}) {
|
||||
|
||||
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();
|
||||
|
||||
if (result.data == null) throw Exception();
|
||||
|
||||
resultData = result.data!;
|
||||
}
|
||||
|
||||
|
@ -30,69 +29,73 @@ class KanjiResultBody extends StatelessWidget {
|
|||
return ListView(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 30.0),
|
||||
margin: const EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 30.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
const Flexible(
|
||||
fit: FlexFit.tight,
|
||||
child: Center(child: SizedBox()),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
fit: FlexFit.tight,
|
||||
child: Center(child: Header(query)),
|
||||
child: Center(child: Header(kanji: query)),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
fit: FlexFit.tight,
|
||||
child: Center(
|
||||
child: (resultData.radical != null) ? Radical(resultData.radical!) : SizedBox(),
|
||||
child: (resultData.radical != null)
|
||||
? Radical(radical: resultData.radical!)
|
||||
: const 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(),
|
||||
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(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),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
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(resultData.onyomiExamples, resultData.kunyomiExamples),
|
||||
Examples(
|
||||
onyomi: resultData.onyomiExamples,
|
||||
kunyomi: resultData.kunyomiExamples,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||
import 'package:unofficial_jisho_api/api.dart';
|
||||
|
||||
class Examples extends StatelessWidget {
|
||||
final List<YomiExample> onyomiExamples;
|
||||
final List<YomiExample> kunyomiExamples;
|
||||
import '../../../../bloc/theme/theme_bloc.dart';
|
||||
|
||||
const Examples(
|
||||
this.onyomiExamples,
|
||||
this.kunyomiExamples,
|
||||
);
|
||||
class Examples extends StatelessWidget {
|
||||
final List<YomiExample> onyomi;
|
||||
final List<YomiExample> kunyomi;
|
||||
|
||||
const Examples({
|
||||
required this.onyomi,
|
||||
required this.kunyomi,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -17,20 +19,21 @@ class Examples extends StatelessWidget {
|
|||
children: [
|
||||
[
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 10),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
'Examples:',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
)
|
||||
],
|
||||
onyomiExamples
|
||||
onyomi
|
||||
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
||||
.toList(),
|
||||
kunyomiExamples
|
||||
kunyomi
|
||||
.map(
|
||||
(kunyomiExample) => _Example(kunyomiExample, _KanaType.kunyomi))
|
||||
(kunyomiExample) => _Example(kunyomiExample, _KanaType.kunyomi),
|
||||
)
|
||||
.toList(),
|
||||
].expand((list) => list).toList(),
|
||||
);
|
||||
|
@ -48,68 +51,66 @@ class _Example extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
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;
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 5.0,
|
||||
horizontal: 10.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _menuColors.background, borderRadius: BorderRadius.circular(10.0)),
|
||||
color: _menuColors.background,
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10.0,
|
||||
horizontal: 10.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _kanaColors.background,
|
||||
borderRadius: BorderRadius.only(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
bottomLeft: Radius.circular(10.0),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
child: Text(
|
||||
yomiExample.reading,
|
||||
style: TextStyle(
|
||||
color: _kanaColors.foreground,
|
||||
fontSize: 15.0,
|
||||
),
|
||||
Text(
|
||||
yomiExample.reading,
|
||||
style: TextStyle(
|
||||
color: _kanaColors.foreground,
|
||||
fontSize: 15.0,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
const SizedBox(
|
||||
height: 5.0,
|
||||
),
|
||||
Container(
|
||||
child: Text(
|
||||
yomiExample.example,
|
||||
style: TextStyle(
|
||||
color: _kanaColors.foreground,
|
||||
fontSize: 20.0,
|
||||
),
|
||||
Text(
|
||||
yomiExample.example,
|
||||
style: TextStyle(
|
||||
color: _kanaColors.foreground,
|
||||
fontSize: 20.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
const SizedBox(
|
||||
width: 15.0,
|
||||
),
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
children: [
|
||||
Container(
|
||||
child: Text(
|
||||
yomiExample.meaning,
|
||||
style: TextStyle(
|
||||
color: _menuColors.foreground,
|
||||
),
|
||||
Text(
|
||||
yomiExample.meaning,
|
||||
style: TextStyle(
|
||||
color: _menuColors.foreground,
|
||||
),
|
||||
)
|
||||
],
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
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 {
|
||||
final String grade;
|
||||
|
||||
const Grade(this.grade);
|
||||
const Grade({required this.grade, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
color: _kanjiColors.background,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text(
|
||||
grade,
|
||||
style: TextStyle(
|
||||
|
@ -19,10 +24,6 @@ class Grade extends StatelessWidget {
|
|||
fontSize: 20.0,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _kanjiColors.background,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
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 {
|
||||
final String kanji;
|
||||
|
||||
const Header(this.kanji);
|
||||
const Header({
|
||||
required this.kanji,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
final _kanjiColors =
|
||||
BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
|
||||
return AspectRatio(
|
||||
aspectRatio: 1,
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
|
||||
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 {
|
||||
final String jlptLevel;
|
||||
|
||||
const JlptLevel(this.jlptLevel);
|
||||
const JlptLevel({
|
||||
required this.jlptLevel,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
final _kanjiColors =
|
||||
BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _kanjiColors.background,
|
||||
),
|
||||
child: Text(
|
||||
jlptLevel,
|
||||
style: TextStyle(
|
||||
|
@ -20,10 +28,6 @@ class JlptLevel extends StatelessWidget {
|
|||
fontSize: 20.0,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _kanjiColors.background,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
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 '../../../../bloc/theme/theme_bloc.dart';
|
||||
|
||||
class Radical extends StatelessWidget {
|
||||
final jisho.Radical radical;
|
||||
|
||||
const Radical(this.radical);
|
||||
const Radical({required this.radical, Key? key,}) : super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _kanjiColors.background,
|
||||
),
|
||||
child: Text(
|
||||
radical.symbol,
|
||||
style: TextStyle(
|
||||
|
@ -20,10 +26,6 @@ class Radical extends StatelessWidget {
|
|||
fontSize: 40.0,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _kanjiColors.background,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
|
||||
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 {
|
||||
final int rank;
|
||||
|
||||
const Rank(this.rank);
|
||||
const Rank({required this.rank, Key? key,}) : super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
|
||||
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(
|
||||
'${rank.toString()} / 2500',
|
||||
style: TextStyle(
|
||||
|
@ -20,10 +25,6 @@ class Rank extends StatelessWidget {
|
|||
fontSize: 20.0,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
color: _kanjiColors.background,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
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 {
|
||||
final String uri;
|
||||
|
||||
const StrokeOrderGif(this.uri);
|
||||
const StrokeOrderGif({required this.uri, Key? key,}) : super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 20.0),
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: ClipRRect(
|
||||
child: Image.network(uri),
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(vertical: 20.0),
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: _kanjiColors.background,
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
child: Image.network(uri),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||
|
||||
import '../../../../bloc/theme/theme_bloc.dart';
|
||||
|
||||
enum YomiType {
|
||||
onyomi,
|
||||
|
@ -37,86 +38,88 @@ class YomiChips extends StatelessWidget {
|
|||
final List<String> yomi;
|
||||
final YomiType type;
|
||||
|
||||
const YomiChips(this.yomi, this.type);
|
||||
const YomiChips({
|
||||
required this.yomi,
|
||||
required this.type,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 10.0,
|
||||
vertical: 5.0,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: _yomiWrapper(context),
|
||||
);
|
||||
}
|
||||
bool get isExpandable => yomi.length > 6;
|
||||
|
||||
bool 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 = this
|
||||
.yomi
|
||||
.map((yomi) => _YomiCard(
|
||||
yomi: yomi,
|
||||
colors: this.type.getColors(context),
|
||||
))
|
||||
Widget yomiWrapper(BuildContext context) {
|
||||
final yomiCards = yomi
|
||||
.map(
|
||||
(y) => yomiCard(
|
||||
context: context,
|
||||
yomi: y,
|
||||
colors: type.getColors(context),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (!this.isExpandable())
|
||||
if (!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),
|
||||
else
|
||||
return ExpansionTile(
|
||||
// initiallyExpanded: false,
|
||||
title: Center(
|
||||
child: yomiCard(
|
||||
context: context,
|
||||
yomi: type.title,
|
||||
colors: type.getColors(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
Wrap(
|
||||
runSpacing: 10.0,
|
||||
children: yomiCards,
|
||||
),
|
||||
SizedBox(
|
||||
height: 25.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
Wrap(
|
||||
runSpacing: 10.0,
|
||||
children: yomiCards,
|
||||
),
|
||||
const 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,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0,
|
||||
vertical: 5.0,
|
||||
),
|
||||
child: Text(
|
||||
this.yomi,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0,
|
||||
color: colors.foreground,
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: colors.background,
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: yomiWrapper(context),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:animated_size_and_fade/animated_size_and_fade.dart';
|
||||
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_body/kanji_grid.dart';
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_body/kanji_search_bar.dart';
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_body/kanji_search_options_bar.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 {
|
||||
KanjiSearchBody({Key? key}) : super(key: key);
|
||||
const KanjiSearchBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_KanjiSearchBodyState createState() => _KanjiSearchBodyState();
|
||||
|
@ -28,16 +28,18 @@ class _KanjiSearchBodyState extends State<KanjiSearchBody>
|
|||
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 200),
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
|
||||
_searchbarMovementAnimation = AlignmentTween(
|
||||
begin: Alignment.center,
|
||||
end: Alignment.topCenter,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
).animate(
|
||||
CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -60,15 +62,15 @@ class _KanjiSearchBodyState extends State<KanjiSearchBody>
|
|||
child: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(),
|
||||
decoration: const BoxDecoration(),
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: AnimatedBuilder(
|
||||
animation: _searchbarMovementAnimation,
|
||||
builder: (BuildContext context, _) {
|
||||
builder: (context, _) {
|
||||
return Container(
|
||||
alignment: _searchbarMovementAnimation.value,
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
@ -83,17 +85,17 @@ class _KanjiSearchBodyState extends State<KanjiSearchBody>
|
|||
child: KanjiSearchBar(
|
||||
key: _kanjiSearchBarState,
|
||||
onChanged: (text) => setState(() {
|
||||
this.suggestions = kanjiSuggestions(text);
|
||||
suggestions = kanjiSuggestions(text);
|
||||
}),
|
||||
),
|
||||
),
|
||||
AnimatedSizeAndFade(
|
||||
vsync: this,
|
||||
child: _controller.value == 1
|
||||
? KanjiGrid(this.suggestions)
|
||||
: KanjiSearchOptionsBar(),
|
||||
fadeDuration: const Duration(milliseconds: 200),
|
||||
sizeDuration: const Duration(milliseconds: 300),
|
||||
child: _controller.value == 1
|
||||
? KanjiGrid(suggestions: suggestions)
|
||||
: const KanjiSearchOptionsBar(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||
import '../../../../bloc/theme/theme_bloc.dart';
|
||||
|
||||
class KanjiGrid extends StatelessWidget {
|
||||
final List<String> suggestions;
|
||||
const KanjiGrid(this.suggestions);
|
||||
|
||||
const KanjiGrid({required this.suggestions, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 20.0,
|
||||
horizontal: 40.0,
|
||||
),
|
||||
|
@ -43,7 +44,7 @@ class _GridItem extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(20.0),
|
||||
),
|
||||
child: Container(
|
||||
margin: EdgeInsets.all(10.0),
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
child: FittedBox(
|
||||
child: Text(
|
||||
kanji,
|
||||
|
|
|
@ -4,16 +4,16 @@ import 'package:flutter/services.dart';
|
|||
class KanjiSearchBar extends StatefulWidget {
|
||||
final Function(String)? onChanged;
|
||||
|
||||
KanjiSearchBar({this.onChanged, Key? key}) : super(key: key);
|
||||
const KanjiSearchBar({this.onChanged, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
KanjiSearchBarState createState() => new KanjiSearchBarState(this.onChanged);
|
||||
KanjiSearchBarState createState() => KanjiSearchBarState(this.onChanged);
|
||||
}
|
||||
|
||||
enum TextFieldButton { clear, paste }
|
||||
|
||||
class KanjiSearchBarState extends State<KanjiSearchBar> {
|
||||
final TextEditingController textController = new TextEditingController();
|
||||
final TextEditingController textController = TextEditingController();
|
||||
TextFieldButton button = TextFieldButton.paste;
|
||||
final Function(String)? onChanged;
|
||||
|
||||
|
@ -33,8 +33,8 @@ class KanjiSearchBarState extends State<KanjiSearchBar> {
|
|||
runOnChanged();
|
||||
}
|
||||
|
||||
void pasteText() async {
|
||||
ClipboardData? clipboardData = await Clipboard.getData('text/plain');
|
||||
Future<void> pasteText() async {
|
||||
final ClipboardData? clipboardData = await Clipboard.getData('text/plain');
|
||||
if (clipboardData != null && clipboardData.text != null) {
|
||||
textController.text = clipboardData.text!;
|
||||
runOnChanged();
|
||||
|
@ -43,24 +43,24 @@ class KanjiSearchBarState extends State<KanjiSearchBar> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
IconButton clearButton = IconButton(
|
||||
icon: Icon(Icons.clear),
|
||||
final IconButton clearButton = IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () => clearText(),
|
||||
);
|
||||
|
||||
IconButton pasteButton = IconButton(
|
||||
icon: Icon(Icons.content_paste),
|
||||
final IconButton pasteButton = IconButton(
|
||||
icon: const Icon(Icons.content_paste),
|
||||
onPressed: () => pasteText(),
|
||||
);
|
||||
|
||||
return TextField(
|
||||
controller: textController,
|
||||
onChanged: (text) {
|
||||
if (this.onChanged != null) this.onChanged!(text);
|
||||
if (onChanged != null) onChanged!(text);
|
||||
},
|
||||
onSubmitted: (_) => {},
|
||||
decoration: new InputDecoration(
|
||||
prefixIcon: Icon(Icons.search),
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.search),
|
||||
hintText: 'Search',
|
||||
// fillColor: Colors.white,
|
||||
// filled: true,
|
||||
|
|
|
@ -12,22 +12,22 @@ class KanjiSearchOptionsBar extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_IconButton(
|
||||
icon: Text(
|
||||
"部",
|
||||
icon: const Text(
|
||||
'部',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
onPressed: () {}
|
||||
onPressed: () {},
|
||||
),
|
||||
_IconButton(
|
||||
icon: Icon(Icons.category),
|
||||
onPressed: () {}
|
||||
icon: const Icon(Icons.category),
|
||||
onPressed: () {},
|
||||
),
|
||||
_IconButton(
|
||||
icon: Icon(Icons.mode),
|
||||
onPressed: () {}
|
||||
icon: const Icon(Icons.mode),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -9,7 +9,7 @@ class OpaqueBox extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor),
|
||||
child: this.child,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../models/themes/theme.dart';
|
||||
|
||||
class LanguageSelector extends StatefulWidget {
|
||||
const LanguageSelector();
|
||||
const LanguageSelector({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LanguageSelectorState createState() => new _LanguageSelectorState();
|
||||
_LanguageSelectorState createState() => _LanguageSelectorState();
|
||||
}
|
||||
|
||||
class _LanguageSelectorState extends State<LanguageSelector> {
|
||||
|
@ -18,27 +19,26 @@ class _LanguageSelectorState extends State<LanguageSelector> {
|
|||
super.initState();
|
||||
isSelected = [false, false, false];
|
||||
|
||||
SharedPreferences.getInstance()
|
||||
.then((prefs) {
|
||||
this.prefs = prefs;
|
||||
setState(() {
|
||||
isSelected = _getSelectedStatus() ?? isSelected;
|
||||
});
|
||||
SharedPreferences.getInstance().then((prefs) {
|
||||
this.prefs = prefs;
|
||||
setState(() {
|
||||
isSelected = _getSelectedStatus() ?? isSelected;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _updateSelectedStatus() async {
|
||||
await prefs.setStringList('languageSelectorStatus',
|
||||
isSelected
|
||||
.map((b) => b ? '1' : '0')
|
||||
.toList());
|
||||
void _updateSelectedStatus() {
|
||||
prefs.setStringList(
|
||||
'languageSelectorStatus',
|
||||
isSelected.map((b) => b ? '1' : '0').toList(),
|
||||
);
|
||||
}
|
||||
|
||||
List<bool>? _getSelectedStatus() {
|
||||
return prefs
|
||||
.getStringList('languageSelectorStatus')
|
||||
?.map((s) => s == '1')
|
||||
.toList();
|
||||
.getStringList('languageSelectorStatus')
|
||||
?.map((s) => s == '1')
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -46,14 +46,14 @@ class _LanguageSelectorState extends State<LanguageSelector> {
|
|||
return ToggleButtons(
|
||||
selectedColor: AppTheme.jishoGreen.background,
|
||||
isSelected: isSelected,
|
||||
children: <Widget> [
|
||||
_LanguageOption("Auto"),
|
||||
_LanguageOption("日本語"),
|
||||
_LanguageOption("English")
|
||||
children: const <Widget>[
|
||||
_LanguageOption('Auto'),
|
||||
_LanguageOption('日本語'),
|
||||
_LanguageOption('English')
|
||||
],
|
||||
onPressed: (int buttonIndex) {
|
||||
onPressed: (buttonIndex) {
|
||||
setState(() {
|
||||
for (var i in Iterable.generate(isSelected.length)) {
|
||||
for (final int i in Iterable.generate(isSelected.length)) {
|
||||
isSelected[i] = i == buttonIndex;
|
||||
}
|
||||
_updateSelectedStatus();
|
||||
|
@ -61,7 +61,6 @@ class _LanguageSelectorState extends State<LanguageSelector> {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _LanguageOption extends StatelessWidget {
|
||||
|
@ -72,8 +71,8 @@ class _LanguageOption extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||
child: Center(child: Text(language)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/view/components/search/language_selector.dart';
|
||||
|
||||
import 'language_selector.dart';
|
||||
|
||||
class SearchBar extends StatelessWidget {
|
||||
const SearchBar();
|
||||
const SearchBar({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
|
@ -21,10 +22,10 @@ class SearchBar extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
const SizedBox(
|
||||
height: 10.0,
|
||||
),
|
||||
LanguageSelector()
|
||||
const LanguageSelector()
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/view/components/search/search_results_body/search_card.dart';
|
||||
import 'package:unofficial_jisho_api/api.dart';
|
||||
|
||||
import 'search_results_body/search_card.dart';
|
||||
|
||||
class SearchResultsBody extends StatelessWidget {
|
||||
final List<JishoResult> results;
|
||||
|
||||
|
@ -13,7 +14,7 @@ class SearchResultsBody extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
children: results.map((result) => SearchResultCard(result)).toList(),
|
||||
children: results.map((result) => SearchResultCard(result: result)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class Badge extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Widget? child;
|
||||
final Color color;
|
||||
|
||||
const Badge(this.child, this.color);
|
||||
const Badge({this.child, required this.color, Key? key,}) : super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: FittedBox(
|
||||
child: Center(
|
||||
child: this.child
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.all(5),
|
||||
padding: const EdgeInsets.all(5),
|
||||
width: 30,
|
||||
height: 30,
|
||||
margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: color
|
||||
color: color,
|
||||
),
|
||||
child: FittedBox(
|
||||
child: Center(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
); }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,21 @@ import './badge.dart';
|
|||
class CommonBadge extends StatelessWidget {
|
||||
final bool isCommon;
|
||||
|
||||
const CommonBadge(this.isCommon);
|
||||
const CommonBadge({
|
||||
required this.isCommon,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Badge(
|
||||
Text(
|
||||
"C",
|
||||
style: TextStyle(color: this.isCommon ? Colors.white : Colors.transparent)
|
||||
color: isCommon ? Colors.green : Colors.transparent,
|
||||
child: Text(
|
||||
'C',
|
||||
style: TextStyle(
|
||||
color: isCommon ? Colors.white : Colors.transparent,
|
||||
),
|
||||
),
|
||||
this.isCommon ? Colors.green : Colors.transparent
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,24 @@ import 'package:unofficial_jisho_api/api.dart';
|
|||
|
||||
class JapaneseHeader extends StatelessWidget {
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
final hasFurigana = (word.word != null && word.reading != null);
|
||||
|
||||
return Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: EdgeInsets.only(left: 10.0),
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// TODO: take a look at this logic
|
||||
(hasFurigana) ? Text(word.reading!) : Text(''),
|
||||
(hasFurigana) ? Text(word.word!) : Text(word.reading ?? word.word!),
|
||||
hasFurigana ? Text(word.reading!) : const Text(''),
|
||||
hasFurigana ? Text(word.word!) : Text(word.reading ?? word.word!),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -4,22 +4,22 @@ import './badge.dart';
|
|||
class JLPTBadge extends StatelessWidget {
|
||||
final String jlptLevel;
|
||||
|
||||
const JLPTBadge(this.jlptLevel);
|
||||
const JLPTBadge({
|
||||
required this.jlptLevel,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
String _extractJlptLevel(String jlptRaw) {
|
||||
return jlptRaw.isNotEmpty ? jlptRaw.substring(5).toUpperCase() : '';
|
||||
}
|
||||
String get formattedJlptLevel =>
|
||||
jlptLevel.isNotEmpty ? jlptLevel.substring(5).toUpperCase() : '';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Badge(
|
||||
Text(
|
||||
_extractJlptLevel(this.jlptLevel),
|
||||
style: TextStyle(
|
||||
color: Colors.white
|
||||
),
|
||||
color: jlptLevel.isNotEmpty ? Colors.blue : Colors.transparent,
|
||||
child: Text(
|
||||
formattedJlptLevel,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
this.jlptLevel.isNotEmpty ? Colors.blue : Colors.transparent
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||
import 'package:unofficial_jisho_api/api.dart';
|
||||
|
||||
class OtherForms extends StatelessWidget {
|
||||
final List<JishoJapaneseWord> otherForms;
|
||||
import '../../../../../bloc/theme/theme_bloc.dart';
|
||||
|
||||
const OtherForms(this.otherForms);
|
||||
class OtherForms extends StatelessWidget {
|
||||
final List<JishoJapaneseWord> forms;
|
||||
|
||||
const OtherForms({required this.forms, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Column(
|
||||
children: this.otherForms.isNotEmpty
|
||||
? [
|
||||
Text(
|
||||
'Other Forms',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Row(
|
||||
children: otherForms.map((form) => _KanaBox(form)).toList(),
|
||||
),
|
||||
]
|
||||
: [],
|
||||
),
|
||||
return Column(
|
||||
children: forms.isNotEmpty
|
||||
? [
|
||||
const Text(
|
||||
'Other Forms',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Row(
|
||||
children: forms.map((form) => _KanaBox(form)).toList(),
|
||||
),
|
||||
]
|
||||
: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,28 +31,19 @@ class _KanaBox extends StatelessWidget {
|
|||
|
||||
const _KanaBox(this.word);
|
||||
|
||||
bool get hasFurigana => word.word != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hasFurigana = (word.word != null);
|
||||
final _menuColors =
|
||||
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
|
||||
|
||||
return Container(
|
||||
child: DefaultTextStyle.merge(
|
||||
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(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 5.0,
|
||||
vertical: 5.0,
|
||||
),
|
||||
padding: EdgeInsets.all(5.0),
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: _menuColors.background,
|
||||
boxShadow: [
|
||||
|
@ -61,10 +51,20 @@ class _KanaBox extends StatelessWidget {
|
|||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 1,
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,18 +3,20 @@ import 'package:unofficial_jisho_api/parser.dart';
|
|||
|
||||
class Senses extends StatelessWidget {
|
||||
final List<JishoWordSense> senses;
|
||||
|
||||
const Senses(this.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 Container(
|
||||
child: Column(
|
||||
return Column(
|
||||
children: senseWidgets,
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,37 +28,35 @@ class _Sense extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
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: [
|
||||
Text(
|
||||
(index + 1).toString() + '. ',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
Text(
|
||||
sense.partsOfSpeech.join(', '),
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.left,
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children:
|
||||
sense.englishDefinitions.map((def) => Text(def)).toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@ class WKBadge extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Badge(
|
||||
Text(
|
||||
child: Text(
|
||||
_extractWkLevel(this.wkLevel),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
this.wkLevel.isNotEmpty ? Colors.red : Colors.transparent
|
||||
color: this.wkLevel.isNotEmpty ? Colors.red : Colors.transparent
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,10 +13,12 @@ class SearchResultCard extends StatelessWidget {
|
|||
late final JishoJapaneseWord mainWord;
|
||||
late final List<JishoJapaneseWord> otherForms;
|
||||
|
||||
SearchResultCard(this.result) {
|
||||
this.mainWord = result.japanese[0];
|
||||
this.otherForms = result.japanese.sublist(1);
|
||||
}
|
||||
SearchResultCard({
|
||||
required this.result,
|
||||
Key? key,
|
||||
}) : mainWord = result.japanese[0],
|
||||
otherForms = result.japanese.sublist(1),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -24,34 +26,40 @@ class SearchResultCard extends StatelessWidget {
|
|||
return ExpansionTile(
|
||||
collapsedBackgroundColor: backgroundColor,
|
||||
backgroundColor: backgroundColor,
|
||||
title:
|
||||
IntrinsicWidth(
|
||||
title: IntrinsicWidth(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
JapaneseHeader(mainWord),
|
||||
JapaneseHeader(word: mainWord),
|
||||
Row(
|
||||
children: [
|
||||
WKBadge(result.tags.firstWhere((tag) => tag.contains("wanikani"), orElse: () => '')),
|
||||
JLPTBadge(result.jlpt.isNotEmpty ? result.jlpt[0] : ''),
|
||||
CommonBadge(result.isCommon ?? false)
|
||||
WKBadge(
|
||||
result.tags.firstWhere(
|
||||
(tag) => tag.contains('wanikani'),
|
||||
orElse: () => '',
|
||||
),
|
||||
),
|
||||
JLPTBadge(
|
||||
jlptLevel: result.jlpt.isNotEmpty ? result.jlpt[0] : '',
|
||||
),
|
||||
CommonBadge(isCommon: result.isCommon ?? false)
|
||||
],
|
||||
)
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Column(
|
||||
children: [
|
||||
Senses(result.senses),
|
||||
OtherForms(otherForms),
|
||||
Senses(senses: result.senses),
|
||||
OtherForms(forms: otherForms),
|
||||
// Text(result.toJson().toString()),
|
||||
// Text(result.attribution.toJson().toString()),
|
||||
// Text(result.japanese.map((e) => e.toJson().toString()).toList().toString()),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 30),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,75 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
||||
import 'package:jisho_study_tool/models/history/search.dart';
|
||||
import 'package:jisho_study_tool/view/components/history/kanji_search_item.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 'package:jisho_study_tool/view/components/opaque_box.dart';
|
||||
import '../../bloc/database/database_bloc.dart';
|
||||
import '../../models/history/search.dart';
|
||||
import '../../objectbox.g.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 {
|
||||
const HistoryView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DatabaseBloc, DatabaseState>(
|
||||
builder: (context, state) {
|
||||
if (state is DatabaseDisconnected)
|
||||
if (state is DatabaseDisconnected) {
|
||||
throw DatabaseNotConnectedException();
|
||||
}
|
||||
|
||||
return StreamBuilder(
|
||||
stream: ((state as DatabaseConnected).database.box<Search>().query()
|
||||
..order(Search_.timestamp, flags: Order.descending))
|
||||
.watch(triggerImmediately: true)
|
||||
.map((query) => query.find()),
|
||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||
if (!snapshot.hasData) return Container();
|
||||
return StreamBuilder<List<Search>>(
|
||||
stream: getAsyncStream(state),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
final List<Search> data = snapshot.data!;
|
||||
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];
|
||||
DateTime searchDate = roundToDay(search.timestamp);
|
||||
|
||||
bool newDate = true;
|
||||
|
||||
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();
|
||||
},
|
||||
itemCount: data.length + 1,
|
||||
itemBuilder: historyEntryWithData(data),
|
||||
separatorBuilder: historyEntrySeparatorWithData(data),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -77,4 +39,68 @@ class HistoryView extends StatelessWidget {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
Stream<List<Search>> getAsyncStream(DatabaseState state) =>
|
||||
((state as DatabaseConnected).database.box<Search>().query()
|
||||
..order(Search_.timestamp, flags: Order.descending))
|
||||
.watch(triggerImmediately: true)
|
||||
.map((query) => query.find());
|
||||
|
||||
Widget Function(BuildContext, int) historyEntryWithData(List<Search> data) =>
|
||||
(context, index) {
|
||||
if (index == 0) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
final Search search = data[index - 1];
|
||||
|
||||
if (search.isKanji()) {
|
||||
return KanjiSearchItem(
|
||||
result: search.kanjiQuery.target!,
|
||||
timestamp: search.timestamp,
|
||||
);
|
||||
} else {
|
||||
return PhraseSearchItem(
|
||||
search: search.wordQuery.target!,
|
||||
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,40 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
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 'package:jisho_study_tool/view/components/common/loading.dart';
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_result_body.dart';
|
||||
import 'package:jisho_study_tool/services/jisho_api/kanji_search.dart';
|
||||
|
||||
import '../../../bloc/database/database_bloc.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);
|
||||
KanjiResultPage({required this.kanjiSearchTerm, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: FutureBuilder(
|
||||
future: fetchKanji(this.kanjiSearchTerm),
|
||||
builder: (context, snapshot) {
|
||||
body: FutureBuilder<KanjiResult>(
|
||||
future: fetchKanji(kanjiSearchTerm),
|
||||
builder: ( context, snapshot) {
|
||||
if (!snapshot.hasData) return LoadingScreen();
|
||||
if (snapshot.hasError) return ErrorWidget(snapshot.error!);
|
||||
|
||||
if (!this.addedToDatabase) {
|
||||
if (!addedToDatabase) {
|
||||
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected)
|
||||
.database
|
||||
.box<Search>()
|
||||
.put(Search(timestamp: DateTime.now())
|
||||
..kanjiQuery.target = KanjiQuery(
|
||||
kanji: this.kanjiSearchTerm,
|
||||
));
|
||||
this.addedToDatabase = true;
|
||||
kanji: kanjiSearchTerm,
|
||||
),);
|
||||
addedToDatabase = true;
|
||||
}
|
||||
|
||||
return KanjiResultBody(result: (snapshot.data as KanjiResult));
|
||||
return KanjiResultBody(result: snapshot.data!);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_body.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 KanjiSearchBody();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_body/kanji_grid.dart';
|
||||
import 'package:jisho_study_tool/view/components/kanji/kanji_search_body/kanji_search_bar.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(this.suggestions);
|
||||
|
||||
const SearchGrid({
|
||||
required this.suggestions,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(height: 10),
|
||||
KanjiSearchBar(),
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: KanjiGrid(suggestions)
|
||||
)
|
||||
],
|
||||
);
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
const KanjiSearchBar(),
|
||||
const SizedBox(height: 10),
|
||||
Expanded(child: KanjiGrid(suggestions: suggestions))
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
const List<List<String>> radicals = [[]];
|
||||
const List<List<String>> radicals = [[]];
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
||||
import 'package:jisho_study_tool/models/history/search.dart';
|
||||
import 'package:jisho_study_tool/models/history/word_query.dart';
|
||||
import 'package:jisho_study_tool/view/components/common/loading.dart';
|
||||
import 'package:jisho_study_tool/view/components/search/search_result_body.dart';
|
||||
import 'package:jisho_study_tool/services/jisho_api/jisho_search.dart';
|
||||
|
||||
import '../../../bloc/database/database_bloc.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;
|
||||
|
@ -12,34 +13,35 @@ class SearchResultsPage extends StatelessWidget {
|
|||
bool addedToDatabase = false;
|
||||
|
||||
SearchResultsPage({required this.searchTerm, Key? key})
|
||||
: this.results = fetchJishoResults(searchTerm),
|
||||
: results = fetchJishoResults(searchTerm),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: FutureBuilder(
|
||||
body: FutureBuilder<JishoAPIResult>(
|
||||
future: results,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) return LoadingScreen();
|
||||
if (snapshot.hasError ||
|
||||
(snapshot.data as JishoAPIResult).data == null)
|
||||
if (snapshot.hasError || snapshot.data!.data == null)
|
||||
return ErrorWidget(snapshot.error!);
|
||||
|
||||
if (!this.addedToDatabase) {
|
||||
if (!addedToDatabase) {
|
||||
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected)
|
||||
.database
|
||||
.box<Search>()
|
||||
.put(Search(timestamp: DateTime.now())
|
||||
..wordQuery.target = WordQuery(
|
||||
query: this.searchTerm,
|
||||
));
|
||||
this.addedToDatabase = true;
|
||||
.put(
|
||||
Search(timestamp: DateTime.now())
|
||||
..wordQuery.target = WordQuery(
|
||||
query: searchTerm,
|
||||
),
|
||||
);
|
||||
addedToDatabase = true;
|
||||
}
|
||||
|
||||
return SearchResultsBody(
|
||||
results: (snapshot.data as JishoAPIResult).data!,
|
||||
results: snapshot.data!.data!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/view/components/search/search_bar.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: [
|
||||
children: const <Widget>[
|
||||
SearchBar(),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import 'package:confirm_dialog/confirm_dialog.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
||||
import 'package:jisho_study_tool/bloc/theme/theme_bloc.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:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../bloc/database/database_bloc.dart';
|
||||
import '../../bloc/theme/theme_bloc.dart';
|
||||
import '../../models/history/search.dart';
|
||||
import '../../models/themes/theme.dart';
|
||||
import '../../objectbox.g.dart';
|
||||
|
||||
class SettingsView extends StatefulWidget {
|
||||
SettingsView({Key? key}) : super(key: key);
|
||||
const SettingsView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_SettingsViewState createState() => _SettingsViewState();
|
||||
|
@ -40,25 +41,27 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
}
|
||||
|
||||
/// Update stored preferences with values from setting page state
|
||||
void _updatePrefs() async {
|
||||
await prefs.setBool('darkThemeEnabled', darkThemeEnabled);
|
||||
await prefs.setBool('autoThemeEnabled', autoThemeEnabled);
|
||||
void _updatePrefs() {
|
||||
prefs.setBool('darkThemeEnabled', darkThemeEnabled);
|
||||
prefs.setBool('autoThemeEnabled', autoThemeEnabled);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TextStyle _titleTextStyle = TextStyle(
|
||||
color: BlocProvider.of<ThemeBloc>(context).state is DarkThemeState
|
||||
? AppTheme.jishoGreen.background
|
||||
: null);
|
||||
color: BlocProvider.of<ThemeBloc>(context).state is DarkThemeState
|
||||
? AppTheme.jishoGreen.background
|
||||
: null,
|
||||
);
|
||||
|
||||
return SettingsList(
|
||||
backgroundColor: Colors.transparent,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 10),
|
||||
sections: [
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 10),
|
||||
sections: <SettingsSection>[
|
||||
SettingsSection(
|
||||
title: 'Theme',
|
||||
titleTextStyle: _titleTextStyle,
|
||||
tiles: [
|
||||
tiles: <SettingsTile>[
|
||||
SettingsTile.switchTile(
|
||||
title: 'Automatically determine theme',
|
||||
onToggle: (b) {
|
||||
|
@ -74,7 +77,8 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
SettingsTile.switchTile(
|
||||
title: 'Dark Theme',
|
||||
onToggle: (b) {
|
||||
BlocProvider.of<ThemeBloc>(context).add(SetTheme(themeIsDark: b));
|
||||
BlocProvider.of<ThemeBloc>(context)
|
||||
.add(SetTheme(themeIsDark: b));
|
||||
setState(() {
|
||||
darkThemeEnabled = b;
|
||||
});
|
||||
|
@ -89,7 +93,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
SettingsSection(
|
||||
title: 'Cache',
|
||||
titleTextStyle: _titleTextStyle,
|
||||
tiles: [
|
||||
tiles: <SettingsTile>[
|
||||
SettingsTile.switchTile(
|
||||
title: 'Cache grade 1-7 kanji',
|
||||
switchValue: false,
|
||||
|
@ -123,13 +127,13 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
SettingsSection(
|
||||
title: 'Data',
|
||||
titleTextStyle: _titleTextStyle,
|
||||
tiles: [
|
||||
SettingsTile(
|
||||
tiles: <SettingsTile>[
|
||||
const SettingsTile(
|
||||
leading: Icon(Icons.file_download),
|
||||
title: 'Export Data',
|
||||
enabled: false,
|
||||
),
|
||||
SettingsTile(
|
||||
const SettingsTile(
|
||||
leading: Icon(Icons.delete),
|
||||
title: 'Clear History',
|
||||
onPressed: _clearHistory,
|
||||
|
@ -137,10 +141,10 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
enabled: false,
|
||||
),
|
||||
SettingsTile(
|
||||
leading: Icon(Icons.delete),
|
||||
leading: const Icon(Icons.delete),
|
||||
title: 'Clear Favourites',
|
||||
onPressed: (c) {},
|
||||
titleTextStyle: TextStyle(color: Colors.red),
|
||||
titleTextStyle: const TextStyle(color: Colors.red),
|
||||
enabled: false,
|
||||
)
|
||||
],
|
||||
|
@ -150,12 +154,14 @@ 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();
|
||||
}
|
||||
void _clearHistory(context) {
|
||||
confirm(context).then((userIsSure) {
|
||||
if (userIsSure) {
|
||||
final Store db =
|
||||
(BlocProvider.of<DatabaseBloc>(context).state as DatabaseConnected)
|
||||
.database;
|
||||
// db.box<Search>().query().build().find()
|
||||
db.box<Search>().removeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ packages:
|
|||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility that Flutter provides. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:jisho_study_tool/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue