From 6ad143195ab91225412f6a349e6c26d8f1f1a271 Mon Sep 17 00:00:00 2001 From: Denys Konovalov Date: Sat, 6 Nov 2021 11:01:44 +0100 Subject: [PATCH] ==0.7.5== - added A LOT, TLTD Settings menu, updated homepage tiles, added color settings... - TODO: - update README - update license & copyright info - cleanup code - merge code parts to server side - complete settings - fix 11/12 - add caching - muuuuuuuch more... --- android/app/build.gradle | 2 +- lib/Settings/Pages/appearance_settings.dart | 23 ++ lib/Settings/Pages/dev_settings.dart | 57 ++++ lib/Settings/Pages/info_settings.dart | 75 +++++ lib/Settings/Pages/plan_settings.dart | 177 ++++++++++++ lib/Settings/Pages/service_settings.dart | 23 ++ lib/Settings/Pages/user_settings.dart | 68 +++++ lib/Settings/dashboard.dart | 100 +++++++ lib/color_presets.dart | 45 +++ lib/dashboard.dart | 301 ++++++++++++++------ lib/login.dart | 20 +- lib/main.dart | 2 +- lib/networking.dart | 179 +++++++++++- lib/schuelerzeitung.dart | 58 +++- lib/settings.dart | 65 ----- lib/subject_presets.dart | 33 +++ lib/teacher_presets.dart | 55 ++++ lib/timetable.dart | 242 +++++++--------- pubspec.yaml | 5 +- 19 files changed, 1213 insertions(+), 317 deletions(-) create mode 100644 lib/Settings/Pages/appearance_settings.dart create mode 100644 lib/Settings/Pages/dev_settings.dart create mode 100644 lib/Settings/Pages/info_settings.dart create mode 100644 lib/Settings/Pages/plan_settings.dart create mode 100644 lib/Settings/Pages/service_settings.dart create mode 100644 lib/Settings/Pages/user_settings.dart create mode 100644 lib/Settings/dashboard.dart create mode 100644 lib/color_presets.dart delete mode 100644 lib/settings.dart create mode 100644 lib/subject_presets.dart create mode 100644 lib/teacher_presets.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 55f22a9..26c5fa5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,7 +44,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "de.cantorgymnasium.meincantor" - minSdkVersion 16 + minSdkVersion 18 targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/lib/Settings/Pages/appearance_settings.dart b/lib/Settings/Pages/appearance_settings.dart new file mode 100644 index 0000000..1ef4a89 --- /dev/null +++ b/lib/Settings/Pages/appearance_settings.dart @@ -0,0 +1,23 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class AppearanceSettings extends StatelessWidget { + const AppearanceSettings({Key? key}) : super(key: key); + + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Aussehen"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), + children: [ + + ], + )); + } +} \ No newline at end of file diff --git a/lib/Settings/Pages/dev_settings.dart b/lib/Settings/Pages/dev_settings.dart new file mode 100644 index 0000000..1ef8f54 --- /dev/null +++ b/lib/Settings/Pages/dev_settings.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../login.dart'; + +class DevSettings extends StatelessWidget { + const DevSettings({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Entwickler-Einstellungen"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + child: TextField( + decoration: const InputDecoration( + icon: Icon(MdiIcons.keyOutline), + border: OutlineInputBorder(), + labelText: 'MeinCantor API-Schlüssel', + ), + onSubmitted: (String value) async { + SharedPreferences prefs = + await SharedPreferences.getInstance(); + String apiKey = value; + await prefs.setString('api_key', apiKey); + final snackBar = SnackBar( + content: Text('Neuer API-Schlüssel gesetzt: $apiKey')); + + // Find the ScaffoldMessenger in the widget tree + // and use it to show a SnackBar. + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); + })), + const Divider(), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + child: OutlinedButton( + onPressed: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => Login()), + ); + }, + child: const Text("Benutzerdaten neu laden"), + ) + ) + ], + )); + } +} \ No newline at end of file diff --git a/lib/Settings/Pages/info_settings.dart b/lib/Settings/Pages/info_settings.dart new file mode 100644 index 0000000..76358ca --- /dev/null +++ b/lib/Settings/Pages/info_settings.dart @@ -0,0 +1,75 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:MeinCantor/const.dart'; + +class InfoSettings extends StatelessWidget { + const InfoSettings({Key? key}) : super(key: key); + + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Informationen"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), + children: [ + const ListTile( + leading: Icon(Icons.info_outlined), + title: Text("Version"), + subtitle: Text(version) + ), + ListTile( + leading: const Icon(Icons.settings_backup_restore_outlined), + title: const Text("Änderungsverlauf"), + onTap: () { + showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: (BuildContext context) { + return Container( + height: 400, + //color: Colors.amber, + child: Column( + //mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + AppBar( + title: const Text("Änderungsverlauf"), + ), + const Padding( + padding: EdgeInsets.all(10), + child: Text(""), + ), + /*ElevatedButton( + child: const Text('Close BottomSheet'), + onPressed: () => Navigator.pop(context), + )*/ + ], + ), + ); + }, + ); + }, + ), + ListTile( + leading: const Icon(Icons.copyright_outlined), + title: const Text("Lizenzen"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => LicensePage( + applicationIcon: Image.asset("assets/images/meincantor_r.png", + height: 64, width: 64), + applicationVersion: version, + )), + ); + }, + ), + ], + )); + } +} \ No newline at end of file diff --git a/lib/Settings/Pages/plan_settings.dart b/lib/Settings/Pages/plan_settings.dart new file mode 100644 index 0000000..a4d3ac8 --- /dev/null +++ b/lib/Settings/Pages/plan_settings.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:MeinCantor/main.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:cyclop/cyclop.dart'; + +import 'package:MeinCantor/networking.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../color_presets.dart'; +import 'package:MeinCantor/subject_presets.dart'; + +import '../../teacher_presets.dart'; + +class PlanSettings extends StatefulWidget { + const PlanSettings({Key? key}) : super(key: key); + + @override + State createState() => _PlanSettingsState(); +} + +Future buildPlanColors(lesson) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (!prefs.containsKey("color$lesson")) { + prefs.setInt("color$lesson", colors[lesson].value ?? Colors.grey.value); + } + await fetchLessonList(); + Color colorDeu = Color(prefs.getInt("color$lesson")!); + return colorDeu; +} + +Future> buildLessonsList() async { + await fetchLessonList(); + SharedPreferences prefs = await SharedPreferences.getInstance(); + String lessonsJson = prefs.getString("lessons")!; + List lessons = jsonDecode(lessonsJson); + return lessons; +} + +class _PlanSettingsState extends State { + Set swatches = {...Colors.primaries, ...Colors.accents, Palette.accent, Palette.primary}; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Plan"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), + children: [ + const ListTile( + title: Text("Kurse/Fächer"), + leading: Icon(Icons.list_alt_outlined), + ), + FutureBuilder( + future: buildLessonsList(), + builder: (context, snapshot) { + if (snapshot.hasData) { + List children = []; + for (var element in (snapshot.data as List)) { + String subject = element['subject']; + String teacher = element['teacher']; + children.add(FutureBuilder( + future: buildPlanColors(subject), + builder: (context, snapshot) { + if (snapshot.hasData) { + Color color = snapshot.data as Color; + return ListTile( + leading: ColorButton( + key: const Key('c1'), + color: color, + config: const ColorPickerConfig( + enableEyePicker: false), + onSwatchesChanged: (Set value) { + swatches = value; + }, + size: 32, + swatches: swatches, + onColorChanged: (Color value) async { + setState(() { + color = value; + }); + SharedPreferences prefs = await SharedPreferences + .getInstance(); + prefs.setInt( + "color$subject", value.value); + } + ), + title: Text(names[subject] ?? ""), + subtitle: Text(teachers[teacher] ?? ""), + ); + } else { + return (const LinearProgressIndicator()); + } + } + ), + ); + } + return Column( + children: children, + ); + } else { + return (const Center( + child: CircularProgressIndicator())); + } + } + ), + /*FutureBuilder( + future: buildPlanColors("Mat"), + builder: (context, snapshot) { + if (snapshot.hasData) { + Color color = snapshot.data as Color; + return ListTile( + leading: ColorButton( + key: const Key('c1'), + color: color, + //boxShape: BoxShape.circle, // default : circle + config: const ColorPickerConfig(enableEyePicker: false), + onSwatchesChanged: (Set value) { + swatches = value; + }, + size: 32, + swatches: swatches, + onColorChanged: (Color value) async { + setState(() { + color = value; + }); + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setInt("colorMat", value.value); + } + ), + title: const Text("Mathematik"), + ); + } else { + return (const Center(child: CircularProgressIndicator())); + } + } + ), + FutureBuilder( + future: buildPlanColors("Bio"), + builder: (context, snapshot) { + if (snapshot.hasData) { + Color color = snapshot.data as Color; + return ListTile( + leading: ColorButton( + key: const Key('c1'), + color: color, + //boxShape: BoxShape.circle, // default : circle + config: const ColorPickerConfig(enableEyePicker: false), + onSwatchesChanged: (Set value) { + swatches = value; + }, + size: 32, + swatches: swatches, + onColorChanged: (Color value) async { + setState(() { + color = value; + }); + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setInt("colorBio", value.value); + } + ), + title: const Text("Biologie"), + ); + } else { + return (const Center(child: CircularProgressIndicator())); + } + } + ),*/ + ], + ) + ); + } +} \ No newline at end of file diff --git a/lib/Settings/Pages/service_settings.dart b/lib/Settings/Pages/service_settings.dart new file mode 100644 index 0000000..f7a43fd --- /dev/null +++ b/lib/Settings/Pages/service_settings.dart @@ -0,0 +1,23 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class ServiceSettings extends StatelessWidget { + const ServiceSettings({Key? key}) : super(key: key); + + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Dienste"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), + children: [ + + ], + )); + } +} \ No newline at end of file diff --git a/lib/Settings/Pages/user_settings.dart b/lib/Settings/Pages/user_settings.dart new file mode 100644 index 0000000..2e97080 --- /dev/null +++ b/lib/Settings/Pages/user_settings.dart @@ -0,0 +1,68 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:MeinCantor/networking.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +Future getSettingsString(String key) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? value = prefs.getString(key); + if (value == null || value.isEmpty) { + value = ""; + } + return value; +} + +class UserSettings extends StatelessWidget { + const UserSettings({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + + //TextEditingController nameController = TextEditingController(text: "Denys Konovalov"); + return Scaffold( + appBar: AppBar( + title: const Text("Benutzereinstellungen"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 10), + child: Container( + width: 128.0, + height: 128.0, + decoration: const BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + fit: BoxFit.scaleDown, + image: AssetImage("assets/images/meincantor_r.png") + ) + ) + ), + ), + FutureBuilder( + future: getSettingsString("name"), + builder: (context, snapshot) { + if (snapshot.hasData) { + return TextField( + decoration: const InputDecoration( + border: OutlineInputBorder(), + labelText: 'Name', + ), + readOnly: true, + controller: TextEditingController(text: snapshot.data as String), + ); + } else { + return (const Center(child: CircularProgressIndicator())); + } + } + ), + Padding( + padding: const EdgeInsets.fromLTRB(5, 20, 5, 5), + child: buildClassesChooser() + ), + ], + )); + } +} \ No newline at end of file diff --git a/lib/Settings/dashboard.dart b/lib/Settings/dashboard.dart new file mode 100644 index 0000000..fcf51ae --- /dev/null +++ b/lib/Settings/dashboard.dart @@ -0,0 +1,100 @@ +import 'package:MeinCantor/Settings/Pages/appearance_settings.dart'; +import 'package:MeinCantor/Settings/Pages/service_settings.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; + +import 'Pages/dev_settings.dart'; +import 'Pages/info_settings.dart'; +import 'Pages/plan_settings.dart'; +import 'Pages/user_settings.dart'; + +class Settings extends StatelessWidget { + const Settings({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Einstellungen"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(5, 5, 5, 5), + children: [ + ListTile( + leading: const Icon(MdiIcons.accountSettingsOutline, color: Colors.cyan), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + title: const Text("Benutzer"), + subtitle: const Text("Profilbild, Klasse & mehr"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const UserSettings()), + ); + }, + ), + ListTile( + leading: const Icon(MdiIcons.timetable, color: Colors.orangeAccent), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + title: const Text("Plan"), + subtitle: const Text("Kurse/Fächer, Farben & mehr"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const PlanSettings()), + ); + }, + ), + ListTile( + leading: const Icon(Icons.color_lens_outlined, color: Colors.pinkAccent), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + title: const Text("Aussehen"), + subtitle: const Text("Widgets, Design & mehr"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const AppearanceSettings()), + ); + }, + ), + ListTile( + leading: const Icon(MdiIcons.server, color: Colors.lightGreen), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + title: const Text("Dienste"), + subtitle: const Text("Konten, Plattformen & mehr"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const ServiceSettings()), + ); + }, + ), + ListTile( + leading: const Icon(Icons.developer_mode_outlined, color: Colors.deepOrangeAccent), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + title: const Text("Entwickleroptionen"), + subtitle: const Text("API, Benutzerdaten & mehr"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const DevSettings()), + ); + }, + ), + ListTile( + leading: const Icon(Icons.info_outlined, color: Colors.greenAccent), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + title: const Text("Informationen"), + subtitle: const Text("Version, Lizenzen & mehr"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const InfoSettings()), + ); + }, + ), + ], + )); + } +} \ No newline at end of file diff --git a/lib/color_presets.dart b/lib/color_presets.dart new file mode 100644 index 0000000..31634e2 --- /dev/null +++ b/lib/color_presets.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; + +dynamic colors = { + 'Bio': Colors.green, + 'Mat': Colors.indigo, + 'matL1': Colors.indigo, + 'matL2': Colors.indigo, + 'matL3': Colors.indigo, + 'Deu': Colors.red, + 'deu1': Colors.red, + 'deu2': Colors.red, + 'deu3': Colors.red, + 'Kun': Colors.deepPurple, + 'kun1': Colors.deepPurple, + 'kun2': Colors.deepPurple, + 'kun3': Colors.deepPurple, + 'Geo': Colors.brown, + 'Lat': Colors.teal, + 'lat1': Colors.teal, + 'lat2': Colors.teal, + 'lat3': Colors.teal, + 'Che': Colors.lightGreen, + 'Eng': Colors.amber, + 'eng1': Colors.amber, + 'eng2': Colors.amber, + 'eng3': Colors.amber, + 'Phy': Colors.cyan, + 'phy1': Colors.cyan, + 'phy2': Colors.cyan, + 'phy3': Colors.cyan, + 'Inf': Colors.tealAccent[400], + 'Mus': Colors.deepOrange, + 'mus1': Colors.deepOrange, + 'mus2': Colors.deepOrange, + 'mus3': Colors.deepOrange, + 'Lme': Colors.amber[700], + 'Ges': Colors.grey, + 'ges1': Colors.grey, + 'ges2': Colors.grey, + 'ges3': Colors.grey, + 'Spa': Colors.redAccent, + 'Frz': Colors.amberAccent[700], + 'frz1': Colors.amberAccent[700], + '---': Colors.white +}; \ No newline at end of file diff --git a/lib/dashboard.dart b/lib/dashboard.dart index 72130ae..f12c111 100644 --- a/lib/dashboard.dart +++ b/lib/dashboard.dart @@ -7,10 +7,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'settings.dart'; +import 'Settings/dashboard.dart'; +// import 'settings.dart'; +import 'main.dart'; import 'networking.dart'; import 'login.dart'; import 'schuelerzeitung.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; class Dashboard extends StatefulWidget { const Dashboard({Key? key, this.restorationId}) : super(key: key); @@ -31,7 +34,7 @@ Future getSettingsString(String key) async { return value; } -Widget buildSettingsString(String key, TextStyle style) { +Widget buildSettingsString(String key, TextStyle? style) { return FutureBuilder( future: getSettingsString(key), builder: (context, snapshot) { @@ -52,9 +55,10 @@ class _DashboardState extends State with RestorationMixin { UserAccountsDrawerHeader( accountName: buildSettingsString('name', const TextStyle()), accountEmail: buildSettingsString('user', const TextStyle()), - currentAccountPicture: const CircularProgressIndicator( + currentAccountPicture: Image.asset("assets/images/meincantor_r.png") + /*const CircularProgressIndicator( backgroundColor: Colors.black, - ), + ),*/ ), ListTile( title: const Text("Einstellungen"), @@ -64,7 +68,7 @@ class _DashboardState extends State with RestorationMixin { MaterialPageRoute(builder: (context) => Settings()), ); }, - leading: const Icon(CupertinoIcons.settings), + leading: const Icon(Icons.settings_outlined), ), ListTile( title: const Text("Abmelden"), @@ -78,31 +82,20 @@ class _DashboardState extends State with RestorationMixin { }, leading: const Icon(Icons.exit_to_app_outlined), ), - AboutListTile( - child: const Text("Info"), - icon: const Icon(CupertinoIcons.info), - applicationVersion: "0.6.5-alpha", - applicationIcon: Image.asset("assets/images/meincantor_r.png", - height: 64, width: 64), - applicationName: "MeinCantor", - aboutBoxChildren: const [ - Text( - "MeinCantor ist die Schulplatform für Schüler des Georg-Cantor-Gymnasiums in Halle (Saale)."), - Divider(), - Text("Copyright © 2021 Denys Konovalov") - ], - // applicationIcon: Image., - ), ], ); var bottomNavBarItems = [ const BottomNavigationBarItem( - icon: Icon(CupertinoIcons.home), + icon: Icon(MdiIcons.homeOutline), label: "Startseite", ), const BottomNavigationBarItem( - icon: Icon(CupertinoIcons.rectangle_grid_1x2), + icon: Icon(MdiIcons.timetable), label: "Vertretungsplan"), + const BottomNavigationBarItem( + icon: Icon(Icons.notifications_outlined), + label: "Hinweise" + ), ]; return Scaffold( appBar: AppBar( @@ -256,13 +249,159 @@ class _DashboardBottomNavView extends StatelessWidget { padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), child: buildTodayClassTimetableLesson(lessonCount), ), - Row(mainAxisSize: MainAxisSize.max, children: [ - Expanded( - child: Padding( + Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), - child: Column( + child: Wrap( children: [ - GestureDetector( + SizedBox( + child: GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SZ()), + ); + }, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: const Padding( + padding: EdgeInsets.all(10), + child: ListTile( + title: Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 10), + child: Icon( + MdiIcons.newspaper, + color: Palette.accent, + size: 48, + ), + ), + subtitle: Center( + child: Padding( + padding: EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Text( + 'Schülerzeitung', + ), + ), + ), + ), + ) + ), + ), + width: 175, + ), + SizedBox( + width: 175, + child: GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SB()), + ); + }, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: const Padding( + padding: EdgeInsets.all(10), + child: ListTile( + title: Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 10), + child: Icon( + MdiIcons.libraryShelves, + color: Palette.accent, + size: 48, + ), + ), + subtitle: Center( + child: Padding( + padding: EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Text( + 'Schulbibliothek', + ), + ), + ), + ), + ) + ), + ), + ), + SizedBox( + width: 175, + child: GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SC()), + ); + }, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: const Padding( + padding: EdgeInsets.all(10), + child: ListTile( + title: Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 10), + child: Icon( + MdiIcons.laptop, + color: Palette.accent, + size: 48, + ), + ), + subtitle: Center( + child: Padding( + padding: EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Text( + 'Schulcomputer', + ), + ), + ), + ), + ) + ), + ), + ), + SizedBox( + width: 175, + child: GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const RoomOverview()), + ); + }, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: const Padding( + padding: EdgeInsets.all(10), + child: ListTile( + title: Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 10), + child: Icon( + MdiIcons.door, + color: Palette.accent, + size: 48, + ), + ), + subtitle: Center( + child: Padding( + padding: EdgeInsets.fromLTRB(0, 10, 0, 0), + child: Text( + 'Raumübersicht', + ), + ), + ), + ), + ) + ), + ), + ) + /*GestureDetector( onTap: () async { Navigator.push( context, @@ -276,27 +415,28 @@ class _DashboardBottomNavView extends StatelessWidget { ), child: Column( mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, children: [ Row( - mainAxisSize: MainAxisSize.max, + //mainAxisSize: MainAxisSize.max, children: const [ Padding( - padding: EdgeInsets.fromLTRB(20, 20, 10, 10), + padding: EdgeInsets.fromLTRB(20, 20, 20, 10), child: Icon( - CupertinoIcons.news, - color: Color(0xFFFFBC3B), + MdiIcons.newspaper, + color: Palette.accent, size: 48, ), ) ], ), Row( - mainAxisSize: MainAxisSize.max, + //mainAxisSize: MainAxisSize.max, children: const [ Align( alignment: Alignment(0, 0), child: Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), + padding: EdgeInsets.fromLTRB(15, 50, 15, 15), child: Text( 'Schülerzeitung', ), @@ -320,35 +460,37 @@ class _DashboardBottomNavView extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Row( - mainAxisSize: MainAxisSize.max, - children: const [ - Padding( - padding: EdgeInsets.fromLTRB(20, 20, 10, 10), - child: Icon( - CupertinoIcons.book, - color: Color(0xFFFFBC3B), - size: 48, - ), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: const [ - Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), - child: Text( - 'Schulbibliothek', - ), - ) - ], - ) - ], - ), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: const [ + Padding( + padding: EdgeInsets.fromLTRB(20, 20, 20, 10), + child: Icon( + MdiIcons.libraryShelves, + color: Color(0xFFFFBC3B), + size: 48, + ), + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.max, + children: const [ + Padding( + padding: EdgeInsets.fromLTRB(15, 50, 15, 15), + child: Text( + 'Schulbibliothek', + ), + ) + ], + ) + ], + ), + ) ), ), GestureDetector( @@ -370,9 +512,9 @@ class _DashboardBottomNavView extends StatelessWidget { mainAxisSize: MainAxisSize.max, children: const [ Padding( - padding: EdgeInsets.fromLTRB(20, 20, 10, 10), + padding: EdgeInsets.fromLTRB(20, 20, 20, 10), child: Icon( - CupertinoIcons.device_laptop, + MdiIcons.laptop, color: Color(0xFFFFBC3B), size: 48, ), @@ -383,7 +525,7 @@ class _DashboardBottomNavView extends StatelessWidget { mainAxisSize: MainAxisSize.max, children: const [ Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), + padding: EdgeInsets.fromLTRB(15, 50, 15, 15), child: Text( 'Schulcomputer', ), @@ -413,9 +555,9 @@ class _DashboardBottomNavView extends StatelessWidget { mainAxisSize: MainAxisSize.max, children: const [ Padding( - padding: EdgeInsets.fromLTRB(20, 20, 10, 10), + padding: EdgeInsets.fromLTRB(20, 20, 20, 10), child: Icon( - CupertinoIcons.house_alt, + MdiIcons.door, color: Color(0xFFFFBC3B), size: 48, ), @@ -426,7 +568,7 @@ class _DashboardBottomNavView extends StatelessWidget { mainAxisSize: MainAxisSize.max, children: const [ Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), + padding: EdgeInsets.fromLTRB(15, 50, 15, 15), child: Text( 'Raumübersicht', ), @@ -436,14 +578,12 @@ class _DashboardBottomNavView extends StatelessWidget { ], ), ), - ), + ),*/ ], ), ), - ) ]), - ], - )); + ); return view; } else if (item.label == "Vertretungsplan") { return LayoutBuilder(builder: (context, constraints) { @@ -471,7 +611,7 @@ class _DashboardBottomNavView extends StatelessWidget { ), child: DefaultTabController( initialIndex: 0, - length: 2, + length: 3, child: Scaffold( appBar: AppBar( elevation: 0, @@ -481,6 +621,10 @@ class _DashboardBottomNavView extends StatelessWidget { text: "Heute", icon: Icon(CupertinoIcons.calendar_today), ), + Tab( + text: "Morgen", + icon: Icon(CupertinoIcons.calendar_today), + ), Tab( text: "Neuster Plan", icon: Icon(CupertinoIcons.calendar), @@ -495,12 +639,8 @@ class _DashboardBottomNavView extends StatelessWidget { body: TabBarView( children: [ buildTodayClassTimetable(), + buildTomorrowClassTimetable(), buildClassTimetable(), - /* - Center( - child: Text("It's sunny here"), - ), - */ ], ), ), @@ -509,8 +649,7 @@ class _DashboardBottomNavView extends StatelessWidget { ); }); } else { - return const Text("Such page does not exist."); + return const Center(child: Text("Derzeit nichts hier...")); } - // return materialCard(item.label); } -} +} \ No newline at end of file diff --git a/lib/login.dart b/lib/login.dart index a9e823b..4645f46 100644 --- a/lib/login.dart +++ b/lib/login.dart @@ -24,7 +24,7 @@ class Login extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { double widgetWidth = constraints.maxWidth; - double widgetHeight = constraints.maxHeight; + //double widgetHeight = constraints.maxHeight; var factor; if (widgetWidth <= 600) { @@ -93,7 +93,7 @@ class Login extends StatelessWidget { obscureText: true, controller: otpController, ), - const Divider(), + /*const Divider(), TextField( decoration: const InputDecoration( icon: Icon(CupertinoIcons.device_laptop), @@ -101,7 +101,7 @@ class Login extends StatelessWidget { labelText: 'Gerätebezeichnung', ), controller: devIdController, - ), + ),*/ const Divider(), OutlinedButton( onPressed: () async { @@ -146,12 +146,14 @@ class Login extends StatelessWidget { prefs .getString('api_key')! .isNotEmpty) { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => - const Dashboard()), - ); + Future.delayed(Duration.zero, () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => + const Dashboard()), + ); + }); } }, child: const Text("Anmelden")) diff --git a/lib/main.dart b/lib/main.dart index 3bc1b69..be35f69 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -46,7 +46,7 @@ class App extends StatelessWidget { ), ), darkTheme: ThemeData.from( - colorScheme: const ColorScheme.dark(primary: Palette.accent)), + colorScheme: const ColorScheme.dark(primary: Palette.accent, secondary: Palette.accent)), title: "GCG.MeinCantor", home: buildHomePage(), ); diff --git a/lib/networking.dart b/lib/networking.dart index fae2991..7bd0f8b 100644 --- a/lib/networking.dart +++ b/lib/networking.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/painting.dart'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -68,6 +69,45 @@ Future fetchTodayClassTimetable() async { return response; } +Future fetchTomorrowClassTimetable() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String classNum; + print(prefs.getString('class_num')); + 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/timetable/$classNum/tomorrow"); + var headers = {"x-api-key": "$apiKey"}; + print(uri); + final response = http.get(uri, headers: headers).onError((error, stackTrace) { return(http.Response("", 404)); } ); + return response; +} + +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 buildClassTimetable() { return FutureBuilder( future: fetchClassTimetable(), @@ -75,9 +115,9 @@ Widget buildClassTimetable() { if (snapshot.hasData) { int statusCode = snapshot.data!.statusCode; if (statusCode == 200) { - ListView timetableView = ClassTimetableBuilder.buildView( - jsonDecode(utf8.decode(snapshot.data!.bodyBytes))) - .view; + Widget timetableView = ClassTimetableBuilder.buildView( + jsonDecode(utf8.decode(snapshot.data!.bodyBytes)), context) + .view.child; return timetableView; } else if (statusCode == 400) { Navigator.pushReplacement( @@ -110,18 +150,93 @@ Widget buildTodayClassTimetable() { if (snapshot.hasData) { int statusCode = snapshot.data!.statusCode; if (statusCode == 200) { - ListView timetableView = ClassTimetableBuilder.buildView( - jsonDecode(utf8.decode(snapshot.data!.bodyBytes))) - .view; + Widget timetableView = ClassTimetableBuilder.buildView( + jsonDecode(utf8.decode(snapshot.data!.bodyBytes)), 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 Vertretungsplan für heute gefunden werden. \u{1F937}'); + List 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: EdgeInsets.fromLTRB(20, 20, 20, 20), + child: ListView( + children: [card], + ) + ); + } else if (statusCode == 404) { return const Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), - child: Center(child: Text("Es konnte kein Vertretungsplan für heute gefunden werden.")), + 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 Center(child: Text('Error $statusCode')); + } else if (snapshot.hasError) { + return Text('$snapshot.error'); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ); +} + +Widget buildTomorrowClassTimetable() { + return FutureBuilder( + future: fetchTomorrowClassTimetable(), + builder: (context, snapshot) { + if (snapshot.hasData) { + int statusCode = snapshot.data!.statusCode; + if (statusCode == 200) { + Widget timetableView = ClassTimetableBuilder.buildView( + jsonDecode(utf8.decode(snapshot.data!.bodyBytes)), 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 Vertretungsplan für morgen gefunden werden. \u{1F937}'); + List 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: EdgeInsets.fromLTRB(20, 20, 20, 20), + child: ListView( + children: [card], + ) + ); + /*return const Padding( + padding: EdgeInsets.fromLTRB(10, 10, 10, 10), + child: Center(child: Text("Es konnte kein Vertretungsplan für heute gefunden werden.")), + );*/ } else if (statusCode == 404) { return const Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), @@ -153,10 +268,25 @@ Widget buildClassTimetableLesson(int count) { Navigator.push( context, MaterialPageRoute(builder: (context) => Login())); } else if (statusCode == 500) { - return const Padding( + var chars = Runes('Es konnte kein Vertretungsplan für gefunden werden. \u{1F937}'); + List 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; + /*return const Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: Center(child: Text("Es konnte kein Vertretungsplan gefunden werden.")), - ); + );*/ } else if (statusCode == 404) { return const Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), @@ -203,13 +333,34 @@ Widget buildTodayClassTimetableLesson(int count) { return card; } } else if (statusCode == 400) { - Navigator.push( - context, MaterialPageRoute(builder: (context) => Login())); + Future.delayed(Duration.zero, () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + Login()), + ); + }); } else if (statusCode == 500) { - return const Padding( + var chars = Runes('Es konnte kein Vertretungsplan für heute gefunden werden. \u{1F937}'); + List 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; + /*return const Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), child: Center(child: Text("Es konnte kein Vertretungsplan für heute gefunden werden.")), - ); + );*/ } else if (statusCode == 404) { return const Padding( padding: EdgeInsets.fromLTRB(10, 10, 10, 10), @@ -304,7 +455,7 @@ class _ClassesChooserState extends State { return DropdownButtonFormField( value: dropdownValue, decoration: const InputDecoration( - icon: Icon(CupertinoIcons.number), + icon: Icon(Icons.people_outline), border: OutlineInputBorder(), labelText: 'Klasse (05/1, 07/3, 10/2...)', ), diff --git a/lib/schuelerzeitung.dart b/lib/schuelerzeitung.dart index 643f792..22c04e5 100644 --- a/lib/schuelerzeitung.dart +++ b/lib/schuelerzeitung.dart @@ -11,8 +11,64 @@ class SZ extends StatelessWidget { title: const Text("Schülerzeitung"), centerTitle: true, ), - body: const Center( + body: ListView( + children: [ + Card( + child: Column(children: [ + Padding( + padding: EdgeInsets.fromLTRB(10, 10, 10, 10), + child: ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => Article()), + ); + }, + title: const Text( + "Schülersprecherwahl 2021: Kandidatenduos im Interview", + style: TextStyle(fontWeight: FontWeight.bold)), + subtitle: const Text( + "17.09.2021, Halle(Saale) Drei Trios stellen sich dieses Jahr zur Wahl...")), + ) + ]), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + ) + ], + ) + /*const Center( child: Text("Derzeit nichts hier..."), + )*/ + + ); + } +} + +class Article extends StatelessWidget { + const Article({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text( + "Schülersprecherwahl 2021: Kandidatenduos im Interview"), + centerTitle: true, + ), + body: ListView( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), + children: const [ + Text(""" + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + + Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. + + Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + + Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer + """) + ], )); } } diff --git a/lib/settings.dart b/lib/settings.dart deleted file mode 100644 index 494ff3a..0000000 --- a/lib/settings.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'networking.dart'; - -class Settings extends StatelessWidget { - const Settings({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text("Einstellungen"), - centerTitle: true, - ), - body: ListView( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), - children: [ - const ListTile( - leading: Icon(CupertinoIcons.rectangle_grid_1x2), - title: Text("Plan")), - /* - Padding( - padding: EdgeInsets.fromLTRB(0, 0, 0, 0), - child: TextField( - decoration: InputDecoration( - icon: Icon(CupertinoIcons.lock), - border: OutlineInputBorder(), - labelText: 'API Key (POST /login)', - ), - onSubmitted: (String value) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - String api_key = value; - print('Set new API key to $api_key'); - await prefs.setString('api_key', api_key); - } - ) - ), - */ - const Divider(), - buildClassesChooser(), - const Divider(), - const ListTile( - leading: Icon(Icons.code), title: Text("Entwickleroptionen")), - const Divider(), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), - child: TextField( - decoration: const InputDecoration( - icon: Icon(CupertinoIcons.lock), - border: OutlineInputBorder(), - labelText: 'API Key (POST /login)', - ), - onSubmitted: (String value) async { - SharedPreferences prefs = - await SharedPreferences.getInstance(); - String apiKey = value; - print('Set new API key to $apiKey'); - await prefs.setString('api_key', apiKey); - })), - const Divider(), - ], - )); - } -} diff --git a/lib/subject_presets.dart b/lib/subject_presets.dart new file mode 100644 index 0000000..fd197aa --- /dev/null +++ b/lib/subject_presets.dart @@ -0,0 +1,33 @@ +dynamic names = { + 'Bio': 'Biologie', + 'Mat': 'Mathematik', + 'matL1': 'Mathematik Leistungskurs 1', + 'Kun': 'Kunst', + 'Mus': 'Musik', + 'Geo': 'Geographie', + 'Ges': 'Geschichte', + 'Che': 'Chemie', + 'Lat': 'Latein', + 'Inf': 'Informatik', + 'Eng': 'Englisch', + 'Frz': 'Französisch', + 'frz1': 'Französisch 1', + 'frz2': 'Französisch 2', + 'frz3': 'Französisch 3', + 'Phy': 'Physik', + '---': '---', + 'Spo': 'Sport', + 'Deu': 'Deutsch', + 'deu1': 'Deutsch 1', + 'deu2': 'Deutsch 2', + 'deu3': 'Deutsch 3', + 'Lme': 'Lernmethoden', + 'Eth': 'Ethik', + 'EvR': 'Evangelische Religion', + 'Soz': 'Sozialkunde', + 'Ast': 'Astronomie', + 'Spa': 'Spanisch', + 'FK': 'Fachkurs', + 'JIA': 'Junior-Ingenieur-Akademie', + 'WoU': 'Wahlobligatorischer Unterricht' +}; \ No newline at end of file diff --git a/lib/teacher_presets.dart b/lib/teacher_presets.dart new file mode 100644 index 0000000..af340b7 --- /dev/null +++ b/lib/teacher_presets.dart @@ -0,0 +1,55 @@ +dynamic teachers = { + 'Poli': 'Herr Polity', + 'Zura': 'Frau Zuralski', + 'Enzi': 'Frau Enzian', + 'Bütt': 'Frau Büttner', + 'Brod': 'Herr Brode', + 'Rink': 'Frau Rinke', + 'Schk': 'Frau Schmidt', + 'Rudo': 'Frau Rudolph', + 'Kipp': 'Frau Kipping', + 'Bach': 'Frau Bachran', + 'Bad': 'Herr Bader', + 'Prei': 'Frau Preiß', + 'Scha': 'Frau Schapitz', + ' ': '', + 'Link': 'Herr Linke', + 'Stei': 'Herr Stein', + 'Tupp': 'Frau Tuppack', + 'Hoff': 'Frau Hoffman', + 'Knol': 'Frau Knoll', + 'Bet': 'Frau Bethin', + 'Schu': 'Frau Schulz', + 'Seid': 'Frau Seidel', + 'Krug': 'Frau Krug', + 'Laer': 'Frau Langer', + 'Youn': 'Frau Younso', + 'Härt': 'Frau Härtig', + 'Bros': 'Frau Brosig', + 'Ber': 'Frau Bernhardt', + 'Stüb': 'Frau Stüber', + 'Bor': 'Frau Borchert', + 'Dubb': 'Frau Dubberstein', + 'Tren': 'Frau Trentsch', + 'Meit': 'Herr Meitzner', + 'Stol': 'Frau Stolpe', + 'Jac': 'Frau Jacob', + 'Jüne': 'Herr Jünemann', + 'Bert': 'Frau Berthelmann', + 'Felk': 'Frau Felke', + 'Kimm': 'Herr Kimmel', + 'PM1': 'Pädagosische(r) Mitarbeiter(in) 1', + 'Schet': 'Herr Schettler', + 'Mani': 'Herr Manigk', + 'Segg': 'Frau von Seggern', + 'Opel': 'Frau Opel-Fritzler', + 'Möll': 'Frau Möller', + 'Laen': 'Herr Langen', + 'Plin': 'Herr Plinke', + 'Koch': 'Herr Koch', + 'Gors': 'Herr Gorsler', + 'Krau': 'Herr Krause', + 'Henk': 'Frau Henke', + 'Wolf': 'Herr Wolf', + 'Gitt': 'Herr Gitter', +}; \ No newline at end of file diff --git a/lib/timetable.dart b/lib/timetable.dart index 7120767..6d74b9f 100644 --- a/lib/timetable.dart +++ b/lib/timetable.dart @@ -1,17 +1,82 @@ +import 'package:MeinCantor/teacher_presets.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'subject_presets.dart'; + +import 'color_presets.dart'; class ClassTimetableBuilder { - final ListView view; + final RefreshIndicator view; ClassTimetableBuilder({required this.view}); - factory ClassTimetableBuilder.buildView(Map json) { + factory ClassTimetableBuilder.buildView(Map json, BuildContext context) { + List list = LessonsListBuilder.buildList(json).lessons; + String info = TimetableInfo.fromJson(json).info; + if(info.isNotEmpty) { + list.insert(0, ListTile(title: Text("Informationen"), leading: Icon(MdiIcons.information), onTap: () { + showModalBottomSheet( + isScrollControlled: true, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(25.0), + ), + context: context, + builder: (BuildContext context) { + return Container( + height: 400, + child: ListView( + //mainAxisAlignment: MainAxisAlignment.center, + //mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: Text("Informationen", style: TextStyle(fontWeight: FontWeight.bold)), + leading: Icon(Icons.arrow_back), + onTap: () { + Navigator.of(context).pop(); + }, + ), + Padding( + padding: const EdgeInsets.all(20), + child: Text(info), + ), + /*ElevatedButton( + child: const Text('Close BottomSheet'), + onPressed: () => Navigator.pop(context), + )*/ + ], + ), + ); + }, + ); + }, + ) + ); + } return ClassTimetableBuilder( - view: ListView( + view: RefreshIndicator( + onRefresh: () { + return Future.delayed(const Duration(seconds: 1)); + }, + child: ListView( + //shrinkWrap: true, physics: const AlwaysScrollableScrollPhysics(), - children: LessonsListBuilder.buildList(json).lessons)); + children: list, + ), + ) + ); } } +Future buildLessonColor(String lesson) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (!prefs.containsKey("color$lesson")) { + Color lessonPresetColor = colors[lesson] ?? Colors.grey[700]; + prefs.setInt("color$lesson", lessonPresetColor.value); + } + Color lessonColor = Color(prefs.getInt("color$lesson")!); + return lessonColor; +} + class LessonsListBuilder { final List lessons; LessonsListBuilder({required this.lessons}); @@ -21,7 +86,6 @@ class LessonsListBuilder { List cardChildren = []; print(element.count.toString() + " " + count.toString()); if (element.count.toString() == count.toString() || count == 0) { - print("teeee"); cardChildren.add(ListTile( title: Text(element.count.toString() + '.' + ' ' + element.name, style: TextStyle(color: element.fontColor)), @@ -40,14 +104,23 @@ class LessonsListBuilder { title: Text(element.info, style: TextStyle(color: element.fontColor)))); } - Card card = Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), - ), - color: element.color, - child: Column( - children: cardChildren, - )); + Widget card = FutureBuilder( + future: element.color, + builder: (context, snapshot) { + if (snapshot.hasData) { + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + color: snapshot.data as Color, + child: Column( + children: cardChildren, + )); + } else { + return (const Center(child: CircularProgressIndicator())); + } + }, + ); children.add(card); } }); @@ -55,6 +128,14 @@ class LessonsListBuilder { } } +class TimetableInfo { + final String info; + TimetableInfo({required this.info}); + factory TimetableInfo.fromJson(Map json) { + return TimetableInfo(info: json['info']); + } +} + class ClassTimetable { final List timetable; ClassTimetable({required this.timetable}); @@ -65,60 +146,7 @@ class ClassTimetable { var name; var teacher; var room; - dynamic teachers = { - 'Poli': 'Herr Polity', - 'Zura': 'Frau Zuralski', - 'Enzi': 'Frau Enzian', - 'Bütt': 'Frau Büttner', - 'Brod': 'Herr Brode', - 'Rink': 'Frau Rinke', - 'Schk': 'Frau Schmidt', - 'Rudo': 'Frau Rudolph', - 'Kipp': 'Frau Kipping', - 'Bach': 'Frau Bachran', - 'Bad': 'Herr Bader', - 'Prei': 'Frau Preiß', - 'Scha': 'Frau Schapitz', - ' ': '', - 'Link': 'Herr Linke', - 'Stei': 'Herr Stein', - 'Tupp': 'Frau Tuppack', - 'Hoff': 'Frau Hoffman', - 'Knol': 'Frau Knoll', - 'Bet': 'Frau Bethin', - 'Schu': 'Frau Schulz', - 'Seid': 'Frau Seidel', - 'Krug': 'Frau Krug', - 'Laer': 'Frau Langer', - 'Youn': 'Frau Younso', - 'Härt': 'Frau Härtig', - 'Bros': 'Frau Brosig', - 'Ber': 'Frau Bernhardt', - 'Stüb': 'Frau Stüber', - 'Bor': 'Frau Borchert', - 'Dubb': 'Frau Dubberstein', - 'Tren': 'Frau Trentsch', - 'Meit': 'Herr Meitzner', - 'Stol': 'Frau Stolpe', - 'Jac': 'Frau Jacob', - 'Jüne': 'Herr Jünemann', - 'Bert': 'Frau Berthelmann', - 'Felk': 'Frau Felke', - 'Kimm': 'Herr Kimmel', - 'PM1': 'Pädagosische(r) Mitarbeiter(in) 1', - 'Schet': 'Herr Schetler', - 'Mani': 'Herr Manigk', - 'Segg': 'Frau Seggern', - 'Opel': 'Frau Opel-Fritzler', - 'Möll': 'Frau Möller', - 'Laen': 'Herr Langen', - 'Plin': 'Herr Plinke', - 'Koch': 'Herr Koch', - 'Gors': 'Herr Gorsler', - 'Krau': 'Herr Krause', - 'Henk': 'Frau Henke', - 'Wolf': 'Herr Wolf' - }; + if (value['Fa'].runtimeType != String) { name = value['Fa']['#text']; } else { @@ -156,81 +184,7 @@ class ClassTimetable { info = value['If']; } - dynamic colors = { - 'Bio': Colors.green, - 'Mat': Colors.indigo, - 'matL1': Colors.indigo, - 'matL2': Colors.indigo, - 'matL3': Colors.indigo, - 'Deu': Colors.red, - 'deu1': Colors.red, - 'deu2': Colors.red, - 'deu3': Colors.red, - 'Kun': Colors.deepPurple, - 'kun1': Colors.deepPurple, - 'kun2': Colors.deepPurple, - 'kun3': Colors.deepPurple, - 'Geo': Colors.brown, - 'Lat': Colors.teal, - 'lat1': Colors.teal, - 'lat2': Colors.teal, - 'lat3': Colors.teal, - 'Che': Colors.lightGreen, - 'Eng': Colors.amber, - 'eng1': Colors.amber, - 'eng2': Colors.amber, - 'eng3': Colors.amber, - 'Phy': Colors.cyan, - 'phy1': Colors.cyan, - 'phy2': Colors.cyan, - 'phy3': Colors.cyan, - 'Inf': Colors.tealAccent[400], - 'Mus': Colors.deepOrange, - 'mus1': Colors.deepOrange, - 'mus2': Colors.deepOrange, - 'mus3': Colors.deepOrange, - 'Lme': Colors.amber[700], - 'Ges': Colors.grey, - 'ges1': Colors.grey, - 'ges2': Colors.grey, - 'ges3': Colors.grey, - 'Spa': Colors.redAccent, - 'Frz': Colors.amberAccent[700], - 'frz1': Colors.amberAccent[700], - '---': Colors.white - }; - - dynamic names = { - 'Bio': 'Biologie', - 'Mat': 'Mathematik', - 'matL1': 'Mathematik Leistungskurs 1', - 'Kun': 'Kunst', - 'Mus': 'Musik', - 'Geo': 'Geographie', - 'Ges': 'Geschichte', - 'Che': 'Chemie', - 'Lat': 'Latein', - 'Inf': 'Informatik', - 'Eng': 'Englisch', - 'Frz': 'Französisch', - 'frz1': 'Französisch 1', - 'Phy': 'Physik', - '---': '---', - 'Spo': 'Sport', - 'Deu': 'Deutsch', - 'deu1': 'Deutsch 1', - 'deu2': 'Deutsch 2', - 'deu3': 'Deutsch 3', - 'Lme': 'Lernmethoden', - 'Eth': 'Ethik', - 'EvR': 'Evangelische Religion', - 'Soz': 'Sozialkunde', - 'Ast': 'Astronomie', - 'Spa': 'Spanisch', - 'FK': 'Fachkurs', - 'JIA': 'Junior-Ingenieur-Akademie', - 'WoU': 'Wahlobligatorischer Unterricht' - }; + Future lessonColor = buildLessonColor(name); lessons.add(TimetableLesson( value['St'], @@ -238,7 +192,7 @@ class ClassTimetable { teachers[teacher] ?? teacher.toString(), room.toString(), value['If'].toString(), - colors[name] ?? Colors.grey[700], + lessonColor, fontColor, info)); }); @@ -253,7 +207,7 @@ class TimetableLesson { final String teacher; final String room; final String comment; - final Color color; + final Future color; final Color fontColor; final String info; const TimetableLesson(this.count, this.name, this.teacher, this.room, diff --git a/pubspec.yaml b/pubspec.yaml index fdbb26f..3f5c16d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.6.5-alpha +version: 0.7.5-beta1.nightly2021-11-04 environment: sdk: ">=2.12.0 <3.0.0" @@ -38,6 +38,9 @@ dependencies: time: ^2.0.0 flutter_launcher_icons: "^0.9.1" fluttertoast: ^8.0.8 + flutter_colorpicker: ^0.6.0 + material_design_icons_flutter: 5.0.5955-rc.1 + cyclop: ^0.5.2 flutter_icons: # image_path: "assets/images/icon-128x128.png"