From bae624dd67ba2b7efbe79ea537ac941049b419d2 Mon Sep 17 00:00:00 2001 From: Denys Konovalov Date: Tue, 14 Sep 2021 20:55:58 +0200 Subject: [PATCH] ==0.6.5== - added A LOT, TLTD - TODO: - update README - update license & copyright info - cleanup code - merge code parts to server side - add more settings - fix 11/12 - add more timetable options - add timetable additional info - muuuuuuuch more... --- lib/Dashboard.dart | 414 -------------- lib/Settings.dart | 38 -- lib/Timetable.dart | 174 ------ lib/dashboard.dart | 516 ++++++++++++++++++ lib/generated_plugin_registrant.dart | 1 + lib/{Login.dart => login.dart} | 93 ++-- lib/main.dart | 51 +- lib/networking.dart | 274 +++++++--- lib/raumuebersicht.dart | 18 + lib/schuelerzeitung.dart | 18 + lib/schulbibliothek.dart | 18 + lib/schulcomputer.dart | 18 + lib/settings.dart | 65 +++ lib/timetable.dart | 261 +++++++++ linux/flutter/generated_plugin_registrant.cc | 2 + linux/flutter/generated_plugin_registrant.h | 2 + pubspec.yaml | 2 +- .../flutter/generated_plugin_registrant.cc | 2 + windows/flutter/generated_plugin_registrant.h | 2 + 19 files changed, 1207 insertions(+), 762 deletions(-) delete mode 100644 lib/Dashboard.dart delete mode 100644 lib/Settings.dart delete mode 100644 lib/Timetable.dart create mode 100644 lib/dashboard.dart rename lib/{Login.dart => login.dart} (58%) create mode 100644 lib/raumuebersicht.dart create mode 100644 lib/schuelerzeitung.dart create mode 100644 lib/schulbibliothek.dart create mode 100644 lib/schulcomputer.dart create mode 100644 lib/settings.dart create mode 100644 lib/timetable.dart diff --git a/lib/Dashboard.dart b/lib/Dashboard.dart deleted file mode 100644 index 0d3889a..0000000 --- a/lib/Dashboard.dart +++ /dev/null @@ -1,414 +0,0 @@ -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 'networking.dart'; -import 'Login.dart'; - -class Dashboard extends StatefulWidget { - const Dashboard({ - Key? key, - this.restorationId - }): super(key: key); - - final String? restorationId; - - @override - State createState() => _DashboardState(); -} - -Future getSettingsString(String key) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - String? value = await prefs.getString(key); - if(value == null || value.isEmpty) { - value = ""; - } - print(value); - return value; -} - -Widget buildSettingsString(String key, TextStyle style) { - return FutureBuilder( - future: getSettingsString(key), - builder: (context, snapshot) { - if(snapshot.hasData) { - return Text(snapshot.data as String, style: style); - } else { - return(Center(child: CircularProgressIndicator())); - } - } - ); -} - -class _DashboardState extends State with RestorationMixin { - final RestorableInt _currentIndex = RestorableInt(0); - @override - Widget build(BuildContext context) { - final drawerElements = ListView( - children: [ - UserAccountsDrawerHeader( - accountName: buildSettingsString('name', TextStyle()), - accountEmail: buildSettingsString('user', TextStyle()), - currentAccountPicture: const CircularProgressIndicator(backgroundColor: Colors.black,), - - ), - ListTile( - title: Text("Einstellungen"), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => Settings()), - ); - }, - leading: Icon(CupertinoIcons.settings), - ), - ListTile( - title: Text("Abmelden"), - onTap: () async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - prefs.setString('api_key', ""); - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => Login()), - ); - }, - leading: Icon(Icons.exit_to_app_outlined), - ), - AboutListTile( - child: Text("Info"), - icon: Icon(CupertinoIcons.info), - applicationVersion: "0.5.0-alpha1", - applicationIcon: Image.asset("assets/images/meincantor_r.png", height: 64, width: 64), - applicationName: "MeinCantor", - aboutBoxChildren: [ - 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 = [ - BottomNavigationBarItem( - icon: const Icon(CupertinoIcons.home), - label: "Startseite", - ), - BottomNavigationBarItem(icon: const Icon(CupertinoIcons.rectangle_grid_1x2), label: "Vertretungsplan"), - ]; - return Scaffold( - appBar: AppBar( - title: Text("GCG.MeinCantor"), - centerTitle: true, - ), - body: _DashboardBottomNavView( - key: UniqueKey(), - item: bottomNavBarItems[_currentIndex.value] - ), - drawer: Drawer( - child: drawerElements, - ), - bottomNavigationBar: BottomNavigationBar( - showUnselectedLabels: false, - items: bottomNavBarItems, - currentIndex: _currentIndex.value, - onTap: (index) { - setState(() { - _currentIndex.value = index; - }); - //print(index); - }, - ), - ); - } - - @override - String? get restorationId => widget.restorationId; - - @override - void restoreState(RestorationBucket? oldBucket, bool initialRestore) { - registerForRestoration(_currentIndex, 'bottom_navigation_tab_index'); - } -} - -class _DashboardBottomNavView extends StatelessWidget { - _DashboardBottomNavView({ - Key? key, - required this.item - }) : super(key:key); - final BottomNavigationBarItem item; - - - @override - Widget build(BuildContext context) { - return materialCard(item.label); - } - - Widget materialCard(String? label) { - if (label == "Startseite") { - var view = SingleChildScrollView( - child: Column( - children: [ - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(20, 30, 20, 5), - child: Text( - 'Hallo,', - style: GoogleFonts.robotoSlab( - fontSize: 20, - ), - ), - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(20, 5, 20, 20), - child: buildSettingsString("name", GoogleFonts.robotoSlab( - fontSize: 28, - fontWeight: FontWeight.w800, - ), - ), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(20, 10, 0, 10), - child: Text( - 'Deine nächste Unterrichtsstunde:', - style: GoogleFonts.robotoSlab( - fontSize: 20, - fontWeight: FontWeight.w100, - ), - ), - ) - ], - ), - Padding( - padding: EdgeInsets.fromLTRB(20, 20, 20, 10), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), - ), - color: Colors.red, - child: Column( - children: [ListTile( - title: Text('3' + '.' + ' ' + 'Deutsch', style: TextStyle(color: Colors.white)), - subtitle: Row( - children: [Icon(CupertinoIcons.person, color: Colors.white), SizedBox(width: 5), Text("Herr Jünemann", style: TextStyle(color: Colors.white)), Spacer(), Icon(CupertinoIcons.home, color: Colors.white), SizedBox(width: 5), Text("106", style: TextStyle(color: Colors.white))] - ), - leading: - Icon(CupertinoIcons.time, color: Colors.white) - )], - ) - ), - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: Padding( - padding: EdgeInsets.fromLTRB(20, 20, 20, 10), - child: Column( - children: [ - Card( - clipBehavior: Clip.antiAliasWithSaveLayer, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: - EdgeInsets.fromLTRB(20, 20, 10, 10), - child: Icon( - CupertinoIcons.news, - color: Color(0xFFFFBC3B), - size: 48, - ), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Align( - alignment: Alignment(0, 0), - child: Padding( - padding: - EdgeInsets.fromLTRB(15, 50, 0, 15), - child: Text( - 'Schülerzeitung', - ), - ), - ), - ], - ) - ], - ), - ), - Card( - clipBehavior: Clip.antiAliasWithSaveLayer, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: - EdgeInsets.fromLTRB(20, 20, 10, 10), - child: Icon( - CupertinoIcons.book, - color: Color(0xFFFFBC3B), - size: 48, - ), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), - child: Text( - 'Schulbibliothek', - ), - ) - ], - ) - ], - ), - ), - Card( - clipBehavior: Clip.antiAliasWithSaveLayer, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: - EdgeInsets.fromLTRB(20, 20, 10, 10), - child: Icon( - CupertinoIcons.device_laptop, - color: Color(0xFFFFBC3B), - size: 48, - ), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), - child: Text( - 'Schulcomputer', - ), - ) - ], - ) - ], - ), - ), - Card( - clipBehavior: Clip.antiAliasWithSaveLayer, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: - EdgeInsets.fromLTRB(20, 20, 10, 10), - child: Icon( - CupertinoIcons.house_alt, - color: Color(0xFFFFBC3B), - size: 48, - ), - ) - ], - ), - Row( - mainAxisSize: MainAxisSize.max, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(15, 50, 0, 15), - child: Text( - 'Raumübersicht', - ), - ) - ], - ) - ], - ), - ) - ], - ), - ), - ) - ] - ), - ], - ) - ); - return view; - } else if (label == "Vertretungsplan") { - return LayoutBuilder( - builder: (context, constraints) { - double widgetWidth = constraints.maxWidth; - double widgetHeight = constraints.maxHeight; - var factor; - - if (widgetWidth <= 600) { - factor = 1; - } else if (widgetWidth <= 1400) { - factor = 2; - } else if (widgetWidth <= 2000) { - factor = 3; - } - - // print(screenType); - return Center( - child: Container( - constraints: BoxConstraints( - // minHeight: 500, //minimum height - // minWidth: 300, // minimum width - //maximum height set to 100% of vertical height - maxWidth: MediaQuery.of(context).size.width / factor, - //maximum width set to 100% of width - ), - child: buildClassTimetable(), - ), - ); - } - ); - } else { - return Text("Such page does not exist."); - } - } -} diff --git a/lib/Settings.dart b/lib/Settings.dart deleted file mode 100644 index d783f31..0000000 --- a/lib/Settings.dart +++ /dev/null @@ -1,38 +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 { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Einstellungen"), - ), - body: ListView( - padding: EdgeInsets.fromLTRB(20, 20, 20, 20), - children: [ - 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); - } - ) - ), - Divider(), - buildClassesChooser() - ], - ) - ); - } -} \ No newline at end of file diff --git a/lib/Timetable.dart b/lib/Timetable.dart deleted file mode 100644 index c28af5e..0000000 --- a/lib/Timetable.dart +++ /dev/null @@ -1,174 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; - - -class ClassTimetableBuilder { - final ListView view; - ClassTimetableBuilder({required this.view}); - factory ClassTimetableBuilder.buildView(Map json) { - List children = []; - ClassTimetable.fromJson(json).timetable.forEach((element) { - List cardChildren = []; - cardChildren.add(ListTile( - title: Text(element.count.toString() + '.' + ' ' + element.name, - style: TextStyle(color: element.fontColor)), - subtitle: Row( - children: [ - Icon(CupertinoIcons.person, color: element.fontColor), - SizedBox(width: 5), - Text(element.teacher, - style: TextStyle(color: element.fontColor)), - Spacer(), - Icon(CupertinoIcons.home, color: element.fontColor), - SizedBox(width: 5), - Text(element.room, style: TextStyle(color: element.fontColor)) - ] - ), - leading: - Icon(CupertinoIcons.time, color: element.fontColor) - )); - if (element.info != '') { - cardChildren.add(ListTile(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, - ) - ); - children.add(card); - }); - return ClassTimetableBuilder( - view: ListView( - physics: const AlwaysScrollableScrollPhysics(), - children: children - ) - ); - } -} - -class ClassTimetable { - final List timetable; - ClassTimetable({required this.timetable}); - factory ClassTimetable.fromJson(Map json){ - print(json); - List lessons = []; - json['courses'].forEach((value){ - var color; - 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'}; - if(value['Fa'].runtimeType != String){ - name = value['Fa']['#text']; - } - else { - name = value['Fa']; - } - if(value['Le'].runtimeType != String){ - teacher = value['Le']['#text']; - } - else { - teacher = value['Le']; - } - print(value['Ra']); - if(value['Ra'].runtimeType != String && value['Ra'].runtimeType != int){ - if(value['Ra']['#text'] == ' ') { - room = ''; - } else { - room = value['Ra']['#text']; - } - } else if(value['Ra'] == ' ') { - room = ''; - } else { - room = value['Ra']; - } - var fontColor; - if(name == '---') { - fontColor = Colors.red; - } else { - fontColor = Colors.white; - } - var info; - if(value['If'].runtimeType != String) { - info = ''; - } else { - info = value['If']; - } - if(name == 'Mat'){ - color = Colors.indigo; - } - else if(name == 'Deu'){ - color = Colors.red; - } - else if(name == 'Kun'){ - color = Colors.deepPurple; - } - else if(name == 'Bio'){ - color = Colors.green; - } - else if(name == 'Geo'){ - color = Colors.brown; - } - else if(name == 'Lat'){ - color = Colors.teal; - } - else if(name == 'Che'){ - color = Colors.lightGreen; - } - else if(name == 'Eng'){ - color = Colors.amber; - } - else if(name == 'Phy'){ - color = Colors.cyan; - } - else if(name == 'Inf'){ - color = Colors.tealAccent[400]; - } - else if(name == 'Mus'){ - color = Colors.deepOrange; - } - else if(name == 'Lme'){ - color = Colors.amber[700]; - } - else if(name == 'Ges'){ - color = Colors.grey; - } - else if(name == 'Spa'){ - color = Colors.redAccent; - } - else if(name == 'Frz'){ - color = Colors.amberAccent[700]; - } - else if(name == '---') { - color = Colors.white; - } - else { - color = Colors.grey[700]; - } - dynamic names = {'Bio':'Biologie', 'Mat':'Mathematik', 'Kun':'Kunst', 'Mus':'Musik', 'Geo':'Geographie', 'Ges':'Geschichte', 'Che':'Chemie', 'Lat':'Latein', 'Inf':'Informatik', 'Eng':'Englisch', 'Frz':'Französisch', 'Phy':'Physik', '---':'---', 'Spo':'Sport', 'Deu':'Deutsch', 'Lme':'Lernmethoden', 'Eth':'Ethik', 'EvR':'Evangelische Religion', 'Spa':'Spanisch', 'Soz':'Sozialkunde', 'Ast':'Astronomie'}; - dynamic colors = {'Bio':Colors.green, 'Mat':Colors.blue}; - lessons.add(TimetableLesson(value['St'], names[name].toString(), teachers[teacher].toString(), room.toString(), value['If'].toString(), color, fontColor, info)); - }); - - return ClassTimetable( - timetable: lessons - ); - } -} - -class TimetableLesson { - final int count; - final String name; - final String teacher; - final String room; - final String comment; - final Color color; - final Color fontColor; - final String info; - const TimetableLesson(this.count, this.name, this.teacher, this.room, this.comment, this.color, this.fontColor, this.info); -} \ No newline at end of file diff --git a/lib/dashboard.dart b/lib/dashboard.dart new file mode 100644 index 0000000..72130ae --- /dev/null +++ b/lib/dashboard.dart @@ -0,0 +1,516 @@ +//import 'package:MeinCantor/timetable.dart'; +//import 'package:MeinCantor/main.dart'; +import 'package:MeinCantor/raumuebersicht.dart'; +import 'package:MeinCantor/schulbibliothek.dart'; +import 'package:MeinCantor/schulcomputer.dart'; +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 'networking.dart'; +import 'login.dart'; +import 'schuelerzeitung.dart'; + +class Dashboard extends StatefulWidget { + const Dashboard({Key? key, this.restorationId}) : super(key: key); + + final String? restorationId; + + @override + State createState() => _DashboardState(); +} + +Future getSettingsString(String key) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? value = prefs.getString(key); + if (value == null || value.isEmpty) { + value = ""; + } + print(value); + return value; +} + +Widget buildSettingsString(String key, TextStyle style) { + return FutureBuilder( + future: getSettingsString(key), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text(snapshot.data as String, style: style); + } else { + return (const Center(child: CircularProgressIndicator())); + } + }); +} + +class _DashboardState extends State with RestorationMixin { + final RestorableInt _currentIndex = RestorableInt(0); + @override + Widget build(BuildContext context) { + final drawerElements = ListView( + children: [ + UserAccountsDrawerHeader( + accountName: buildSettingsString('name', const TextStyle()), + accountEmail: buildSettingsString('user', const TextStyle()), + currentAccountPicture: const CircularProgressIndicator( + backgroundColor: Colors.black, + ), + ), + ListTile( + title: const Text("Einstellungen"), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => Settings()), + ); + }, + leading: const Icon(CupertinoIcons.settings), + ), + ListTile( + title: const Text("Abmelden"), + onTap: () async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setString('api_key', ""); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => Login()), + ); + }, + 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), + label: "Startseite", + ), + const BottomNavigationBarItem( + icon: Icon(CupertinoIcons.rectangle_grid_1x2), + label: "Vertretungsplan"), + ]; + return Scaffold( + appBar: AppBar( + title: const Text("GCG.MeinCantor"), + centerTitle: true, + ), + body: _DashboardBottomNavView( + key: UniqueKey(), item: bottomNavBarItems[_currentIndex.value]), + drawer: Drawer( + child: drawerElements, + ), + bottomNavigationBar: BottomNavigationBar( + showUnselectedLabels: false, + items: bottomNavBarItems, + currentIndex: _currentIndex.value, + onTap: (index) { + setState(() { + _currentIndex.value = index; + }); + //print(index); + }, + ), + ); + } + + @override + String? get restorationId => widget.restorationId; + + @override + void restoreState(RestorationBucket? oldBucket, bool initialRestore) { + registerForRestoration(_currentIndex, 'bottom_navigation_tab_index'); + } +} + +class _DashboardBottomNavView extends StatelessWidget { + const _DashboardBottomNavView({Key? key, required this.item}) + : super(key: key); + final BottomNavigationBarItem item; + + @override + Widget build(BuildContext context) { + if (item.label == "Startseite") { + double _timeOfDayToDouble(TimeOfDay tod) => tod.hour + tod.minute / 60.0; + var lessonCount; + if (_timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 7, minute: 30))) { + lessonCount = 1; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 7, minute: 30)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 8, minute: 20))) { + lessonCount = 2; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 8, minute: 20)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 9, minute: 25))) { + lessonCount = 3; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 9, minute: 25)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 10, minute: 15))) { + lessonCount = 4; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 10, minute: 15)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 11, minute: 30))) { + lessonCount = 5; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 11, minute: 30)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 12, minute: 20))) { + lessonCount = 6; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 12, minute: 20)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 13, minute: 30))) { + lessonCount = 7; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 13, minute: 30)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 14, minute: 20))) { + lessonCount = 8; + } else if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: 14, minute: 20)) && + _timeOfDayToDouble(TimeOfDay.now()) <= + _timeOfDayToDouble(const TimeOfDay(hour: 15, minute: 10))) { + lessonCount = 9; + } else { + lessonCount = -1; + } + + /* + Widget timetable; + if (_timeOfDayToDouble(TimeOfDay.now()) > + _timeOfDayToDouble(const TimeOfDay(hour: , minute: 55))) { + timetable = buildClassTimetable(); + } else { + timetable = buildTodayClassTimetable(); + } + */ + + print(lessonCount); + var view = SingleChildScrollView( + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(20, 30, 20, 5), + child: Text( + 'Hallo,', + style: GoogleFonts.robotoSlab( + fontSize: 20, + ), + ), + ), + ], + ), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(20, 5, 20, 20), + child: buildSettingsString( + "name", + GoogleFonts.robotoSlab( + fontSize: 28, + fontWeight: FontWeight.w800, + ), + ), + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(20, 10, 0, 10), + child: Text( + 'Deine nächste Unterrichtsstunde:', + style: GoogleFonts.robotoSlab( + fontSize: 20, + fontWeight: FontWeight.w100, + ), + ), + ) + ], + ), + Padding( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), + child: buildTodayClassTimetableLesson(lessonCount), + ), + Row(mainAxisSize: MainAxisSize.max, children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), + child: Column( + children: [ + GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SZ()), + ); + }, + child: Card( + clipBehavior: Clip.antiAliasWithSaveLayer, + 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.news, + color: Color(0xFFFFBC3B), + size: 48, + ), + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.max, + children: const [ + Align( + alignment: Alignment(0, 0), + child: Padding( + padding: EdgeInsets.fromLTRB(15, 50, 0, 15), + child: Text( + 'Schülerzeitung', + ), + ), + ), + ], + ) + ], + ), + ), + ), + GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SB()), + ); + }, + child: Card( + clipBehavior: Clip.antiAliasWithSaveLayer, + 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', + ), + ) + ], + ) + ], + ), + ), + ), + GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SC()), + ); + }, + child: Card( + clipBehavior: Clip.antiAliasWithSaveLayer, + 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.device_laptop, + color: Color(0xFFFFBC3B), + size: 48, + ), + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.max, + children: const [ + Padding( + padding: EdgeInsets.fromLTRB(15, 50, 0, 15), + child: Text( + 'Schulcomputer', + ), + ) + ], + ) + ], + ), + ), + ), + GestureDetector( + onTap: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const RoomOverview()), + ); + }, + child: Card( + clipBehavior: Clip.antiAliasWithSaveLayer, + 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.house_alt, + color: Color(0xFFFFBC3B), + size: 48, + ), + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.max, + children: const [ + Padding( + padding: EdgeInsets.fromLTRB(15, 50, 0, 15), + child: Text( + 'Raumübersicht', + ), + ) + ], + ) + ], + ), + ), + ), + ], + ), + ), + ) + ]), + ], + )); + return view; + } else if (item.label == "Vertretungsplan") { + return LayoutBuilder(builder: (context, constraints) { + double widgetWidth = constraints.maxWidth; + // double widgetHeight = constraints.maxHeight; + var factor; + + if (widgetWidth <= 600) { + factor = 1; + } else if (widgetWidth <= 1400) { + factor = 2; + } else if (widgetWidth <= 2000) { + factor = 3; + } + + // print(screenType); + return Center( + child: Container( + constraints: BoxConstraints( + // minHeight: 500, //minimum height + // minWidth: 300, // minimum width + //maximum height set to 100% of vertical height + maxWidth: MediaQuery.of(context).size.width / factor, + //maximum width set to 100% of width + ), + child: DefaultTabController( + initialIndex: 0, + length: 2, + child: Scaffold( + appBar: AppBar( + elevation: 0, + title: const TabBar( + tabs: [ + Tab( + text: "Heute", + icon: Icon(CupertinoIcons.calendar_today), + ), + Tab( + text: "Neuster Plan", + icon: Icon(CupertinoIcons.calendar), + ), + /*Tab( + text: "Archiv", + icon: Icon(CupertinoIcons.archivebox), + ),*/ + ], + ), + ), + body: TabBarView( + children: [ + buildTodayClassTimetable(), + buildClassTimetable(), + /* + Center( + child: Text("It's sunny here"), + ), + */ + ], + ), + ), + ), + ), + ); + }); + } else { + return const Text("Such page does not exist."); + } + // return materialCard(item.label); + } +} diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index aaa4093..7933e85 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -2,6 +2,7 @@ // Generated file. Do not edit. // +// ignore_for_file: directives_ordering // ignore_for_file: lines_longer_than_80_chars import 'package:fluttertoast/fluttertoast_web.dart'; diff --git a/lib/Login.dart b/lib/login.dart similarity index 58% rename from lib/Login.dart rename to lib/login.dart index 7b1722a..a9e823b 100644 --- a/lib/Login.dart +++ b/lib/login.dart @@ -2,15 +2,15 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; +import 'package:http/http.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'networking.dart'; -import 'Dashboard.dart'; +import 'dashboard.dart'; Future checkKey() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - String? api_key = await prefs.getString('api_key'); - return api_key != null && api_key.isNotEmpty; + String? apiKey = prefs.getString('api_key'); + return apiKey != null && apiKey.isNotEmpty; } class Login extends StatelessWidget { @@ -37,12 +37,12 @@ class Login extends StatelessWidget { return Scaffold( appBar: AppBar( - title: Text("Anmelden"), + title: const Text("Anmelden"), ), body: Center( child: SingleChildScrollView( child: Padding( - padding: EdgeInsets.fromLTRB(20, 20, 20, 20), + padding: const EdgeInsets.fromLTRB(20, 20, 20, 20), child: Container( constraints: BoxConstraints( maxWidth: @@ -53,23 +53,27 @@ class Login extends StatelessWidget { children: [ Image.asset("assets/images/meincantor_r.png", height: 192, width: 192), - Divider(), + const Divider(), AutofillGroup( child: Column( children: [ TextField( - autofillHints: [AutofillHints.username], - decoration: InputDecoration( + autofillHints: const [ + AutofillHints.username + ], + decoration: const InputDecoration( icon: Icon(CupertinoIcons.person), border: OutlineInputBorder(), labelText: 'Benutzername', ), controller: userController, ), - Divider(), + const Divider(), TextField( - autofillHints: [AutofillHints.password], - decoration: InputDecoration( + autofillHints: const [ + AutofillHints.password + ], + decoration: const InputDecoration( icon: Icon(CupertinoIcons.lock), border: OutlineInputBorder(), labelText: 'Passwort', @@ -79,9 +83,9 @@ class Login extends StatelessWidget { ), ], )), - Divider(), + const Divider(), TextField( - decoration: InputDecoration( + decoration: const InputDecoration( icon: Icon(CupertinoIcons.lock), border: OutlineInputBorder(), labelText: '2F2-Code (OTP) [falls aktiviert]', @@ -89,37 +93,55 @@ class Login extends StatelessWidget { obscureText: true, controller: otpController, ), - Divider(), + const Divider(), TextField( - decoration: InputDecoration( + decoration: const InputDecoration( icon: Icon(CupertinoIcons.device_laptop), border: OutlineInputBorder(), labelText: 'Gerätebezeichnung', ), controller: devIdController, ), - Divider(), + const Divider(), OutlinedButton( onPressed: () async { SharedPreferences prefs = await SharedPreferences.getInstance(); - String api_key = await getToken( + Response loginResponse = await getToken( userController.text, passwordController.text, otpController.text, devIdController.text); - print('Set new API key to $api_key'); - await prefs.setString('api_key', api_key); - dynamic userinfo = jsonDecode( - await getUserInfo( - userController.text, - passwordController.text, - otpController.text, - devIdController.text)); - await prefs.setString( - 'user', userinfo['preferred_username']); - await prefs.setString( - 'name', userinfo['name']); + if (loginResponse.statusCode == 200) { + String apiKey = jsonDecode(utf8.decode( + loginResponse.bodyBytes))['token']; + print('Set new API key to $apiKey'); + await prefs.setString('api_key', apiKey); + dynamic userinfo = jsonDecode( + await getUserInfo( + userController.text, + passwordController.text, + otpController.text, + devIdController.text)); + await prefs.setString('user', + userinfo['preferred_username']); + await prefs.setString( + 'name', userinfo['name']); + await prefs.setString( + 'class_num', + userinfo['groups'][0] + .replaceAll("_", "/")); + } else if (loginResponse.statusCode == + 401) { + String text = loginResponse.body; + final snackBar = SnackBar( + content: Text('Fehler: $text')); + + // Find the ScaffoldMessenger in the widget tree + // and use it to show a SnackBar. + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); + } if (prefs.getString('api_key') != null && prefs .getString('api_key')! @@ -127,18 +149,15 @@ class Login extends StatelessWidget { Navigator.pushReplacement( context, MaterialPageRoute( - builder: (context) => Dashboard()), + builder: (context) => + const Dashboard()), ); } }, - child: Text("Anmelden")) + child: const Text("Anmelden")) ], ), - ) - ) - ) - ) - ); + ))))); }, ); } diff --git a/lib/main.dart b/lib/main.dart index 8828976..3bc1b69 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,13 +1,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'Dashboard.dart'; -import 'Login.dart'; +import 'dashboard.dart'; +import 'login.dart'; import 'dart:math'; -void main() => runApp(App()); +void main() => runApp(const App()); class App extends StatelessWidget { + const App({Key? key}) : super(key: key); + MaterialColor generateMaterialColor(Color color) { return MaterialColor(color.value, { 50: tintColor(color, 0.5), @@ -38,47 +40,40 @@ class App extends StatelessWidget { theme: ThemeData( primaryColor: Palette.primary, colorScheme: ColorScheme.fromSwatch( - primarySwatch: generateMaterialColor(Palette.accent), + primarySwatch: generateMaterialColor(Palette.primary), ).copyWith( secondary: generateMaterialColor(Palette.accent), ), ), - darkTheme: ThemeData.from(colorScheme: ColorScheme.dark(primary: Palette.accent)), + darkTheme: ThemeData.from( + colorScheme: const ColorScheme.dark(primary: Palette.accent)), title: "GCG.MeinCantor", home: buildHomePage(), - /* - routes: { - "/": (_) => Dashboard(), - "/login": (_) => Login() - }, - - */ ); } } Future apiKeyEmpty() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - String? api_key = await prefs.getString("api_key"); - return api_key == null || api_key.isEmpty; + String? apiKey = prefs.getString("api_key"); + return apiKey == null || apiKey.isEmpty; } Widget buildHomePage() { return FutureBuilder( - future: apiKeyEmpty(), - builder: (context, snapshot) { - if(snapshot.data == true) { - return Login(); - } else if(snapshot.data == false) { - return Dashboard(); - } else { - return Center(child: CircularProgressIndicator()); - } - } - ); + future: apiKeyEmpty(), + builder: (context, snapshot) { + if (snapshot.data == true) { + return Login(); + } else if (snapshot.data == false) { + return const Dashboard(); + } else { + return const Center(child: CircularProgressIndicator()); + } + }); } class Palette { -static const Color primary = Color(0xFF1A1A37); -static const Color accent = Color(0xFFFFBC3B); -} \ No newline at end of file + static const Color primary = Color(0xFF1A1A37); + static const Color accent = Color(0xFFFFBC3B); +} diff --git a/lib/networking.dart b/lib/networking.dart index 29e7040..fae2991 100644 --- a/lib/networking.dart +++ b/lib/networking.dart @@ -1,39 +1,21 @@ import 'dart:convert'; -import 'main.dart'; import 'package:flutter/cupertino.dart'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'Timetable.dart'; -import 'Login.dart'; +import 'timetable.dart'; +import 'login.dart'; +import 'main.dart'; -Future getToken( +Future 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"}'; print(uri); final response = await http.post(uri, body: body); - - if (response.statusCode == 200) { - return jsonDecode(utf8.decode(response.bodyBytes))['token']; - } else if(response.statusCode == 401) { - var body = response.body; - Fluttertoast.showToast( - msg: "Fehler: $body", - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.CENTER, - timeInSecForIosWeb: 1, - backgroundColor: Colors.red, - textColor: Colors.white, - fontSize: 16.0 - ); - throw Exception('Failed to log in'); - } else { - throw Exception('Undefined error'); - } + return (response); } Future getUserInfo( @@ -53,18 +35,36 @@ Future getUserInfo( Future fetchClassTimetable() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - var class_num; + String classNum; print(prefs.getString('class_num')); if (prefs.getString('class_num') != null) { - class_num = prefs.getString('class_num')!; + classNum = prefs.getString('class_num')!.replaceAll("/", "_"); } else { - class_num = '07_1'; + classNum = '05_1'; } - var api_key = prefs.getString('api_key'); - var uri = Uri.https("mein.cantorgymnasium.de", "/api/timetable/$class_num"); - var headers = {"x-api-key": "$api_key"}; + var apiKey = prefs.getString('api_key'); + var uri = Uri.https("mein.cantorgymnasium.de", "/api/timetable/$classNum"); + var headers = {"x-api-key": "$apiKey"}; print(uri); - final response = http.get(uri, headers: headers); + final response = http.get(uri, headers: headers).onError((error, stackTrace) { return(http.Response("", 404)); } ); + return response; +} + +Future fetchTodayClassTimetable() 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/today"); + var headers = {"x-api-key": "$apiKey"}; + print(uri); + final response = http.get(uri, headers: headers).onError((error, stackTrace) { return(http.Response("", 404)); } ); return response; } @@ -79,15 +79,148 @@ Widget buildClassTimetable() { jsonDecode(utf8.decode(snapshot.data!.bodyBytes))) .view; return timetableView; - } - else if(statusCode == 400) { - Navigator.push(context, MaterialPageRoute(builder: (context) => Login())); + } else if (statusCode == 400) { + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (context) => Login())); + } else if (statusCode == 500) { + 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), + 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 Center(child: CircularProgressIndicator()); + return const Center(child: CircularProgressIndicator()); + } + }, + ); +} + +Widget buildTodayClassTimetable() { + return FutureBuilder( + future: fetchTodayClassTimetable(), + builder: (context, snapshot) { + if (snapshot.hasData) { + int statusCode = snapshot.data!.statusCode; + if (statusCode == 200) { + ListView timetableView = ClassTimetableBuilder.buildView( + jsonDecode(utf8.decode(snapshot.data!.bodyBytes))) + .view; + return timetableView; + } 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("Es konnte kein Vertretungsplan für heute gefunden werden.")), + ); + } 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 Center(child: Text('Error $statusCode')); + } else if (snapshot.hasError) { + return Text('$snapshot.error'); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ); +} + +Widget buildClassTimetableLesson(int count) { + return FutureBuilder( + future: fetchClassTimetable(), + builder: (context, snapshot) { + if (snapshot.hasData) { + int statusCode = snapshot.data!.statusCode; + if (statusCode == 200) { + List lessons = LessonsListBuilder.buildList( + jsonDecode(utf8.decode(snapshot.data!.bodyBytes)), count: count) + .lessons; + return Column(children: lessons); + } 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("Es konnte kein Vertretungsplan gefunden werden.")), + ); + } 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 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( + future: fetchTodayClassTimetable(), + builder: (context, snapshot) { + if (snapshot.hasData) { + int statusCode = snapshot.data!.statusCode; + if (statusCode == 200) { + List lessons = LessonsListBuilder.buildList( + jsonDecode(utf8.decode(snapshot.data!.bodyBytes)), 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 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 == 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("Es konnte kein Vertretungsplan für heute gefunden werden.")), + ); + } 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 Center(child: Text('Error $statusCode')); + } else if (snapshot.hasError) { + return Text('$snapshot.error'); + } else { + return const Center(child: CircularProgressIndicator()); } }, ); @@ -95,21 +228,11 @@ Widget buildClassTimetable() { Future fetchClassesList() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - /* - var class_num; - print(prefs.getString('class_num')); - if(prefs.getString('class_num') != null){ - class_num = prefs.getString('class_num')!; - } else { - class_num = '07_1'; - } - */ - // await prefs.setString('api_key', "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJHZW9yZy1DYW50b3ItR3ltbmFzaXVtIEhhbGxlKFNhYWxlKSIsInVzZXIiOiJkZW55cy5rb25vdmFsb3ZAcG0ubWUiLCJyb2xlcyI6WyJTdHVkZW50IiwiQWRtaW4iXSwiYmxhY2tsaXN0IjpbIi9jbGFzc2VzIl0sIndoaXRlbGlzdCI6WyIvaGVsbG8vc2Vuc2l0aXZlIl0sImppZCI6IkFwcERldiBBbHBoYSBkdW1teSBrZXlAMDIvMDgvMjAyMSAxOTowODowOSIsImV4cCI6MTY1OTQ2NzI4OX0.a7Q83PK3ybeV7Bui-_rX1o6IZx1cNa6vsvUGG-kfqtc"); - var api_key = prefs.getString('api_key'); + var apiKey = prefs.getString('api_key'); var uri = Uri.https("mein.cantorgymnasium.de", "/api/classes"); - var headers = {"x-api-key": "$api_key"}; + var headers = {"x-api-key": "$apiKey"}; print(uri); - final response = http.get(uri, headers: headers); + final response = http.get(uri, headers: headers).onError((error, stackTrace) { return(http.Response("", 404)); } ); return response; } @@ -120,20 +243,30 @@ Widget buildClassesChooser() { if (snapshot.hasData) { int statusCode = snapshot.data!.statusCode; if (statusCode == 200) { - // List children = []; - //ClassTimetable.fromJson(jsonDecode(utf8.decode(snapshot.data!.bodyBytes))).timetable.forEach((element) { - //}); List 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 Center(child: CircularProgressIndicator()); + return const Center(child: CircularProgressIndicator()); } }, ); @@ -150,37 +283,38 @@ class ClassesChooser extends StatefulWidget { class _ClassesChooserState extends State { final List items; //final String dropdownValue; - var dropdownValue; + 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) { - // var dropdown_items = return DropdownButtonFormField( - // value: dropdownValue, - /*icon: const Icon(Icons.arrow_downward), - iconSize: 24, - elevation: 16,*/ - // style: const TextStyle(color: Color(0xFFFFBC3B)), - /*underline: Container( - height: 2, - color: Color(0xFFFFBC3B), - ) - */ - decoration: InputDecoration( + value: dropdownValue, + decoration: const InputDecoration( icon: Icon(CupertinoIcons.number), border: OutlineInputBorder(), - labelText: 'Klasse (05_1, 07_3, 10_2...)', + labelText: 'Klasse (05/1, 07/3, 10/2...)', ), - // icon: Icon(CupertinoIcons.number), - onChanged: (String? newValue) { setState(() async { dropdownValue = newValue!; SharedPreferences prefs = await SharedPreferences.getInstance(); - String class_num = newValue; - print('Set new class to $class_num'); - await prefs.setString('class_num', class_num); + String classNum = newValue; + print('Set new class to $classNum'); + await prefs.setString('class_num', classNum); }); }, items: items.map>((String value) { diff --git a/lib/raumuebersicht.dart b/lib/raumuebersicht.dart new file mode 100644 index 0000000..21ab6bd --- /dev/null +++ b/lib/raumuebersicht.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class RoomOverview extends StatelessWidget { + const RoomOverview ({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Raumübersicht"), + centerTitle: true, + ), + body: const Center( + child: Text("Derzeit nichts hier..."), + )); + } +} diff --git a/lib/schuelerzeitung.dart b/lib/schuelerzeitung.dart new file mode 100644 index 0000000..643f792 --- /dev/null +++ b/lib/schuelerzeitung.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class SZ extends StatelessWidget { + const SZ({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Schülerzeitung"), + centerTitle: true, + ), + body: const Center( + child: Text("Derzeit nichts hier..."), + )); + } +} diff --git a/lib/schulbibliothek.dart b/lib/schulbibliothek.dart new file mode 100644 index 0000000..34fbd9f --- /dev/null +++ b/lib/schulbibliothek.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class SB extends StatelessWidget { + const SB ({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Schulbibliothek"), + centerTitle: true, + ), + body: const Center( + child: Text("Derzeit nichts hier..."), + )); + } +} diff --git a/lib/schulcomputer.dart b/lib/schulcomputer.dart new file mode 100644 index 0000000..b5ac204 --- /dev/null +++ b/lib/schulcomputer.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class SC extends StatelessWidget { + const SC ({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Schulcomputer"), + centerTitle: true, + ), + body: const Center( + child: Text("Derzeit nichts hier..."), + )); + } +} diff --git a/lib/settings.dart b/lib/settings.dart new file mode 100644 index 0000000..494ff3a --- /dev/null +++ b/lib/settings.dart @@ -0,0 +1,65 @@ +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/timetable.dart b/lib/timetable.dart new file mode 100644 index 0000000..7120767 --- /dev/null +++ b/lib/timetable.dart @@ -0,0 +1,261 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +class ClassTimetableBuilder { + final ListView view; + ClassTimetableBuilder({required this.view}); + factory ClassTimetableBuilder.buildView(Map json) { + return ClassTimetableBuilder( + view: ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: LessonsListBuilder.buildList(json).lessons)); + } +} + +class LessonsListBuilder { + final List lessons; + LessonsListBuilder({required this.lessons}); + factory LessonsListBuilder.buildList(Map json, {int count: 0}) { + List children = []; + ClassTimetable.fromJson(json).timetable.forEach((element) { + 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)), + subtitle: Row(children: [ + Icon(CupertinoIcons.person, color: element.fontColor), + const SizedBox(width: 5), + Text(element.teacher, style: TextStyle(color: element.fontColor)), + const Spacer(), + Icon(CupertinoIcons.home, color: element.fontColor), + const SizedBox(width: 5), + Text(element.room, style: TextStyle(color: element.fontColor)) + ]), + leading: Icon(CupertinoIcons.time, color: element.fontColor))); + if (element.info != '') { + cardChildren.add(ListTile( + 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, + )); + children.add(card); + } + }); + return LessonsListBuilder(lessons: children); + } +} + +class ClassTimetable { + final List timetable; + ClassTimetable({required this.timetable}); + factory ClassTimetable.fromJson(Map json) { + print(json); + List lessons = []; + json['courses'].forEach((value) { + 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 { + name = value['Fa']; + } + if (value['Le'].runtimeType != String) { + teacher = value['Le']['#text']; + } else { + teacher = value['Le']; + } + print(value['Ra']); + if (value['Ra'].runtimeType != String && value['Ra'].runtimeType != int) { + if (value['Ra']['#text'] == ' ') { + room = ''; + } else if (value['Ra']['#text'] == null) { + room = ''; + } else { + room = value['Ra']['#text']; + } + } else if (value['Ra'] == ' ') { + room = ''; + } else { + room = value['Ra']; + } + Color fontColor; + if (name == '---') { + fontColor = Colors.red; + } else { + fontColor = Colors.white; + } + var info; + if (value['If'].runtimeType != String) { + info = ''; + } else { + 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' + }; + + lessons.add(TimetableLesson( + value['St'], + names[name] ?? name.toString(), + teachers[teacher] ?? teacher.toString(), + room.toString(), + value['If'].toString(), + colors[name] ?? Colors.grey[700], + fontColor, + info)); + }); + + return ClassTimetable(timetable: lessons); + } +} + +class TimetableLesson { + final int count; + final String name; + final String teacher; + final String room; + final String comment; + final Color color; + final Color fontColor; + final String info; + const TimetableLesson(this.count, this.name, this.teacher, this.room, + this.comment, this.color, this.fontColor, this.info); +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index d38195a..e71a16d 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -2,6 +2,8 @@ // Generated file. Do not edit. // +// clang-format off + #include "generated_plugin_registrant.h" diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h index 9bf7478..e0f0a47 100644 --- a/linux/flutter/generated_plugin_registrant.h +++ b/linux/flutter/generated_plugin_registrant.h @@ -2,6 +2,8 @@ // Generated file. Do not edit. // +// clang-format off + #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ diff --git a/pubspec.yaml b/pubspec.yaml index 090a3e6..fdbb26f 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: 1.0.0+1 +version: 0.6.5-alpha environment: sdk: ">=2.12.0 <3.0.0" diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 4bfa0f3..8b6d468 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -2,6 +2,8 @@ // Generated file. Do not edit. // +// clang-format off + #include "generated_plugin_registrant.h" diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h index 9846246..dc139d8 100644 --- a/windows/flutter/generated_plugin_registrant.h +++ b/windows/flutter/generated_plugin_registrant.h @@ -2,6 +2,8 @@ // Generated file. Do not edit. // +// clang-format off + #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_