add custom srs

This commit is contained in:
Rene Kievits
2025-10-30 02:00:29 +01:00
parent fe5ac30294
commit b58a4020e1
12 changed files with 802 additions and 250 deletions

View File

@@ -18,14 +18,14 @@ class VocabScreen extends StatefulWidget {
State<VocabScreen> createState() => _VocabScreenState();
}
class _VocabScreenState extends State<VocabScreen> {
class _VocabScreenState extends State<VocabScreen> with SingleTickerProviderStateMixin {
late TabController _tabController;
List<VocabularyItem> _deck = [];
bool _loading = false;
String _status = 'Loading deck...';
final DistractorGenerator _dg = DistractorGenerator();
final _audioPlayer = AudioPlayer();
VocabQuizMode _mode = VocabQuizMode.vocabToEnglish;
VocabularyItem? _current;
List<String> _options = [];
List<String> _correctAnswers = [];
@@ -33,14 +33,26 @@ class _VocabScreenState extends State<VocabScreen> {
int _asked = 0;
bool _playAudio = true;
bool _playCorrectSound = true;
bool _apiKeyMissing = false;
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
_tabController.addListener(() {
setState(() {});
_nextQuestion();
});
_loadSettings();
_loadDeck();
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
@@ -61,11 +73,10 @@ class _VocabScreenState extends State<VocabScreen> {
final apiKey = repo.apiKey;
if (apiKey == null || apiKey.isEmpty) {
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const SettingsScreen()),
);
}
setState(() {
_apiKeyMissing = true;
_loading = false;
});
return;
}
@@ -82,6 +93,7 @@ class _VocabScreenState extends State<VocabScreen> {
_deck = items;
_status = 'Loaded ${items.length} vocabulary';
_loading = false;
_apiKeyMissing = false;
});
_nextQuestion();
@@ -101,6 +113,19 @@ class _VocabScreenState extends State<VocabScreen> {
.join(' ');
}
VocabQuizMode get _mode {
switch (_tabController.index) {
case 0:
return VocabQuizMode.vocabToEnglish;
case 1:
return VocabQuizMode.englishToVocab;
case 2:
return VocabQuizMode.audioToEnglish;
default:
return VocabQuizMode.vocabToEnglish;
}
}
void _nextQuestion() {
if (_deck.isEmpty) return;
@@ -257,6 +282,30 @@ class _VocabScreenState extends State<VocabScreen> {
@override
Widget build(BuildContext context) {
if (_apiKeyMissing) {
return Scaffold(
appBar: AppBar(title: const Text('Vocabulary Quiz')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('WaniKani API key is not set.', style: TextStyle(color: Colors.white)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const SettingsScreen()),
);
_loadDeck();
},
child: const Text('Go to Settings'),
),
],
),
),
);
}
Widget promptWidget;
if (_current == null) {
@@ -283,24 +332,18 @@ class _VocabScreenState extends State<VocabScreen> {
}
return Scaffold(
backgroundColor: const Color(0xFF121212),
appBar: AppBar(
title: const Text('Hirameki SRS - Vocab'),
backgroundColor: const Color(0xFF1F1F1F),
foregroundColor: Colors.white,
elevation: 2,
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const SettingsScreen()),
);
_loadSettings();
},
)
],
title: const Text('Vocabulary Quiz'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(text: 'Vocab→English'),
Tab(text: 'English→Vocab'),
Tab(text: 'Listening'),
],
),
),
backgroundColor: const Color(0xFF121212),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
@@ -317,17 +360,6 @@ class _VocabScreenState extends State<VocabScreen> {
const CircularProgressIndicator(color: Colors.blueAccent),
],
),
const SizedBox(height: 12),
Wrap(
spacing: 6,
runSpacing: 4,
alignment: WrapAlignment.center,
children: [
_buildChoiceChip('Vocab→English', VocabQuizMode.vocabToEnglish),
_buildChoiceChip('English→Vocab', VocabQuizMode.englishToVocab),
_buildChoiceChip('Listening', VocabQuizMode.audioToEnglish),
],
),
const SizedBox(height: 18),
Expanded(
flex: 3,
@@ -370,23 +402,5 @@ class _VocabScreenState extends State<VocabScreen> {
),
),
);
}
ChoiceChip _buildChoiceChip(String label, VocabQuizMode mode) {
final selected = _mode == mode;
return ChoiceChip(
label: Text(
label,
style: TextStyle(color: selected ? Colors.white : Colors.grey[400]),
),
selected: selected,
onSelected: (v) {
setState(() => _mode = mode);
_nextQuestion();
},
selectedColor: Colors.blueAccent,
backgroundColor: const Color(0xFF1E1E1E),
);
}
}
}