possible to exclude levels and change how questions are served
This commit is contained in:
@@ -123,9 +123,14 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(color: Theme.of(context).colorScheme.primary),
|
||||
CircularProgressIndicator(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(_status, style: TextStyle(color: Theme.of(context).colorScheme.onSurface)),
|
||||
Text(
|
||||
_status,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -151,6 +156,7 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
List<int> sortedLevels,
|
||||
PageController pageController,
|
||||
Widget Function(List<dynamic>) buildPageContent,
|
||||
dynamic repository,
|
||||
) {
|
||||
if (sortedLevels.isEmpty) {
|
||||
return Center(
|
||||
@@ -167,18 +173,34 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
itemBuilder: (context, index) {
|
||||
final level = sortedLevels[index];
|
||||
final levelItems = groupedItems[level]!;
|
||||
final bool isDisabled = levelItems.every(
|
||||
(item) => (item as dynamic).srsItems.values.every(
|
||||
(srs) => (srs as SrsItem).disabled,
|
||||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Level $level',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Level $level',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Checkbox(
|
||||
value: !isDisabled,
|
||||
onChanged: (value) {
|
||||
_toggleLevelExclusion(level, repository);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(child: buildPageContent(levelItems)),
|
||||
@@ -199,31 +221,55 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: List.generate(levels.length, (index) {
|
||||
final level = levels[index];
|
||||
final isSelected = index == currentPage;
|
||||
final items = isKanji ? _kanjiByLevel[level] : _vocabByLevel[level];
|
||||
final bool isDisabled =
|
||||
items?.every(
|
||||
(item) => (item as dynamic).srsItems.values.every(
|
||||
(srs) => (srs as SrsItem).disabled,
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
controller.animateToPage(
|
||||
index,
|
||||
|
||||
duration: const Duration(milliseconds: 300),
|
||||
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
},
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: isSelected
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: isDisabled
|
||||
? Theme.of(context).colorScheme.surfaceVariant
|
||||
: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
foregroundColor: Theme.of(context).colorScheme.onPrimary,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
|
||||
foregroundColor: isSelected
|
||||
? Theme.of(context).colorScheme.onPrimary
|
||||
: isDisabled
|
||||
? Theme.of(context).colorScheme.onSurfaceVariant
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
padding: const EdgeInsets.all(12),
|
||||
),
|
||||
|
||||
child: Text(level.toString()),
|
||||
),
|
||||
),
|
||||
@@ -295,7 +341,10 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.characters,
|
||||
style: TextStyle(fontSize: 24, color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
@@ -306,7 +355,9 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
children: [
|
||||
Text(
|
||||
item.meanings.join(', '),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -355,7 +406,10 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
children: [
|
||||
Text(
|
||||
item.characters,
|
||||
style: TextStyle(fontSize: 32, color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -375,7 +429,9 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
height: 10,
|
||||
child: LinearProgressIndicator(
|
||||
value: level / 9.0,
|
||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceContainerHighest,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
_getColorForSrsLevel(level),
|
||||
),
|
||||
@@ -444,29 +500,39 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
children: [
|
||||
Text(
|
||||
'Level: ${kanji.level}',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (kanji.meanings.isNotEmpty)
|
||||
Text(
|
||||
'Meanings: ${kanji.meanings.join(', ')}',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (kanji.onyomi.isNotEmpty)
|
||||
Text(
|
||||
'On\'yomi: ${kanji.onyomi.join(', ')}',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
if (kanji.kunyomi.isNotEmpty)
|
||||
Text(
|
||||
'Kun\'yomi: ${kanji.kunyomi.join(', ')}',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
if (kanji.onyomi.isEmpty && kanji.kunyomi.isEmpty)
|
||||
Text(
|
||||
'No readings available.',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Divider(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
@@ -481,7 +547,9 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
...srsScores.entries.map(
|
||||
(entry) => Text(
|
||||
' ${entry.key}: ${entry.value}',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -568,6 +636,42 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
_vocabSortedLevels = _vocabByLevel.keys.toList()..sort();
|
||||
}
|
||||
|
||||
Future<void> _toggleLevelExclusion(int level, dynamic repository) async {
|
||||
final List<SrsItem> itemsToUpdate = [];
|
||||
final bool currentlyDisabled;
|
||||
|
||||
if (repository is DeckRepository) {
|
||||
final items = _kanjiByLevel[level] ?? [];
|
||||
currentlyDisabled = items.every(
|
||||
(item) => item.srsItems.values.every((srs) => srs.disabled),
|
||||
);
|
||||
for (final item in items) {
|
||||
for (final srsItem in item.srsItems.values) {
|
||||
itemsToUpdate.add(srsItem);
|
||||
}
|
||||
}
|
||||
} else if (repository is VocabDeckRepository) {
|
||||
final items = _vocabByLevel[level] ?? [];
|
||||
currentlyDisabled = items.every(
|
||||
(item) => item.srsItems.values.every((srs) => srs.disabled),
|
||||
);
|
||||
for (final item in items) {
|
||||
for (final srsItem in item.srsItems.values) {
|
||||
itemsToUpdate.add(srsItem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final item in itemsToUpdate) {
|
||||
item.disabled = !currentlyDisabled;
|
||||
}
|
||||
|
||||
await repository.updateSrsItems(itemsToUpdate);
|
||||
_loadDecks();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -586,6 +690,7 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
_kanjiSortedLevels,
|
||||
_kanjiPageController,
|
||||
(items) => _buildGridView(items.cast<KanjiItem>()),
|
||||
Provider.of<DeckRepository>(context, listen: false),
|
||||
),
|
||||
),
|
||||
_buildWaniKaniTab(
|
||||
@@ -594,6 +699,7 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
_vocabSortedLevels,
|
||||
_vocabPageController,
|
||||
(items) => _buildListView(items.cast<VocabularyItem>()),
|
||||
Provider.of<VocabDeckRepository>(context, listen: false),
|
||||
),
|
||||
),
|
||||
_buildCustomSrsTab(),
|
||||
@@ -673,8 +779,7 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
setState(() {
|
||||
if (_selectedItems.length == _customDeck.length) {
|
||||
_selectedItems.clear();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
_selectedItems = List.from(_customDeck);
|
||||
}
|
||||
});
|
||||
@@ -799,12 +904,17 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
child: Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: isSelected
|
||||
? BorderSide(color: Theme.of(context).colorScheme.primary, width: 2.0)
|
||||
? BorderSide(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
width: 2.0,
|
||||
)
|
||||
: BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
color: isSelected
|
||||
? Theme.of(context).colorScheme.primary.withAlpha((255 * 0.5).round())
|
||||
? Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withAlpha((255 * 0.5).round())
|
||||
: Theme.of(context).colorScheme.surfaceContainer,
|
||||
child: Stack(
|
||||
children: [
|
||||
@@ -854,7 +964,11 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||
Positioned(
|
||||
top: 4,
|
||||
right: 4,
|
||||
child: Icon(Icons.timer, color: Theme.of(context).colorScheme.tertiary, size: 16),
|
||||
child: Icon(
|
||||
Icons.timer,
|
||||
color: Theme.of(context).colorScheme.tertiary,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -912,11 +1026,15 @@ class _VocabDetailsDialogState extends State<_VocabDetailsDialog> {
|
||||
children: [
|
||||
Text(
|
||||
japaneseWord,
|
||||
style: TextStyle(color: widget.theme.colorScheme.onSurface),
|
||||
style: TextStyle(
|
||||
color: widget.theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
englishDefinition,
|
||||
style: TextStyle(color: widget.theme.colorScheme.onSurfaceVariant),
|
||||
style: TextStyle(
|
||||
color: widget.theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
@@ -1012,7 +1130,10 @@ class _VocabDetailsDialogState extends State<_VocabDetailsDialog> {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'SRS Scores:',
|
||||
style: TextStyle(color: widget.theme.colorScheme.onSurface, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
color: widget.theme.colorScheme.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
...srsScores.entries.map(
|
||||
(entry) => Text(
|
||||
@@ -1025,7 +1146,10 @@ class _VocabDetailsDialogState extends State<_VocabDetailsDialog> {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Example Sentences:',
|
||||
style: TextStyle(color: widget.theme.colorScheme.onSurface, fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
color: widget.theme.colorScheme.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
..._exampleSentences,
|
||||
],
|
||||
@@ -1059,4 +1183,3 @@ void _showVocabDetailsDialog(BuildContext context, VocabularyItem vocab) {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user