Add theming functionality

This commit is contained in:
Oystein Kristoffer Tveit 2021-08-08 23:16:54 +02:00
parent 0a7b71037b
commit feee76c2b6
42 changed files with 816 additions and 502 deletions

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View 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);
}
}

View 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});
}

View 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();
}

View File

@ -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<MyApp> {
late final Store _store;
bool dbConnected = false;
@override
void initState() {
@ -40,6 +43,9 @@ class _MyAppState extends State<MyApp> {
);
_databaseBloc.add(ConnectedToDatabase(_store));
setState(() {
dbConnected = true;
});
});
}
@ -52,30 +58,24 @@ class _MyAppState extends State<MyApp> {
@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<DatabaseBloc, DatabaseState>(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<ThemeBloc, ThemeState>(
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<NavigationBloc, NavigationState>(
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<NavigationBloc>(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<ThemeBloc, ThemeState>(
builder: (context, themeState) {
return Scaffold(
appBar: AppBar(
title: pages[selectedPage].titleBar,
centerTitle: true,
backgroundColor: AppTheme.jishoGreen.background,
foregroundColor: AppTheme.jishoGreen.foreground,
),
body: Stack(
children: [
Positioned(
child: Image.asset(
'assets/images/denshi_jisho_background_overlay.png'),
right: 30,
left: 100,
bottom: 30,
),
pages[selectedPage].content,
],
),
bottomNavigationBar: BottomNavigationBar(
fixedColor: AppTheme.jishoGreen.background,
currentIndex: selectedPage,
onTap: (int index) => BlocProvider.of<NavigationBloc>(context)
.add(ChangePage(index)),
items: pages.map((p) => p.item).toList(),
showSelectedLabels: false,
showUnselectedLabels: false,
unselectedItemColor: themeState.theme.menuGreyDark.background,
),
);
},
);
},
);

View File

@ -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),
);
}
}

View File

@ -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,
);
}
}

View 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);
}

View File

@ -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<int, String> 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<ThemeBloc>(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,
);
}
}

View File

@ -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<ThemeBloc>(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,
),
),

View File

@ -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';

View File

@ -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<String> suggestions;
@ -35,9 +35,13 @@ class _GridItem extends StatelessWidget {
onTap: () {
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(
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),
),
),
),
);
},
),
);
}

View File

@ -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<KanjiSearchBar> {
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),
),

View File

@ -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

View File

@ -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<ThemeBloc>(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,
),
),
)
],
),
),
],
),
),
],
),
);
}

View File

@ -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<ThemeBloc>(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,
),
);

View File

@ -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<ThemeBloc>(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),
),
),
),

View File

@ -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<ThemeBloc>(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,
),
);
}

View File

@ -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),
),
);
}
}

View File

@ -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),
),
);
}
}

View File

@ -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),
),
);
}
}

View File

@ -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<ThemeBloc>(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,
),
);
}

View File

@ -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<ThemeBloc>(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,
),
);
}

View File

@ -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<ThemeBloc>(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),
),
);

View 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),
),
);
}
}

View 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,
);
}
}

View File

@ -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<LanguageSelector> {
@override
Widget build(BuildContext context) {
return ToggleButtons(
selectedColor: AppTheme.jishoGreen.background,
isSelected: isSelected,
children: <Widget> [
_LanguageOption("Auto"),
_LanguageOption("日本語"),
_LanguageOption("English")
],
selectedColor: Colors.blue,
onPressed: (int buttonIndex) {
setState(() {
for (var i in Iterable.generate(isSelected.length)) {