diff --git a/lib/learn.dart b/lib/learn.dart index 283f343..b1d6af0 100644 --- a/lib/learn.dart +++ b/lib/learn.dart @@ -3,46 +3,69 @@ import 'package:ju_learn/main.dart'; class QuizPage extends StatefulWidget { Vault v; - QuizPage(this.v, {super.key}); + Function saveState; + QuizPage(this.v, this.saveState, {super.key}); @override // ignore: no_logic_in_create_state, library_private_types_in_public_api - _QuizPageState createState() { - v.randomize(); - return _QuizPageState(v); - } + _QuizPageState createState() => _QuizPageState(v, saveState); } class _QuizPageState extends State { - int _currentQuestionIndex = 0; - int ask_state = -1; - int _score = 0; + int run = 0; + Question _currentQuestion = Question("Dummy", ["Dummy aws"], 0, "dummy"); + int askState = -1; Vault v; - _QuizPageState(this.v); + Function saveState; + _QuizPageState(this.v, this.saveState) { + _currentQuestion.drawer = 0x0fffffff; + v.softReset(); + _nextQuestion(); + } void _checkAnswer(int selectedIndex) { - //if (selectedIndex == v.questions[_currentQuestionIndex].correct) { - // setState(() { - // _score++; - // }); - //} + if (selectedIndex == _currentQuestion.correct) { + _currentQuestion.drawer++; + } else { + _currentQuestion.drawer = 0; + } + _currentQuestion.lastInRun = run; + saveState(); setState(() { - ask_state = selectedIndex; + askState = selectedIndex; }); } void _nextQuestion() { - setState(() { - if (_currentQuestionIndex < v.questions.length - 1) { - ask_state = -1; - _currentQuestionIndex++; - } else { - _showResultDialog(); + Question lowestQ = _currentQuestion; + for (var a in v.questions) { + if (a == _currentQuestion) continue; + int i = a.drawer - lowestQ.drawer; + if (i > 1) { + continue; } - }); + if (i < -1) { + lowestQ = a; + continue; + } + if ((run - a.lastInRun - 10).abs() - + (run - lowestQ.lastInRun - 10).abs() < + 0) { + lowestQ = a; + } + } + if (mounted) { + setState(() { + _currentQuestion = lowestQ; + askState = -1; + }); + } else { + _currentQuestion = lowestQ; + } + run++; } - void _showResultDialog() { + /*void _showResultDialog() { showDialog( context: context, builder: (BuildContext context) { @@ -64,7 +87,7 @@ class _QuizPageState extends State { ); }, ); - } + }*/ @override Widget build(BuildContext context) { @@ -78,40 +101,38 @@ class _QuizPageState extends State { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( - v.questions[_currentQuestionIndex].quest, + _currentQuestion.quest, style: const TextStyle( fontSize: 20.0, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 20.0), - ...v.questions[_currentQuestionIndex].answers.map( + ..._currentQuestion.answers.map( (option) { return Container( margin: const EdgeInsets.symmetric(vertical: 8.0), child: FilledButton( - onPressed: () => ask_state == -1 + onPressed: () => askState == -1 ? _checkAnswer( - v.questions[_currentQuestionIndex].answers - .indexOf(option), + _currentQuestion.answers.indexOf(option), ) : _nextQuestion(), style: FilledButton.styleFrom( padding: const EdgeInsets.all(16.0), - backgroundColor: ask_state == -1 + backgroundColor: askState == -1 ? null - : (v.questions[_currentQuestionIndex].correct == - v.questions[_currentQuestionIndex].answers - .indexOf(option) + : (_currentQuestion.correct == + _currentQuestion.answers.indexOf(option) ? Colors.green : Colors.red), ), child: Text(option))); }, ), - if (ask_state != -1) + if (askState != -1) Text( - v.questions[_currentQuestionIndex].explanation, + _currentQuestion.explanation, style: const TextStyle( fontSize: 15.0, fontWeight: FontWeight.bold, diff --git a/lib/main.dart b/lib/main.dart index cd6b646..f00f7d7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,21 +28,37 @@ class MainPage extends StatefulWidget { const MainPage({super.key}); @override - _MainPageState createState() => _MainPageState(); + MainPageState createState() => MainPageState(); } -class _MainPageState extends State { +class MainPageState extends State { List _vaults = []; - _MainPageState() { + MainPageState() { loadList(); } + + Vault? getByName(String name) { + for (var v in _vaults) { + if (v.name == name) return v; + } + return null; + } + loadList() async { final prefs = await SharedPreferences.getInstance(); List? json = prefs.getStringList("vaults"); + List? jsonState = prefs.getStringList("vaultStates"); if (json == null) return; setState(() { _vaults = json.map((e) => Vault.fromJson(jsonDecode(e))).toList(); }); + if (jsonState == null) return; + for (var s in jsonState) { + var sMap = jsonDecode(s); + Vault? v = getByName(sMap["name"]); + if (v == null) continue; + v.loadState(sMap); + } } saveList() async { @@ -51,33 +67,99 @@ class _MainPageState extends State { "vaults", _vaults.map((e) => jsonEncode(e.toJson())).toList()); } - askToDeleteVault(Vault v) async { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Delete Vault'), - content: Text('Do you want to delete „${v.name}“ Vault?'), - actions: [ - TextButton( - child: const Text('Delete'), - onPressed: () { - setState(() { - _vaults.remove(v); - }); - saveList(); - Navigator.of(context).pop(); - }, - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Cancle')) - ], - ); - }, - ); + saveStateList() async { + final prefs = await SharedPreferences.getInstance(); + prefs.setStringList("vaultStates", + _vaults.map((e) => jsonEncode(e.toStateJson())).toList()); + } + + _vaultMenu(Vault v) async { + showModalBottomSheet( + context: context, + builder: (context) => BottomSheet( + builder: (context) => Column(children: [ + Padding( + padding: const EdgeInsets.all(8), + child: Text(v.name, + style: const TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + ))), + ListTile( + leading: const Icon(Icons.restore), + title: const Text("Reset Vault"), + subtitle: const Text("Reset Vault learn Data to default."), + trailing: const Icon(Icons.chevron_right), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Reset Vault'), + content: + Text('Do you want to reset „${v.name}“ Vault?'), + actions: [ + TextButton( + child: const Text('Reset'), + onPressed: () { + setState(() { + v.reset(); + }); + saveStateList(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Cancle')) + ], + ); + }, + ); + }, + ), + ListTile( + leading: const Icon(Icons.delete), + title: const Text("Vault löschen"), + subtitle: Text('Do you want to delete „${v.name}“ Vault?'), + trailing: const Icon(Icons.chevron_right), + onTap: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Delete Vault'), + content: Text( + 'Do you want to delete „${v.name}“ Vault?'), + actions: [ + TextButton( + child: const Text('Delete'), + onPressed: () { + setState(() { + _vaults.remove(v); + }); + saveList(); + saveStateList(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Cancle')) + ], + ); + }, + ); + }) + ]), + onClosing: () {}, + )); } _pickFile() async { @@ -95,9 +177,8 @@ class _MainPageState extends State { }); saveList(); } catch (e) { - if (kDebugMode) { - print(e); - } + print(e); + AlertDialog( title: const Text('Error'), content: const Text('An error has occurred.'), @@ -114,6 +195,8 @@ class _MainPageState extends State { } } + + @override Widget build(BuildContext context) { return Scaffold( @@ -130,11 +213,11 @@ class _MainPageState extends State { onPressed: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => QuizPage(e)), + MaterialPageRoute(builder: (context) => QuizPage(e, saveStateList)), ); }, onLongPress: () { - askToDeleteVault(e); + _vaultMenu(e); }, child: Text(e.name), ))) @@ -153,6 +236,8 @@ class Question { List answers; int correct; String explanation; + int drawer = 0; + int lastInRun = 0; Question(this.quest, this.answers, this.correct, this.explanation); @@ -201,8 +286,21 @@ class Vault { }; } - void randomize() { - questions.shuffle(Random()); + Map toStateJson() { + return {"name": name, "drawers": questions.map((d) => d.drawer).toList()}; + } + + void reset() { + for (var q in questions) { + q.drawer = 0; + q.lastInRun = 0; + } + } + + void softReset() { + for (var q in questions) { + q.lastInRun = 0; + } } factory Vault.fromJson(Map json) { @@ -219,4 +317,17 @@ class Vault { .toList(), ); } + loadState(Map json) { + if (json["name"] != name) throw ErrorDescription("Wrong Vault Error"); + if (json["drawers"] is! List) { + throw ErrorDescription("fromJSON Error: questions"); + } + var stateList = json["drawers"]; + for (var i = 0; i < stateList.length; i++) { + var q = questions.elementAtOrNull(i); + if (q != null) { + q.drawer = stateList[i] as int; + } + } + } }