JuLearn/lib/main.dart

224 lines
5.8 KiB
Dart
Raw Normal View History

2023-06-01 16:11:03 +02:00
import 'dart:convert';
import 'dart:io';
2023-06-01 16:38:20 +02:00
import 'dart:math';
2023-06-01 16:11:03 +02:00
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:ju_learn/learn.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(const LearnApp());
class LearnApp extends StatelessWidget {
const LearnApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Learn App',
2023-06-01 16:38:20 +02:00
theme: ThemeData(useMaterial3: true, brightness: Brightness.light),
darkTheme: ThemeData(useMaterial3: true, brightness: Brightness.dark),
2023-06-01 16:11:03 +02:00
home: const MainPage(),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
List<Vault> _vaults = [];
_MainPageState() {
loadList();
}
loadList() async {
final prefs = await SharedPreferences.getInstance();
List<String>? json = prefs.getStringList("vaults");
if (json == null) return;
setState(() {
_vaults = json.map((e) => Vault.fromJson(jsonDecode(e))).toList();
});
}
saveList() async {
final prefs = await SharedPreferences.getInstance();
prefs.setStringList(
"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'))
],
);
},
);
}
_pickFile() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['json'],
allowMultiple: false);
if (result != null && result.files.single.path != null) {
File file = File(result.files.single.path ?? "");
String data = file.readAsStringSync();
try {
Vault v = Vault.fromJson(jsonDecode(data));
setState(() {
_vaults.add(v);
});
saveList();
} catch (e) {
if (kDebugMode) {
print(e);
}
AlertDialog(
title: const Text('Error'),
content: const Text('An error has occurred.'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
]);
return;
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Learn App'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child:
Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
..._vaults.map((e) => Container(
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => QuizPage(e)),
);
},
onLongPress: () {
askToDeleteVault(e);
},
child: Text(e.name),
)))
]),
),
floatingActionButton: FloatingActionButton(
onPressed: _pickFile,
backgroundColor: Colors.blue,
child: const Icon(Icons.add),
),
);
}
}
class Question {
String quest;
List<String> answers;
int correct;
String explanation;
Question(this.quest, this.answers, this.correct, this.explanation);
Map<String, dynamic> toJson() {
return {
"quest": quest,
"answers": answers,
"correct": correct,
"explanation": explanation,
};
}
factory Question.fromJson(Map<String, dynamic> json) {
if (json["quest"] is! String) {
throw ErrorDescription("fromJSON Error: quest");
}
if (json["answers"] is! List<dynamic>) {
throw ErrorDescription("fromJSON Error: awnsers");
}
if (json["correct"] is! int ||
json["correct"] < 0 ||
json["correct"] >= json["answers"].length) {
throw ErrorDescription("fromJSON Error: correct");
}
if (json["explanation"] is! String) {
throw ErrorDescription("fromJSON Error: explanation");
}
return Question(
json["quest"],
(json["answers"] as List<dynamic>).map((d) => d.toString()).toList(),
json["correct"],
json["explanation"],
);
}
}
class Vault {
String name;
List<Question> questions;
Vault(this.name, this.questions);
Map<String, dynamic> toJson() {
2023-06-01 16:38:20 +02:00
return {
"name": name,
"questions": questions.map((e) => e.toJson()).toList()
};
}
void randomize() {
questions.shuffle(Random());
2023-06-01 16:11:03 +02:00
}
factory Vault.fromJson(Map<String, dynamic> json) {
if (json["name"] is! String) {
throw ErrorDescription("fromJSON Error: name");
}
if (json["questions"] is! List<dynamic>) {
throw ErrorDescription("fromJSON Error: questions");
}
return Vault(
json["name"],
(json["questions"] as List<dynamic>)
.map((d) => Question.fromJson(d))
.toList(),
);
}
}