==Initial version==
- many hardcoded placeholders - TODO: - update README - update license & copyright info - cleanup code - merge code parts to server side - muuuuuuuch more...
This commit is contained in:
parent
38c9e85166
commit
20a50d66f7
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="meincantor_app_icon_background">#1A1A37</color>
|
||||||
|
</resources>
|
53
assets/images/meincantor-round.svg
Normal file
53
assets/images/meincantor-round.svg
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 135.46666 135.46667"
|
||||||
|
version="1.1"
|
||||||
|
id="svg826"
|
||||||
|
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||||
|
sodipodi:docname="meincantor-round.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview828"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:zoom="0.69130191"
|
||||||
|
inkscape:cx="155.50369"
|
||||||
|
inkscape:cy="289.3092"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs823" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<circle
|
||||||
|
style="fill:#1a1a37;fill-opacity:1;stroke:#1a1a37;stroke-width:0.450144"
|
||||||
|
id="path909"
|
||||||
|
cx="67.733337"
|
||||||
|
cy="67.73333"
|
||||||
|
r="67.508263" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffbc3b;fill-opacity:1;stroke-width:0.101646"
|
||||||
|
d="m 64.24865,118.49569 c -7.57703,-0.68874 -13.07166,-2.17953 -19.26191,-5.2261 -5.07555,-2.49796 -9.21616,-5.48508 -13.36935,-9.64492 -4.24296,-4.249748 -7.18643,-8.372728 -9.76459,-13.677468 -2.38531,-4.90795 -3.83281,-9.66485 -4.68595,-15.39936 -0.22167,-1.49001 -0.23434,-1.86236 -0.23348,-6.8611 0.001,-5.75731 0.0112,-5.8938 0.70967,-9.50389 1.41498,-7.31325 4.31986,-14.09787 8.56776,-20.0108 1.08578,-1.51136 1.26945,-1.74578 2.75696,-3.5186 1.18989,-1.41811 4.6051,-4.79494 6.00686,-5.93934 3.49341,-2.85204 6.3554,-4.71248 10.01212,-6.5084 5.63599,-2.76798 11.01697,-4.33808 17.27981,-5.04202 1.95056,-0.21925 6.49813,-0.3028 8.6399,-0.15874 10.85994,0.73043 21.22025,4.91354 29.47732,11.90184 2.31994,1.96346 5.11657,4.85756 7.09311,7.34031 1.57267,1.97545 4.42364,6.27134 4.29746,6.47549 -0.0302,0.0489 -0.7301,0.46721 -1.55528,0.92956 -0.82517,0.46235 -3.16985,1.77924 -5.2104,2.92642 -2.04054,1.14718 -4.41905,2.48273 -5.285584,2.96789 -0.866532,0.48516 -2.853543,1.5992 -4.415576,2.47565 -1.56203,0.87645 -2.89756,1.57148 -2.96783,1.54451 -0.0703,-0.027 -0.20565,-0.20004 -0.30085,-0.38461 -0.0952,-0.18456 -0.48635,-0.80286 -0.86925,-1.37398 -4.1041,-6.12164 -10.66138,-10.54941 -17.7976,-12.01774 -2.2308,-0.45901 -3.29135,-0.55802 -5.9723,-0.55754 -2.92886,5.9e-4 -4.34012,0.16701 -6.9277,0.81733 -7.54602,1.89648 -14.13772,6.9369 -17.91778,13.70103 -2.42291,4.33561 -3.62944,8.99167 -3.62434,13.98646 0.005,4.49962 0.87661,8.34811 2.79831,12.34998 1.52084,3.16708 3.34414,5.69426 5.87291,8.14011 4.37146,4.22814 9.64698,6.83554 15.74744,7.78309 1.95735,0.30402 6.10417,0.32974 7.9137,0.0491 5.50205,-0.85338 10.03859,-2.80989 14.13339,-6.09541 2.48209,-1.99153 5.02262,-4.91055 6.59534,-7.57789 l 0.29239,-0.4959 -8.29976,-4.8114 c -14.86737,-8.61866 -16.12525,-9.35129 -16.22306,-9.44874 -0.0607,-0.0605 4.47285,-0.0962 12.22224,-0.0962 h 12.3188 l 0.0261,7.12925 0.0261,7.12924 1.01647,0.57703 c 0.55905,0.31738 2.20571,1.24258 3.659248,2.05601 2.917256,1.63257 9.810502,5.49793 12.783782,7.16846 1.04922,0.5895 1.92802,1.10474 1.95288,1.14498 0.11707,0.18942 -1.95992,3.3969 -3.62221,5.59375 -6.11193,8.077428 -14.10926,13.942658 -23.64336,17.339998 -3.49711,1.24615 -7.65379,2.19049 -11.61375,2.63848 -1.40508,0.15896 -7.48873,0.2887 -8.63815,0.18422 z"
|
||||||
|
id="path6437" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
54
assets/images/meincantor.svg
Normal file
54
assets/images/meincantor.svg
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 135.46666 135.46666"
|
||||||
|
version="1.1"
|
||||||
|
id="svg825"
|
||||||
|
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||||
|
sodipodi:docname="meincantor.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview827"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:zoom="0.34565095"
|
||||||
|
inkscape:cx="392.01396"
|
||||||
|
inkscape:cy="324.0263"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs822" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#1a1a37;stroke:#1a1a37;stroke-width:0.407031;fill-opacity:1;stroke-opacity:1"
|
||||||
|
id="rect908"
|
||||||
|
width="135.05963"
|
||||||
|
height="135.05963"
|
||||||
|
x="0.20351535"
|
||||||
|
y="0.20351535" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffbc3b;stroke-width:0.0677639;fill-opacity:1"
|
||||||
|
d="m 65.410221,101.57495 c -5.05135,-0.45916 -8.71443,-1.45302 -12.84127,-3.484075 -3.38371,-1.66531 -6.14411,-3.65673 -8.91291,-6.42995 -2.82864,-2.83317 -4.79095,-5.58183 -6.50973,-9.11832 -1.59021,-3.27197 -2.55521,-6.44324 -3.12397,-10.26624 -0.14777,-0.99334 -0.15622,-1.24158 -0.15565,-4.57407 6.6e-4,-3.83821 0.007,-3.9292 0.47311,-6.33593 0.94332,-4.87551 2.87992,-9.39859 5.71184,-13.34054 0.72385,-1.00758 0.84631,-1.16386 1.83798,-2.34574 0.79326,-0.94541 3.07007,-3.19663 4.00458,-3.95956 2.32894,-1.90136 4.23693,-3.14166 6.67475,-4.33893 3.75732,-1.84533 7.34464,-2.89206 11.51987,-3.36136 1.30038,-0.14616 4.3321,-0.20186 5.75995,-0.10583 7.23996,0.48696 14.14684,3.2757 19.65155,7.93458 1.54663,1.30896 3.41106,3.23837 4.72874,4.89353 1.04845,1.31697 2.9491,4.1809 2.86499,4.317 -0.0202,0.0326 -0.48674,0.31148 -1.03686,0.61971 -0.55012,0.30823 -2.11324,1.18616 -3.47361,1.95095 -1.36035,0.76478 -2.94603,1.65515 -3.52372,1.97859 -0.57769,0.32344 -1.90236,1.06613 -2.94372,1.65043 -1.04136,0.58431 -1.93171,1.04766 -1.97855,1.02968 -0.0469,-0.018 -0.13711,-0.13336 -0.20057,-0.2564 -0.0635,-0.12305 -0.32424,-0.53524 -0.5795,-0.916 -2.73607,-4.08109 -7.10759,-7.03294 -11.86507,-8.01183 -1.48721,-0.30601 -2.19424,-0.37201 -3.98154,-0.37169 -1.95258,3.9e-4 -2.89342,0.11134 -4.61847,0.54488 -5.03068,1.26433 -9.42516,4.62461 -11.94519,9.13404 -1.61528,2.8904 -2.41964,5.99444 -2.41623,9.3243 0.003,2.99976 0.5844,5.56542 1.86554,8.23333 1.01389,2.11139 2.22943,3.79617 3.91527,5.42675 2.91431,2.81875 6.43132,4.55701 10.4983,5.18872 1.30491,0.20268 4.06945,0.21983 5.27581,0.0327 3.66804,-0.56892 6.69239,-1.87326 9.42226,-4.06361 1.65472,-1.32769 3.34842,-3.27371 4.39689,-5.05193 l 0.19494,-0.33061 -5.53317,-3.20759 c -9.9116,-5.74579 -10.75019,-6.2342 -10.81539,-6.29917 -0.0405,-0.0403 2.9819,-0.0641 8.14817,-0.0641 h 8.21253 l 0.0174,4.75284 0.0174,4.75283 0.67764,0.38469 c 0.37271,0.21158 1.47048,0.82838 2.43951,1.37067 1.94484,1.08838 6.54034,3.66529 8.52252,4.77898 0.69949,0.39299 1.28535,0.73649 1.30193,0.76332 0.078,0.12627 -1.30662,2.26459 -2.41482,3.72917 -4.07462,5.38495 -9.40618,9.29511 -15.76224,11.56 -2.33141,0.830765 -5.10253,1.460335 -7.74251,1.758995 -0.93672,0.10597 -4.99249,0.19246 -5.75877,0.12281 z"
|
||||||
|
id="path6437" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
BIN
assets/images/meincantor_r.png
Normal file
BIN
assets/images/meincantor_r.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
414
lib/Dashboard.dart
Normal file
414
lib/Dashboard.dart
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
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<StatefulWidget> createState() => _DashboardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> 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<Dashboard> 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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
145
lib/Login.dart
Normal file
145
lib/Login.dart
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'networking.dart';
|
||||||
|
import 'Dashboard.dart';
|
||||||
|
|
||||||
|
Future<bool> checkKey() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
String? api_key = await prefs.getString('api_key');
|
||||||
|
return api_key != null && api_key.isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Login extends StatelessWidget {
|
||||||
|
final userController = TextEditingController();
|
||||||
|
final passwordController = TextEditingController();
|
||||||
|
final otpController = TextEditingController();
|
||||||
|
final devIdController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("Anmelden"),
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
|
||||||
|
child: Container(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxWidth:
|
||||||
|
MediaQuery.of(context).size.width / factor,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Image.asset("assets/images/meincantor_r.png",
|
||||||
|
height: 192, width: 192),
|
||||||
|
Divider(),
|
||||||
|
AutofillGroup(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
autofillHints: [AutofillHints.username],
|
||||||
|
decoration: InputDecoration(
|
||||||
|
icon: Icon(CupertinoIcons.person),
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: 'Benutzername',
|
||||||
|
),
|
||||||
|
controller: userController,
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
TextField(
|
||||||
|
autofillHints: [AutofillHints.password],
|
||||||
|
decoration: InputDecoration(
|
||||||
|
icon: Icon(CupertinoIcons.lock),
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: 'Passwort',
|
||||||
|
),
|
||||||
|
obscureText: true,
|
||||||
|
controller: passwordController,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
Divider(),
|
||||||
|
TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
icon: Icon(CupertinoIcons.lock),
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: '2F2-Code (OTP) [falls aktiviert]',
|
||||||
|
),
|
||||||
|
obscureText: true,
|
||||||
|
controller: otpController,
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
icon: Icon(CupertinoIcons.device_laptop),
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: 'Gerätebezeichnung',
|
||||||
|
),
|
||||||
|
controller: devIdController,
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
SharedPreferences prefs =
|
||||||
|
await SharedPreferences.getInstance();
|
||||||
|
String api_key = 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 (prefs.getString('api_key') != null &&
|
||||||
|
prefs
|
||||||
|
.getString('api_key')!
|
||||||
|
.isNotEmpty) {
|
||||||
|
Navigator.pushReplacement(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => Dashboard()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text("Anmelden"))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
38
lib/Settings.dart
Normal file
38
lib/Settings.dart
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
174
lib/Timetable.dart
Normal file
174
lib/Timetable.dart
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class ClassTimetableBuilder {
|
||||||
|
final ListView view;
|
||||||
|
ClassTimetableBuilder({required this.view});
|
||||||
|
factory ClassTimetableBuilder.buildView(Map<String, dynamic> json) {
|
||||||
|
List<Widget> children = [];
|
||||||
|
ClassTimetable.fromJson(json).timetable.forEach((element) {
|
||||||
|
List<Widget> 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<String, dynamic> json){
|
||||||
|
print(json);
|
||||||
|
List<TimetableLesson> 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);
|
||||||
|
}
|
17
lib/generated_plugin_registrant.dart
Normal file
17
lib/generated_plugin_registrant.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Generated file. Do not edit.
|
||||||
|
//
|
||||||
|
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
import 'package:fluttertoast/fluttertoast_web.dart';
|
||||||
|
import 'package:shared_preferences_web/shared_preferences_web.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
void registerPlugins(Registrar registrar) {
|
||||||
|
FluttertoastWebPlugin.registerWith(registrar);
|
||||||
|
SharedPreferencesPlugin.registerWith(registrar);
|
||||||
|
registrar.registerMessageHandler();
|
||||||
|
}
|
84
lib/main.dart
Normal file
84
lib/main.dart
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'Dashboard.dart';
|
||||||
|
import 'Login.dart';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
void main() => runApp(App());
|
||||||
|
|
||||||
|
class App extends StatelessWidget {
|
||||||
|
MaterialColor generateMaterialColor(Color color) {
|
||||||
|
return MaterialColor(color.value, {
|
||||||
|
50: tintColor(color, 0.5),
|
||||||
|
100: tintColor(color, 0.4),
|
||||||
|
200: tintColor(color, 0.3),
|
||||||
|
300: tintColor(color, 0.2),
|
||||||
|
400: tintColor(color, 0.1),
|
||||||
|
500: tintColor(color, 0),
|
||||||
|
600: tintColor(color, -0.1),
|
||||||
|
700: tintColor(color, -0.2),
|
||||||
|
800: tintColor(color, -0.3),
|
||||||
|
900: tintColor(color, -0.4),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int tintValue(int value, double factor) =>
|
||||||
|
max(0, min((value + ((255 - value) * factor)).round(), 255));
|
||||||
|
|
||||||
|
Color tintColor(Color color, double factor) => Color.fromRGBO(
|
||||||
|
tintValue(color.red, factor),
|
||||||
|
tintValue(color.green, factor),
|
||||||
|
tintValue(color.blue, factor),
|
||||||
|
1);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: ThemeData(
|
||||||
|
primaryColor: Palette.primary,
|
||||||
|
colorScheme: ColorScheme.fromSwatch(
|
||||||
|
primarySwatch: generateMaterialColor(Palette.accent),
|
||||||
|
).copyWith(
|
||||||
|
secondary: generateMaterialColor(Palette.accent),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
darkTheme: ThemeData.from(colorScheme: ColorScheme.dark(primary: Palette.accent)),
|
||||||
|
title: "GCG.MeinCantor",
|
||||||
|
home: buildHomePage(),
|
||||||
|
/*
|
||||||
|
routes: <String, WidgetBuilder>{
|
||||||
|
"/": (_) => Dashboard(),
|
||||||
|
"/login": (_) => Login()
|
||||||
|
},
|
||||||
|
|
||||||
|
*/
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> apiKeyEmpty() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
String? api_key = await prefs.getString("api_key");
|
||||||
|
return api_key == null || api_key.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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Palette {
|
||||||
|
static const Color primary = Color(0xFF1A1A37);
|
||||||
|
static const Color accent = Color(0xFFFFBC3B);
|
||||||
|
}
|
194
lib/networking.dart
Normal file
194
lib/networking.dart
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
Future<String> getToken(
|
||||||
|
String user, String password, String otp, String devId) async {
|
||||||
|
var uri = Uri.http("localhost:3000", "/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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getUserInfo(
|
||||||
|
String user, String password, String otp, String devId) async {
|
||||||
|
var uri = Uri.http("localhost:3000", "/api/userinfo");
|
||||||
|
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 utf8.decode(response.bodyBytes);
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to log in');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<http.Response> fetchClassTimetable() 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';
|
||||||
|
}
|
||||||
|
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"};
|
||||||
|
print(uri);
|
||||||
|
final response = http.get(uri, headers: headers);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildClassTimetable() {
|
||||||
|
return FutureBuilder<http.Response>(
|
||||||
|
future: fetchClassTimetable(),
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
return Center(child: Text('Error $statusCode'));
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Text('$snapshot.error');
|
||||||
|
} else {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<http.Response> 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 uri = Uri.https("mein.cantorgymnasium.de", "/api/classes");
|
||||||
|
var headers = {"x-api-key": "$api_key"};
|
||||||
|
print(uri);
|
||||||
|
final response = http.get(uri, headers: headers);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildClassesChooser() {
|
||||||
|
return FutureBuilder<http.Response>(
|
||||||
|
future: fetchClassesList(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
int statusCode = snapshot.data!.statusCode;
|
||||||
|
if (statusCode == 200) {
|
||||||
|
// List<Widget> children = [];
|
||||||
|
//ClassTimetable.fromJson(jsonDecode(utf8.decode(snapshot.data!.bodyBytes))).timetable.forEach((element) {
|
||||||
|
//});
|
||||||
|
List<String> items = [];
|
||||||
|
jsonDecode(utf8.decode(snapshot.data!.bodyBytes)).forEach((value) {
|
||||||
|
items.add(value..toString());
|
||||||
|
});
|
||||||
|
return ClassesChooser(items: items);
|
||||||
|
}
|
||||||
|
return Text('$statusCode');
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Text('$snapshot.error');
|
||||||
|
} else {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassesChooser extends StatefulWidget {
|
||||||
|
final List<String> items;
|
||||||
|
const ClassesChooser({Key? key, required this.items}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ClassesChooser> createState() => _ClassesChooserState(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ClassesChooserState extends State<ClassesChooser> {
|
||||||
|
final List<String> items;
|
||||||
|
//final String dropdownValue;
|
||||||
|
var dropdownValue;
|
||||||
|
_ClassesChooserState(this.items);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// var dropdown_items =
|
||||||
|
return DropdownButtonFormField<String>(
|
||||||
|
// 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(
|
||||||
|
icon: Icon(CupertinoIcons.number),
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items: items.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user