2dc41b7e24
- fixed issues
359 lines
13 KiB
Dart
359 lines
13 KiB
Dart
// GCG.MeinCantor - Die Schulplattform für Cantorianer.
|
|
// Copyright (C) 2021-2022 Georg-Cantor-Gymnasium Halle (Saale)
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published
|
|
// by the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:meincantor/cache_manager.dart';
|
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:meincantor/const.dart';
|
|
import 'package:meincantor/timetable.dart';
|
|
import 'package:meincantor/login.dart';
|
|
import 'package:meincantor/main.dart';
|
|
|
|
Future<http.Response> getArticles() async {
|
|
var uri = Uri.https(szUrl["url"]! as String, "/api/articles");
|
|
final response =
|
|
await http.get(uri, headers: szUrl["headers"]! as Map<String, String>);
|
|
return (response);
|
|
}
|
|
|
|
Future<http.Response> getNews() async {
|
|
var uri = Uri.https(szUrl["url"]! as String, "/api/aktuelles");
|
|
final response =
|
|
await http.get(uri, headers: szUrl["headers"]! as Map<String, String>);
|
|
return (response);
|
|
}
|
|
|
|
Future<http.Response> getToken(
|
|
String user, String password, String otp, String devId) async {
|
|
var uri = Uri.https("mein.cantorgymnasium.de", "/login");
|
|
String body =
|
|
'{"user":"$user", "password": "$password", "otp": "$otp", "devid": "$devId"}';
|
|
final response = await http.post(uri, body: body);
|
|
return (response);
|
|
}
|
|
|
|
Future<String> getUserInfo(
|
|
String user, String password, String otp, String devId) async {
|
|
var uri = Uri.https("mein.cantorgymnasium.de", "/api/userinfo");
|
|
String body =
|
|
'{"user":"$user", "password": "$password", "otp": "$otp", "devid": "$devId"}';
|
|
final response = await http.post(uri, body: body);
|
|
|
|
if (response.statusCode == 200) {
|
|
return utf8.decode(response.bodyBytes);
|
|
} else {
|
|
throw Exception('Failed to log in');
|
|
}
|
|
}
|
|
|
|
Future<http.Response> fetchClassTimetable(String ext, String? classNum) async {
|
|
try {
|
|
return (http.Response(await getCachedTimetable(ext, classNum), 200));
|
|
} on HttpExceptionWithStatus catch (e) {
|
|
return http.Response(e.message, e.statusCode);
|
|
} on HttpException catch (e) {
|
|
return http.Response(e.message, 500);
|
|
} on SocketException catch (e) {
|
|
return http.Response(e.message, 404);
|
|
}
|
|
}
|
|
|
|
fetchLessonList() async {
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
String classNum;
|
|
if (prefs.getString('class_num') != null) {
|
|
classNum = prefs.getString('class_num')!.replaceAll("/", "_");
|
|
} else {
|
|
classNum = '05_1';
|
|
}
|
|
var apiKey = prefs.getString('api_key');
|
|
var uri = Uri.https("mein.cantorgymnasium.de", "/api/lessons/$classNum");
|
|
var headers = {"x-api-key": "$apiKey"};
|
|
final response =
|
|
await http.get(uri, headers: headers).onError((error, stackTrace) {
|
|
return (http.Response("", 404));
|
|
});
|
|
if (response.statusCode == 200) {
|
|
prefs.setString("lessons", utf8.decode(response.bodyBytes));
|
|
} else {
|
|
prefs.setString("lessons", jsonEncode([]));
|
|
}
|
|
}
|
|
|
|
Widget buildTimetable(Future<http.Response> future, String info) {
|
|
return FutureBuilder<http.Response>(
|
|
future: future,
|
|
builder: (context, snapshot) {
|
|
if (snapshot.hasData) {
|
|
int statusCode = snapshot.data!.statusCode;
|
|
if (statusCode == 200) {
|
|
Widget timetableView = ClassTimetableBuilder.buildView(
|
|
jsonDecode(snapshot.data!.body), context)
|
|
.view
|
|
.child;
|
|
return timetableView;
|
|
} else if (statusCode == 400) {
|
|
Navigator.push(
|
|
context, MaterialPageRoute(builder: (context) => Login()));
|
|
} else if (statusCode == 500) {
|
|
var chars = Runes('Es konnte kein $info gefunden werden. \u{1F937}');
|
|
List<Widget> cardChildren = [];
|
|
cardChildren.add(ListTile(
|
|
title: Text(String.fromCharCodes(chars),
|
|
style: const TextStyle(color: Palette.primary)),
|
|
));
|
|
Card card = Card(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
),
|
|
color: Colors.white,
|
|
child: Column(
|
|
children: cardChildren,
|
|
));
|
|
return Padding(
|
|
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
|
|
child: ListView(
|
|
children: [card],
|
|
));
|
|
} else if (statusCode == 404) {
|
|
var chars = Runes(
|
|
'Keine Verbindung mit dem MeinCantor-Server möglich. Bitte prüfe deine Internet-Verbindung und deine DNS-Einstellungen oder wende dich an den MeinCantor-Support. \u{1F4e1}');
|
|
List<Widget> cardChildren = [];
|
|
cardChildren.add(ListTile(
|
|
title: Text(String.fromCharCodes(chars),
|
|
style: const TextStyle(color: Palette.primary)),
|
|
));
|
|
Card card = Card(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
),
|
|
color: Colors.white,
|
|
child: Column(
|
|
children: cardChildren,
|
|
));
|
|
return Padding(
|
|
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
|
|
child: ListView(
|
|
children: [card],
|
|
));
|
|
}
|
|
return Center(child: Text('Error $statusCode'));
|
|
} else if (snapshot.hasError) {
|
|
return Text('$snapshot.error');
|
|
} else {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget buildTodayClassTimetableLesson(int count) {
|
|
return FutureBuilder<http.Response>(
|
|
future: fetchClassTimetable(
|
|
"/${DateFormat("yyyyMMdd").format(DateTime.now())}", null),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.hasData) {
|
|
int statusCode = snapshot.data!.statusCode;
|
|
if (statusCode == 200) {
|
|
List<Widget> lessons = LessonsListBuilder.buildList(
|
|
jsonDecode(snapshot.data!.body),
|
|
count: count)
|
|
.lessons;
|
|
if (lessons.isNotEmpty) {
|
|
return Column(children: lessons);
|
|
} else {
|
|
var chars = Runes(
|
|
'Keine Stunden mehr gefunden. Sieht so aus als hättest du Schluss für heute \u{1F389}');
|
|
List<Widget> cardChildren = [];
|
|
cardChildren.add(ListTile(
|
|
title: Text(String.fromCharCodes(chars),
|
|
style: const TextStyle(color: Palette.primary))));
|
|
Card card = Card(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
),
|
|
color: Colors.white,
|
|
child: Column(
|
|
children: cardChildren,
|
|
));
|
|
return Column(children: [card]);
|
|
}
|
|
} else if (statusCode == 400) {
|
|
Future.delayed(Duration.zero, () {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(builder: (context) => Login()),
|
|
);
|
|
});
|
|
} else if (statusCode == 500) {
|
|
var chars = Runes(
|
|
'Es konnte kein Vertretungsplan für heute gefunden werden. \u{1F937}');
|
|
List<Widget> cardChildren = [];
|
|
cardChildren.add(ListTile(
|
|
title: Text(String.fromCharCodes(chars),
|
|
style: const TextStyle(color: Palette.primary))));
|
|
Card card = Card(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
),
|
|
color: Colors.white,
|
|
child: Column(
|
|
children: cardChildren,
|
|
));
|
|
return card;
|
|
} else if (statusCode == 404) {
|
|
var chars = Runes(
|
|
'Keine Verbindung mit dem MeinCantor-Server möglich. Bitte prüfe deine Internet-Verbindung und deine DNS-Einstellungen oder wende dich an den MeinCantor-Support. \u{1F4e1}');
|
|
List<Widget> cardChildren = [];
|
|
cardChildren.add(ListTile(
|
|
title: Text(String.fromCharCodes(chars),
|
|
style: const TextStyle(color: Palette.primary)),
|
|
));
|
|
Card card = Card(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
),
|
|
color: Colors.white,
|
|
child: Column(
|
|
children: cardChildren,
|
|
));
|
|
return Column(
|
|
children: [card],
|
|
);
|
|
}
|
|
return Center(child: Text('Error $statusCode'));
|
|
} else if (snapshot.hasError) {
|
|
return Text('$snapshot.error');
|
|
} else {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<http.Response> fetchClassesList() async {
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
var apiKey = prefs.getString('api_key');
|
|
var uri = Uri.https("mein.cantorgymnasium.de", "/api/classes");
|
|
var headers = {"x-api-key": "$apiKey"};
|
|
final response = http.get(uri, headers: headers).onError((error, stackTrace) {
|
|
return (http.Response("", 404));
|
|
});
|
|
return response;
|
|
}
|
|
|
|
Widget buildClassesChooser() {
|
|
return FutureBuilder<http.Response>(
|
|
future: fetchClassesList(),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.hasData) {
|
|
int statusCode = snapshot.data!.statusCode;
|
|
if (statusCode == 200) {
|
|
List<String> items = [];
|
|
jsonDecode(utf8.decode(snapshot.data!.bodyBytes)).forEach((value) {
|
|
items.add(value.toString());
|
|
});
|
|
return ClassesChooser(items: items);
|
|
} else if (statusCode == 400) {
|
|
Navigator.push(
|
|
context, MaterialPageRoute(builder: (context) => Login()));
|
|
} else if (statusCode == 500) {
|
|
return const Padding(
|
|
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
|
|
child: Center(
|
|
child: Text(
|
|
"Serverfehler. Bitte wende dich an den MeinCantor-Support.")),
|
|
);
|
|
} else if (statusCode == 404) {
|
|
return const Padding(
|
|
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
|
|
child: Center(
|
|
child: Text(
|
|
"Keine Verbindung mit dem MeinCantor-Server möglich. Bitte prüfe deine Internetverbindung und deine DNS-Einstellungen oder wende dich an den MeinCantor-Support")),
|
|
);
|
|
}
|
|
return Text('$statusCode');
|
|
} else if (snapshot.hasError) {
|
|
return Text('$snapshot.error');
|
|
} else {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
class ClassesChooser extends StatefulWidget {
|
|
final List<String> items;
|
|
const ClassesChooser({Key? key, required this.items}) : super(key: key);
|
|
|
|
@override
|
|
State<ClassesChooser> createState() => _ClassesChooserState(items);
|
|
}
|
|
|
|
class _ClassesChooserState extends State<ClassesChooser> {
|
|
final List<String> items;
|
|
String? dropdownValue;
|
|
_ClassesChooserState(this.items);
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_read(); // read in initState
|
|
}
|
|
|
|
_read() async {
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
setState(() {
|
|
dropdownValue = prefs.getString("class_num"); // get the value
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return DropdownButtonFormField<String>(
|
|
value: dropdownValue,
|
|
decoration: const InputDecoration(
|
|
icon: Icon(Icons.people_outline),
|
|
border: OutlineInputBorder(),
|
|
labelText: 'Klasse (05/1, 07/3, 10/2...)',
|
|
),
|
|
onChanged: (String? newValue) async {
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
String classNum = newValue!;
|
|
prefs.setString('class_num', classNum);
|
|
prefs.remove("lessons");
|
|
prefs.remove("todayTImetable");
|
|
prefs.remove("tomorrowTimetable");
|
|
setState(() {
|
|
dropdownValue = newValue;
|
|
});
|
|
},
|
|
items: items.map<DropdownMenuItem<String>>((String value) {
|
|
return DropdownMenuItem<String>(
|
|
value: value,
|
|
child: Text(value),
|
|
);
|
|
}).toList(),
|
|
);
|
|
}
|
|
}
|