mirror of
https://github.com/h7x4/Jisho-Study-Tool.git
synced 2024-12-21 13:37:29 +01:00
Add theming functionality
This commit is contained in:
parent
0a7b71037b
commit
feee76c2b6
@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
import './database_event.dart';
|
import './database_event.dart';
|
||||||
import './database_state.dart';
|
import './database_state.dart';
|
||||||
|
|
||||||
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
export './database_event.dart';
|
export './database_event.dart';
|
||||||
export './database_state.dart';
|
export './database_state.dart';
|
||||||
export './database_not_connected_exception.dart';
|
export './database_not_connected_exception.dart';
|
||||||
|
@ -3,6 +3,8 @@ import 'dart:async';
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
part 'history_event.dart';
|
part 'history_event.dart';
|
||||||
part 'history_state.dart';
|
part 'history_state.dart';
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ import 'package:bloc/bloc.dart';
|
|||||||
import 'package:jisho_study_tool/services/jisho_api/kanji_search.dart';
|
import 'package:jisho_study_tool/services/jisho_api/kanji_search.dart';
|
||||||
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
import 'package:jisho_study_tool/services/kanji_suggestions.dart';
|
||||||
|
|
||||||
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
export './kanji_event.dart';
|
export './kanji_event.dart';
|
||||||
export './kanji_state.dart';
|
export './kanji_state.dart';
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
import './navigation_event.dart';
|
import './navigation_event.dart';
|
||||||
import './navigation_state.dart';
|
import './navigation_state.dart';
|
||||||
|
|
||||||
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
export './navigation_event.dart';
|
export './navigation_event.dart';
|
||||||
export './navigation_state.dart';
|
export './navigation_state.dart';
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ import 'package:jisho_study_tool/bloc/database/database_bloc.dart';
|
|||||||
import 'package:jisho_study_tool/services/jisho_api/jisho_search.dart';
|
import 'package:jisho_study_tool/services/jisho_api/jisho_search.dart';
|
||||||
import 'package:unofficial_jisho_api/parser.dart';
|
import 'package:unofficial_jisho_api/parser.dart';
|
||||||
|
|
||||||
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
part 'search_event.dart';
|
part 'search_event.dart';
|
||||||
part 'search_state.dart';
|
part 'search_state.dart';
|
||||||
|
|
||||||
|
35
lib/bloc/theme/theme_bloc.dart
Normal file
35
lib/bloc/theme/theme_bloc.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
export 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
export 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
|
|
||||||
|
part 'theme_event.dart';
|
||||||
|
part 'theme_state.dart';
|
||||||
|
|
||||||
|
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
|
||||||
|
bool prefsAreLoaded = false;
|
||||||
|
|
||||||
|
ThemeBloc() : super(LightThemeState()) {
|
||||||
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
|
this.prefsAreLoaded = true;
|
||||||
|
this.add(
|
||||||
|
SetTheme(
|
||||||
|
themeIsDark: prefs.getBool('darkThemeEnabled') ?? false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<ThemeState> mapEventToState(ThemeEvent event) async* {
|
||||||
|
if (event is SetTheme)
|
||||||
|
yield event.themeIsDark
|
||||||
|
? DarkThemeState(prefsAreLoaded: prefsAreLoaded)
|
||||||
|
: LightThemeState(prefsAreLoaded: prefsAreLoaded);
|
||||||
|
}
|
||||||
|
}
|
12
lib/bloc/theme/theme_event.dart
Normal file
12
lib/bloc/theme/theme_event.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
part of 'theme_bloc.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
abstract class ThemeEvent {
|
||||||
|
const ThemeEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SetTheme extends ThemeEvent {
|
||||||
|
final bool themeIsDark;
|
||||||
|
|
||||||
|
const SetTheme({required this.themeIsDark});
|
||||||
|
}
|
26
lib/bloc/theme/theme_state.dart
Normal file
26
lib/bloc/theme/theme_state.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
part of 'theme_bloc.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
abstract class ThemeState {
|
||||||
|
final bool prefsAreLoaded;
|
||||||
|
|
||||||
|
const ThemeState(this.prefsAreLoaded);
|
||||||
|
|
||||||
|
AppTheme get theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LightThemeState extends ThemeState {
|
||||||
|
final bool prefsAreLoaded;
|
||||||
|
|
||||||
|
const LightThemeState({this.prefsAreLoaded = false}) : super(prefsAreLoaded);
|
||||||
|
|
||||||
|
AppTheme get theme => LightTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
class DarkThemeState extends ThemeState {
|
||||||
|
final bool prefsAreLoaded;
|
||||||
|
|
||||||
|
const DarkThemeState({this.prefsAreLoaded = false}) : super(prefsAreLoaded);
|
||||||
|
|
||||||
|
AppTheme get theme => DarkTheme();
|
||||||
|
}
|
106
lib/main.dart
106
lib/main.dart
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||||
import 'package:jisho_study_tool/view/screens/loading.dart';
|
import 'package:jisho_study_tool/view/screens/splash.dart';
|
||||||
import 'package:mdi/mdi.dart';
|
import 'package:mdi/mdi.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
@ -17,6 +17,8 @@ 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/search/view.dart';
|
||||||
import 'package:jisho_study_tool/view/screens/settings.dart';
|
import 'package:jisho_study_tool/view/screens/settings.dart';
|
||||||
|
|
||||||
|
import 'models/themes/theme.dart';
|
||||||
|
|
||||||
void main() => runApp(MyApp());
|
void main() => runApp(MyApp());
|
||||||
|
|
||||||
DatabaseBloc _databaseBloc = DatabaseBloc();
|
DatabaseBloc _databaseBloc = DatabaseBloc();
|
||||||
@ -28,6 +30,7 @@ class MyApp extends StatefulWidget {
|
|||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
late final Store _store;
|
late final Store _store;
|
||||||
|
bool dbConnected = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -40,6 +43,9 @@ class _MyAppState extends State<MyApp> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
_databaseBloc.add(ConnectedToDatabase(_store));
|
_databaseBloc.add(ConnectedToDatabase(_store));
|
||||||
|
setState(() {
|
||||||
|
dbConnected = true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,30 +58,24 @@ class _MyAppState extends State<MyApp> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MultiBlocProvider(
|
||||||
title: 'Jisho Study Tool',
|
providers: [
|
||||||
|
BlocProvider(create: (context) => SearchBloc(_databaseBloc)),
|
||||||
// TODO: Add color theme
|
BlocProvider(create: (context) => KanjiBloc(_databaseBloc)),
|
||||||
theme: ThemeData(
|
BlocProvider(create: (context) => _databaseBloc),
|
||||||
primarySwatch: Colors.blue,
|
BlocProvider(create: (context) => NavigationBloc()),
|
||||||
),
|
BlocProvider(create: (context) => ThemeBloc()),
|
||||||
home: MultiBlocProvider(
|
],
|
||||||
providers: [
|
child: BlocBuilder<ThemeBloc, ThemeState>(
|
||||||
BlocProvider(create: (context) => SearchBloc(_databaseBloc)),
|
builder: (context, themeState) {
|
||||||
BlocProvider(create: (context) => KanjiBloc(_databaseBloc)),
|
return MaterialApp(
|
||||||
BlocProvider(create: (context) => _databaseBloc),
|
title: 'Jisho Study Tool',
|
||||||
BlocProvider(create: (context) => NavigationBloc()),
|
theme: themeState.theme.getMaterialTheme(),
|
||||||
],
|
home: dbConnected && themeState.prefsAreLoaded
|
||||||
child:
|
? Home()
|
||||||
BlocBuilder<DatabaseBloc, DatabaseState>(builder: (context, state) {
|
: SplashScreen(),
|
||||||
if (state is DatabaseDisconnected)
|
);
|
||||||
return Container(
|
},
|
||||||
child: LoadingScreen(),
|
|
||||||
decoration: BoxDecoration(color: Colors.white),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Home();
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -85,25 +85,41 @@ class Home extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<NavigationBloc, NavigationState>(
|
return BlocBuilder<NavigationBloc, NavigationState>(
|
||||||
builder: (context, state) {
|
builder: (context, navigationState) {
|
||||||
int selectedPage = (state as NavigationPage).pageNum;
|
int selectedPage = (navigationState as NavigationPage).pageNum;
|
||||||
|
return BlocBuilder<ThemeBloc, ThemeState>(
|
||||||
return Scaffold(
|
builder: (context, themeState) {
|
||||||
appBar: AppBar(
|
return Scaffold(
|
||||||
title: pages[selectedPage].titleBar,
|
appBar: AppBar(
|
||||||
centerTitle: true,
|
title: pages[selectedPage].titleBar,
|
||||||
),
|
centerTitle: true,
|
||||||
body: pages[selectedPage].content,
|
backgroundColor: AppTheme.jishoGreen.background,
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
foregroundColor: AppTheme.jishoGreen.foreground,
|
||||||
currentIndex: selectedPage,
|
),
|
||||||
onTap: (int index) =>
|
body: Stack(
|
||||||
BlocProvider.of<NavigationBloc>(context).add(ChangePage(index)),
|
children: [
|
||||||
items: pages.map((p) => p.item).toList(),
|
Positioned(
|
||||||
showSelectedLabels: false,
|
child: Image.asset(
|
||||||
showUnselectedLabels: false,
|
'assets/images/denshi_jisho_background_overlay.png'),
|
||||||
unselectedItemColor: Colors.blue,
|
right: 30,
|
||||||
selectedItemColor: Colors.green,
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
part of './theme.dart';
|
||||||
|
|
||||||
|
class DarkTheme extends AppTheme {
|
||||||
|
ColorSet get kanjiResultColor => const ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.green,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get onyomiColor => const ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.orange,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get kunyomiColor => const ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.lightBlue,
|
||||||
|
);
|
||||||
|
|
||||||
|
Color get foreground => Colors.black;
|
||||||
|
Color get background => Colors.white;
|
||||||
|
|
||||||
|
ColorSet get menuGreyLight => ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.grey.shade700,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get menuGreyNormal => ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.grey,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get menuGreyDark => ColorSet(
|
||||||
|
foreground: Colors.black,
|
||||||
|
background: Colors.grey.shade300,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ThemeData getMaterialTheme() {
|
||||||
|
return ThemeData(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
primarySwatch: createMaterialColor(AppTheme.jishoGreen.background),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
part of './theme.dart';
|
||||||
|
|
||||||
|
class LightTheme extends AppTheme {
|
||||||
|
ColorSet get kanjiResultColor => const ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.blue,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get onyomiColor => const ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.orange,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get kunyomiColor => const ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.lightBlue,
|
||||||
|
);
|
||||||
|
|
||||||
|
Color get foreground => Colors.black;
|
||||||
|
Color get background => Colors.white;
|
||||||
|
|
||||||
|
ColorSet get menuGreyLight => ColorSet(
|
||||||
|
foreground: Colors.black,
|
||||||
|
background: Colors.grey.shade300,
|
||||||
|
);
|
||||||
|
ColorSet get menuGreyNormal => ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.grey,
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get menuGreyDark => ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Colors.grey.shade700,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ThemeData getMaterialTheme() {
|
||||||
|
return ThemeData(
|
||||||
|
brightness: Brightness.light,
|
||||||
|
primarySwatch: createMaterialColor(AppTheme.jishoGreen.background),
|
||||||
|
// primarySwatch: Colors.green,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
69
lib/models/themes/theme.dart
Normal file
69
lib/models/themes/theme.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
part 'light.dart';
|
||||||
|
part 'dark.dart';
|
||||||
|
|
||||||
|
abstract class AppTheme {
|
||||||
|
|
||||||
|
static const ColorSet jishoGreen = ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Color(0xFF3EDD00),
|
||||||
|
);
|
||||||
|
|
||||||
|
static const Color jishoGrey = Color(0xFF5A5A5B);
|
||||||
|
|
||||||
|
static const ColorSet jishoLabel = ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Color(0xFF909DC0),
|
||||||
|
);
|
||||||
|
|
||||||
|
static const ColorSet jishoCommon = ColorSet(
|
||||||
|
foreground: Colors.white,
|
||||||
|
background: Color(0xFF8ABC83),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColorSet get kanjiResultColor;
|
||||||
|
|
||||||
|
ColorSet get onyomiColor;
|
||||||
|
ColorSet get kunyomiColor;
|
||||||
|
|
||||||
|
Color get foreground;
|
||||||
|
Color get background;
|
||||||
|
|
||||||
|
ColorSet get menuGreyLight;
|
||||||
|
ColorSet get menuGreyNormal;
|
||||||
|
ColorSet get menuGreyDark;
|
||||||
|
|
||||||
|
ThemeData getMaterialTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorSet {
|
||||||
|
final Color foreground;
|
||||||
|
final Color background;
|
||||||
|
|
||||||
|
const ColorSet({
|
||||||
|
required this.foreground,
|
||||||
|
required this.background,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Source: https://blog.usejournal.com/creating-a-custom-color-swatch-in-flutter-554bcdcb27f3
|
||||||
|
MaterialColor createMaterialColor(Color color) {
|
||||||
|
List strengths = <double>[.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) {
|
||||||
|
final double ds = 0.5 - strength;
|
||||||
|
swatch[(strength * 1000).round()] = Color.fromRGBO(
|
||||||
|
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
|
||||||
|
g + ((ds < 0 ? g : (255 - g)) * ds).round(),
|
||||||
|
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return MaterialColor(color.value, swatch);
|
||||||
|
}
|
@ -1,10 +1,18 @@
|
|||||||
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';
|
||||||
|
|
||||||
class DateDivider extends StatelessWidget {
|
class DateDivider extends StatelessWidget {
|
||||||
final String? text;
|
final String? text;
|
||||||
final DateTime? date;
|
final DateTime? date;
|
||||||
|
final EdgeInsets? margin;
|
||||||
|
|
||||||
const DateDivider({this.text, this.date, Key? key}) : super(key: key);
|
const DateDivider({
|
||||||
|
this.text,
|
||||||
|
this.date,
|
||||||
|
this.margin = const EdgeInsets.symmetric(vertical: 10),
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
String getHumanReadableDate(DateTime date) {
|
String getHumanReadableDate(DateTime date) {
|
||||||
const Map<int, String> monthTable = {
|
const Map<int, String> monthTable = {
|
||||||
@ -22,30 +30,34 @@ class DateDivider extends StatelessWidget {
|
|||||||
12: 'Dec',
|
12: 'Dec',
|
||||||
};
|
};
|
||||||
|
|
||||||
int day = date.day;
|
final int day = date.day;
|
||||||
String month = monthTable[date.month]!;
|
final String month = monthTable[date.month]!;
|
||||||
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) {
|
||||||
Widget header = (this.text != null)
|
final Widget header = (this.text != null)
|
||||||
? Text(this.text!)
|
? Text(this.text!)
|
||||||
: (this.date != null)
|
: (this.date != null)
|
||||||
? Text(getHumanReadableDate(this.date!))
|
? Text(getHumanReadableDate(this.date!))
|
||||||
: SizedBox.shrink();
|
: SizedBox.shrink();
|
||||||
|
|
||||||
|
final ColorSet _menuColors =
|
||||||
|
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyNormal;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: DefaultTextStyle.merge(
|
child: DefaultTextStyle.merge(
|
||||||
child: header,
|
child: header,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: _menuColors.foreground),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(color: Colors.grey),
|
decoration: BoxDecoration(color: _menuColors.background),
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: 5,
|
vertical: 5,
|
||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
),
|
),
|
||||||
|
margin: this.margin,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.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/kanji/kanji_bloc.dart';
|
||||||
import 'package:jisho_study_tool/bloc/navigation/navigation_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/history/kanji_query.dart';
|
||||||
|
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
|
|
||||||
import './search_item.dart';
|
import './search_item.dart';
|
||||||
|
|
||||||
@ -14,13 +15,15 @@ class _KanjiBox extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
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: EdgeInsets.all(5),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[300],
|
color: _menuColors.background,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
@ -28,7 +31,7 @@ class _KanjiBox extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
kanji,
|
kanji,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black,
|
color: _menuColors.foreground,
|
||||||
fontSize: 25,
|
fontSize: 25,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.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/navigation/navigation_bloc.dart';
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import 'package:jisho_study_tool/bloc/kanji/kanji_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;
|
||||||
@ -35,9 +35,13 @@ class _GridItem extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
BlocProvider.of<KanjiBloc>(context).add(GetKanji(kanji));
|
BlocProvider.of<KanjiBloc>(context).add(GetKanji(kanji));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: BlocBuilder<ThemeBloc, ThemeState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final _menuColors = state.theme.menuGreyLight;
|
||||||
|
return
|
||||||
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[300],
|
color: _menuColors.background,
|
||||||
borderRadius: BorderRadius.circular(20.0),
|
borderRadius: BorderRadius.circular(20.0),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -45,10 +49,12 @@ class _GridItem extends StatelessWidget {
|
|||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
child: Text(
|
child: Text(
|
||||||
kanji,
|
kanji,
|
||||||
style: TextStyle(color: Colors.black),
|
style: TextStyle(color: _menuColors.foreground),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
|
|
||||||
class KanjiSearchBar extends StatefulWidget {
|
class KanjiSearchBar extends StatefulWidget {
|
||||||
@ -59,9 +58,8 @@ class _KanjiSearchBarState extends State<KanjiSearchBar> {
|
|||||||
decoration: new InputDecoration(
|
decoration: new InputDecoration(
|
||||||
prefixIcon: Icon(Icons.search),
|
prefixIcon: Icon(Icons.search),
|
||||||
hintText: 'Search',
|
hintText: 'Search',
|
||||||
fillColor: Colors.white,
|
// fillColor: Colors.white,
|
||||||
filled: true,
|
// filled: true,
|
||||||
|
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
|
|
||||||
//TODO: Make buttons have an effect
|
//TODO: Make buttons have an effect
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
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 {
|
class Examples extends StatelessWidget {
|
||||||
@ -12,32 +13,27 @@ class Examples extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ExpansionTile(
|
return Column(
|
||||||
title: Center(
|
children: [
|
||||||
child: Container(
|
[
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
|
Container(
|
||||||
decoration: BoxDecoration(
|
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||||
color: Colors.blue,
|
alignment: Alignment.centerLeft,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'Examples',
|
'Examples:',
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 20),
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 20.0,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
),
|
],
|
||||||
children: [
|
onyomiExamples
|
||||||
onyomiExamples
|
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
||||||
.map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi))
|
.toList(),
|
||||||
.toList(),
|
kunyomiExamples
|
||||||
kunyomiExamples
|
.map(
|
||||||
.map((kunyomiExample) =>
|
(kunyomiExample) => _Example(kunyomiExample, _KanaType.kunyomi))
|
||||||
_Example(kunyomiExample, _KanaType.kunyomi))
|
.toList(),
|
||||||
.toList(),
|
].expand((list) => list).toList(),
|
||||||
].expand((list) => list).toList());
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,75 +47,75 @@ class _Example extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
final _themeData = BlocProvider.of<ThemeBloc>(context).state.theme;
|
||||||
|
final _kanaColors = kanaType == _KanaType.kunyomi ? _themeData.kunyomiColor : _themeData.onyomiColor;
|
||||||
|
final _menuColors = _themeData.menuGreyNormal;
|
||||||
|
|
||||||
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(
|
margin: EdgeInsets.symmetric(
|
||||||
vertical: 10.0,
|
vertical: 5.0,
|
||||||
horizontal: 10.0,
|
horizontal: 10.0,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey, borderRadius: BorderRadius.circular(10.0)),
|
color: _menuColors.background, borderRadius: BorderRadius.circular(10.0)),
|
||||||
child: IntrinsicHeight(
|
child: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
Container(
|
||||||
Container(
|
padding: EdgeInsets.symmetric(
|
||||||
padding: EdgeInsets.symmetric(
|
vertical: 10.0,
|
||||||
vertical: 10.0,
|
horizontal: 10.0,
|
||||||
horizontal: 10.0,
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _kanaColors.background,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10.0),
|
||||||
|
bottomLeft: Radius.circular(10.0),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
color: (kanaType == _KanaType.kunyomi)
|
child: Column(
|
||||||
? Colors.lightBlue
|
children: [
|
||||||
: Colors.orange,
|
Container(
|
||||||
borderRadius: BorderRadius.only(
|
child: Text(
|
||||||
topLeft: Radius.circular(10.0),
|
yomiExample.reading,
|
||||||
bottomLeft: Radius.circular(10.0),
|
style: TextStyle(
|
||||||
|
color: _kanaColors.foreground,
|
||||||
|
fontSize: 15.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(
|
||||||
child: Column(
|
height: 5.0,
|
||||||
children: [
|
),
|
||||||
Container(
|
Container(
|
||||||
child: Text(
|
child: Text(
|
||||||
yomiExample.reading,
|
yomiExample.example,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _kanaColors.foreground,
|
||||||
fontSize: 15.0,
|
fontSize: 20.0,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
height: 5.0,
|
],
|
||||||
),
|
),
|
||||||
Container(
|
),
|
||||||
child: Text(
|
SizedBox(
|
||||||
yomiExample.example,
|
width: 15.0,
|
||||||
style: TextStyle(
|
),
|
||||||
color: Colors.white,
|
Expanded(
|
||||||
fontSize: 20.0,
|
child: Wrap(
|
||||||
),
|
children: [
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
yomiExample.meaning,
|
||||||
|
style: TextStyle(
|
||||||
|
color: _menuColors.foreground,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
width: 15.0,
|
],
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Wrap(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
child: Text(
|
|
||||||
yomiExample.meaning,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Grade extends StatelessWidget {
|
class Grade extends StatelessWidget {
|
||||||
final String grade;
|
final String grade;
|
||||||
@ -7,17 +8,19 @@ class Grade extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
grade,
|
grade,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _kanjiColors.foreground,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blue,
|
color: _kanjiColors.background,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Header extends StatelessWidget {
|
class Header extends StatelessWidget {
|
||||||
final String kanji;
|
final String kanji;
|
||||||
@ -7,17 +8,19 @@ class Header extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return AspectRatio(
|
return AspectRatio(
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
color: Colors.blue,
|
color: _kanjiColors.background,
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
kanji,
|
kanji,
|
||||||
style: TextStyle(fontSize: 70.0, color: Colors.white),
|
style: TextStyle(fontSize: 70.0, color: _kanjiColors.foreground),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class JlptLevel extends StatelessWidget {
|
class JlptLevel extends StatelessWidget {
|
||||||
final String jlptLevel;
|
final String jlptLevel;
|
||||||
@ -8,18 +9,20 @@ class JlptLevel extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
jlptLevel,
|
jlptLevel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _kanjiColors.foreground,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: Colors.blue,
|
color: _kanjiColors.background,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class Kunyomi extends StatelessWidget {
|
|
||||||
final List<String> kunyomi;
|
|
||||||
late final List<_KunyomiCard> kunyomiCards;
|
|
||||||
late final bool expandable;
|
|
||||||
|
|
||||||
Kunyomi(this.kunyomi) {
|
|
||||||
kunyomiCards = kunyomi.map((kunyomi) => _KunyomiCard(kunyomi)).toList();
|
|
||||||
expandable = (kunyomi.length > 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 10.0,
|
|
||||||
vertical: 5.0,
|
|
||||||
),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: _kunyomiWrapper(context),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _kunyomiWrapper(BuildContext context) {
|
|
||||||
if (expandable) {
|
|
||||||
return ExpansionTile(
|
|
||||||
initiallyExpanded: false,
|
|
||||||
title: Center(child: _KunyomiCard('Kunyomi')),
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 20.0,
|
|
||||||
),
|
|
||||||
Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: kunyomiCards,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 25.0,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: kunyomiCards,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _KunyomiCard extends StatelessWidget {
|
|
||||||
final String kunyomi;
|
|
||||||
const _KunyomiCard(this.kunyomi);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 10.0,
|
|
||||||
horizontal: 10.0,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
kunyomi,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20.0,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.lightBlue,
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class Meaning extends StatelessWidget {
|
|
||||||
late final List<String> meanings;
|
|
||||||
late final List<_MeaningCard> meaningCards;
|
|
||||||
late final bool expandable;
|
|
||||||
|
|
||||||
Meaning(meaning) {
|
|
||||||
this.meanings = meaning.split(', ');
|
|
||||||
this.meaningCards =
|
|
||||||
meanings.map((m) => _MeaningCard(m)).toList();
|
|
||||||
this.expandable = (this.meanings.length > 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 10.0,
|
|
||||||
vertical: 5.0,
|
|
||||||
),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: _meaningWrapper(context),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _meaningWrapper(BuildContext context) {
|
|
||||||
if (expandable) {
|
|
||||||
return ExpansionTile(
|
|
||||||
initiallyExpanded: false,
|
|
||||||
title: Center(child: _MeaningCard('Meanings')),
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 20.0,
|
|
||||||
),
|
|
||||||
Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: meaningCards,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 25.0,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: meaningCards,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MeaningCard extends StatelessWidget {
|
|
||||||
final String meaning;
|
|
||||||
|
|
||||||
const _MeaningCard(this.meaning);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
horizontal: 10.0,
|
|
||||||
vertical: 10.0,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
meaning,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20.0,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey,
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class Onyomi extends StatelessWidget {
|
|
||||||
final List<String> onyomi;
|
|
||||||
late final List<_OnyomiCard> onyomiCards;
|
|
||||||
late final bool expandable;
|
|
||||||
|
|
||||||
Onyomi(this.onyomi) {
|
|
||||||
onyomiCards = onyomi.map((onyomi) => _OnyomiCard(onyomi)).toList();
|
|
||||||
expandable = (onyomi.length > 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 10.0,
|
|
||||||
vertical: 5.0,
|
|
||||||
),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: _onyomiWrapper(context),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _onyomiWrapper(BuildContext context) {
|
|
||||||
if (expandable) {
|
|
||||||
return ExpansionTile(
|
|
||||||
initiallyExpanded: false,
|
|
||||||
title: Center(child: _OnyomiCard('Onyomi')),
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 20.0,
|
|
||||||
),
|
|
||||||
Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: onyomiCards,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 25.0,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Wrap(
|
|
||||||
runSpacing: 10.0,
|
|
||||||
children: onyomiCards,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _OnyomiCard extends StatelessWidget {
|
|
||||||
final String onyomi;
|
|
||||||
|
|
||||||
const _OnyomiCard(this.onyomi);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: EdgeInsets.symmetric(horizontal: 10.0),
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: 10.0,
|
|
||||||
horizontal: 10.0,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
onyomi,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20.0,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.orange,
|
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
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;
|
||||||
|
|
||||||
class Radical extends StatelessWidget {
|
class Radical extends StatelessWidget {
|
||||||
@ -8,18 +9,20 @@ class Radical extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
radical.symbol,
|
radical.symbol,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _kanjiColors.foreground,
|
||||||
fontSize: 40.0,
|
fontSize: 40.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: Colors.blue,
|
color: _kanjiColors.background,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class Rank extends StatelessWidget {
|
class Rank extends StatelessWidget {
|
||||||
final int rank;
|
final int rank;
|
||||||
@ -8,18 +9,20 @@ class Rank extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${rank.toString()} / 2500',
|
'${rank.toString()} / 2500',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: _kanjiColors.foreground,
|
||||||
fontSize: 20.0,
|
fontSize: 20.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
color: Colors.blue,
|
color: _kanjiColors.background,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart';
|
||||||
|
|
||||||
class StrokeOrderGif extends StatelessWidget {
|
class StrokeOrderGif extends StatelessWidget {
|
||||||
final String uri;
|
final String uri;
|
||||||
@ -7,6 +8,8 @@ class StrokeOrderGif extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _kanjiColors = BlocProvider.of<ThemeBloc>(context).state.theme.kanjiResultColor;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(vertical: 20.0),
|
margin: EdgeInsets.symmetric(vertical: 20.0),
|
||||||
padding: EdgeInsets.all(5.0),
|
padding: EdgeInsets.all(5.0),
|
||||||
@ -15,7 +18,7 @@ class StrokeOrderGif extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blue,
|
color: _kanjiColors.background,
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
122
lib/view/components/kanji/result/yomi_chips.dart
Normal file
122
lib/view/components/kanji/result/yomi_chips.dart
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
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),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
15
lib/view/components/opaque_box.dart
Normal file
15
lib/view/components/opaque_box.dart
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class OpaqueBox extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const OpaqueBox({required this.child, Key? key,}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor),
|
||||||
|
child: this.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class LanguageSelector extends StatefulWidget {
|
class LanguageSelector extends StatefulWidget {
|
||||||
@ -43,13 +44,13 @@ class _LanguageSelectorState extends State<LanguageSelector> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ToggleButtons(
|
return ToggleButtons(
|
||||||
|
selectedColor: AppTheme.jishoGreen.background,
|
||||||
isSelected: isSelected,
|
isSelected: isSelected,
|
||||||
children: <Widget> [
|
children: <Widget> [
|
||||||
_LanguageOption("Auto"),
|
_LanguageOption("Auto"),
|
||||||
_LanguageOption("日本語"),
|
_LanguageOption("日本語"),
|
||||||
_LanguageOption("English")
|
_LanguageOption("English")
|
||||||
],
|
],
|
||||||
selectedColor: Colors.blue,
|
|
||||||
onPressed: (int buttonIndex) {
|
onPressed: (int buttonIndex) {
|
||||||
setState(() {
|
setState(() {
|
||||||
for (var i in Iterable.generate(isSelected.length)) {
|
for (var i in Iterable.generate(isSelected.length)) {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
||||||
import 'package:jisho_study_tool/view/components/search/language_selector.dart';
|
import 'package:jisho_study_tool/view/components/search/language_selector.dart';
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
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 {
|
class OtherForms extends StatelessWidget {
|
||||||
@ -10,18 +11,17 @@ class OtherForms extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children:
|
children: this.otherForms.isNotEmpty
|
||||||
this.otherForms.isNotEmpty
|
? [
|
||||||
? [
|
Text(
|
||||||
Text(
|
'Other Forms',
|
||||||
'Other Forms',
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
),
|
||||||
),
|
Row(
|
||||||
Row(
|
children: otherForms.map((form) => _KanaBox(form)).toList(),
|
||||||
children: otherForms.map((form) => _KanaBox(form)).toList(),
|
),
|
||||||
),
|
]
|
||||||
]
|
: [],
|
||||||
: [],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -35,14 +35,19 @@ class _KanaBox extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final hasFurigana = (word.word != null);
|
final hasFurigana = (word.word != null);
|
||||||
|
final _menuColors =
|
||||||
|
BlocProvider.of<ThemeBloc>(context).state.theme.menuGreyLight;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: DefaultTextStyle.merge(
|
||||||
children: [
|
child: Column(
|
||||||
// TODO: take a look at this logic
|
children: [
|
||||||
(hasFurigana) ? Text(word.reading ?? '') : Text(''),
|
// TODO: take a look at this logic
|
||||||
(hasFurigana) ? Text(word.word!) : Text(word.reading ?? ''),
|
(hasFurigana) ? Text(word.reading ?? '') : Text(''),
|
||||||
],
|
(hasFurigana) ? Text(word.word!) : Text(word.reading ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: TextStyle(color: _menuColors.foreground),
|
||||||
),
|
),
|
||||||
margin: EdgeInsets.symmetric(
|
margin: EdgeInsets.symmetric(
|
||||||
horizontal: 5.0,
|
horizontal: 5.0,
|
||||||
@ -50,7 +55,7 @@ class _KanaBox extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
padding: EdgeInsets.all(5.0),
|
padding: EdgeInsets.all(5.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: _menuColors.background,
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.grey.withOpacity(0.5),
|
color: Colors.grey.withOpacity(0.5),
|
||||||
|
@ -21,7 +21,10 @@ class SearchResultCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final backgroundColor = Theme.of(context).scaffoldBackgroundColor;
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
|
collapsedBackgroundColor: backgroundColor,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
title:
|
title:
|
||||||
IntrinsicWidth(
|
IntrinsicWidth(
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.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/search.dart';
|
||||||
import 'package:jisho_study_tool/view/components/history/kanji_search_item.dart';
|
import 'package:jisho_study_tool/view/components/history/kanji_search_item.dart';
|
||||||
@ -7,6 +6,7 @@ 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/view/components/history/date_divider.dart';
|
||||||
|
|
||||||
import 'package:jisho_study_tool/objectbox.g.dart';
|
import 'package:jisho_study_tool/objectbox.g.dart';
|
||||||
|
import 'package:jisho_study_tool/view/components/opaque_box.dart';
|
||||||
|
|
||||||
class HistoryView extends StatelessWidget {
|
class HistoryView extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
@ -23,50 +23,54 @@ class HistoryView extends StatelessWidget {
|
|||||||
.map((query) => query.find()),
|
.map((query) => query.find()),
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||||
if (!snapshot.hasData) return Container();
|
if (!snapshot.hasData) return Container();
|
||||||
return ListView.separated(
|
return OpaqueBox(
|
||||||
itemCount: snapshot.data.length + 1,
|
child: ListView.separated(
|
||||||
itemBuilder: (context, index) {
|
itemCount: snapshot.data.length + 1,
|
||||||
if (index == 0) return Container();
|
itemBuilder: (context, index) {
|
||||||
Search search = snapshot.data[index - 1];
|
if (index == 0) return Container();
|
||||||
if (search.isKanji()) {
|
Search search = snapshot.data[index - 1];
|
||||||
return KanjiSearchItem(
|
if (search.isKanji()) {
|
||||||
result: search.kanjiQuery.target!,
|
return KanjiSearchItem(
|
||||||
|
result: search.kanjiQuery.target!,
|
||||||
|
timestamp: search.timestamp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return PhraseSearchItem(
|
||||||
|
search: search.wordQuery.target!,
|
||||||
timestamp: search.timestamp,
|
timestamp: search.timestamp,
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
return PhraseSearchItem(
|
separatorBuilder: (context, index) {
|
||||||
search: search.wordQuery.target!,
|
Function roundToDay = (DateTime date) =>
|
||||||
timestamp: search.timestamp,
|
DateTime(date.year, date.month, date.day);
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (context, index) {
|
|
||||||
Function roundToDay = (DateTime date) =>
|
|
||||||
DateTime(date.year, date.month, date.day);
|
|
||||||
|
|
||||||
Search search = snapshot.data[index];
|
Search search = snapshot.data[index];
|
||||||
DateTime searchDate = roundToDay(search.timestamp);
|
DateTime searchDate = roundToDay(search.timestamp);
|
||||||
|
|
||||||
bool newDate = true;
|
bool newDate = true;
|
||||||
|
|
||||||
if (index != 0) {
|
EdgeInsets? margin;
|
||||||
Search prevSearch = snapshot.data[index - 1];
|
if (index != 0) {
|
||||||
|
Search prevSearch = snapshot.data[index - 1];
|
||||||
|
|
||||||
DateTime prevSearchDate = roundToDay(prevSearch.timestamp);
|
DateTime prevSearchDate = roundToDay(prevSearch.timestamp);
|
||||||
newDate = prevSearchDate != searchDate;
|
newDate = prevSearchDate != searchDate;
|
||||||
}
|
margin = EdgeInsets.only(bottom: 10);
|
||||||
|
}
|
||||||
|
|
||||||
if (newDate) {
|
if (newDate) {
|
||||||
if (searchDate == roundToDay(DateTime.now()))
|
if (searchDate == roundToDay(DateTime.now()))
|
||||||
return DateDivider(text: "Today");
|
return DateDivider(text: "Today", margin: margin);
|
||||||
else if (searchDate ==
|
else if (searchDate ==
|
||||||
roundToDay(
|
roundToDay(
|
||||||
DateTime.now().subtract(const Duration(days: 1))))
|
DateTime.now().subtract(const Duration(days: 1))))
|
||||||
return DateDivider(text: "Yesterday");
|
return DateDivider(text: "Yesterday", margin: margin);
|
||||||
return DateDivider(date: searchDate);
|
return DateDivider(date: searchDate, margin: margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Divider();
|
return Divider();
|
||||||
},
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,23 +1,30 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
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/grade.dart';
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/header.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/jlpt_level.dart';
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/meaning.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/radical.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/rank.dart';
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/stroke_order_gif.dart';
|
import 'package:jisho_study_tool/view/components/kanji/result/stroke_order_gif.dart';
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/onyomi.dart';
|
import 'package:jisho_study_tool/view/components/kanji/result/yomi_chips.dart';
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/kunyomi.dart';
|
|
||||||
import 'package:jisho_study_tool/view/components/kanji/result/examples.dart';
|
|
||||||
|
|
||||||
class KanjiResultCard extends StatelessWidget {
|
class KanjiResultCard extends StatelessWidget {
|
||||||
late final String query;
|
late final String query;
|
||||||
late final jisho.KanjiResultData resultData;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
@ -47,9 +54,9 @@ class KanjiResultCard extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Meaning(resultData.meaning),
|
YomiChips(resultData.meaning.split(', '), YomiType.meaning),
|
||||||
resultData.onyomi.length != 0 ? Onyomi(resultData.onyomi) : SizedBox.shrink(),
|
resultData.onyomi.length != 0 ? YomiChips(resultData.onyomi, YomiType.onyomi) : SizedBox.shrink(),
|
||||||
resultData.kunyomi.length != 0 ? Kunyomi(resultData.kunyomi) : SizedBox.shrink(),
|
resultData.kunyomi.length != 0 ? YomiChips(resultData.kunyomi, YomiType.kunyomi) : SizedBox.shrink(),
|
||||||
IntrinsicHeight(
|
IntrinsicHeight(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
@ -88,15 +95,4 @@ class KanjiResultCard extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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!;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
import 'package:animated_size_and_fade/animated_size_and_fade.dart';
|
import 'package:animated_size_and_fade/animated_size_and_fade.dart';
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart';
|
||||||
import 'package:jisho_study_tool/view/screens/loading.dart';
|
import 'package:jisho_study_tool/view/screens/loading.dart';
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
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;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
import 'package:jisho_study_tool/bloc/search/search_bloc.dart';
|
||||||
import 'package:jisho_study_tool/view/components/search/search_bar.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/loading.dart';
|
||||||
import 'package:jisho_study_tool/view/components/search/search_result_page/search_card.dart';
|
import 'package:jisho_study_tool/view/screens/search/results.dart';
|
||||||
|
|
||||||
class SearchView extends StatelessWidget {
|
class SearchView extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
@ -16,18 +15,7 @@ class SearchView extends StatelessWidget {
|
|||||||
else if (state is SearchLoading)
|
else if (state is SearchLoading)
|
||||||
return LoadingScreen();
|
return LoadingScreen();
|
||||||
else if (state is SearchFinished) {
|
else if (state is SearchFinished) {
|
||||||
return WillPopScope(
|
return SearchResults(results: state.results);
|
||||||
child: ListView(
|
|
||||||
children: state.results
|
|
||||||
.map((result) => SearchResultCard(result))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
onWillPop: () async {
|
|
||||||
BlocProvider.of<SearchBloc>(context).add(ReturnToInitialState());
|
|
||||||
print('Popped');
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
throw 'No such event found';
|
throw 'No such event found';
|
||||||
},
|
},
|
||||||
|
@ -1,61 +1,150 @@
|
|||||||
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:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:jisho_study_tool/bloc/database/database_bloc.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/history/search.dart';
|
||||||
|
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
import 'package:jisho_study_tool/objectbox.g.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';
|
||||||
|
|
||||||
|
class SettingsView extends StatefulWidget {
|
||||||
|
SettingsView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SettingsViewState createState() => _SettingsViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SettingsViewState extends State<SettingsView> {
|
||||||
|
late final SharedPreferences prefs;
|
||||||
|
|
||||||
|
bool darkThemeEnabled = false;
|
||||||
|
bool autoThemeEnabled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
|
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
|
||||||
|
void _updatePrefs() async {
|
||||||
|
await prefs.setBool('darkThemeEnabled', darkThemeEnabled);
|
||||||
|
await prefs.setBool('autoThemeEnabled', autoThemeEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
class SettingsView extends StatelessWidget {
|
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final TextStyle _titleTextStyle = TextStyle(
|
||||||
|
color: BlocProvider.of<ThemeBloc>(context).state is DarkThemeState
|
||||||
|
? AppTheme.jishoGreen.background
|
||||||
|
: null);
|
||||||
|
|
||||||
return SettingsList(
|
return SettingsList(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 10),
|
||||||
sections: [
|
sections: [
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Cache',
|
title: 'Theme',
|
||||||
|
titleTextStyle: _titleTextStyle,
|
||||||
tiles: [
|
tiles: [
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Cache grade 1-7 kanji (N/A)',
|
title: 'Automatically determine theme',
|
||||||
switchValue: false,
|
onToggle: (b) {
|
||||||
onToggle: (v) {},
|
setState(() {
|
||||||
|
autoThemeEnabled = b;
|
||||||
|
});
|
||||||
|
_updatePrefs();
|
||||||
|
},
|
||||||
|
switchValue: autoThemeEnabled,
|
||||||
|
enabled: false,
|
||||||
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
),
|
),
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Cache grade standard kanji (N/A)',
|
title: 'Dark Theme',
|
||||||
|
onToggle: (b) {
|
||||||
|
BlocProvider.of<ThemeBloc>(context).add(SetTheme(themeIsDark: b));
|
||||||
|
setState(() {
|
||||||
|
darkThemeEnabled = b;
|
||||||
|
});
|
||||||
|
_updatePrefs();
|
||||||
|
},
|
||||||
|
switchValue: darkThemeEnabled,
|
||||||
|
enabled: !autoThemeEnabled,
|
||||||
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SettingsSection(
|
||||||
|
title: 'Cache',
|
||||||
|
titleTextStyle: _titleTextStyle,
|
||||||
|
tiles: [
|
||||||
|
SettingsTile.switchTile(
|
||||||
|
title: 'Cache grade 1-7 kanji',
|
||||||
switchValue: false,
|
switchValue: false,
|
||||||
onToggle: (v) {},
|
onToggle: (v) {},
|
||||||
|
enabled: false,
|
||||||
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
),
|
),
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Cache all favourites (N/A)',
|
title: 'Cache grade standard kanji',
|
||||||
switchValue: false,
|
switchValue: false,
|
||||||
onToggle: (v) {},
|
onToggle: (v) {},
|
||||||
|
enabled: false,
|
||||||
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
),
|
),
|
||||||
SettingsTile.switchTile(
|
SettingsTile.switchTile(
|
||||||
title: 'Cache all searches (N/A)',
|
title: 'Cache all favourites',
|
||||||
switchValue: false,
|
switchValue: false,
|
||||||
onToggle: (v) {},
|
onToggle: (v) {},
|
||||||
|
enabled: false,
|
||||||
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
|
),
|
||||||
|
SettingsTile.switchTile(
|
||||||
|
title: 'Cache all searches',
|
||||||
|
switchValue: false,
|
||||||
|
onToggle: (v) {},
|
||||||
|
enabled: false,
|
||||||
|
switchActiveColor: AppTheme.jishoGreen.background,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
title: 'Data',
|
title: 'Data',
|
||||||
|
titleTextStyle: _titleTextStyle,
|
||||||
tiles: [
|
tiles: [
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: Icon(Icons.file_download),
|
leading: Icon(Icons.file_download),
|
||||||
title: 'Export Data (N/A)',
|
title: 'Export Data',
|
||||||
|
enabled: false,
|
||||||
),
|
),
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: Icon(Icons.delete),
|
leading: Icon(Icons.delete),
|
||||||
title: 'Clear History (N/A)',
|
title: 'Clear History',
|
||||||
onPressed: _clearHistory,
|
onPressed: _clearHistory,
|
||||||
titleTextStyle: TextStyle(color: Colors.red),
|
titleTextStyle: TextStyle(color: Colors.red),
|
||||||
|
enabled: false,
|
||||||
),
|
),
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
leading: Icon(Icons.delete),
|
leading: Icon(Icons.delete),
|
||||||
title: 'Clear Favourites (N/A)',
|
title: 'Clear Favourites',
|
||||||
onPressed: (c) {},
|
onPressed: (c) {},
|
||||||
titleTextStyle: TextStyle(color: Colors.red),
|
titleTextStyle: TextStyle(color: Colors.red),
|
||||||
|
enabled: false,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
16
lib/view/screens/splash.dart
Normal file
16
lib/view/screens/splash.dart
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jisho_study_tool/models/themes/theme.dart';
|
||||||
|
|
||||||
|
class SplashScreen extends StatelessWidget {
|
||||||
|
const SplashScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(color: AppTheme.jishoGreen.background),
|
||||||
|
child: Center(
|
||||||
|
child: Image.asset('assets/images/logo/logo_icon_transparent.png'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user