import 'dart:convert'; import 'dart:io'; import 'dart:math'; 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', theme: ThemeData(useMaterial3: true, brightness: Brightness.light), darkTheme: ThemeData(useMaterial3: true, brightness: Brightness.dark), home: const MainPage(), ); } } class MainPage extends StatefulWidget { const MainPage({super.key}); @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State { List _vaults = []; _MainPageState() { loadList(); } loadList() async { final prefs = await SharedPreferences.getInstance(); List? 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, child: const Icon(Icons.add), ), ); } } class Question { String quest; List answers; int correct; String explanation; Question(this.quest, this.answers, this.correct, this.explanation); Map toJson() { return { "quest": quest, "answers": answers, "correct": correct, "explanation": explanation, }; } factory Question.fromJson(Map json) { if (json["quest"] is! String) { throw ErrorDescription("fromJSON Error: quest"); } if (json["answers"] is! List) { 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).map((d) => d.toString()).toList(), json["correct"], json["explanation"], ); } } class Vault { String name; List questions; Vault(this.name, this.questions); Map toJson() { return { "name": name, "questions": questions.map((e) => e.toJson()).toList() }; } void randomize() { questions.shuffle(Random()); } factory Vault.fromJson(Map json) { if (json["name"] is! String) { throw ErrorDescription("fromJSON Error: name"); } if (json["questions"] is! List) { throw ErrorDescription("fromJSON Error: questions"); } return Vault( json["name"], (json["questions"] as List) .map((d) => Question.fromJson(d)) .toList(), ); } }