diff --git a/lib/bloc/database/database_bloc.dart b/lib/bloc/database/database_bloc.dart index a5e6efa..37d338c 100644 --- a/lib/bloc/database/database_bloc.dart +++ b/lib/bloc/database/database_bloc.dart @@ -1,9 +1,11 @@ -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:bloc/bloc.dart'; import './database_event.dart'; import './database_state.dart'; +export 'package:flutter_bloc/flutter_bloc.dart'; + export './database_event.dart'; export './database_state.dart'; export './database_not_connected_exception.dart'; diff --git a/lib/bloc/history/history_bloc.dart b/lib/bloc/history/history_bloc.dart index 9396c8c..93e33f7 100644 --- a/lib/bloc/history/history_bloc.dart +++ b/lib/bloc/history/history_bloc.dart @@ -3,6 +3,8 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:meta/meta.dart'; +export 'package:flutter_bloc/flutter_bloc.dart'; + part 'history_event.dart'; part 'history_state.dart'; diff --git a/lib/bloc/kanji/kanji_bloc.dart b/lib/bloc/kanji/kanji_bloc.dart index 505f7db..0533b9c 100644 --- a/lib/bloc/kanji/kanji_bloc.dart +++ b/lib/bloc/kanji/kanji_bloc.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/kanji_suggestions.dart'; +export 'package:flutter_bloc/flutter_bloc.dart'; + export './kanji_event.dart'; export './kanji_state.dart'; diff --git a/lib/bloc/navigation/navigation_bloc.dart b/lib/bloc/navigation/navigation_bloc.dart index bb8852d..f48fc48 100644 --- a/lib/bloc/navigation/navigation_bloc.dart +++ b/lib/bloc/navigation/navigation_bloc.dart @@ -1,8 +1,10 @@ -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:bloc/bloc.dart'; import './navigation_event.dart'; import './navigation_state.dart'; +export 'package:flutter_bloc/flutter_bloc.dart'; + export './navigation_event.dart'; export './navigation_state.dart'; diff --git a/lib/bloc/search/search_bloc.dart b/lib/bloc/search/search_bloc.dart index 6a0e5fa..24498cc 100644 --- a/lib/bloc/search/search_bloc.dart +++ b/lib/bloc/search/search_bloc.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:unofficial_jisho_api/parser.dart'; +export 'package:flutter_bloc/flutter_bloc.dart'; + part 'search_event.dart'; part 'search_state.dart'; diff --git a/lib/bloc/theme/theme_bloc.dart b/lib/bloc/theme/theme_bloc.dart new file mode 100644 index 0000000..49167b7 --- /dev/null +++ b/lib/bloc/theme/theme_bloc.dart @@ -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 { + bool prefsAreLoaded = false; + + ThemeBloc() : super(LightThemeState()) { + SharedPreferences.getInstance().then((prefs) { + this.prefsAreLoaded = true; + this.add( + SetTheme( + themeIsDark: prefs.getBool('darkThemeEnabled') ?? false, + ), + ); + }); + } + + @override + Stream mapEventToState(ThemeEvent event) async* { + if (event is SetTheme) + yield event.themeIsDark + ? DarkThemeState(prefsAreLoaded: prefsAreLoaded) + : LightThemeState(prefsAreLoaded: prefsAreLoaded); + } +} diff --git a/lib/bloc/theme/theme_event.dart b/lib/bloc/theme/theme_event.dart new file mode 100644 index 0000000..7c13741 --- /dev/null +++ b/lib/bloc/theme/theme_event.dart @@ -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}); +} diff --git a/lib/bloc/theme/theme_state.dart b/lib/bloc/theme/theme_state.dart new file mode 100644 index 0000000..d4bb021 --- /dev/null +++ b/lib/bloc/theme/theme_state.dart @@ -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(); +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 8ca5b4e..8210f71 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:jisho_study_tool/view/screens/loading.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; +import 'package:jisho_study_tool/view/screens/splash.dart'; import 'package:mdi/mdi.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart'; @@ -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/settings.dart'; +import 'models/themes/theme.dart'; + void main() => runApp(MyApp()); DatabaseBloc _databaseBloc = DatabaseBloc(); @@ -28,6 +30,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { late final Store _store; + bool dbConnected = false; @override void initState() { @@ -40,6 +43,9 @@ class _MyAppState extends State { ); _databaseBloc.add(ConnectedToDatabase(_store)); + setState(() { + dbConnected = true; + }); }); } @@ -52,30 +58,24 @@ class _MyAppState extends State { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Jisho Study Tool', - - // TODO: Add color theme - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: MultiBlocProvider( - providers: [ - BlocProvider(create: (context) => SearchBloc(_databaseBloc)), - BlocProvider(create: (context) => KanjiBloc(_databaseBloc)), - BlocProvider(create: (context) => _databaseBloc), - BlocProvider(create: (context) => NavigationBloc()), - ], - child: - BlocBuilder(builder: (context, state) { - if (state is DatabaseDisconnected) - return Container( - child: LoadingScreen(), - decoration: BoxDecoration(color: Colors.white), - ); - - return Home(); - }), + return MultiBlocProvider( + providers: [ + BlocProvider(create: (context) => SearchBloc(_databaseBloc)), + BlocProvider(create: (context) => KanjiBloc(_databaseBloc)), + BlocProvider(create: (context) => _databaseBloc), + BlocProvider(create: (context) => NavigationBloc()), + BlocProvider(create: (context) => ThemeBloc()), + ], + child: BlocBuilder( + builder: (context, themeState) { + return MaterialApp( + title: 'Jisho Study Tool', + theme: themeState.theme.getMaterialTheme(), + home: dbConnected && themeState.prefsAreLoaded + ? Home() + : SplashScreen(), + ); + }, ), ); } @@ -85,25 +85,41 @@ class Home extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - builder: (context, state) { - int selectedPage = (state as NavigationPage).pageNum; - - return Scaffold( - appBar: AppBar( - title: pages[selectedPage].titleBar, - centerTitle: true, - ), - body: pages[selectedPage].content, - bottomNavigationBar: BottomNavigationBar( - currentIndex: selectedPage, - onTap: (int index) => - BlocProvider.of(context).add(ChangePage(index)), - items: pages.map((p) => p.item).toList(), - showSelectedLabels: false, - showUnselectedLabels: false, - unselectedItemColor: Colors.blue, - selectedItemColor: Colors.green, - ), + builder: (context, navigationState) { + int selectedPage = (navigationState as NavigationPage).pageNum; + return BlocBuilder( + builder: (context, themeState) { + return Scaffold( + appBar: AppBar( + title: pages[selectedPage].titleBar, + centerTitle: true, + backgroundColor: AppTheme.jishoGreen.background, + foregroundColor: AppTheme.jishoGreen.foreground, + ), + body: Stack( + children: [ + Positioned( + child: Image.asset( + 'assets/images/denshi_jisho_background_overlay.png'), + right: 30, + left: 100, + bottom: 30, + ), + pages[selectedPage].content, + ], + ), + bottomNavigationBar: BottomNavigationBar( + fixedColor: AppTheme.jishoGreen.background, + currentIndex: selectedPage, + onTap: (int index) => BlocProvider.of(context) + .add(ChangePage(index)), + items: pages.map((p) => p.item).toList(), + showSelectedLabels: false, + showUnselectedLabels: false, + unselectedItemColor: themeState.theme.menuGreyDark.background, + ), + ); + }, ); }, ); diff --git a/lib/models/themes/dark.dart b/lib/models/themes/dark.dart index e69de29..618fc73 100644 --- a/lib/models/themes/dark.dart +++ b/lib/models/themes/dark.dart @@ -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), + ); + } +} diff --git a/lib/models/themes/light.dart b/lib/models/themes/light.dart index e69de29..d1cccc2 100644 --- a/lib/models/themes/light.dart +++ b/lib/models/themes/light.dart @@ -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, + ); + } +} diff --git a/lib/models/themes/theme.dart b/lib/models/themes/theme.dart new file mode 100644 index 0000000..d1a591f --- /dev/null +++ b/lib/models/themes/theme.dart @@ -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 = [.05]; + final swatch = {}; + 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); +} \ No newline at end of file diff --git a/lib/view/components/history/date_divider.dart b/lib/view/components/history/date_divider.dart index 2696acc..992728e 100644 --- a/lib/view/components/history/date_divider.dart +++ b/lib/view/components/history/date_divider.dart @@ -1,10 +1,18 @@ 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 { final String? text; 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) { const Map monthTable = { @@ -22,30 +30,34 @@ class DateDivider extends StatelessWidget { 12: 'Dec', }; - int day = date.day; - String month = monthTable[date.month]!; - int year = date.year; + final int day = date.day; + final String month = monthTable[date.month]!; + final int year = date.year; return "$day. $month $year"; } @override Widget build(BuildContext context) { - Widget header = (this.text != null) + final Widget header = (this.text != null) ? Text(this.text!) : (this.date != null) ? Text(getHumanReadableDate(this.date!)) : SizedBox.shrink(); + final ColorSet _menuColors = + BlocProvider.of(context).state.theme.menuGreyNormal; + return Container( child: DefaultTextStyle.merge( 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( vertical: 5, horizontal: 10, ), + margin: this.margin, ); } } diff --git a/lib/view/components/history/kanji_search_item.dart b/lib/view/components/history/kanji_search_item.dart index 79428cd..eb7be2f 100644 --- a/lib/view/components/history/kanji_search_item.dart +++ b/lib/view/components/history/kanji_search_item.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart'; import 'package:jisho_study_tool/bloc/navigation/navigation_bloc.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; import 'package:jisho_study_tool/models/history/kanji_query.dart'; +import 'package:jisho_study_tool/models/themes/theme.dart'; import './search_item.dart'; @@ -14,13 +15,15 @@ class _KanjiBox extends StatelessWidget { @override Widget build(BuildContext context) { + final ColorSet _menuColors = BlocProvider.of(context).state.theme.menuGreyLight; + return IntrinsicHeight( child: AspectRatio( aspectRatio: 1, child: Container( padding: EdgeInsets.all(5), decoration: BoxDecoration( - color: Colors.grey[300], + color: _menuColors.background, borderRadius: BorderRadius.circular(10.0), ), child: Center( @@ -28,7 +31,7 @@ class _KanjiBox extends StatelessWidget { child: Text( kanji, style: TextStyle( - color: Colors.black, + color: _menuColors.foreground, fontSize: 25, ), ), diff --git a/lib/view/components/history/phrase_search_item.dart b/lib/view/components/history/phrase_search_item.dart index 8cf0252..30273bd 100644 --- a/lib/view/components/history/phrase_search_item.dart +++ b/lib/view/components/history/phrase_search_item.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:jisho_study_tool/bloc/navigation/navigation_bloc.dart'; import 'package:jisho_study_tool/bloc/search/search_bloc.dart'; diff --git a/lib/view/components/kanji/kanji_grid.dart b/lib/view/components/kanji/kanji_grid.dart index 52ea485..5ea3802 100644 --- a/lib/view/components/kanji/kanji_grid.dart +++ b/lib/view/components/kanji/kanji_grid.dart @@ -1,7 +1,7 @@ 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/theme/theme_bloc.dart'; class KanjiGrid extends StatelessWidget { final List suggestions; @@ -35,9 +35,13 @@ class _GridItem extends StatelessWidget { onTap: () { BlocProvider.of(context).add(GetKanji(kanji)); }, - child: Container( + child: BlocBuilder( + builder: (context, state) { + final _menuColors = state.theme.menuGreyLight; + return + Container( decoration: BoxDecoration( - color: Colors.grey[300], + color: _menuColors.background, borderRadius: BorderRadius.circular(20.0), ), child: Container( @@ -45,10 +49,12 @@ class _GridItem extends StatelessWidget { child: FittedBox( child: Text( kanji, - style: TextStyle(color: Colors.black), + style: TextStyle(color: _menuColors.foreground), ), ), ), + ); + }, ), ); } diff --git a/lib/view/components/kanji/kanji_search_bar.dart b/lib/view/components/kanji/kanji_search_bar.dart index ebcbc8a..fba6409 100644 --- a/lib/view/components/kanji/kanji_search_bar.dart +++ b/lib/view/components/kanji/kanji_search_bar.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart'; class KanjiSearchBar extends StatefulWidget { @@ -59,9 +58,8 @@ class _KanjiSearchBarState extends State { decoration: new InputDecoration( prefixIcon: Icon(Icons.search), hintText: 'Search', - fillColor: Colors.white, - filled: true, - + // fillColor: Colors.white, + // filled: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10.0), ), diff --git a/lib/view/components/kanji/kanji_search_options_bar.dart b/lib/view/components/kanji/kanji_search_options_bar.dart index 7ba4d49..6c2085a 100644 --- a/lib/view/components/kanji/kanji_search_options_bar.dart +++ b/lib/view/components/kanji/kanji_search_options_bar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart'; //TODO: Make buttons have an effect diff --git a/lib/view/components/kanji/result/examples.dart b/lib/view/components/kanji/result/examples.dart index 1fe4df0..9f4b78e 100644 --- a/lib/view/components/kanji/result/examples.dart +++ b/lib/view/components/kanji/result/examples.dart @@ -1,4 +1,5 @@ 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 { @@ -12,32 +13,27 @@ class Examples extends StatelessWidget { @override Widget build(BuildContext context) { - return ExpansionTile( - title: Center( - child: Container( - padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(10.0), - ), + return Column( + children: [ + [ + Container( + margin: EdgeInsets.symmetric(horizontal: 10), + alignment: Alignment.centerLeft, child: Text( - 'Examples', - style: TextStyle( - color: Colors.white, - fontSize: 20.0, - ), + 'Examples:', + style: TextStyle(fontSize: 20), ), - ), - ), - children: [ - onyomiExamples - .map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi)) - .toList(), - kunyomiExamples - .map((kunyomiExample) => - _Example(kunyomiExample, _KanaType.kunyomi)) - .toList(), - ].expand((list) => list).toList()); + ) + ], + onyomiExamples + .map((onyomiExample) => _Example(onyomiExample, _KanaType.onyomi)) + .toList(), + kunyomiExamples + .map( + (kunyomiExample) => _Example(kunyomiExample, _KanaType.kunyomi)) + .toList(), + ].expand((list) => list).toList(), + ); } } @@ -51,75 +47,75 @@ class _Example extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + final _themeData = BlocProvider.of(context).state.theme; + final _kanaColors = kanaType == _KanaType.kunyomi ? _themeData.kunyomiColor : _themeData.onyomiColor; + final _menuColors = _themeData.menuGreyNormal; + + return Container( margin: EdgeInsets.symmetric( - vertical: 10.0, + vertical: 5.0, horizontal: 10.0, ), decoration: BoxDecoration( - color: Colors.grey, borderRadius: BorderRadius.circular(10.0)), - child: IntrinsicHeight( - child: Row( - children: [ - Container( - padding: EdgeInsets.symmetric( - vertical: 10.0, - horizontal: 10.0, + color: _menuColors.background, borderRadius: BorderRadius.circular(10.0)), + child: Row( + children: [ + Container( + padding: EdgeInsets.symmetric( + vertical: 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) - ? Colors.lightBlue - : Colors.orange, - borderRadius: 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, + ), + ), ), - ), - child: Column( - children: [ - Container( - child: Text( - yomiExample.reading, - style: TextStyle( - color: Colors.white, - fontSize: 15.0, - ), + SizedBox( + height: 5.0, + ), + Container( + child: Text( + yomiExample.example, + style: TextStyle( + color: _kanaColors.foreground, + fontSize: 20.0, ), ), - SizedBox( - height: 5.0, - ), - Container( - child: Text( - yomiExample.example, - style: TextStyle( - color: Colors.white, - fontSize: 20.0, - ), + ), + ], + ), + ), + SizedBox( + width: 15.0, + ), + Expanded( + 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, - ), - ), - ) - ], - ), - ), - ], - ), + ), + ], ), ); } diff --git a/lib/view/components/kanji/result/grade.dart b/lib/view/components/kanji/result/grade.dart index a5c7c9d..12fb36e 100644 --- a/lib/view/components/kanji/result/grade.dart +++ b/lib/view/components/kanji/result/grade.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; class Grade extends StatelessWidget { final String grade; @@ -7,17 +8,19 @@ class Grade extends StatelessWidget { @override Widget build(BuildContext context) { + final _kanjiColors = BlocProvider.of(context).state.theme.kanjiResultColor; + return Container( padding: EdgeInsets.all(10.0), child: Text( grade, style: TextStyle( - color: Colors.white, + color: _kanjiColors.foreground, fontSize: 20.0, ), ), decoration: BoxDecoration( - color: Colors.blue, + color: _kanjiColors.background, shape: BoxShape.circle, ), ); diff --git a/lib/view/components/kanji/result/header.dart b/lib/view/components/kanji/result/header.dart index c20c94e..d0f999c 100644 --- a/lib/view/components/kanji/result/header.dart +++ b/lib/view/components/kanji/result/header.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; class Header extends StatelessWidget { final String kanji; @@ -7,17 +8,19 @@ class Header extends StatelessWidget { @override Widget build(BuildContext context) { + final _kanjiColors = BlocProvider.of(context).state.theme.kanjiResultColor; + return AspectRatio( aspectRatio: 1, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10.0), - color: Colors.blue, + color: _kanjiColors.background, ), child: Center( child: Text( kanji, - style: TextStyle(fontSize: 70.0, color: Colors.white), + style: TextStyle(fontSize: 70.0, color: _kanjiColors.foreground), ), ), ), diff --git a/lib/view/components/kanji/result/jlpt_level.dart b/lib/view/components/kanji/result/jlpt_level.dart index 1c07ee4..2cc2fe1 100644 --- a/lib/view/components/kanji/result/jlpt_level.dart +++ b/lib/view/components/kanji/result/jlpt_level.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; class JlptLevel extends StatelessWidget { final String jlptLevel; @@ -8,18 +9,20 @@ class JlptLevel extends StatelessWidget { @override Widget build(BuildContext context) { + final _kanjiColors = BlocProvider.of(context).state.theme.kanjiResultColor; + return Container( padding: EdgeInsets.all(10.0), child: Text( jlptLevel, style: TextStyle( - color: Colors.white, + color: _kanjiColors.foreground, fontSize: 20.0, ), ), decoration: BoxDecoration( shape: BoxShape.circle, - color: Colors.blue, + color: _kanjiColors.background, ), ); } diff --git a/lib/view/components/kanji/result/kunyomi.dart b/lib/view/components/kanji/result/kunyomi.dart deleted file mode 100644 index beaec3f..0000000 --- a/lib/view/components/kanji/result/kunyomi.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; - -class Kunyomi extends StatelessWidget { - final List 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), - ), - ); - } -} diff --git a/lib/view/components/kanji/result/meaning.dart b/lib/view/components/kanji/result/meaning.dart deleted file mode 100644 index a54e0d4..0000000 --- a/lib/view/components/kanji/result/meaning.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'package:flutter/material.dart'; - -class Meaning extends StatelessWidget { - late final List 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), - ), - ); - } -} diff --git a/lib/view/components/kanji/result/onyomi.dart b/lib/view/components/kanji/result/onyomi.dart deleted file mode 100644 index c9c1a1e..0000000 --- a/lib/view/components/kanji/result/onyomi.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:flutter/material.dart'; - -class Onyomi extends StatelessWidget { - final List 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), - ), - ); - } -} diff --git a/lib/view/components/kanji/result/radical.dart b/lib/view/components/kanji/result/radical.dart index fd193f6..d208e00 100644 --- a/lib/view/components/kanji/result/radical.dart +++ b/lib/view/components/kanji/result/radical.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; import 'package:unofficial_jisho_api/api.dart' as jisho; class Radical extends StatelessWidget { @@ -8,18 +9,20 @@ class Radical extends StatelessWidget { @override Widget build(BuildContext context) { + final _kanjiColors = BlocProvider.of(context).state.theme.kanjiResultColor; + return Container( padding: EdgeInsets.all(10.0), child: Text( radical.symbol, style: TextStyle( - color: Colors.white, + color: _kanjiColors.foreground, fontSize: 40.0, ), ), decoration: BoxDecoration( shape: BoxShape.circle, - color: Colors.blue, + color: _kanjiColors.background, ), ); } diff --git a/lib/view/components/kanji/result/rank.dart b/lib/view/components/kanji/result/rank.dart index 441af58..24356fb 100644 --- a/lib/view/components/kanji/result/rank.dart +++ b/lib/view/components/kanji/result/rank.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; class Rank extends StatelessWidget { final int rank; @@ -8,18 +9,20 @@ class Rank extends StatelessWidget { @override Widget build(BuildContext context) { + final _kanjiColors = BlocProvider.of(context).state.theme.kanjiResultColor; + return Container( padding: EdgeInsets.all(10.0), child: Text( '${rank.toString()} / 2500', style: TextStyle( - color: Colors.white, + color: _kanjiColors.foreground, fontSize: 20.0, ), ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10.0), - color: Colors.blue, + color: _kanjiColors.background, ), ); } diff --git a/lib/view/components/kanji/result/stroke_order_gif.dart b/lib/view/components/kanji/result/stroke_order_gif.dart index f3a85d8..ecda698 100644 --- a/lib/view/components/kanji/result/stroke_order_gif.dart +++ b/lib/view/components/kanji/result/stroke_order_gif.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/bloc/theme/theme_bloc.dart'; class StrokeOrderGif extends StatelessWidget { final String uri; @@ -7,6 +8,8 @@ class StrokeOrderGif extends StatelessWidget { @override Widget build(BuildContext context) { + final _kanjiColors = BlocProvider.of(context).state.theme.kanjiResultColor; + return Container( margin: EdgeInsets.symmetric(vertical: 20.0), padding: EdgeInsets.all(5.0), @@ -15,7 +18,7 @@ class StrokeOrderGif extends StatelessWidget { borderRadius: BorderRadius.circular(10.0), ), decoration: BoxDecoration( - color: Colors.blue, + color: _kanjiColors.background, borderRadius: BorderRadius.circular(15.0), ), ); diff --git a/lib/view/components/kanji/result/yomi_chips.dart b/lib/view/components/kanji/result/yomi_chips.dart new file mode 100644 index 0000000..7ee1757 --- /dev/null +++ b/lib/view/components/kanji/result/yomi_chips.dart @@ -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(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 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), + ), + ); + } +} diff --git a/lib/view/components/opaque_box.dart b/lib/view/components/opaque_box.dart new file mode 100644 index 0000000..c8cc7db --- /dev/null +++ b/lib/view/components/opaque_box.dart @@ -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, + ); + } +} \ No newline at end of file diff --git a/lib/view/components/search/language_selector.dart b/lib/view/components/search/language_selector.dart index c5d206d..b28cbe1 100644 --- a/lib/view/components/search/language_selector.dart +++ b/lib/view/components/search/language_selector.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:jisho_study_tool/models/themes/theme.dart'; import 'package:shared_preferences/shared_preferences.dart'; class LanguageSelector extends StatefulWidget { @@ -43,13 +44,13 @@ class _LanguageSelectorState extends State { @override Widget build(BuildContext context) { return ToggleButtons( + selectedColor: AppTheme.jishoGreen.background, isSelected: isSelected, children: [ _LanguageOption("Auto"), _LanguageOption("日本語"), _LanguageOption("English") ], - selectedColor: Colors.blue, onPressed: (int buttonIndex) { setState(() { for (var i in Iterable.generate(isSelected.length)) { diff --git a/lib/view/components/search/search_bar.dart b/lib/view/components/search/search_bar.dart index 1ace9d0..b8d63d2 100644 --- a/lib/view/components/search/search_bar.dart +++ b/lib/view/components/search/search_bar.dart @@ -1,5 +1,4 @@ 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/view/components/search/language_selector.dart'; diff --git a/lib/view/components/search/search_result_page/parts/other_forms.dart b/lib/view/components/search/search_result_page/parts/other_forms.dart index 598ab95..8ea8dc1 100644 --- a/lib/view/components/search/search_result_page/parts/other_forms.dart +++ b/lib/view/components/search/search_result_page/parts/other_forms.dart @@ -1,4 +1,5 @@ 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 { @@ -10,18 +11,17 @@ class OtherForms extends StatelessWidget { 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(), - ), - ] - : [], + children: this.otherForms.isNotEmpty + ? [ + Text( + 'Other Forms', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Row( + children: otherForms.map((form) => _KanaBox(form)).toList(), + ), + ] + : [], ), ); } @@ -35,14 +35,19 @@ class _KanaBox extends StatelessWidget { @override Widget build(BuildContext context) { final hasFurigana = (word.word != null); + final _menuColors = + BlocProvider.of(context).state.theme.menuGreyLight; return Container( - child: Column( - children: [ - // TODO: take a look at this logic - (hasFurigana) ? Text(word.reading ?? '') : Text(''), - (hasFurigana) ? Text(word.word!) : Text(word.reading ?? ''), - ], + 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( horizontal: 5.0, @@ -50,7 +55,7 @@ class _KanaBox extends StatelessWidget { ), padding: EdgeInsets.all(5.0), decoration: BoxDecoration( - color: Colors.white, + color: _menuColors.background, boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), diff --git a/lib/view/components/search/search_result_page/search_card.dart b/lib/view/components/search/search_result_page/search_card.dart index ea30552..4b045dd 100644 --- a/lib/view/components/search/search_result_page/search_card.dart +++ b/lib/view/components/search/search_result_page/search_card.dart @@ -21,7 +21,10 @@ class SearchResultCard extends StatelessWidget { @override Widget build(BuildContext context) { + final backgroundColor = Theme.of(context).scaffoldBackgroundColor; return ExpansionTile( + collapsedBackgroundColor: backgroundColor, + backgroundColor: backgroundColor, title: IntrinsicWidth( child: Row( diff --git a/lib/view/screens/history.dart b/lib/view/screens/history.dart index 124bbed..0a45b19 100644 --- a/lib/view/screens/history.dart +++ b/lib/view/screens/history.dart @@ -1,5 +1,4 @@ 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/models/history/search.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/objectbox.g.dart'; +import 'package:jisho_study_tool/view/components/opaque_box.dart'; class HistoryView extends StatelessWidget { @override @@ -23,50 +23,54 @@ class HistoryView extends StatelessWidget { .map((query) => query.find()), builder: (BuildContext context, AsyncSnapshot snapshot) { if (!snapshot.hasData) return Container(); - return 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!, + 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, ); - } - return PhraseSearchItem( - search: search.wordQuery.target!, - timestamp: search.timestamp, - ); - }, - separatorBuilder: (context, index) { - Function roundToDay = (DateTime date) => - 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]; - DateTime searchDate = roundToDay(search.timestamp); + Search search = snapshot.data[index]; + DateTime searchDate = roundToDay(search.timestamp); - bool newDate = true; + bool newDate = true; - if (index != 0) { - Search prevSearch = snapshot.data[index - 1]; + EdgeInsets? margin; + if (index != 0) { + Search prevSearch = snapshot.data[index - 1]; - DateTime prevSearchDate = roundToDay(prevSearch.timestamp); - newDate = prevSearchDate != searchDate; - } + DateTime prevSearchDate = roundToDay(prevSearch.timestamp); + newDate = prevSearchDate != searchDate; + margin = EdgeInsets.only(bottom: 10); + } - if (newDate) { - if (searchDate == roundToDay(DateTime.now())) - return DateDivider(text: "Today"); - else if (searchDate == - roundToDay( - DateTime.now().subtract(const Duration(days: 1)))) - return DateDivider(text: "Yesterday"); - return DateDivider(date: searchDate); - } + 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(); - }, + return Divider(); + }, + ), ); }, ); diff --git a/lib/view/screens/kanji/result.dart b/lib/view/screens/kanji/result.dart index 1d8e247..3e3a754 100644 --- a/lib/view/screens/kanji/result.dart +++ b/lib/view/screens/kanji/result.dart @@ -1,23 +1,30 @@ - import 'package:flutter/material.dart'; - import 'package:unofficial_jisho_api/api.dart' as jisho; +import 'package:jisho_study_tool/view/components/kanji/result/examples.dart'; import 'package:jisho_study_tool/view/components/kanji/result/grade.dart'; import 'package:jisho_study_tool/view/components/kanji/result/header.dart'; import 'package:jisho_study_tool/view/components/kanji/result/jlpt_level.dart'; -import 'package:jisho_study_tool/view/components/kanji/result/meaning.dart'; import 'package:jisho_study_tool/view/components/kanji/result/radical.dart'; import 'package:jisho_study_tool/view/components/kanji/result/rank.dart'; import 'package:jisho_study_tool/view/components/kanji/result/stroke_order_gif.dart'; -import 'package:jisho_study_tool/view/components/kanji/result/onyomi.dart'; -import 'package:jisho_study_tool/view/components/kanji/result/kunyomi.dart'; -import 'package:jisho_study_tool/view/components/kanji/result/examples.dart'; +import 'package:jisho_study_tool/view/components/kanji/result/yomi_chips.dart'; class KanjiResultCard extends StatelessWidget { late final String query; late final jisho.KanjiResultData resultData; + KanjiResultCard({required jisho.KanjiResult result}) { + + query = result.query; + + // TODO: Handle this kind of exception before widget is initialized + if (result.data == null) + throw Exception(); + + resultData = result.data!; + } + @override Widget build(BuildContext context) { return ListView( @@ -47,9 +54,9 @@ class KanjiResultCard extends StatelessWidget { ], ), ), - Meaning(resultData.meaning), - resultData.onyomi.length != 0 ? Onyomi(resultData.onyomi) : SizedBox.shrink(), - resultData.kunyomi.length != 0 ? Kunyomi(resultData.kunyomi) : SizedBox.shrink(), + YomiChips(resultData.meaning.split(', '), YomiType.meaning), + resultData.onyomi.length != 0 ? YomiChips(resultData.onyomi, YomiType.onyomi) : SizedBox.shrink(), + resultData.kunyomi.length != 0 ? YomiChips(resultData.kunyomi, YomiType.kunyomi) : SizedBox.shrink(), IntrinsicHeight( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -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!; - } } \ No newline at end of file diff --git a/lib/view/screens/kanji/search.dart b/lib/view/screens/kanji/search.dart index ad2d5c4..0c3d803 100644 --- a/lib/view/screens/kanji/search.dart +++ b/lib/view/screens/kanji/search.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:jisho_study_tool/bloc/kanji/kanji_bloc.dart'; import 'package:animated_size_and_fade/animated_size_and_fade.dart'; diff --git a/lib/view/screens/kanji/view.dart b/lib/view/screens/kanji/view.dart index f223ccc..4dfd38b 100644 --- a/lib/view/screens/kanji/view.dart +++ b/lib/view/screens/kanji/view.dart @@ -1,6 +1,5 @@ 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/view/screens/loading.dart'; diff --git a/lib/view/screens/search/results.dart b/lib/view/screens/search/results.dart index e69de29..8f42aff 100644 --- a/lib/view/screens/search/results.dart +++ b/lib/view/screens/search/results.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 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(context).add(ReturnToInitialState()); + return false; + }, + ); + } +} diff --git a/lib/view/screens/search/view.dart b/lib/view/screens/search/view.dart index c1fad0e..651a7c5 100644 --- a/lib/view/screens/search/view.dart +++ b/lib/view/screens/search/view.dart @@ -1,9 +1,8 @@ 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/view/components/search/search_bar.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 { @override @@ -16,18 +15,7 @@ class SearchView extends StatelessWidget { else if (state is SearchLoading) return LoadingScreen(); else if (state is SearchFinished) { - return WillPopScope( - child: ListView( - children: state.results - .map((result) => SearchResultCard(result)) - .toList(), - ), - onWillPop: () async { - BlocProvider.of(context).add(ReturnToInitialState()); - print('Popped'); - return false; - }, - ); + return SearchResults(results: state.results); } throw 'No such event found'; }, diff --git a/lib/view/screens/settings.dart b/lib/view/screens/settings.dart index ed1c35e..40d4709 100644 --- a/lib/view/screens/settings.dart +++ b/lib/view/screens/settings.dart @@ -1,61 +1,150 @@ import 'package:confirm_dialog/confirm_dialog.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/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'; + +class SettingsView extends StatefulWidget { + SettingsView({Key? key}) : super(key: key); + + @override + _SettingsViewState createState() => _SettingsViewState(); +} + +class _SettingsViewState extends State { + 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) { + final TextStyle _titleTextStyle = TextStyle( + color: BlocProvider.of(context).state is DarkThemeState + ? AppTheme.jishoGreen.background + : null); + return SettingsList( + backgroundColor: Colors.transparent, + contentPadding: EdgeInsets.symmetric(vertical: 10), sections: [ SettingsSection( - title: 'Cache', + title: 'Theme', + titleTextStyle: _titleTextStyle, tiles: [ SettingsTile.switchTile( - title: 'Cache grade 1-7 kanji (N/A)', - switchValue: false, - onToggle: (v) {}, + title: 'Automatically determine theme', + onToggle: (b) { + setState(() { + autoThemeEnabled = b; + }); + _updatePrefs(); + }, + switchValue: autoThemeEnabled, + enabled: false, + switchActiveColor: AppTheme.jishoGreen.background, ), SettingsTile.switchTile( - title: 'Cache grade standard kanji (N/A)', + title: 'Dark Theme', + onToggle: (b) { + BlocProvider.of(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, onToggle: (v) {}, + enabled: false, + switchActiveColor: AppTheme.jishoGreen.background, ), SettingsTile.switchTile( - title: 'Cache all favourites (N/A)', + title: 'Cache grade standard kanji', switchValue: false, onToggle: (v) {}, + enabled: false, + switchActiveColor: AppTheme.jishoGreen.background, ), SettingsTile.switchTile( - title: 'Cache all searches (N/A)', + title: 'Cache all favourites', switchValue: false, 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( title: 'Data', + titleTextStyle: _titleTextStyle, tiles: [ SettingsTile( leading: Icon(Icons.file_download), - title: 'Export Data (N/A)', + title: 'Export Data', + enabled: false, ), SettingsTile( leading: Icon(Icons.delete), - title: 'Clear History (N/A)', + title: 'Clear History', onPressed: _clearHistory, titleTextStyle: TextStyle(color: Colors.red), + enabled: false, ), SettingsTile( leading: Icon(Icons.delete), - title: 'Clear Favourites (N/A)', + title: 'Clear Favourites', onPressed: (c) {}, titleTextStyle: TextStyle(color: Colors.red), + enabled: false, ) ], - ) + ), ], ); } diff --git a/lib/view/screens/splash.dart b/lib/view/screens/splash.dart new file mode 100644 index 0000000..350d7d2 --- /dev/null +++ b/lib/view/screens/splash.dart @@ -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'), + ), + ); + } +} \ No newline at end of file