2022-01-16 15:28:42 +01:00
// GCG.MeinCantor - Die Schulplattform für Cantorianer.
// Copyright (C) 2021-2022 Georg-Cantor-Gymnasium Halle (Saale)
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2021-12-19 22:20:56 +01:00
import ' dart:convert ' ;
import ' dart:math ' ;
import ' package:background_fetch/background_fetch.dart ' ;
2022-01-19 19:30:09 +01:00
import ' package:flutter_local_notifications/flutter_local_notifications.dart ' ;
2021-12-19 22:20:56 +01:00
import ' package:meincantor/background_fetch.dart ' ;
2021-12-13 13:39:06 +01:00
import ' package:meincantor/const.dart ' ;
import ' package:meincantor/schuelerzeitung.dart ' ;
import ' package:meincantor/Settings/dashboard.dart ' ;
2021-11-16 19:41:35 +01:00
2021-12-13 13:39:06 +01:00
import ' package:meincantor/main.dart ' ;
import ' package:meincantor/networking.dart ' ;
import ' package:meincantor/login.dart ' ;
2021-11-16 19:41:35 +01:00
2021-09-14 20:55:58 +02:00
import ' package:flutter/material.dart ' ;
import ' package:google_fonts/google_fonts.dart ' ;
2021-12-13 13:39:06 +01:00
import ' package:intl/intl.dart ' ;
2021-09-14 20:55:58 +02:00
import ' package:shared_preferences/shared_preferences.dart ' ;
2021-11-06 11:01:44 +01:00
import ' package:material_design_icons_flutter/material_design_icons_flutter.dart ' ;
2021-12-19 22:20:56 +01:00
import ' package:http/http.dart ' as http ;
2021-09-14 20:55:58 +02:00
2021-12-19 22:20:56 +01:00
import ' package:meincantor/news.dart ' ;
2021-09-14 20:55:58 +02:00
Future < String > getSettingsString ( String key ) async {
SharedPreferences prefs = await SharedPreferences . getInstance ( ) ;
String ? value = prefs . getString ( key ) ;
if ( value = = null | | value . isEmpty ) {
value = " " ;
}
return value ;
}
2021-11-06 11:01:44 +01:00
Widget buildSettingsString ( String key , TextStyle ? style ) {
2021-09-14 20:55:58 +02:00
return FutureBuilder (
future: getSettingsString ( key ) ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
return Text ( snapshot . data as String , style: style ) ;
} else {
2021-12-19 22:20:56 +01:00
return const SizedBox . shrink ( ) ;
2021-09-14 20:55:58 +02:00
}
} ) ;
}
2021-12-19 22:20:56 +01:00
Future < List < String > > getFavClasses ( ) async {
SharedPreferences prefs = await SharedPreferences . getInstance ( ) ;
List < String > ? listJson = prefs . getStringList ( " favClasses " ) ;
if ( listJson = = null | | listJson . isEmpty ) {
return < String > [ ] ;
} else {
return listJson ;
}
}
List < Widget > buildFavClasses (
BuildContext context , List < String > favClasses , Function removeFavClass ) {
if ( favClasses . isEmpty ) {
return [ const SizedBox . shrink ( ) ] ;
} else {
List < Widget > list = [ ] ;
for ( var element in favClasses ) {
var card = SizedBox (
width: 170 ,
child: GestureDetector (
onTap: ( ) async {
2021-09-14 20:55:58 +02:00
Navigator . push (
2021-12-19 22:20:56 +01:00
context ,
MaterialPageRoute (
builder: ( context ) = > DefaultTabController (
initialIndex: 0 ,
length: 3 ,
child: Scaffold (
appBar: AppBar (
leading: null ,
elevation: 0 ,
title: Text ( " Klasse $ element " ) ,
bottom: const TabBar (
indicatorColor: Palette . accent ,
enableFeedback: true ,
indicatorPadding: EdgeInsets . all ( 5 ) ,
indicatorSize: TabBarIndicatorSize . label ,
tabs: < Widget > [
Tab (
text: " Heute " ,
icon: Icon ( Icons . calendar_today_outlined ) ,
) ,
Tab (
text: " Morgen " ,
icon: Icon ( MdiIcons . calendarToday ) ,
) ,
Tab (
text: " Neuster Plan " ,
icon: Icon ( Icons . calendar_view_day_outlined ) ,
) ,
] ,
) ,
) ,
body: TabBarView (
children: < Widget > [
LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
int factor ;
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
return Center (
heightFactor: 1 ,
child: Container (
constraints: BoxConstraints (
maxWidth:
MediaQuery . of ( context ) . size . width /
factor ,
) ,
child: buildTimetable (
fetchClassTimetable (
" / ${ DateFormat ( " yyyyMMdd " ) . format ( DateTime . now ( ) ) } " ,
element ) ,
" Vertretungsplan für heute " ) ,
) ) ;
} ) ,
LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
int factor ;
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
return Center (
heightFactor: 1 ,
child: Container (
constraints: BoxConstraints (
maxWidth:
MediaQuery . of ( context ) . size . width /
factor ,
) ,
child: buildTimetable (
fetchClassTimetable (
" / ${ DateFormat ( " yyyyMMdd " ) . format ( DateTime . now ( ) . add ( const Duration ( days: 1 ) ) ) } " ,
element ) ,
" Vertretungsplan für morgen " ) ,
) ) ;
} ) ,
LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
int factor ;
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
return Center (
heightFactor: 1 ,
child: Container (
constraints: BoxConstraints (
maxWidth: MediaQuery . of ( context )
. size
. width /
factor ,
) ,
child: buildTimetable (
fetchClassTimetable (
" /latest " , element ) ,
" aktueller Vertretungsplan " ) ) ) ;
} ) ,
] ,
) ,
) ) ) ) ;
2021-09-14 20:55:58 +02:00
} ,
2021-12-19 22:20:56 +01:00
onLongPress: ( ) async {
2021-09-14 20:55:58 +02:00
SharedPreferences prefs = await SharedPreferences . getInstance ( ) ;
2021-12-19 22:20:56 +01:00
List < String > stringList = prefs . getStringList ( " favClasses " ) ! ;
stringList . remove ( element ) ;
prefs . setStringList ( " favClasses " , stringList ) ;
removeFavClass ( element ) ;
2021-09-14 20:55:58 +02:00
} ,
2021-12-19 22:20:56 +01:00
child: Card (
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 10 ) ,
) ,
child: Container (
decoration: BoxDecoration (
borderRadius: BorderRadius . circular ( 10 ) ,
gradient: LinearGradient (
begin: Alignment . topRight ,
end: Alignment . bottomLeft ,
colors: [
Colors . primaries [
Random ( ) . nextInt ( Colors . primaries . length ) ] ,
Colors . primaries [
Random ( ) . nextInt ( Colors . primaries . length ) ] ,
] ,
) ) ,
child: Padding (
padding: const EdgeInsets . all ( 10 ) ,
child: Center (
child: Padding (
padding: const EdgeInsets . fromLTRB ( 15 , 15 , 15 , 15 ) ,
child: Text (
element ,
style: const TextStyle ( color: Colors . white ) ,
textScaleFactor: 2.0 ,
) ,
) ,
) ,
) ) ,
) ,
2021-09-14 20:55:58 +02:00
) ,
2021-12-19 22:20:56 +01:00
) ;
list . add ( card ) ;
}
return ( list ) ;
}
}
class Dashboard extends StatefulWidget {
const Dashboard ( { Key ? key , this . restorationId } ) : super ( key: key ) ;
final String ? restorationId ;
@ override
State < StatefulWidget > createState ( ) = > _DashboardState ( ) ;
}
class _DashboardState extends State < Dashboard > with RestorationMixin {
final RestorableInt _currentIndex = RestorableInt ( 0 ) ;
@ override
void initState ( ) {
super . initState ( ) ;
initPlatformState ( ) ;
2022-01-19 19:30:09 +01:00
initNotifications ( ) ;
}
Future < void > initNotifications ( ) async {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin ( ) ;
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings ( ' app_icon ' ) ;
const DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings ( ) ;
const InitializationSettings initializationSettings =
InitializationSettings (
android: initializationSettingsAndroid ,
iOS: initializationSettingsDarwin ,
macOS: initializationSettingsDarwin ) ;
await flutterLocalNotificationsPlugin . initialize ( initializationSettings ,
onSelectNotification: selectNotification ) ;
}
void selectNotification ( String ? payload ) async {
if ( payload = = null ) {
debugPrint ( ' notification payload: $ payload ' ) ;
} else if ( payload = = " today " ) {
await Navigator . push (
context ,
MaterialPageRoute < void > (
builder: ( context ) = > Scaffold (
appBar: AppBar ( title: const Text ( " Vertretungsplan für heute " ) ) ,
body: buildTimetable (
fetchClassTimetable (
" / ${ DateFormat ( " yyyyMMdd " ) . format ( DateTime . now ( ) ) } " ,
null ) ,
" Vertretungsplan für heute " ) ) ) ,
) ;
} else if ( payload = = " tomorrow " ) {
await Navigator . push (
context ,
MaterialPageRoute < void > (
builder: ( context ) = > Scaffold (
appBar: AppBar ( title: const Text ( " Vertretungsplan für morgen " ) ) ,
body: buildTimetable (
fetchClassTimetable (
" / ${ DateFormat ( " yyyyMMdd " ) . format ( DateTime . now ( ) . add ( const Duration ( days: 1 ) ) ) } " ,
null ) ,
" Vertretungsplan für morgen " ) ) ) ,
) ;
} else if ( payload = = " sz " ) {
await Navigator . push (
context ,
MaterialPageRoute < void > (
builder: ( context ) = > const SZ ( ) ) ,
) ;
} else if ( payload = = " articles " ) {
await Navigator . push (
context ,
MaterialPageRoute < void > (
builder: ( context ) = > const News ( ) ) ,
) ;
}
2021-12-19 22:20:56 +01:00
}
Future < void > initPlatformState ( ) async {
// Configure BackgroundFetch.
int status = await BackgroundFetch . configure (
BackgroundFetchConfig (
minimumFetchInterval: 15 ,
stopOnTerminate: false ,
enableHeadless: true ,
startOnBoot: true ,
requiresBatteryNotLow: false ,
requiresCharging: false ,
requiresStorageNotLow: false ,
requiresDeviceIdle: false ,
requiredNetworkType: NetworkType . ANY ) , ( String taskId ) async {
// <-- Event handler
// This is the fetch-event callback.
print ( " [BackgroundFetch] Event received $ taskId " ) ;
await backgroundFetchTimetable ( ) ;
await backgroundFetchArticles ( ) ;
// IMPORTANT: You must signal completion of your task or the OS can punish your app
// for taking too long in the background.
BackgroundFetch . finish ( taskId ) ;
} , ( String taskId ) async {
// <-- Task timeout handler.
// This task has exceeded its allowed running-time. You must stop what you're doing and immediately .finish(taskId)
print ( " [BackgroundFetch] TASK TIMEOUT taskId: $ taskId " ) ;
BackgroundFetch . finish ( taskId ) ;
} ) ;
print ( ' [BackgroundFetch] configure success: $ status ' ) ;
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if ( ! mounted ) return ;
}
@ override
Widget build ( BuildContext context ) {
2021-09-14 20:55:58 +02:00
var bottomNavBarItems = [
const BottomNavigationBarItem (
2021-11-06 11:01:44 +01:00
icon: Icon ( MdiIcons . homeOutline ) ,
2021-09-14 20:55:58 +02:00
label: " Startseite " ,
) ,
const BottomNavigationBarItem (
2021-11-16 19:41:35 +01:00
icon: Icon ( MdiIcons . timetable ) , label: " Vertretungsplan " ) ,
2021-09-14 20:55:58 +02:00
] ;
return Scaffold (
body: _DashboardBottomNavView (
key: UniqueKey ( ) , item: bottomNavBarItems [ _currentIndex . value ] ) ,
bottomNavigationBar: BottomNavigationBar (
showUnselectedLabels: false ,
items: bottomNavBarItems ,
currentIndex: _currentIndex . value ,
onTap: ( index ) {
setState ( ( ) {
_currentIndex . value = index ;
} ) ;
} ,
) ,
) ;
}
@ override
String ? get restorationId = > widget . restorationId ;
@ override
void restoreState ( RestorationBucket ? oldBucket , bool initialRestore ) {
registerForRestoration ( _currentIndex , ' bottom_navigation_tab_index ' ) ;
}
}
2021-12-19 22:20:56 +01:00
class _DashboardBottomNavView extends StatefulWidget {
2021-09-14 20:55:58 +02:00
const _DashboardBottomNavView ( { Key ? key , required this . item } )
: super ( key: key ) ;
final BottomNavigationBarItem item ;
2021-12-19 22:20:56 +01:00
@ override
// ignore: no_logic_in_create_state
State < StatefulWidget > createState ( ) = > _DashboardBottomNavViewState ( item ) ;
}
class _DashboardBottomNavViewState extends State < _DashboardBottomNavView > {
final BottomNavigationBarItem item ;
_DashboardBottomNavViewState ( this . item ) ;
List < String > favClasses = [ ] ;
void removeFavClass ( String classNum ) {
setState ( ( ) {
favClasses . remove ( classNum ) ;
} ) ;
}
2021-09-14 20:55:58 +02:00
@ override
Widget build ( BuildContext context ) {
2021-12-19 22:20:56 +01:00
final drawerElements = ListView (
children: [
UserAccountsDrawerHeader (
accountName: buildSettingsString ( ' name ' , const TextStyle ( ) ) ,
accountEmail: buildSettingsString ( ' email ' , const TextStyle ( ) ) ,
currentAccountPicture: FutureBuilder (
future: Future . sync ( ( ) async {
SharedPreferences prefs = await SharedPreferences . getInstance ( ) ;
String ? user = prefs . getString ( " user " ) ;
if ( user = = null | | user . isEmpty ) {
user = " " ;
}
String ? name = prefs . getString ( " name " ) ;
if ( name = = null | | name . isEmpty ) {
name = " " ;
}
Map data = { " user " : user , " name " : name } ;
return data ;
} ) ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
String url = " $ avatarUrl / ${ ( snapshot . data ! as Map ) [ ' user ' ] } " ;
return Container (
decoration: BoxDecoration (
shape: BoxShape . circle ,
image: DecorationImage (
fit: BoxFit . scaleDown ,
image: NetworkImage ( url ) ) ) ) ;
} else {
return const CircularProgressIndicator ( ) ;
}
} ,
) ) ,
Padding (
padding: const EdgeInsets . all ( 5 ) ,
child: ListTile (
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 15.0 ) ) ,
title: const Text ( " Einstellungen " ) ,
onTap: ( ) {
Navigator . push (
context ,
MaterialPageRoute ( builder: ( context ) = > const Settings ( ) ) ,
) ;
} ,
leading: const Icon ( Icons . settings_outlined ) ,
) ,
) ,
Padding (
padding: const EdgeInsets . all ( 5 ) ,
child: ListTile (
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 15.0 ) ) ,
title: const Text ( " Abmelden " ) ,
onTap: ( ) async {
return showDialog < void > (
context: context ,
barrierDismissible: false , // user must tap button!
builder: ( BuildContext context ) {
return AlertDialog (
title: const Text ( ' Abmelden ' ) ,
content: SingleChildScrollView (
child: ListBody (
children: const < Widget > [
Text (
' Dabei werden alle persönlichen Enstellungen gelöscht! ' ) ,
] ,
) ,
) ,
actions: < Widget > [
TextButton (
child: const Text ( ' Bestätigen ' ) ,
onPressed: ( ) async {
SharedPreferences prefs =
await SharedPreferences . getInstance ( ) ;
prefs . clear ( ) ;
Navigator . pushReplacement (
context ,
MaterialPageRoute ( builder: ( context ) = > Login ( ) ) ,
) ;
} ,
) ,
] ,
) ;
} ,
) ;
} ,
leading: const Icon ( Icons . exit_to_app_outlined ) ,
) ,
) ,
] ,
) ;
2021-09-14 20:55:58 +02:00
if ( item . label = = " Startseite " ) {
double _timeOfDayToDouble ( TimeOfDay tod ) = > tod . hour + tod . minute / 60.0 ;
2021-11-16 19:41:35 +01:00
int lessonCount ;
2021-12-19 22:20:56 +01:00
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble ( const TimeOfDay ( hour: 7 , minute: 30 ) )
? lessonCount = 1
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 7 , minute: 30 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble ( const TimeOfDay ( hour: 8 , minute: 20 ) )
? lessonCount = 2
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 8 , minute: 20 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble (
const TimeOfDay ( hour: 9 , minute: 25 ) )
? lessonCount = 3
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 9 , minute: 25 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble (
const TimeOfDay ( hour: 10 , minute: 15 ) )
? lessonCount = 4
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) >
_timeOfDayToDouble (
const TimeOfDay ( hour: 10 , minute: 15 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble (
const TimeOfDay ( hour: 11 , minute: 30 ) )
? lessonCount = 5
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 11 , minute: 30 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble (
const TimeOfDay ( hour: 12 , minute: 20 ) )
? lessonCount = 6
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 12 , minute: 20 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble ( const TimeOfDay (
hour: 13 , minute: 30 ) )
? lessonCount = 7
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 13 , minute: 30 ) ) & &
_timeOfDayToDouble ( TimeOfDay . now ( ) ) < =
_timeOfDayToDouble ( const TimeOfDay ( hour: 14 , minute: 20 ) )
? lessonCount = 8
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 14 , minute: 20 ) ) & & _timeOfDayToDouble ( TimeOfDay . now ( ) ) < = _timeOfDayToDouble ( const TimeOfDay ( hour: 15 , minute: 10 ) )
? lessonCount = 9
: _timeOfDayToDouble ( TimeOfDay . now ( ) ) > _timeOfDayToDouble ( const TimeOfDay ( hour: 15 , minute: 10 ) ) & & _timeOfDayToDouble ( TimeOfDay . now ( ) ) < = _timeOfDayToDouble ( const TimeOfDay ( hour: 16 , minute: 00 ) )
? lessonCount = 10
: lessonCount = - 1 ;
2021-09-14 20:55:58 +02:00
var view = SingleChildScrollView (
2021-11-16 19:41:35 +01:00
child: Column ( children: [
Row (
mainAxisSize: MainAxisSize . max ,
2021-09-14 20:55:58 +02:00
children: [
2021-11-16 19:41:35 +01:00
Padding (
padding: const EdgeInsets . fromLTRB ( 20 , 30 , 20 , 5 ) ,
child: Text (
' Hallo, ' ,
style: GoogleFonts . robotoSlab (
fontSize: 20 ,
2021-09-14 20:55:58 +02:00
) ,
2021-11-16 19:41:35 +01:00
) ,
2021-09-14 20:55:58 +02:00
) ,
2021-11-16 19:41:35 +01:00
] ,
) ,
Row (
mainAxisSize: MainAxisSize . max ,
children: [
2021-09-14 20:55:58 +02:00
Padding (
2021-11-16 19:41:35 +01:00
padding: const EdgeInsets . fromLTRB ( 20 , 5 , 20 , 20 ) ,
child: buildSettingsString (
" name " ,
GoogleFonts . robotoSlab (
fontSize: 28 ,
fontWeight: FontWeight . w800 ,
) ,
) ,
)
] ,
) ,
Row (
mainAxisSize: MainAxisSize . max ,
children: [
2021-11-06 11:01:44 +01:00
Padding (
2021-11-16 19:41:35 +01:00
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 ) ,
) ,
Padding (
padding: const EdgeInsets . fromLTRB ( 20 , 20 , 20 , 10 ) ,
child: Wrap (
children: [
SizedBox (
2021-12-19 22:20:56 +01:00
width: 175 ,
child: GestureDetector (
onTap: ( ) async {
Navigator . push (
context ,
MaterialPageRoute ( builder: ( context ) = > const SZ ( ) ) ,
) ;
} ,
child: Card (
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 10 ) ,
2021-09-14 20:55:58 +02:00
) ,
2021-12-19 22:20:56 +01:00
child: const Padding (
padding: EdgeInsets . all ( 10 ) ,
child: ListTile (
title: Padding (
padding: EdgeInsets . fromLTRB ( 0 , 0 , 0 , 10 ) ,
child: Icon (
MdiIcons . newspaper ,
color: Palette . accent ,
size: 48 ,
2021-09-14 20:55:58 +02:00
) ,
2021-11-16 19:41:35 +01:00
) ,
2021-12-19 22:20:56 +01:00
subtitle: Center (
child: Padding (
padding: EdgeInsets . fromLTRB ( 0 , 10 , 0 , 0 ) ,
child: Text ( ' Schülerzeitung ' ) ,
2021-09-14 20:55:58 +02:00
) ,
2021-11-16 19:41:35 +01:00
) ,
2021-09-14 20:55:58 +02:00
) ,
2021-12-19 22:20:56 +01:00
) ) ,
) ) ,
2021-12-13 13:39:06 +01:00
SizedBox (
2021-12-19 22:20:56 +01:00
width: 175 ,
2021-12-13 13:39:06 +01:00
child: GestureDetector (
onTap: ( ) async {
Navigator . push (
context ,
MaterialPageRoute ( builder: ( context ) = > const News ( ) ) ,
) ;
} ,
child: Card (
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 10 ) ,
) ,
child: const Padding (
padding: EdgeInsets . all ( 10 ) ,
child: ListTile (
title: Padding (
padding: EdgeInsets . fromLTRB ( 0 , 0 , 0 , 10 ) ,
child: Icon (
MdiIcons . newspaperVariantOutline ,
color: Palette . accent ,
size: 48 ,
) ,
) ,
subtitle: Center (
child: Padding (
padding: EdgeInsets . fromLTRB ( 0 , 10 , 0 , 0 ) ,
child: Text (
' Aktuelles ' ,
) ,
) ,
) ,
) ,
) ) ,
) ,
2021-11-16 19:41:35 +01:00
)
] ,
) ,
) ,
2021-12-19 22:20:56 +01:00
Padding (
padding: const EdgeInsets . fromLTRB ( 20 , 0 , 20 , 20 ) ,
child: Column (
children: [
const ListTile ( title: Text ( " Favorisierte Klassen " ) ) ,
FutureBuilder (
future: getFavClasses ( ) ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
favClasses = snapshot . data ! as List < String > ;
return Wrap ( children: [
. . . ( buildFavClasses (
context , favClasses , removeFavClass ) ) ,
SizedBox (
width: 170 ,
child: GestureDetector (
onTap: ( ) async {
showModalBottomSheet < void > (
isScrollControlled: true ,
shape: const RoundedRectangleBorder (
borderRadius: BorderRadius . only (
topLeft: Radius . circular ( 25.0 ) ,
topRight: Radius . circular ( 25.0 ) ) ,
) ,
context: context ,
builder: ( BuildContext context ) {
return SizedBox (
height: 400 ,
child: ListView (
children: < Widget > [
ListTile (
title: const Text (
" Klasse hinzufügen " ,
style: TextStyle (
fontWeight:
FontWeight . bold ) ) ,
leading:
const Icon ( Icons . arrow_back ) ,
onTap: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
FutureBuilder < http . Response > (
future: fetchClassesList ( ) ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
if ( snapshot
. data ! . statusCode = =
200 ) {
List < Widget > classesList =
[ ] ;
for ( var classNum
in jsonDecode ( snapshot
. data ! . body ) ) {
classesList
. add ( ListTile (
title: Text ( classNum ) ,
onTap: ( ) async {
SharedPreferences
prefs =
await SharedPreferences
. getInstance ( ) ;
if ( prefs
. getStringList (
" favClasses " ) ! =
null & &
prefs
. getStringList (
" favClasses " ) !
. contains (
classNum ) ) {
const snackBar = SnackBar (
content: Text (
' Klasse bereits in den Favoriten ' ) ) ;
ScaffoldMessenger
. of (
context )
. showSnackBar (
snackBar ) ;
} else if ( prefs
. getStringList (
" favClasses " ) = =
null ) {
List < String >
stringList = [
classNum
] ;
prefs . setStringList (
" favClasses " ,
stringList ) ;
} else {
List < String >
stringList =
prefs . getStringList (
" favClasses " ) ! ;
stringList . add (
classNum ) ;
prefs . setStringList (
" favClasses " ,
stringList ) ;
setState ( ( ) {
favClasses =
stringList ;
} ) ;
}
} ,
) ) ;
classesList . add (
const Divider ( ) ) ;
}
return Column (
children:
classesList ) ;
} else if ( snapshot
. data ! . 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 ( snapshot
. data ! . 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 " ) ) ,
) ;
} else {
return const Center (
child: Text (
" Uups... etwas ist schief gelaufen... " ) ) ;
}
} else if ( snapshot
. hasError ) {
return const Center (
child: Text (
" Uups... etwas ist schief gelaufen... " ) ) ;
} else {
return const Center (
child:
CircularProgressIndicator ( ) ) ;
}
} )
] ,
) ,
) ;
} ,
) ;
} ,
child: Card (
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 10 ) ,
) ,
child: const Padding (
padding: EdgeInsets . all ( 6 ) ,
child: ListTile (
title: Center ( child: Text ( " + " ) ) ,
subtitle: Center (
child: Text (
' Klasse hinzufügen ' ,
textScaleFactor: 0.9 ,
) ,
) ,
) ,
) ) ,
) ,
)
] ) ;
} else if ( snapshot . hasError ) {
return const Center (
child:
Text ( " Uups... etwas ist schief gelaufen... " ) ) ;
} else {
return const CircularProgressIndicator ( ) ;
}
} ) ,
] ,
) )
2021-11-16 19:41:35 +01:00
] ) ,
) ;
2021-12-19 22:20:56 +01:00
return Scaffold (
appBar: AppBar (
title: const Text ( " GCG.MeinCantor " ) ,
centerTitle: true ,
) ,
drawer: Drawer (
child: drawerElements ,
) ,
body: LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
int factor ;
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
return Center (
heightFactor: 1 ,
child: Container (
constraints: BoxConstraints (
maxWidth: MediaQuery . of ( context ) . size . width / factor ,
) ,
child: view ) ,
) ;
} ) ,
) ;
2021-09-14 20:55:58 +02:00
} else if ( item . label = = " Vertretungsplan " ) {
2021-12-19 22:20:56 +01:00
List < Widget > children = < Widget > [
LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
2021-11-16 19:41:35 +01:00
2021-12-19 22:20:56 +01:00
int factor ;
2021-09-14 20:55:58 +02:00
2021-12-19 22:20:56 +01:00
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
2021-09-14 20:55:58 +02:00
2021-12-19 22:20:56 +01:00
return Center (
child: Container (
constraints: BoxConstraints (
maxWidth: MediaQuery . of ( context ) . size . width / factor ,
) ,
child: buildTimetable (
fetchClassTimetable (
" / ${ DateFormat ( " yyyyMMdd " ) . format ( DateTime . now ( ) ) } " ,
null ) ,
" Vertretungsplan für heute " ) ,
2021-09-14 20:55:58 +02:00
) ,
2021-12-19 22:20:56 +01:00
) ;
} ) ,
LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
int factor ;
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
return Center (
child: Container (
constraints: BoxConstraints (
maxWidth: MediaQuery . of ( context ) . size . width / factor ,
) ,
child: buildTimetable (
fetchClassTimetable (
" / ${ DateFormat ( " yyyyMMdd " ) . format ( DateTime . now ( ) . add ( const Duration ( days: 1 ) ) ) } " ,
null ) ,
" Vertretungsplan für morgen " ) ,
) ,
) ;
} ) ,
LayoutBuilder ( builder: ( context , constraints ) {
double widgetWidth = constraints . maxWidth ;
int factor ;
if ( widgetWidth < = 600 ) {
factor = 1 ;
} else if ( widgetWidth < = 1400 ) {
factor = 2 ;
} else if ( widgetWidth < = 2000 ) {
factor = 3 ;
} else {
factor = 1 ;
}
return Center (
child: Container (
constraints: BoxConstraints (
maxWidth: MediaQuery . of ( context ) . size . width / factor ,
2021-09-14 20:55:58 +02:00
) ,
2021-12-19 22:20:56 +01:00
child: buildTimetable ( fetchClassTimetable ( " /latest " , null ) ,
" aktueller Vertretungsplan " ) ) ,
) ;
} )
] ;
return DefaultTabController (
initialIndex: 0 ,
length: 3 ,
child: Scaffold (
appBar: AppBar (
title: const Text ( " GCG.MeinCantor " ) ,
centerTitle: true ,
bottom: const TabBar (
indicatorColor: Palette . accent ,
enableFeedback: true ,
indicatorPadding: EdgeInsets . all ( 5 ) ,
indicatorSize: TabBarIndicatorSize . label ,
tabs: < Widget > [
Tab (
text: " Heute " ,
icon: Icon ( Icons . calendar_today_outlined ) ,
2021-09-14 20:55:58 +02:00
) ,
2021-12-19 22:20:56 +01:00
Tab (
text: " Morgen " ,
icon: Icon ( MdiIcons . calendarToday ) ,
) ,
Tab (
text: " Neuster Plan " ,
icon: Icon ( Icons . calendar_view_day_outlined ) ,
) ,
] ,
2021-09-14 20:55:58 +02:00
) ,
) ,
2021-12-19 22:20:56 +01:00
drawer: Drawer ( child: drawerElements ) ,
body: TabBarView ( children: children ) ,
) ,
) ;
2021-09-14 20:55:58 +02:00
} else {
2021-11-06 11:01:44 +01:00
return const Center ( child: Text ( " Derzeit nichts hier... " ) ) ;
2021-09-14 20:55:58 +02:00
}
}
2021-11-16 19:41:35 +01:00
}