Jisho-Study-Tool/lib/screens/search/search_mechanisms/radical_list.dart

214 lines
6.2 KiB
Dart

import 'package:flutter/material.dart';
import '../../../../bloc/theme/theme_bloc.dart';
import '../../../../data/radicals.dart';
import '../../../../routing/routes.dart';
import '../../../../services/jisho_api/radicals_search.dart';
import '../../../settings.dart';
class KanjiRadicalSearch extends StatefulWidget {
final String? prechosenRadical;
const KanjiRadicalSearch({Key? key, this.prechosenRadical}) : super(key: key);
@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
};
@override
void initState() {
if (widget.prechosenRadical != null &&
radicalToggles.containsKey(widget.prechosenRadical))
radicalToggles[widget.prechosenRadical!] = true;
updateSuggestions();
super.initState();
}
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
? LightTheme.defaultMenuGreyDark
: radicalToggles[radical]!
? AppTheme.jishoGreen
: LightTheme.defaultMenuGreyNormal;
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,
),
),
),
);
}
List<Widget> get radicalGridElements => <Widget>[
IconButton(
onPressed: () => setState(() {
suggestions.clear();
resetRadicalToggles();
resetAllowedToggles();
}),
icon: const Icon(Icons.restore),
color: AppTheme.jishoGreen.background,
iconSize: fontSize * 1.3,
),
...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()
];
Widget kanjiGridElement(String kanji) {
const color = LightTheme.defaultMenuGreyNormal;
return InkWell(
onTap: () => Navigator.popAndPushNamed(
context,
Routes.kanjiSearch,
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')),
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,
),
),
),
)
: GridView.count(
crossAxisCount: 6,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
padding: const EdgeInsets.all(10),
children:
suggestions.map((s) => kanjiGridElement(s)).toList(),
),
),
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,
),
),
],
),
),
);
}
}