2022-01-14 17:43:39 +01:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
import '../../../../bloc/theme/theme_bloc.dart';
|
2022-01-17 14:44:02 +01:00
|
|
|
import '../../../../data/radicals.dart';
|
2022-01-19 02:10:05 +01:00
|
|
|
import '../../../../routing/routes.dart';
|
2022-01-14 17:43:39 +01:00
|
|
|
import '../../../../services/jisho_api/radicals_search.dart';
|
2022-01-23 23:56:26 +01:00
|
|
|
import '../../../settings.dart';
|
2022-01-14 17:43:39 +01:00
|
|
|
|
|
|
|
class KanjiRadicalSearch extends StatefulWidget {
|
2022-01-23 21:29:54 +01:00
|
|
|
final String? prechosenRadical;
|
|
|
|
|
|
|
|
const KanjiRadicalSearch({Key? key, this.prechosenRadical}) : super(key: key);
|
2022-01-14 17:43:39 +01:00
|
|
|
|
|
|
|
@override
|
|
|
|
_KanjiRadicalSearchState createState() => _KanjiRadicalSearchState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _KanjiRadicalSearchState extends State<KanjiRadicalSearch> {
|
|
|
|
static const double fontSize = 25;
|
|
|
|
|
|
|
|
List<String> suggestions = [];
|
|
|
|
|
|
|
|
Map<String, bool> radicalToggles = {
|
|
|
|
for (final String r in radicals.values.expand((l) => l)) r: false
|
|
|
|
};
|
|
|
|
|
|
|
|
Map<String, bool> allowedToggles = {
|
|
|
|
for (final String r in radicals.values.expand((l) => l)) r: true
|
|
|
|
};
|
|
|
|
|
2022-01-23 21:29:54 +01:00
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
if (widget.prechosenRadical != null &&
|
|
|
|
radicalToggles.containsKey(widget.prechosenRadical))
|
|
|
|
radicalToggles[widget.prechosenRadical!] = true;
|
2022-01-23 23:56:26 +01:00
|
|
|
updateSuggestions();
|
2022-01-23 21:29:54 +01:00
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
2022-01-14 17:43:39 +01:00
|
|
|
void resetRadicalToggles() => radicalToggles.forEach((k, _) {
|
|
|
|
radicalToggles[k] = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
void resetAllowedToggles() => allowedToggles.forEach((k, _) {
|
|
|
|
allowedToggles[k] = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
Future<void> updateSuggestions() async {
|
|
|
|
final toggledRadicals =
|
|
|
|
radicalToggles.keys.where((r) => radicalToggles[r] ?? false).toList();
|
|
|
|
|
|
|
|
if (toggledRadicals.isEmpty) {
|
|
|
|
suggestions.clear();
|
|
|
|
resetAllowedToggles();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
final newSuggestions = await searchKanjiByRadicals(toggledRadicals);
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
allowedToggles.forEach((key, value) {
|
|
|
|
allowedToggles[key] = false;
|
|
|
|
});
|
|
|
|
for (final r in newSuggestions.validRadicals) {
|
|
|
|
allowedToggles[r] = true;
|
|
|
|
}
|
|
|
|
suggestions = (newSuggestions.kanji
|
|
|
|
..sort((a, b) => a.strokes.compareTo(b.strokes)))
|
|
|
|
.map((k) => k.kanji)
|
|
|
|
.toList();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget radicalGridElement(String radical, {bool isNumber = false}) {
|
|
|
|
final color = isNumber
|
2022-01-17 14:50:01 +01:00
|
|
|
? LightTheme.defaultMenuGreyDark
|
2022-01-14 17:43:39 +01:00
|
|
|
: radicalToggles[radical]!
|
|
|
|
? AppTheme.jishoGreen
|
2022-01-17 14:50:01 +01:00
|
|
|
: LightTheme.defaultMenuGreyNormal;
|
2022-01-14 17:43:39 +01:00
|
|
|
|
|
|
|
return InkWell(
|
|
|
|
onTap: isNumber
|
|
|
|
? () {}
|
|
|
|
: () => setState(() {
|
|
|
|
// TODO: Don't let the user toggle on another kanji before the last one is updated
|
|
|
|
radicalToggles[radical] = !radicalToggles[radical]!;
|
|
|
|
updateSuggestions();
|
|
|
|
}),
|
|
|
|
child: Container(
|
|
|
|
alignment: Alignment.center,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
borderRadius: const BorderRadius.all(Radius.circular(5)),
|
|
|
|
color: color.background,
|
|
|
|
),
|
|
|
|
child: Text(
|
|
|
|
radical,
|
|
|
|
style: TextStyle(
|
|
|
|
color: color.foreground,
|
|
|
|
fontSize: fontSize,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-23 03:18:05 +01:00
|
|
|
List<Widget> get radicalGridElements => <Widget>[
|
2022-01-14 17:43:39 +01:00
|
|
|
IconButton(
|
|
|
|
onPressed: () => setState(() {
|
|
|
|
suggestions.clear();
|
|
|
|
resetRadicalToggles();
|
|
|
|
resetAllowedToggles();
|
|
|
|
}),
|
|
|
|
icon: const Icon(Icons.restore),
|
|
|
|
color: AppTheme.jishoGreen.background,
|
|
|
|
iconSize: fontSize * 1.3,
|
|
|
|
),
|
2022-01-23 03:18:05 +01:00
|
|
|
...radicals
|
|
|
|
.map(
|
|
|
|
(key, value) => MapEntry(
|
|
|
|
key,
|
|
|
|
value
|
|
|
|
.where((r) => allowedToggles[r]!)
|
|
|
|
.map((r) => radicalGridElement(r))
|
|
|
|
.toList()
|
|
|
|
..insert(
|
|
|
|
0,
|
|
|
|
radicalGridElement(key.toString(), isNumber: true),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.values
|
|
|
|
.where((element) => element.length != 1)
|
|
|
|
.expand((l) => l)
|
|
|
|
.toList()
|
|
|
|
];
|
2022-01-14 17:43:39 +01:00
|
|
|
|
|
|
|
Widget kanjiGridElement(String kanji) {
|
2022-01-17 14:50:01 +01:00
|
|
|
const color = LightTheme.defaultMenuGreyNormal;
|
2022-01-14 17:43:39 +01:00
|
|
|
return InkWell(
|
|
|
|
onTap: () => Navigator.popAndPushNamed(
|
|
|
|
context,
|
2022-01-19 02:10:05 +01:00
|
|
|
Routes.kanjiSearch,
|
2022-01-14 17:43:39 +01:00
|
|
|
arguments: kanji,
|
|
|
|
),
|
|
|
|
child: Container(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
borderRadius: const BorderRadius.all(Radius.circular(5)),
|
|
|
|
color: color.background,
|
|
|
|
),
|
|
|
|
alignment: Alignment.center,
|
|
|
|
child: Text(
|
|
|
|
kanji,
|
|
|
|
style: TextStyle(
|
|
|
|
color: color.foreground,
|
|
|
|
fontSize: fontSize,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(title: const Text('Choose by radicals')),
|
2022-01-23 23:56:26 +01:00
|
|
|
body: DefaultTextStyle.merge(
|
|
|
|
style: japaneseFont.textStyle,
|
|
|
|
child: Column(
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
child: (suggestions.isEmpty)
|
|
|
|
? Center(
|
|
|
|
child: BlocBuilder<ThemeBloc, ThemeState>(
|
|
|
|
builder: (context, state) => Text(
|
|
|
|
'Toggle a radical to start',
|
|
|
|
style: TextStyle(
|
|
|
|
fontSize: fontSize * 0.8,
|
|
|
|
color: state.theme.menuGreyNormal.background,
|
|
|
|
),
|
2022-01-23 04:52:28 +01:00
|
|
|
),
|
2022-01-14 17:43:39 +01:00
|
|
|
),
|
2022-01-23 23:56:26 +01:00
|
|
|
)
|
|
|
|
: GridView.count(
|
|
|
|
crossAxisCount: 6,
|
|
|
|
mainAxisSpacing: 10,
|
|
|
|
crossAxisSpacing: 10,
|
|
|
|
padding: const EdgeInsets.all(10),
|
|
|
|
children:
|
|
|
|
suggestions.map((s) => kanjiGridElement(s)).toList(),
|
2022-01-14 17:43:39 +01:00
|
|
|
),
|
|
|
|
),
|
2022-01-23 23:56:26 +01:00
|
|
|
Divider(
|
|
|
|
color: AppTheme.jishoGreen.background,
|
|
|
|
thickness: 3,
|
|
|
|
height: 30,
|
|
|
|
indent: 5,
|
|
|
|
endIndent: 5,
|
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: GridView.count(
|
|
|
|
crossAxisCount: 6,
|
|
|
|
mainAxisSpacing: 10,
|
|
|
|
crossAxisSpacing: 10,
|
|
|
|
padding: const EdgeInsets.all(10),
|
|
|
|
children: radicalGridElements,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
2022-01-14 17:43:39 +01:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|