diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..32b90da
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+ // Verwendet IntelliSense zum Ermitteln möglicher Attribute.
+ // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
+ // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "app",
+ "request": "launch",
+ "type": "dart"
+ },
+ {
+ "name": "app (profile mode)",
+ "request": "launch",
+ "type": "dart",
+ "flutterMode": "profile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/android.zip b/android.zip
new file mode 100644
index 0000000..dc96427
Binary files /dev/null and b/android.zip differ
diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml
index 80f1a96..682acbf 100644
--- a/android/.idea/gradle.xml
+++ b/android/.idea/gradle.xml
@@ -4,15 +4,21 @@
\ No newline at end of file
diff --git a/android/.idea/libraries/Flutter_Plugins.xml b/android/.idea/libraries/Flutter_Plugins.xml
deleted file mode 100644
index b0f6971..0000000
--- a/android/.idea/libraries/Flutter_Plugins.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__androidx_activity_activity_1_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_activity_activity_1_0_0_aar.xml
index 06d1f86..de662e1 100644
--- a/android/.idea/libraries/Gradle__androidx_activity_activity_1_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_activity_activity_1_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_annotation_annotation_1_1_0.xml b/android/.idea/libraries/Gradle__androidx_annotation_annotation_1_1_0.xml
deleted file mode 100644
index b2158ac..0000000
--- a/android/.idea/libraries/Gradle__androidx_annotation_annotation_1_1_0.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml
index 2809833..1d30de5 100644
--- a/android/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_core_core_1_1_0_aar.xml b/android/.idea/libraries/Gradle__androidx_core_core_1_1_0_aar.xml
deleted file mode 100644
index b5d056e..0000000
--- a/android/.idea/libraries/Gradle__androidx_core_core_1_1_0_aar.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml
index cbcb46a..ae103ed 100644
--- a/android/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_fragment_fragment_1_1_0_aar.xml b/android/.idea/libraries/Gradle__androidx_fragment_fragment_1_1_0_aar.xml
index c1e4382..e2d579b 100644
--- a/android/.idea/libraries/Gradle__androidx_fragment_fragment_1_1_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_fragment_fragment_1_1_0_aar.xml
@@ -1,12 +1,13 @@
-
+
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml
index 15e56dd..1b458b8 100644
--- a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_0_0_aar.xml
index 73bb1d5..2116e61 100644
--- a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_2_0_aar.xml b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_2_0_aar.xml
index a05f202..d835567 100644
--- a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_2_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_2_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_1_0_aar.xml b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_1_0_aar.xml
index bcfcd11..ae54ce2 100644
--- a/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_1_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_1_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml
index 2f72bdd..2cea050 100644
--- a/android/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_0_0_aar.xml
index 811dc16..fcdc9b4 100644
--- a/android/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_0_aar.xml b/android/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_0_aar.xml
deleted file mode 100644
index 944df01..0000000
--- a/android/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_0_aar.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml b/android/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml
index 4f21492..2a6fc1e 100644
--- a/android/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml
+++ b/android/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml
@@ -1,9 +1,10 @@
-
-
+
+
+
diff --git a/android/.idea/libraries/Gradle__io_flutter_arm64_v8a_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml b/android/.idea/libraries/Gradle__io_flutter_arm64_v8a_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
deleted file mode 100644
index 5eb1eaf..0000000
--- a/android/.idea/libraries/Gradle__io_flutter_arm64_v8a_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__io_flutter_armeabi_v7a_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml b/android/.idea/libraries/Gradle__io_flutter_armeabi_v7a_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
deleted file mode 100644
index 466a0f8..0000000
--- a/android/.idea/libraries/Gradle__io_flutter_armeabi_v7a_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__io_flutter_flutter_embedding_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml b/android/.idea/libraries/Gradle__io_flutter_flutter_embedding_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
deleted file mode 100644
index 05d5808..0000000
--- a/android/.idea/libraries/Gradle__io_flutter_flutter_embedding_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__io_flutter_x86_64_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml b/android/.idea/libraries/Gradle__io_flutter_x86_64_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
deleted file mode 100644
index be9188f..0000000
--- a/android/.idea/libraries/Gradle__io_flutter_x86_64_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/libraries/Gradle__io_flutter_x86_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml b/android/.idea/libraries/Gradle__io_flutter_x86_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
deleted file mode 100644
index 4d125f3..0000000
--- a/android/.idea/libraries/Gradle__io_flutter_x86_debug_1_0_0_241c87ad800beeab545ab867354d4683d5bfb6ce.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml
index 5500d01..8401cbc 100644
--- a/android/.idea/misc.xml
+++ b/android/.idea/misc.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/android/.idea/modules.xml b/android/.idea/modules.xml
index 5333642..4cfe785 100644
--- a/android/.idea/modules.xml
+++ b/android/.idea/modules.xml
@@ -4,8 +4,13 @@
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/modules/-442492029/android.path_provider.iml b/android/.idea/modules/-442492029/android.path_provider.iml
deleted file mode 100644
index 1b6d5cf..0000000
--- a/android/.idea/modules/-442492029/android.path_provider.iml
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/modules/1049519328/android.shared_preferences.iml b/android/.idea/modules/1049519328/android.shared_preferences.iml
deleted file mode 100644
index 5a1a7ce..0000000
--- a/android/.idea/modules/1049519328/android.shared_preferences.iml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/.idea/modules/android.iml b/android/.idea/modules/android.iml
index 616d2d8..4e86d15 100644
--- a/android/.idea/modules/android.iml
+++ b/android/.idea/modules/android.iml
@@ -3,12 +3,11 @@
-
-
+
diff --git a/android/.idea/modules/app/android.app.iml b/android/.idea/modules/app/android.app.iml
index 7ddc274..bf05337 100644
--- a/android/.idea/modules/app/android.app.iml
+++ b/android/.idea/modules/app/android.app.iml
@@ -4,8 +4,8 @@
-
-
+
+
@@ -31,7 +31,7 @@
-
+
@@ -81,35 +81,49 @@
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/.idea/runConfigurations.xml b/android/.idea/runConfigurations.xml
deleted file mode 100644
index 797acea..0000000
--- a/android/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index cfa383a..3c0bd5e 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion 30
+ compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@@ -45,7 +45,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "de.cantorgymnasium.meincantor"
minSdkVersion 20
- targetSdkVersion 30
+ targetSdkVersion rootProject.ext.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 729401f..de345fe 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,9 @@
+
android:showWhenLocked="true"
android:turnScreenOn="true"
+ android:windowSoftInputMode="adjustResize">
+
+
diff --git a/assets/images/meincantor-big.png b/assets/images/meincantor-big.png
new file mode 100644
index 0000000..4830a8c
Binary files /dev/null and b/assets/images/meincantor-big.png differ
diff --git a/assets/images/meincantor-big.svg b/assets/images/meincantor-big.svg
new file mode 100644
index 0000000..43834c7
--- /dev/null
+++ b/assets/images/meincantor-big.svg
@@ -0,0 +1,136 @@
+
+
+
+
diff --git a/lib/Settings/Pages/appearance_settings.dart b/lib/Settings/Pages/appearance_settings.dart
index a379840..9360819 100644
--- a/lib/Settings/Pages/appearance_settings.dart
+++ b/lib/Settings/Pages/appearance_settings.dart
@@ -1,4 +1,3 @@
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class AppearanceSettings extends StatelessWidget {
@@ -13,7 +12,7 @@ class AppearanceSettings extends StatelessWidget {
),
body: ListView(
padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
- children: [],
+ children: const [],
));
}
}
diff --git a/lib/Settings/Pages/dev_settings.dart b/lib/Settings/Pages/dev_settings.dart
index 4e40844..4883132 100644
--- a/lib/Settings/Pages/dev_settings.dart
+++ b/lib/Settings/Pages/dev_settings.dart
@@ -1,12 +1,29 @@
+import 'package:background_fetch/background_fetch.dart';
import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
+import 'package:meincantor/background_fetch.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import '../../login.dart';
+import 'package:meincantor/login.dart';
-class DevSettings extends StatelessWidget {
+class DevSettings extends StatefulWidget {
const DevSettings({Key? key}) : super(key: key);
+ @override
+ State createState() => _DevSettingsState();
+}
+
+class _DevSettingsState extends State {
+ int _status = 0;
+
+ void _onClickStatus() async {
+ int status = await BackgroundFetch.status;
+ print('[BackgroundFetch] status: $status');
+ setState(() {
+ _status = status;
+ });
+ }
+
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -14,41 +31,98 @@ class DevSettings extends StatelessWidget {
title: const Text("Entwickler-Einstellungen"),
centerTitle: true,
),
- body: ListView(
- padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
- children: [
- Padding(
- padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
- child: TextField(
- decoration: const InputDecoration(
- icon: Icon(MdiIcons.keyOutline),
- border: OutlineInputBorder(),
- labelText: 'MeinCantor API-Schlüssel',
- ),
- onSubmitted: (String value) async {
- SharedPreferences prefs =
- await SharedPreferences.getInstance();
- String apiKey = value;
- await prefs.setString('api_key', apiKey);
- final snackBar = SnackBar(
- content:
- Text('Neuer API-Schlüssel gesetzt: $apiKey'));
- ScaffoldMessenger.of(context).showSnackBar(snackBar);
- })),
- const Divider(),
- Padding(
- padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
- child: OutlinedButton(
- onPressed: () async {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => Login()),
- );
- },
- child: const Text("Benutzerdaten neu laden"),
- )
- )
- ],
- ));
+ 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: ListView(
+ padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
+ children: [
+ Padding(
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
+ child: TextField(
+ decoration: const InputDecoration(
+ icon: Icon(MdiIcons.keyOutline),
+ border: OutlineInputBorder(),
+ labelText: 'MeinCantor API-Schlüssel',
+ ),
+ onSubmitted: (String value) async {
+ SharedPreferences prefs =
+ await SharedPreferences.getInstance();
+ String apiKey = value;
+ await prefs.setString('api_key', apiKey);
+ final snackBar = SnackBar(
+ content: Text(
+ 'Neuer API-Schlüssel gesetzt: $apiKey'));
+ ScaffoldMessenger.of(context)
+ .showSnackBar(snackBar);
+ })),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
+ child: OutlinedButton(
+ onPressed: () async {
+ Navigator.push(
+ context,
+ MaterialPageRoute(builder: (context) => Login()),
+ );
+ },
+ child: const Text("Benutzerdaten neu laden"),
+ )),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
+ child: OutlinedButton(
+ onPressed: () {
+ _onClickStatus();
+ },
+ child: const Text(
+ "Status der Hintergrundoperation anzeigen"),
+ )),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
+ child: Text(_status.toString())),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
+ child: OutlinedButton(
+ onPressed: () async {
+ await backgroundFetchTimetable();
+ },
+ child: const Text(
+ "Stundenplan im Hintergrund neu laden"),
+ )),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
+ child: OutlinedButton(
+ onPressed: () async {
+ await backgroundFetchArticles();
+ },
+ child: const Text(
+ "Schülerzeitung im Hintergrund neu laden"),
+ )),
+ ],
+ )),
+ );
+ }));
}
}
diff --git a/lib/Settings/Pages/info_settings.dart b/lib/Settings/Pages/info_settings.dart
index f82c1f8..730e44e 100644
--- a/lib/Settings/Pages/info_settings.dart
+++ b/lib/Settings/Pages/info_settings.dart
@@ -1,6 +1,3 @@
-import 'dart:io';
-
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:meincantor/const.dart';
@@ -17,79 +14,136 @@ class InfoSettings extends StatelessWidget {
title: const Text("Informationen"),
centerTitle: true,
),
- body: ListView(
- padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
- children: [
- const ListTile(
- leading: Icon(Icons.info_outlined),
- title: Text("Version"),
- subtitle: Text(version)),
- ListTile(
- leading: Icon(Icons.person_outlined),
- title: Text("Autor"),
- subtitle: Text(author),
- onTap: () => launch("https://git.cantorgymnasium.de/denyskon"),
- ),
- ListTile(
- leading: const Icon(Icons.source_outlined),
- title: const Text("Quellcode"),
- subtitle: Linkify(
- onOpen: (link) async {
- if (await canLaunch(link.url)) {
- await launch(link.url);
- } else {
- throw 'Could not launch $link';
- }
- },
- text: "https://git.cantorgymnasium.de/cantortechnik/meincantor-app",
- linkStyle: const TextStyle(color: Palette.accent),
+ 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,
),
- ),
- ListTile(
- leading: const Icon(Icons.settings_backup_restore_outlined),
- title: const Text("Änderungsverlauf"),
- subtitle: const Text("Was ist neu?"),
- onTap: () {
- showModalBottomSheet(
- isScrollControlled: true,
- context: context,
- builder: (BuildContext context) {
- return SizedBox(
- height: 400,
- child: Column(
- children: [
- AppBar(
- title: const Text("Änderungsverlauf"),
- ),
- const Padding(
- padding: EdgeInsets.all(10),
- child: Text("1.0 --\nErste Release-Version!"),
- ),
- ],
+ child: ListView(
+ padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
+ children: [
+ const Padding(
+ padding: EdgeInsets.all(5),
+ child: ListTile(
+ leading: Icon(Icons.info_outlined),
+ title: Text("Version"),
+ subtitle: Text(version)),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(Icons.person_outlined),
+ title: const Text("Autor"),
+ subtitle: const Text(author),
+ onTap: () =>
+ launch("https://git.cantorgymnasium.de/denyskon"),
),
- );
- },
- );
- },
- ),
- ListTile(
- leading: const Icon(Icons.copyright_outlined),
- title: const Text("Lizenzen"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => LicensePage(
- applicationIcon: Image.asset(
- "assets/images/meincantor_r.png",
- height: 64,
- width: 64),
- applicationVersion: version,
- )),
- );
- },
- ),
- ],
- ));
+ ),
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(Icons.source_outlined),
+ title: const Text("Quellcode"),
+ subtitle: Linkify(
+ onOpen: (link) async {
+ if (await canLaunch(link.url)) {
+ await launch(link.url);
+ } else {
+ throw 'Could not launch $link';
+ }
+ },
+ text:
+ "https://git.cantorgymnasium.de/cantortechnik/meincantor-app",
+ linkStyle: const TextStyle(color: Palette.accent),
+ ),
+ onTap: () => launch(
+ "https://git.cantorgymnasium.de/cantortechnik/meincantor-app")),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading:
+ const Icon(Icons.settings_backup_restore_outlined),
+ title: const Text("Änderungsverlauf"),
+ subtitle: const Text("Was ist neu?"),
+ onTap: () {
+ showModalBottomSheet(
+ isScrollControlled: true,
+ context: context,
+ builder: (BuildContext context) {
+ return SizedBox(
+ height: 400,
+ child: Column(
+ children: [
+ AppBar(
+ title: const Text("Änderungsverlauf"),
+ ),
+ const Padding(
+ padding: EdgeInsets.all(10),
+ child: Text(
+ "1.0.0 --\nErste Release-Version!"),
+ ),
+ ],
+ ),
+ );
+ },
+ );
+ },
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(Icons.copyright_outlined),
+ title: const Text("Lizenzen"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => LicensePage(
+ applicationIcon: Padding(
+ padding: const EdgeInsets.all(5),
+ child: MediaQuery.of(context).platformBrightness == Brightness.light
+ ? Image.asset(
+ "assets/images/meincantor-big.png",
+ width: 196)
+ : Image.asset(
+ "assets/images/meincantor-big-dark.png",
+ width: 196)
+ ),
+ applicationVersion: version,
+ )),
+ );
+ },
+ ),
+ ),
+ ],
+ )),
+ );
+ }));
}
}
diff --git a/lib/Settings/Pages/plan_settings.dart b/lib/Settings/Pages/plan_settings.dart
index 0e34b7b..1b8c39e 100644
--- a/lib/Settings/Pages/plan_settings.dart
+++ b/lib/Settings/Pages/plan_settings.dart
@@ -1,9 +1,9 @@
import 'dart:convert';
import 'package:meincantor/main.dart';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cyclop/cyclop.dart';
+import 'package:meincantor/networking.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -12,52 +12,6 @@ import 'package:meincantor/presets/subjects.dart';
import 'package:meincantor/presets/teachers.dart';
-class PlanSettings extends StatelessWidget {
- const PlanSettings({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text("Plan"),
- centerTitle: true,
- ),
- body: ListView(
- padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
- children: [
- ListTile(
- leading: const Icon(Icons.list_alt_outlined, color: Colors.red),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Kurse"),
- subtitle: const Text("Konfiguration der Kurse (Whitelist)"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => const WhitelistSettings()),
- );
- },
- ),
- ListTile(
- leading:
- const Icon(Icons.color_lens_outlined, color: Colors.teal),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Farben"),
- subtitle:
- const Text("Konfiguration der Farben für die Plankacheln"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => const PlanColorSettings()),
- );
- },
- ),
- ],
- ));
- }
-}
-
class WhitelistSettings extends StatefulWidget {
const WhitelistSettings({Key? key}) : super(key: key);
@@ -77,7 +31,7 @@ class _WhitelistSettingsState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- title: const Text("Farben"),
+ title: const Text("Kurse"),
centerTitle: true,
),
body: ListView(
@@ -106,11 +60,36 @@ class _WhitelistSettingsState extends State {
snapshot.data! as List;
final _blacklisted =
_blacklist.contains(id);
- return ListTile(
- leading: Checkbox(
- value:
- _blacklisted ? false : true,
- onChanged: (state) async {
+ return Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.circular(
+ 15.0)),
+ leading: Checkbox(
+ value: _blacklisted
+ ? false
+ : true,
+ onChanged: (state) async {
+ SharedPreferences prefs =
+ await SharedPreferences
+ .getInstance();
+ setState(() {
+ _blacklisted
+ ? _blacklist
+ .remove(id)
+ : _blacklist.add(id);
+ });
+ prefs.setString("blacklist",
+ jsonEncode(_blacklist));
+ },
+ activeColor: color),
+ title: Text(
+ subjects[subject] ?? subject),
+ subtitle: Text(
+ teachers[teacher] ?? teacher),
+ onTap: () async {
SharedPreferences prefs =
await SharedPreferences
.getInstance();
@@ -122,23 +101,7 @@ class _WhitelistSettingsState extends State {
prefs.setString("blacklist",
jsonEncode(_blacklist));
},
- activeColor: color),
- title: Text(subjects[subject] ?? ""),
- subtitle:
- Text(teachers[teacher] ?? ""),
- onTap: () async {
- SharedPreferences prefs =
- await SharedPreferences
- .getInstance();
- setState(() {
- _blacklisted
- ? _blacklist.remove(id)
- : _blacklist.add(id);
- });
- prefs.setString("blacklist",
- jsonEncode(_blacklist));
- },
- );
+ ));
} else {
return const LinearProgressIndicator();
}
@@ -187,8 +150,12 @@ Future buildPlanColors(String lesson) async {
Future> buildLessonsList() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
- String lessonsJson = prefs.getString("lessons")!;
- List lessons = jsonDecode(lessonsJson);
+ String? lessonsJson = prefs.getString("lessons");
+ if (lessonsJson == null || lessonsJson.isEmpty) {
+ await fetchLessonList();
+ lessonsJson = prefs.getString("lessons");
+ }
+ List lessons = jsonDecode(lessonsJson!);
return lessons;
}
@@ -235,30 +202,37 @@ class _PlanColorSettingsState extends State {
builder: (context, snapshot) {
if (snapshot.hasData) {
Color color = snapshot.data as Color;
- return ListTile(
- leading: ColorButton(
- key: const Key('c1'),
- color: color,
- config: const ColorPickerConfig(
- enableEyePicker: false),
- onSwatchesChanged: (Set value) {
- swatches = value;
- },
- size: 32,
- swatches: swatches,
- onColorChanged: (Color value) async {
- setState(() {
- color = value;
- });
- SharedPreferences prefs =
- await SharedPreferences
- .getInstance();
- prefs.setInt(
- "color$subject", value.value);
- }),
- title: Text(subjects[subject] ?? ""),
- subtitle: Text(teachers[teacher] ?? ""),
- );
+ return Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.circular(15.0)),
+ leading: ColorButton(
+ key: const Key('c1'),
+ color: color,
+ config: const ColorPickerConfig(
+ enableEyePicker: false),
+ onSwatchesChanged:
+ (Set value) {
+ swatches = value;
+ },
+ size: 32,
+ swatches: swatches,
+ onColorChanged: (Color value) async {
+ setState(() {
+ color = value;
+ });
+ SharedPreferences prefs =
+ await SharedPreferences
+ .getInstance();
+ prefs.setInt(
+ "color$subject", value.value);
+ }),
+ title: Text(subjects[subject] ?? subject),
+ subtitle:
+ Text(teachers[teacher] ?? teacher),
+ ));
} else {
return (const LinearProgressIndicator());
}
diff --git a/lib/Settings/Pages/service_settings.dart b/lib/Settings/Pages/service_settings.dart
index d2d583f..6ca0056 100644
--- a/lib/Settings/Pages/service_settings.dart
+++ b/lib/Settings/Pages/service_settings.dart
@@ -1,4 +1,3 @@
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class ServiceSettings extends StatelessWidget {
@@ -13,7 +12,7 @@ class ServiceSettings extends StatelessWidget {
),
body: ListView(
padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
- children: [],
+ children: const [],
));
}
}
diff --git a/lib/Settings/Pages/user_settings.dart b/lib/Settings/Pages/user_settings.dart
index 3407fbf..717b0d9 100644
--- a/lib/Settings/Pages/user_settings.dart
+++ b/lib/Settings/Pages/user_settings.dart
@@ -1,14 +1,10 @@
-import 'package:cyclop/cyclop.dart';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
-import 'package:meincantor/Settings/Pages/plan_settings.dart';
import 'package:meincantor/networking.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import 'package:webview_flutter/webview_flutter.dart';
-import 'dart:io' show Platform;
-import '../../const.dart';
+import 'package:meincantor/const.dart';
+import 'package:webviewx/webviewx.dart';
Future getSettingsString(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
@@ -30,104 +26,172 @@ class UserSettings extends StatelessWidget {
title: const Text("Benutzereinstellungen"),
centerTitle: true,
),
- body: ListView(
- padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
- children: [
- Padding(
- padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
- child: 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) {
- // .svg?text=${(snapshot.data! as Map)['name'][0]}
- String url = "$avatarUrl/${(snapshot.data! as Map)['user']}";
- return Container(
- width: 120.0,
- height: 120.0,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- image: DecorationImage(
- fit: BoxFit.scaleDown,
- image: NetworkImage(url)
- )
- )
- );
- } else {
- return const CircularProgressIndicator();
- }
- },
- ),
- ),
- FutureBuilder(
- future: getSettingsString("name"),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- return TextField(
- decoration: const InputDecoration(
- border: OutlineInputBorder(),
- labelText: 'Name',
+ 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: ListView(
+ padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
+ children: [
+ Padding(
+ padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
+ child: 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(
+ width: 120.0,
+ height: 120.0,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ image: DecorationImage(
+ fit: BoxFit.scaleDown,
+ image: NetworkImage(url))));
+ } else {
+ return const CircularProgressIndicator();
+ }
+ },
),
- readOnly: true,
- controller:
- TextEditingController(text: snapshot.data as String),
- );
- } else {
- return (const Center(child: CircularProgressIndicator()));
- }
- }),
- Padding(
- padding: const EdgeInsets.fromLTRB(5, 20, 5, 5),
- child: buildClassesChooser()),
- ListTile(
- leading: const Icon(MdiIcons.accountSettingsOutline),
- trailing: const Icon(Icons.link, size: 16),
- title: const Text("Account-Konsole"),
- subtitle: const Text("Konto-Einstellungen öffnen"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => AccountConsole()),
- );
- },
- ),
- ],
- )
- );
+ ),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
+ child: FutureBuilder(
+ future: getSettingsString("name"),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ return TextField(
+ decoration: const InputDecoration(
+ border: OutlineInputBorder(),
+ labelText: 'Name',
+ icon: Icon(MdiIcons.passport)),
+ readOnly: true,
+ controller: TextEditingController(
+ text: snapshot.data as String),
+ );
+ } else {
+ return (const Center(
+ child: CircularProgressIndicator()));
+ }
+ }),
+ ),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
+ child: FutureBuilder(
+ future: getSettingsString("user"),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ return TextField(
+ decoration: const InputDecoration(
+ border: OutlineInputBorder(),
+ labelText: 'Benutzername',
+ icon: Icon(MdiIcons.identifier)),
+ readOnly: true,
+ controller: TextEditingController(
+ text: snapshot.data as String),
+ );
+ } else {
+ return (const Center(
+ child: CircularProgressIndicator()));
+ }
+ }),
+ ),
+ const Divider(),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
+ child: FutureBuilder(
+ future: getSettingsString("email"),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ return TextField(
+ decoration: const InputDecoration(
+ border: OutlineInputBorder(),
+ labelText: 'E-Mail-Adresse',
+ icon: Icon(Icons.email_outlined)),
+ readOnly: true,
+ controller: TextEditingController(
+ text: snapshot.data as String),
+ );
+ } else {
+ return (const Center(
+ child: CircularProgressIndicator()));
+ }
+ }),
+ ),
+ Padding(
+ padding: const EdgeInsets.fromLTRB(5, 20, 5, 5),
+ child: buildClassesChooser()),
+ ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(MdiIcons.accountSettingsOutline),
+ trailing: const Icon(Icons.link, size: 16),
+ title: const Text("Account-Konsole"),
+ subtitle: const Text("Konto-Einstellungen öffnen"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const AccountConsole()),
+ );
+ },
+ ),
+ ],
+ )),
+ );
+ }));
}
}
-
class AccountConsole extends StatefulWidget {
+ const AccountConsole({Key? key}) : super(key: key);
+
@override
AccountConsoleState createState() => AccountConsoleState();
}
class AccountConsoleState extends State {
- @override
- void initState() {
- super.initState();
- // Enable virtual display.
- if (Platform.isAndroid) WebView.platform = AndroidWebView();
- }
@override
Widget build(BuildContext context) {
- return const WebView(
- initialUrl: 'https://mein.cantorgymnasium.de/auth/realms/GCG.MeinCantor/account/',
+ return WebViewX(
+ height: MediaQuery.of(context).size.height,
+ initialContent: 'https://mein.cantorgymnasium.de/auth/realms/GCG.MeinCantor/account/',
+ initialSourceType: SourceType.url,
+ javascriptMode: JavascriptMode.unrestricted,
+ width: MediaQuery.of(context).size.width
);
}
}
-
diff --git a/lib/Settings/dashboard.dart b/lib/Settings/dashboard.dart
index 09672ac..0c83aba 100644
--- a/lib/Settings/dashboard.dart
+++ b/lib/Settings/dashboard.dart
@@ -1,13 +1,10 @@
-import 'package:meincantor/Settings/Pages/appearance_settings.dart';
-import 'package:meincantor/Settings/Pages/service_settings.dart';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
-import 'Pages/dev_settings.dart';
-import 'Pages/info_settings.dart';
-import 'Pages/plan_settings.dart';
-import 'Pages/user_settings.dart';
+import 'package:meincantor/Settings/Pages/dev_settings.dart';
+import 'package:meincantor/Settings/Pages/info_settings.dart';
+import 'package:meincantor/Settings/Pages/plan_settings.dart';
+import 'package:meincantor/Settings/Pages/user_settings.dart';
class Settings extends StatelessWidget {
const Settings({Key? key}) : super(key: key);
@@ -22,84 +19,100 @@ class Settings extends StatelessWidget {
body: ListView(
padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
children: [
- ListTile(
- leading: const Icon(MdiIcons.accountSettingsOutline,
- color: Colors.cyan),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Benutzer"),
- subtitle: const Text("Profilbild, Klasse & mehr"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const UserSettings()),
- );
- },
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(MdiIcons.accountSettingsOutline,
+ color: Colors.cyan),
+ trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ title: const Text("Benutzer"),
+ subtitle: const Text("Profilbild, Klasse & mehr"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const UserSettings()),
+ );
+ },
+ ),
),
- ListTile(
- leading:
- const Icon(MdiIcons.timetable, color: Colors.orangeAccent),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Plan"),
- subtitle: const Text("Kurse/Fächer, Farben & mehr"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const PlanSettings()),
- );
- },
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(Icons.list_alt_outlined, color: Colors.red),
+ trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ title: const Text("Kurse"),
+ subtitle: const Text("Konfiguration der Kurse"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const WhitelistSettings()),
+ );
+ },
+ ),
),
- ListTile(
- leading: const Icon(Icons.color_lens_outlined,
- color: Colors.pinkAccent),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Aussehen"),
- subtitle: const Text("Widgets, Design & mehr"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => const AppearanceSettings()),
- );
- },
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading:
+ const Icon(Icons.color_lens_outlined, color: Colors.teal),
+ trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ title: const Text("Farben"),
+ subtitle:
+ const Text("Konfiguration der Farben für die Plankacheln"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const PlanColorSettings()),
+ );
+ },
+ ),
),
- ListTile(
- leading: const Icon(MdiIcons.server, color: Colors.lightGreen),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Dienste"),
- subtitle: const Text("Konten, Plattformen & mehr"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => const ServiceSettings()),
- );
- },
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading: const Icon(Icons.developer_mode_outlined,
+ color: Colors.deepOrangeAccent),
+ trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ title: const Text("Entwickleroptionen"),
+ subtitle: const Text("API, Benutzerdaten & mehr"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const DevSettings()),
+ );
+ },
+ ),
),
- ListTile(
- leading: const Icon(Icons.developer_mode_outlined,
- color: Colors.deepOrangeAccent),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Entwickleroptionen"),
- subtitle: const Text("API, Benutzerdaten & mehr"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const DevSettings()),
- );
- },
- ),
- ListTile(
- leading:
- const Icon(Icons.info_outlined, color: Colors.greenAccent),
- trailing: const Icon(Icons.arrow_forward_ios, size: 16),
- title: const Text("Informationen"),
- subtitle: const Text("Version, Lizenzen & mehr"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const InfoSettings()),
- );
- },
+ Padding(
+ padding: const EdgeInsets.all(5),
+ child: ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15.0)),
+ leading:
+ const Icon(Icons.info_outlined, color: Colors.greenAccent),
+ trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ title: const Text("Informationen"),
+ subtitle: const Text("Version, Lizenzen & mehr"),
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const InfoSettings()),
+ );
+ },
+ ),
),
],
));
diff --git a/lib/background_fetch.dart b/lib/background_fetch.dart
new file mode 100644
index 0000000..11b7da0
--- /dev/null
+++ b/lib/background_fetch.dart
@@ -0,0 +1,258 @@
+import 'dart:convert';
+
+import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+import 'package:intl/intl.dart';
+import 'package:meincantor/timetable.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'package:http/http.dart' as http;
+
+import 'package:meincantor/networking.dart';
+
+Future backgroundFetchTimetable() async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+
+ String? todayTimetable = prefs.getString("todayTimetable");
+ String? tomorrowTimetable = prefs.getString("tomorrowTimetable");
+
+ http.Response todayResponse = await fetchClassTimetable(
+ "/${DateFormat("yyyyMMdd").format(DateTime.now())}", null);
+
+ http.Response tomorrowResponse = await fetchClassTimetable(
+ "/${DateFormat("yyyyMMdd").format(DateTime.now().add(const Duration(days: 1)))}",
+ null);
+
+ if (todayResponse.statusCode == 200) {
+ if (todayTimetable != todayResponse.body) {
+ FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+ const AndroidNotificationDetails
+ androidPlatformChannelSpecificsTodayPlan = AndroidNotificationDetails(
+ 'de.cantorgymnasium.meincantor.today.plan',
+ 'Vertretungsplan für heute',
+ channelDescription: '',
+ importance: Importance.max,
+ priority: Priority.high,
+ ticker: 'ticker');
+ const NotificationDetails platformChannelSpecificsTodayPlan =
+ NotificationDetails(
+ android: androidPlatformChannelSpecificsTodayPlan);
+
+ const AndroidNotificationDetails
+ androidPlatformChannelSpecificsTodayInfo = AndroidNotificationDetails(
+ 'de.cantorgymnasium.meincantor.today.info',
+ 'Informationen für heute',
+ channelDescription: '',
+ importance: Importance.max,
+ priority: Priority.high,
+ ticker: 'ticker');
+ const NotificationDetails platformChannelSpecificsTodayInfo =
+ NotificationDetails(
+ android: androidPlatformChannelSpecificsTodayInfo);
+
+ List lessonsList =
+ ClassTimetable.fromJson(jsonDecode(todayResponse.body)).timetable;
+ List changedLessons = [];
+ for (var element in lessonsList) {
+ if (element.info.isNotEmpty) {
+ changedLessons.add(element.count);
+ }
+ }
+ String subtitle;
+ if (changedLessons.isNotEmpty && changedLessons.length > 1) {
+ subtitle = "Änderungen in den Stunden ";
+ for (var i in changedLessons) {
+ subtitle += "$i";
+ if (changedLessons.indexOf(i) != changedLessons.length - 1) {
+ subtitle += ", ";
+ }
+ }
+ } else if (changedLessons.isNotEmpty && changedLessons.length == 1) {
+ subtitle = "Änderungen in Stunde ${changedLessons[0]}";
+ } else {
+ subtitle = "Keine Änderungen im Plan gefunden!";
+ }
+ await flutterLocalNotificationsPlugin.show(
+ 0,
+ 'Neuer Vertretungsplan für heute geladen!',
+ subtitle,
+ platformChannelSpecificsTodayPlan,
+ payload: 'item x');
+ if ((jsonDecode(todayResponse.body)["info"] as String).isNotEmpty) {
+ await flutterLocalNotificationsPlugin.show(
+ 1,
+ 'Informationen für heute',
+ (jsonDecode(todayResponse.body)["info"] as String),
+ platformChannelSpecificsTodayInfo,
+ payload: 'item x');
+ }
+ prefs.setString("todayTimetable", todayResponse.body);
+ }
+ }
+
+ if (tomorrowResponse.statusCode == 200) {
+ if (tomorrowTimetable != tomorrowResponse.body) {
+ FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+ const AndroidNotificationDetails
+ androidPlatformChannelSpecificsTomorrowPlan =
+ AndroidNotificationDetails(
+ 'de.cantorgymnasium.meincantor.tomorrow.plan',
+ 'Vertretungsplan für morgen',
+ channelDescription: '',
+ importance: Importance.max,
+ priority: Priority.high,
+ ticker: 'ticker');
+ const NotificationDetails platformChannelSpecificsTomorrowPlan =
+ NotificationDetails(
+ android: androidPlatformChannelSpecificsTomorrowPlan);
+
+ const AndroidNotificationDetails
+ androidPlatformChannelSpecificsTomorrowInfo =
+ AndroidNotificationDetails(
+ 'de.cantorgymnasium.meincantor.tomorrow.info',
+ 'Informationen für morgen',
+ channelDescription: '',
+ importance: Importance.max,
+ priority: Priority.high,
+ ticker: 'ticker');
+ const NotificationDetails platformChannelSpecificsTomorrowInfo =
+ NotificationDetails(
+ android: androidPlatformChannelSpecificsTomorrowInfo);
+
+ List lessonsList =
+ ClassTimetable.fromJson(jsonDecode(tomorrowResponse.body)).timetable;
+ List changedLessons = [];
+ for (var element in lessonsList) {
+ if (element.info.isNotEmpty) {
+ changedLessons.add(element.count);
+ }
+ }
+ String subtitle;
+ if (changedLessons.isNotEmpty && changedLessons.length > 1) {
+ subtitle = "Änderungen in den Stunden ";
+ for (var i in changedLessons) {
+ subtitle += "$i";
+ if (changedLessons.indexOf(i) != changedLessons.length - 1) {
+ subtitle += ", ";
+ }
+ }
+ } else if (changedLessons.isNotEmpty && changedLessons.length == 1) {
+ subtitle = "Änderungen in Stunde ${changedLessons[0]}";
+ } else {
+ subtitle = "Keine Änderungen im Plan gefunden!";
+ }
+ await flutterLocalNotificationsPlugin.show(
+ 2,
+ 'Neuer Vertretungsplan für morgen geladen!',
+ subtitle,
+ platformChannelSpecificsTomorrowPlan,
+ payload: 'item x');
+ if ((jsonDecode(tomorrowResponse.body)["info"] as String).isNotEmpty) {
+ await flutterLocalNotificationsPlugin.show(
+ 3,
+ 'Informationen für morgen',
+ (jsonDecode(tomorrowResponse.body)["info"] as String),
+ platformChannelSpecificsTomorrowInfo,
+ payload: 'item x');
+ }
+ prefs.setString("tomorrowTimetable", tomorrowResponse.body);
+ }
+ }
+}
+
+Future backgroundFetchArticles() async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+
+ String? articles = prefs.getString("articles");
+ String? news = prefs.getString("news");
+
+ http.Response fetchedArticles = await getArticles();
+
+ http.Response fetchedNews = await getNews();
+
+ if (fetchedArticles.statusCode == 200) {
+ if (articles != fetchedArticles.body) {
+ FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+ const AndroidNotificationDetails androidPlatformChannelSpecificsSZ =
+ AndroidNotificationDetails(
+ 'de.cantorgymnasium.meincantor.sz', 'Schülerzeitung',
+ channelDescription: '',
+ importance: Importance.max,
+ priority: Priority.high,
+ ticker: 'ticker');
+ const NotificationDetails platformChannelSpecificsSZ =
+ NotificationDetails(android: androidPlatformChannelSpecificsSZ);
+
+ String subtitle;
+ List listFetchedArticles = jsonDecode(fetchedArticles.body)["data"];
+ if (articles != null && articles.isNotEmpty) {
+ List listSavedArticles = jsonDecode(articles)["data"];
+ int diff = listFetchedArticles.length - listSavedArticles.length;
+ diff == 1
+ ? subtitle = "1 neuer Artikel!"
+ : diff > 1
+ ? subtitle = "$diff neue Artikel!"
+ : subtitle = "Fehler beim Ermitteln der Änderungen!";
+ } else {
+ int len = listFetchedArticles.length;
+ len == 1
+ ? subtitle = "1 neuer Artikel!"
+ : len > 1
+ ? subtitle = "$len neue Artikel!"
+ : subtitle = "Fehler beim Ermitteln der Änderungen!";
+ }
+
+ await flutterLocalNotificationsPlugin.show(
+ 4,
+ 'Neuer Inhalt von der Schülerzeitung verfügbar!',
+ subtitle,
+ platformChannelSpecificsSZ,
+ payload: 'item x');
+ prefs.setString("articles", fetchedArticles.body);
+ }
+ }
+
+ if (fetchedNews.statusCode == 200) {
+ if (news != fetchedNews.body) {
+ FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+ const AndroidNotificationDetails androidPlatformChannelSpecificsNews =
+ AndroidNotificationDetails(
+ 'de.cantorgymnasium.meincantor.news', 'Aktuelles',
+ channelDescription: '',
+ importance: Importance.max,
+ priority: Priority.high,
+ ticker: 'ticker');
+ const NotificationDetails platformChannelSpecificsNews =
+ NotificationDetails(android: androidPlatformChannelSpecificsNews);
+
+ String subtitle;
+ List listFetchedNews = jsonDecode(fetchedNews.body)["data"];
+ if (news != null && news.isNotEmpty) {
+ List listSavedNews = jsonDecode(news)["data"];
+ int diff = listFetchedNews.length - listSavedNews.length;
+ diff == 1
+ ? subtitle = "1 neuer Artikel!"
+ : diff > 1
+ ? subtitle = "$diff neue Artikel!"
+ : subtitle = "Fehler beim Ermitteln der Änderungen!";
+ } else {
+ int len = listFetchedNews.length;
+ len == 1
+ ? subtitle = "1 neuer Artikel!"
+ : len > 1
+ ? subtitle = "$len neue Artikel!"
+ : subtitle = "Fehler beim Ermitteln der Änderungen!";
+ }
+
+ await flutterLocalNotificationsPlugin.show(
+ 5,
+ 'Neue Informationen verfügbar!',
+ subtitle,
+ platformChannelSpecificsNews,
+ payload: 'item x');
+ prefs.setString("news", fetchedNews.body);
+ }
+ }
+}
diff --git a/lib/cache_manager.dart b/lib/cache_manager.dart
index 4f384b9..1ebb3b3 100644
--- a/lib/cache_manager.dart
+++ b/lib/cache_manager.dart
@@ -3,10 +3,12 @@ import 'dart:convert';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:shared_preferences/shared_preferences.dart';
-Future getCachedTimetable(String ext) async {
+Future getCachedTimetable(String ext, String? presetClassNum) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String classNum;
- if (prefs.getString('class_num') != null) {
+ if (presetClassNum != null) {
+ classNum = presetClassNum.replaceAll("/", "_");
+ } else if (prefs.getString('class_num') != null) {
classNum = prefs.getString('class_num')!.replaceAll("/", "_");
} else {
classNum = '05_1';
diff --git a/lib/dashboard.dart b/lib/dashboard.dart
index 486d737..5444e89 100644
--- a/lib/dashboard.dart
+++ b/lib/dashboard.dart
@@ -1,8 +1,9 @@
-import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+import 'dart:convert';
+import 'dart:math';
+
+import 'package:background_fetch/background_fetch.dart';
+import 'package:meincantor/background_fetch.dart';
import 'package:meincantor/const.dart';
-import 'package:meincantor/raumuebersicht.dart';
-import 'package:meincantor/schulbibliothek.dart';
-import 'package:meincantor/schulcomputer.dart';
import 'package:meincantor/schuelerzeitung.dart';
import 'package:meincantor/Settings/dashboard.dart';
@@ -16,17 +17,9 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
+import 'package:http/http.dart' as http;
-import 'news.dart';
-
-class Dashboard extends StatefulWidget {
- const Dashboard({Key? key, this.restorationId}) : super(key: key);
-
- final String? restorationId;
-
- @override
- State createState() => _DashboardState();
-}
+import 'package:meincantor/news.dart';
Future getSettingsString(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
@@ -44,77 +37,262 @@ Widget buildSettingsString(String key, TextStyle? style) {
if (snapshot.hasData) {
return Text(snapshot.data as String, style: style);
} else {
- return (const Center(child: CircularProgressIndicator()));
+ return const SizedBox.shrink();
}
});
}
+Future> getFavClasses() async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ List? listJson = prefs.getStringList("favClasses");
+ if (listJson == null || listJson.isEmpty) {
+ return [];
+ } else {
+ return listJson;
+ }
+}
+
+List buildFavClasses(
+ BuildContext context, List favClasses, Function removeFavClass) {
+ if (favClasses.isEmpty) {
+ return [const SizedBox.shrink()];
+ } else {
+ List list = [];
+ for (var element in favClasses) {
+ var card = SizedBox(
+ width: 170,
+ child: GestureDetector(
+ onTap: () async {
+ Navigator.push(
+ 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: [
+ 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: [
+ 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")));
+ }),
+ ],
+ ),
+ ))));
+ },
+ onLongPress: () async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ List stringList = prefs.getStringList("favClasses")!;
+ stringList.remove(element);
+ prefs.setStringList("favClasses", stringList);
+ removeFavClass(element);
+ },
+ 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,
+ ),
+ ),
+ ),
+ )),
+ ),
+ ),
+ );
+ list.add(card);
+ }
+ return (list);
+ }
+}
+
+class Dashboard extends StatefulWidget {
+ const Dashboard({Key? key, this.restorationId}) : super(key: key);
+
+ final String? restorationId;
+
+ @override
+ State createState() => _DashboardState();
+}
+
class _DashboardState extends State with RestorationMixin {
final RestorableInt _currentIndex = RestorableInt(0);
+
+ @override
+ void initState() {
+ super.initState();
+ initPlatformState();
+ }
+
+ Future 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) {
- final drawerElements = ListView(
- children: [
- UserAccountsDrawerHeader(
- accountName: buildSettingsString('name', const TextStyle()),
- accountEmail: buildSettingsString('user', 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) {
- // .svg?text=${(snapshot.data! as Map)['name'][0]}
- 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();
- }
- },
- )
- ),
- ListTile(
- title: const Text("Einstellungen"),
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const Settings()),
- );
- },
- leading: const Icon(Icons.settings_outlined),
- ),
- 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),
- ),
- ],
- );
var bottomNavBarItems = [
const BottomNavigationBarItem(
icon: Icon(MdiIcons.homeOutline),
@@ -122,19 +300,10 @@ class _DashboardState extends State with RestorationMixin {
),
const BottomNavigationBarItem(
icon: Icon(MdiIcons.timetable), label: "Vertretungsplan"),
- const BottomNavigationBarItem(
- icon: Icon(Icons.notifications_outlined), label: "Hinweise"),
];
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,
@@ -157,67 +326,168 @@ class _DashboardState extends State with RestorationMixin {
}
}
-class _DashboardBottomNavView extends StatelessWidget {
+class _DashboardBottomNavView extends StatefulWidget {
const _DashboardBottomNavView({Key? key, required this.item})
: super(key: key);
final BottomNavigationBarItem item;
+ @override
+ // ignore: no_logic_in_create_state
+ State createState() => _DashboardBottomNavViewState(item);
+}
+
+class _DashboardBottomNavViewState extends State<_DashboardBottomNavView> {
+ final BottomNavigationBarItem item;
+ _DashboardBottomNavViewState(this.item);
+
+ List favClasses = [];
+
+ void removeFavClass(String classNum) {
+ setState(() {
+ favClasses.remove(classNum);
+ });
+ }
+
@override
Widget build(BuildContext context) {
+ 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(
+ context: context,
+ barrierDismissible: false, // user must tap button!
+ builder: (BuildContext context) {
+ return AlertDialog(
+ title: const Text('Abmelden'),
+ content: SingleChildScrollView(
+ child: ListBody(
+ children: const [
+ Text(
+ 'Dabei werden alle persönlichen Enstellungen gelöscht!'),
+ ],
+ ),
+ ),
+ actions: [
+ 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),
+ ),
+ ),
+ ],
+ );
if (item.label == "Startseite") {
double _timeOfDayToDouble(TimeOfDay tod) => tod.hour + tod.minute / 60.0;
int 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 if (_timeOfDayToDouble(TimeOfDay.now()) >
- _timeOfDayToDouble(const TimeOfDay(hour: 15, minute: 10)) &&
- _timeOfDayToDouble(TimeOfDay.now()) <=
- _timeOfDayToDouble(const TimeOfDay(hour: 16, minute: 00))) {
- lessonCount = 10;
- } else {
- lessonCount = -1;
- }
+ _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;
var view = SingleChildScrollView(
child: Column(children: [
@@ -274,152 +544,40 @@ class _DashboardBottomNavView extends StatelessWidget {
child: Wrap(
children: [
SizedBox(
- child: GestureDetector(
- onTap: () async {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const SZ()),
- );
- },
- child: Card(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- child: const Padding(
- padding: EdgeInsets.all(10),
- child: ListTile(
- title: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
- child: Icon(
- MdiIcons.newspaper,
- color: Palette.accent,
- size: 48,
+ width: 175,
+ child: GestureDetector(
+ onTap: () async {
+ Navigator.push(
+ context,
+ MaterialPageRoute(builder: (context) => const SZ()),
+ );
+ },
+ child: Card(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(10),
+ ),
+ child: const Padding(
+ padding: EdgeInsets.all(10),
+ child: ListTile(
+ title: Padding(
+ padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
+ child: Icon(
+ MdiIcons.newspaper,
+ color: Palette.accent,
+ size: 48,
+ ),
),
- ),
- subtitle: Center(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
- child: Text(
- 'Schülerzeitung',
+ subtitle: Center(
+ child: Padding(
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
+ child: Text('Schülerzeitung'),
),
),
),
- ),
- )),
- ),
- width: 170,
- ),
+ )),
+ )),
SizedBox(
- width: 170,
- child: GestureDetector(
- onTap: () async {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const SB()),
- );
- },
- child: Card(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- child: const Padding(
- padding: EdgeInsets.all(10),
- child: ListTile(
- title: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
- child: Icon(
- MdiIcons.libraryShelves,
- color: Palette.accent,
- size: 48,
- ),
- ),
- subtitle: Center(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
- child: Text(
- 'Schulbibliothek',
- ),
- ),
- ),
- ),
- )),
- ),
- ),
- SizedBox(
- width: 170,
- child: GestureDetector(
- onTap: () async {
- Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => const SC()),
- );
- },
- child: Card(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- child: const Padding(
- padding: EdgeInsets.all(10),
- child: ListTile(
- title: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
- child: Icon(
- MdiIcons.laptop,
- color: Palette.accent,
- size: 48,
- ),
- ),
- subtitle: Center(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
- child: Text(
- 'Schulcomputer',
- ),
- ),
- ),
- ),
- )),
- ),
- ),
- SizedBox(
- width: 170,
- child: GestureDetector(
- onTap: () async {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => const RoomOverview()),
- );
- },
- child: Card(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- child: const Padding(
- padding: EdgeInsets.all(10),
- child: ListTile(
- title: Padding(
- padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
- child: Icon(
- MdiIcons.door,
- color: Palette.accent,
- size: 48,
- ),
- ),
- subtitle: Center(
- child: Padding(
- padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
- child: Text(
- 'Raumübersicht',
- ),
- ),
- ),
- ),
- )),
- ),
- ),
- SizedBox(
- width: 170,
+ width: 175,
child: GestureDetector(
onTap: () async {
Navigator.push(
@@ -457,77 +615,342 @@ class _DashboardBottomNavView extends StatelessWidget {
],
),
),
+ 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;
+ return Wrap(children: [
+ ...(buildFavClasses(
+ context, favClasses, removeFavClass)),
+ SizedBox(
+ width: 170,
+ child: GestureDetector(
+ onTap: () async {
+ showModalBottomSheet(
+ 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: [
+ ListTile(
+ title: const Text(
+ "Klasse hinzufügen",
+ style: TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ leading:
+ const Icon(Icons.arrow_back),
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ FutureBuilder(
+ future: fetchClassesList(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ if (snapshot
+ .data!.statusCode ==
+ 200) {
+ List 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
+ stringList = [
+ classNum
+ ];
+ prefs.setStringList(
+ "favClasses",
+ stringList);
+ } else {
+ List
+ 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();
+ }
+ }),
+ ],
+ ))
]),
);
- return view;
+ 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),
+ );
+ }),
+ );
} else if (item.label == "Vertretungsplan") {
- return LayoutBuilder(builder: (context, constraints) {
- double widgetWidth = constraints.maxWidth;
+ List children = [
+ LayoutBuilder(builder: (context, constraints) {
+ double widgetWidth = constraints.maxWidth;
- int factor;
+ int factor;
- if (widgetWidth <= 600) {
- factor = 1;
- } else if (widgetWidth <= 1400) {
- factor = 2;
- } else if (widgetWidth <= 2000) {
- factor = 3;
- } else {
- factor = 1;
- }
+ if (widgetWidth <= 600) {
+ factor = 1;
+ } else if (widgetWidth <= 1400) {
+ factor = 2;
+ } else if (widgetWidth <= 2000) {
+ factor = 3;
+ } else {
+ factor = 1;
+ }
- // 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: 3,
- child: Scaffold(
- appBar: AppBar(
- elevation: 0,
- title: const TabBar(
- tabs: [
- Tab(
- text: "Heute",
- icon: Icon(CupertinoIcons.calendar_today),
- ),
- Tab(
- text: "Morgen",
- icon: Icon(CupertinoIcons.calendar_today),
- ),
- Tab(
- text: "Neuster Plan",
- icon: Icon(CupertinoIcons.calendar),
- ),
- ],
- ),
- ),
- body: TabBarView(
- children: [
- buildTimetable(
- fetchClassTimetable(
- "/${DateFormat("yyyyMMdd").format(DateTime.now())}"),
- "Vertretungsplan für heute"),
- buildTimetable(
- fetchClassTimetable(
- "/${DateFormat("yyyyMMdd").format(DateTime.now().add(const Duration(days: 1)))}"),
- "Vertretungsplan für morgen"),
- buildTimetable(fetchClassTimetable("/latest"),
- "aktueller Vertretungsplan")
- ],
- ),
+ 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"),
+ ),
+ );
+ }),
+ 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,
+ ),
+ 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: [
+ 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),
+ ),
+ ],
),
),
- );
- });
+ drawer: Drawer(child: drawerElements),
+ body: TabBarView(children: children),
+ ),
+ );
} else {
return const Center(child: Text("Derzeit nichts hier..."));
}
diff --git a/lib/login.dart b/lib/login.dart
index 434e9f7..a5c57c6 100644
--- a/lib/login.dart
+++ b/lib/login.dart
@@ -3,9 +3,10 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
+import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import 'networking.dart';
-import 'dashboard.dart';
+import 'package:meincantor/networking.dart';
+import 'package:meincantor/dashboard.dart';
Future checkKey() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
@@ -14,6 +15,7 @@ Future checkKey() async {
}
class Login extends StatelessWidget {
+ Login({Key? key}) : super(key: key);
final userController = TextEditingController();
final passwordController = TextEditingController();
@@ -39,9 +41,6 @@ class Login extends StatelessWidget {
}
return Scaffold(
- appBar: AppBar(
- title: const Text("Anmelden"),
- ),
body: Center(
child: SingleChildScrollView(
child: Padding(
@@ -54,8 +53,14 @@ class Login extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- Image.asset("assets/images/meincantor_r.png",
- height: 192, width: 192),
+ MediaQuery.of(context).platformBrightness ==
+ Brightness.light
+ ? Image.asset(
+ "assets/images/meincantor-big.png",
+ width: 256)
+ : Image.asset(
+ "assets/images/meincantor-big-dark.png",
+ width: 256),
const Divider(),
AutofillGroup(
child: Column(
@@ -65,7 +70,7 @@ class Login extends StatelessWidget {
AutofillHints.username
],
decoration: const InputDecoration(
- icon: Icon(CupertinoIcons.person),
+ icon: Icon(MdiIcons.identifier),
border: OutlineInputBorder(),
labelText: 'Benutzername',
),
@@ -77,7 +82,7 @@ class Login extends StatelessWidget {
AutofillHints.password
],
decoration: const InputDecoration(
- icon: Icon(CupertinoIcons.lock),
+ icon: Icon(MdiIcons.lock),
border: OutlineInputBorder(),
labelText: 'Passwort',
),
@@ -89,9 +94,9 @@ class Login extends StatelessWidget {
const Divider(),
TextField(
decoration: const InputDecoration(
- icon: Icon(CupertinoIcons.lock),
+ icon: Icon(MdiIcons.twoFactorAuthentication),
border: OutlineInputBorder(),
- labelText: '2F2-Code (OTP) [falls aktiviert]',
+ labelText: '2F2-Code',
),
obscureText: true,
controller: otpController,
@@ -109,18 +114,21 @@ class Login extends StatelessWidget {
if (loginResponse.statusCode == 200) {
String apiKey = jsonDecode(utf8.decode(
loginResponse.bodyBytes))['token'];
- await prefs.setString('api_key', apiKey);
+ prefs.setString('api_key', apiKey);
dynamic userinfo = jsonDecode(
await getUserInfo(
userController.text,
passwordController.text,
otpController.text,
devIdController.text));
- await prefs.setString('user',
+ prefs.setString('user',
userinfo['preferred_username']);
- await prefs.setString(
- 'name', userinfo['name']);
- await prefs.setString(
+ prefs.setString('user',
+ userinfo['preferred_username']);
+ prefs.setString('name', userinfo['name']);
+ prefs.setString(
+ 'email', userinfo['email']);
+ prefs.setString(
'class_num',
userinfo['groups'][0]
.replaceAll("_", "/"));
diff --git a/lib/main.dart b/lib/main.dart
index 261669d..cdb3a93 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,32 +1,52 @@
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart';
-import 'dashboard.dart';
-import 'login.dart';
+import 'package:meincantor/dashboard.dart';
+import 'package:meincantor/login.dart';
import 'dart:math';
+import 'package:background_fetch/background_fetch.dart';
+
+void backgroundFetchHeadlessTask(HeadlessTask task) async {
+ String taskId = task.taskId;
+ bool isTimeout = task.timeout;
+ if (isTimeout) {
+ // This task has exceeded its allowed running-time.
+ // You must stop what you're doing and immediately .finish(taskId)
+ print("[BackgroundFetch] Headless task timed-out: $taskId");
+ BackgroundFetch.finish(taskId);
+ return;
+ }
+ print('[BackgroundFetch] Headless event received.');
+ // Do your work here...
+ BackgroundFetch.finish(taskId);
+}
void main() async {
- WidgetsFlutterBinding.ensureInitialized();
+ runApp(const App());
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');
- final IOSInitializationSettings initializationSettingsIOS =
+ const IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings();
- final MacOSInitializationSettings initializationSettingsMacOS =
+ const MacOSInitializationSettings initializationSettingsMacOS =
MacOSInitializationSettings();
- final InitializationSettings initializationSettings = InitializationSettings(
+ const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: initializationSettingsMacOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
- runApp(const App());
+ BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
}
-class App extends StatelessWidget {
+class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
+ @override
+ _AppState createState() => _AppState();
+}
+class _AppState extends State {
MaterialColor generateMaterialColor(Color color) {
return MaterialColor(color.value, {
50: tintColor(color, 0.5),
diff --git a/lib/networking.dart b/lib/networking.dart
index fff30a9..02d3867 100644
--- a/lib/networking.dart
+++ b/lib/networking.dart
@@ -1,10 +1,7 @@
import 'dart:convert';
import 'dart:io';
-import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:meincantor/cache_manager.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/painting.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
@@ -16,14 +13,16 @@ import 'package:meincantor/login.dart';
import 'package:meincantor/main.dart';
Future getArticles() async {
- var uri = Uri.https(szUrl["url"]!, "/articles");
- final response = await http.get(uri);
+ var uri = Uri.https(szUrl["url"]! as String, "/api/articles");
+ final response =
+ await http.get(uri, headers: szUrl["headers"]! as Map);
return (response);
}
Future getNews() async {
- var uri = Uri.https(szUrl["url"]!, "/aktuelles");
- final response = await http.get(uri);
+ var uri = Uri.https(szUrl["url"]! as String, "/api/aktuelles");
+ final response =
+ await http.get(uri, headers: szUrl["headers"]! as Map);
return (response);
}
@@ -50,21 +49,9 @@ Future getUserInfo(
}
}
-Future fetchClassTimetable(String ext) async {
- FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
- const AndroidNotificationDetails androidPlatformChannelSpecifics =
- AndroidNotificationDetails('de.cantorgymnasium.meincantor', 'GCG.MeinCantor',
- channelDescription: '',
- importance: Importance.max,
- priority: Priority.high,
- ticker: 'ticker');
- const NotificationDetails platformChannelSpecifics =
- NotificationDetails(android: androidPlatformChannelSpecifics);
- await flutterLocalNotificationsPlugin.show(
- 0, 'Neuer Vertretungsplan geladen!', 'Du hast folgende Vertretungen:\nSt. 8 Deutsch Frau Rinke, Raum 203\nSt. 4 Biologie Frau Borchert, Raum 107', platformChannelSpecifics,
- payload: 'item x');
+Future fetchClassTimetable(String ext, String? classNum) async {
try {
- return (http.Response(await getCachedTimetable(ext), 200));
+ return (http.Response(await getCachedTimetable(ext, classNum), 200));
} on HttpExceptionWithStatus catch (e) {
return http.Response(e.message, e.statusCode);
} on HttpException catch (e) {
@@ -72,20 +59,6 @@ Future fetchClassTimetable(String ext) async {
} on SocketException catch (e) {
return http.Response(e.message, 404);
}
- /*SharedPreferences prefs = await SharedPreferences.getInstance();
- String classNum;
- if (prefs.getString('class_num') != null) {
- classNum = prefs.getString('class_num')!.replaceAll("/", "_");
- } else {
- classNum = '05_1';
- }
- var apiKey = prefs.getString('api_key');
- var uri = Uri.https("mein.cantorgymnasium.de", "/api/timetable/$classNum$ext");
- var headers = {"x-api-key": "$apiKey"};
- final response = http.get(uri, headers: headers).onError((error, stackTrace) {
- return (http.Response("", 404));
- });
- return response;*/
}
fetchLessonList() async {
@@ -180,7 +153,7 @@ Widget buildTimetable(Future future, String info) {
Widget buildTodayClassTimetableLesson(int count) {
return FutureBuilder(
future: fetchClassTimetable(
- "/${DateFormat("yyyyMMdd").format(DateTime.now())}"),
+ "/${DateFormat("yyyyMMdd").format(DateTime.now())}", null),
builder: (context, snapshot) {
if (snapshot.hasData) {
int statusCode = snapshot.data!.statusCode;
@@ -281,7 +254,7 @@ Widget buildClassesChooser() {
if (statusCode == 200) {
List items = [];
jsonDecode(utf8.decode(snapshot.data!.bodyBytes)).forEach((value) {
- items.add(value..toString());
+ items.add(value.toString());
});
return ClassesChooser(items: items);
} else if (statusCode == 400) {
@@ -322,7 +295,6 @@ class ClassesChooser extends StatefulWidget {
class _ClassesChooserState extends State {
final List items;
- //final String dropdownValue;
String? dropdownValue;
_ClassesChooserState(this.items);
@@ -348,12 +320,15 @@ class _ClassesChooserState extends State {
border: OutlineInputBorder(),
labelText: 'Klasse (05/1, 07/3, 10/2...)',
),
- onChanged: (String? newValue) {
- setState(() async {
- dropdownValue = newValue!;
- SharedPreferences prefs = await SharedPreferences.getInstance();
- String classNum = newValue;
- await prefs.setString('class_num', classNum);
+ onChanged: (String? newValue) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ String classNum = newValue!;
+ prefs.setString('class_num', classNum);
+ prefs.remove("lessons");
+ prefs.remove("todayTImetable");
+ prefs.remove("tomorrowTimetable");
+ setState(() {
+ dropdownValue = newValue;
});
},
items: items.map>((String value) {
diff --git a/lib/news.dart b/lib/news.dart
index 0e3d141..e7e5189 100644
--- a/lib/news.dart
+++ b/lib/news.dart
@@ -30,162 +30,197 @@ class _NewsState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- appBar: AppBar(
- title: const Text("Aktuelles"),
- centerTitle: true,
- ),
- body: FutureBuilder(
- future: getNews(),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- int statusCode = snapshot.data!.statusCode;
- if (statusCode == 200) {
- String data = utf8.decode(snapshot.data!.bodyBytes);
- List articles = jsonDecode(data);
- List articleTiles = [];
- for (var element in articles) {
- Color color = Colors.white70;
- Widget card = FutureBuilder(
- future: getNewsRead(),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- List readList = snapshot.data! as List;
- if (!readList.contains(element["id"])) {
- return GestureDetector(
- onTap: () async {
- SharedPreferences prefs =
- await SharedPreferences.getInstance();
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => Article.fromData(
- element["title"],
- element["content"],
- element["author"],
- element["published_at"])
- .widget),
- );
- readList.add(element["id"]);
- prefs.setString("newsRead", jsonEncode(readList));
- setState(() {
- color = Colors.transparent;
- });
- },
- child: Card(
- color: color,
- child: Padding(
- padding:
- const EdgeInsets.fromLTRB(10, 10, 10, 10),
- child: FutureBuilder(
- future: Future.delayed(
- const Duration(seconds: 0)),
- builder: (context, snapshot) {
- if (element["summary"] != null &&
- (element["summary"] as String)
- .isNotEmpty) {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- subtitle: Text(
- element["summary"],
- overflow: TextOverflow.ellipsis,
- maxLines: 2,
- softWrap: true,
- ),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- } else {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- }
- },
- )),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(15),
- )),
- );
- } else {
- return GestureDetector(
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => Article.fromData(
- element["title"],
- element["content"],
- element["author"],
- element["published_at"])
- .widget),
- );
- },
- child: Card(
- child: Padding(
- padding:
- const EdgeInsets.fromLTRB(10, 10, 10, 10),
- child: FutureBuilder(
- future: Future.delayed(
- const Duration(seconds: 0)),
- builder: (context, snapshot) {
- if (element["summary"] != null &&
- (element["summary"] as String)
- .isNotEmpty) {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- subtitle: Text(
- element["summary"],
- overflow: TextOverflow.ellipsis,
- maxLines: 2,
- softWrap: true,
- ),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- } else {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)
- ),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- }
- },
- )),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(15),
- )),
- );
- }
- } else {
- return const LinearProgressIndicator();
- }
- },
- );
- articleTiles.add(card);
- }
- return ListView(
- children: articleTiles.reversed.toList(),
- );
- } else {
- return (const Center(
- child: Text("Uups... Irgendwas ist schief gelaufen")));
- }
+ appBar: AppBar(
+ title: const Text("Aktuelles"),
+ centerTitle: true,
+ ),
+ 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 {
- return (const Center(child: CircularProgressIndicator()));
+ factor = 1;
}
- },
- ),
- );
+
+ return Center(
+ heightFactor: 1,
+ child: Container(
+ constraints: BoxConstraints(
+ maxWidth: MediaQuery.of(context).size.width / factor,
+ ),
+ child: FutureBuilder(
+ future: getNews(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ int statusCode = snapshot.data!.statusCode;
+ if (statusCode == 200) {
+ String data = utf8.decode(snapshot.data!.bodyBytes);
+ List articles = jsonDecode(data)["data"];
+ List articleTiles = [];
+ for (var element in articles) {
+ int id = element["id"];
+ element = element["attributes"];
+ Color color = Colors.white70;
+ Widget card = FutureBuilder(
+ future: getNewsRead(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ List readList =
+ snapshot.data! as List;
+ if (!readList.contains(id)) {
+ return GestureDetector(
+ onTap: () async {
+ SharedPreferences prefs =
+ await SharedPreferences.getInstance();
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ Article.fromData(
+ element["title"],
+ element["content"],
+ element["author"],
+ element["publish_date"])
+ .widget),
+ );
+ readList.add(id);
+ prefs.setString(
+ "newsRead", jsonEncode(readList));
+ setState(() {
+ color = Colors.transparent;
+ });
+ },
+ child: Card(
+ color: color,
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(
+ 10, 10, 10, 10),
+ child: FutureBuilder(
+ future: Future.delayed(
+ const Duration(seconds: 0)),
+ builder: (context, snapshot) {
+ if (element["summary"] != null &&
+ (element["summary"] as String)
+ .isNotEmpty) {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ subtitle: Text(
+ element["summary"],
+ overflow:
+ TextOverflow.ellipsis,
+ maxLines: 2,
+ softWrap: true,
+ ),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ } else {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ }
+ },
+ )),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ )),
+ );
+ } else {
+ return GestureDetector(
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ Article.fromData(
+ element["title"],
+ element["content"],
+ element["author"],
+ element["publish_date"])
+ .widget),
+ );
+ },
+ child: Card(
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(
+ 10, 10, 10, 10),
+ child: FutureBuilder(
+ future: Future.delayed(
+ const Duration(seconds: 0)),
+ builder: (context, snapshot) {
+ if (element["summary"] != null &&
+ (element["summary"] as String)
+ .isNotEmpty) {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ subtitle: Text(
+ element["summary"],
+ overflow:
+ TextOverflow.ellipsis,
+ maxLines: 2,
+ softWrap: true,
+ ),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ } else {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ }
+ },
+ )),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ )),
+ );
+ }
+ } else {
+ return const LinearProgressIndicator();
+ }
+ },
+ );
+ articleTiles.add(card);
+ }
+ return ListView(
+ children: articleTiles.reversed.toList(),
+ );
+ } else {
+ return (const Center(
+ child:
+ Text("Uups... Irgendwas ist schief gelaufen")));
+ }
+ } else {
+ return (const Center(child: CircularProgressIndicator()));
+ }
+ },
+ ),
+ ),
+ );
+ }));
}
}
diff --git a/lib/notifications.dart b/lib/notifications.dart
deleted file mode 100644
index 8b13789..0000000
--- a/lib/notifications.dart
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/lib/presets/colors.dart b/lib/presets/colors.dart
index 8704493..f34417c 100644
--- a/lib/presets/colors.dart
+++ b/lib/presets/colors.dart
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
Map colors = {
'Bio': Colors.green,
+ 'bio1': Colors.green,
+ 'bioL1': Colors.green,
'Mat': Colors.indigo,
'matL1': Colors.indigo,
'matL2': Colors.indigo,
@@ -10,20 +12,26 @@ Map colors = {
'deu1': Colors.red,
'deu2': Colors.red,
'deu3': Colors.red,
+ 'deuL1': Colors.red,
'Kun': Colors.deepPurple,
'kun1': Colors.deepPurple,
'kun2': Colors.deepPurple,
'kun3': Colors.deepPurple,
'Geo': Colors.brown,
+ 'geo1': Colors.brown,
'Lat': Colors.teal,
'lat1': Colors.teal,
'lat2': Colors.teal,
'lat3': Colors.teal,
'Che': Colors.lightGreen,
+ 'che1': Colors.lightGreen,
+ 'cheL1': Colors.lightGreen,
'Eng': Colors.amber,
'eng1': Colors.amber,
'eng2': Colors.amber,
'eng3': Colors.amber,
+ 'engL1': Colors.amber,
+ 'engL2': Colors.amber,
'Phy': Colors.cyan,
'phy1': Colors.cyan,
'phy2': Colors.cyan,
diff --git a/lib/presets/subjects.dart b/lib/presets/subjects.dart
index 0bd39d3..45283c5 100644
--- a/lib/presets/subjects.dart
+++ b/lib/presets/subjects.dart
@@ -1,30 +1,63 @@
dynamic subjects = {
'---': '---',
'Bio': 'Biologie',
+ 'bio1': 'Biologie 1',
+ 'bioL1': 'Biologie Leistungskurs 1',
'Mat': 'Mathematik',
'matL1': 'Mathematik Leistungskurs 1',
+ 'matL2': 'Mathematik Leistungskurs 2',
+ 'matL3': 'Mathematik Leistungskurs 3',
'Kun': 'Kunst',
+ 'kun1': 'Kunst 1',
'Mus': 'Musik',
+ 'mus1': 'Musik 1',
+ 'mus2': 'Musik 2',
'Geo': 'Geographie',
+ 'geo1': 'Geographie 1',
'Ges': 'Geschichte',
+ 'ges1': 'Geschichte 1',
+ 'ges2': 'Geschichte 2',
+ 'ges3': 'Geschichte 3',
'Che': 'Chemie',
+ 'che1': 'Chemie 1',
+ 'cheL1': 'Chemie Leistungskurs 1',
'Lat': 'Latein',
+ 'lat1': 'Latein 1',
'Inf': 'Informatik',
+ 'inf1': 'Informatik 1',
+ 'inf2': 'Informatik 2',
+ 'infL1': 'Informatik Leistungskurs 1',
'Eng': 'Englisch',
+ 'eng1': 'Englisch 1',
+ 'eng2': 'Englisch 2',
+ 'engL1': 'Englisch Leistungskurs 1',
+ 'engL2': 'Englisch Leistungskurs 2',
'Frz': 'Französisch',
'frz1': 'Französisch 1',
'frz2': 'Französisch 2',
'frz3': 'Französisch 3',
'Phy': 'Physik',
+ 'phy1': 'Physik 1',
+ 'phyL1': 'Physik Leistungskurs 1',
+ 'phyL2': 'Physik Leistungskurs 2',
+ 'psy1': 'Psychologie 1',
'Spo': 'Sport',
+ 'spo1': 'Sport 1',
+ 'spo2': 'Sport 2',
+ 'spo3': 'Sport 3',
'Deu': 'Deutsch',
'deu1': 'Deutsch 1',
'deu2': 'Deutsch 2',
'deu3': 'Deutsch 3',
+ 'deuL1': 'Deutsch Leistungskurs 1',
'Lme': 'Lernmethoden',
'Eth': 'Ethik',
+ 'eth1': 'Ethik 1',
'EvR': 'Evangelische Religion',
+ 'evr1': 'Evangelische Religion 1',
'Soz': 'Sozialkunde',
+ 'soz1': 'Sozialkunde 1',
+ 'soz2': 'Sozialkunde 2',
'Ast': 'Astronomie',
'Spa': 'Spanisch',
'FK': 'Fachkurs',
diff --git a/lib/raumuebersicht.dart b/lib/raumuebersicht.dart
index 2cf97d9..0f5659b 100644
--- a/lib/raumuebersicht.dart
+++ b/lib/raumuebersicht.dart
@@ -1,4 +1,3 @@
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class RoomOverview extends StatelessWidget {
diff --git a/lib/saved.dart b/lib/saved.dart
new file mode 100644
index 0000000..01c82b4
--- /dev/null
+++ b/lib/saved.dart
@@ -0,0 +1,198 @@
+// SizedBox(
+ // width: 170,
+ // child: GestureDetector(
+ // onTap: () async {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(builder: (context) => const SB()),
+ // );
+ // },
+ // child: Card(
+ // shape: RoundedRectangleBorder(
+ // borderRadius: BorderRadius.circular(10),
+ // ),
+ // child: const Padding(
+ // padding: EdgeInsets.all(10),
+ // child: ListTile(
+ // title: Padding(
+ // padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
+ // child: Icon(
+ // MdiIcons.libraryShelves,
+ // color: Palette.accent,
+ // size: 48,
+ // ),
+ // ),
+ // subtitle: Center(
+ // child: Padding(
+ // padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
+ // child: Text(
+ // 'Schulbibliothek',
+ // ),
+ // ),
+ // ),
+ // ),
+ // )),
+ // ),
+ // ),
+ // SizedBox(
+ // width: 170,
+ // child: GestureDetector(
+ // onTap: () async {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(builder: (context) => const SC()),
+ // );
+ // },
+ // child: Card(
+ // shape: RoundedRectangleBorder(
+ // borderRadius: BorderRadius.circular(10),
+ // ),
+ // child: const Padding(
+ // padding: EdgeInsets.all(10),
+ // child: ListTile(
+ // title: Padding(
+ // padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
+ // child: Icon(
+ // MdiIcons.laptop,
+ // color: Palette.accent,
+ // size: 48,
+ // ),
+ // ),
+ // subtitle: Center(
+ // child: Padding(
+ // padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
+ // child: Text(
+ // 'Schulcomputer',
+ // ),
+ // ),
+ // ),
+ // ),
+ // )),
+ // ),
+ // ),
+ // SizedBox(
+ // width: 170,
+ // child: GestureDetector(
+ // onTap: () async {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => const RoomOverview()),
+ // );
+ // },
+ // child: Card(
+ // shape: RoundedRectangleBorder(
+ // borderRadius: BorderRadius.circular(10),
+ // ),
+ // child: const Padding(
+ // padding: EdgeInsets.all(10),
+ // child: ListTile(
+ // title: Padding(
+ // padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
+ // child: Icon(
+ // MdiIcons.door,
+ // color: Palette.accent,
+ // size: 48,
+ // ),
+ // ),
+ // subtitle: Center(
+ // child: Padding(
+ // padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
+ // child: Text(
+ // 'Raumübersicht',
+ // ),
+ // ),
+ // ),
+ // ),
+ // )),
+ // ),
+ // ),
+
+
+
+ // ListTile(
+ // leading:
+ // const Icon(MdiIcons.timetable, color: Colors.orangeAccent),
+ // trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ // title: const Text("Plan"),
+ // subtitle: const Text("Kurse/Fächer, Farben & mehr"),
+ // onTap: () {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(builder: (context) => const PlanSettings()),
+ // );
+ // },
+ // ),
+ // ListTile(
+ // leading: const Icon(Icons.color_lens_outlined,
+ // color: Colors.pinkAccent),
+ // trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ // title: const Text("Aussehen"),
+ // subtitle: const Text("Widgets, Design & mehr"),
+ // onTap: () {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => const AppearanceSettings()),
+ // );
+ // },
+ // ),
+ // ListTile(
+ // leading: const Icon(MdiIcons.server, color: Colors.lightGreen),
+ // trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+ // title: const Text("Dienste"),
+ // subtitle: const Text("Konten, Plattformen & mehr"),
+ // onTap: () {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => const ServiceSettings()),
+ // );
+ // },
+ // ),
+
+// class PlanSettings extends StatelessWidget {
+// const PlanSettings({Key? key}) : super(key: key);
+
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// appBar: AppBar(
+// title: const Text("Plan"),
+// centerTitle: true,
+// ),
+// body: ListView(
+// padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
+// children: [
+// ListTile(
+// leading: const Icon(Icons.list_alt_outlined, color: Colors.red),
+// trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+// title: const Text("Kurse"),
+// subtitle: const Text("Konfiguration der Kurse"),
+// onTap: () {
+// Navigator.push(
+// context,
+// MaterialPageRoute(
+// builder: (context) => const WhitelistSettings()),
+// );
+// },
+// ),
+// ListTile(
+// leading:
+// const Icon(Icons.color_lens_outlined, color: Colors.teal),
+// trailing: const Icon(Icons.arrow_forward_ios, size: 16),
+// title: const Text("Farben"),
+// subtitle:
+// const Text("Konfiguration der Farben für die Plankacheln"),
+// onTap: () {
+// Navigator.push(
+// context,
+// MaterialPageRoute(
+// builder: (context) => const PlanColorSettings()),
+// );
+// },
+// ),
+// ],
+// ));
+// }
+// }
\ No newline at end of file
diff --git a/lib/schuelerzeitung.dart b/lib/schuelerzeitung.dart
index e211464..4de519f 100644
--- a/lib/schuelerzeitung.dart
+++ b/lib/schuelerzeitung.dart
@@ -5,6 +5,8 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:http/http.dart' as http;
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
+import 'package:url_launcher/url_launcher.dart';
+import 'package:markdown/markdown.dart' as md;
Future getSZread() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
@@ -30,161 +32,197 @@ class _SZState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- appBar: AppBar(
- title: const Text("Schülerzeitung"),
- centerTitle: true,
- ),
- body: FutureBuilder(
- future: getArticles(),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- int statusCode = snapshot.data!.statusCode;
- if (statusCode == 200) {
- String data = utf8.decode(snapshot.data!.bodyBytes);
- List articles = jsonDecode(data);
- List articleTiles = [];
- for (var element in articles) {
- Color color = Colors.white70;
- Widget card = FutureBuilder(
- future: getSZread(),
- builder: (context, snapshot) {
- if (snapshot.hasData) {
- List readList = snapshot.data! as List;
- if (!readList.contains(element["id"])) {
- return GestureDetector(
- onTap: () async {
- SharedPreferences prefs =
- await SharedPreferences.getInstance();
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => Article.fromData(
- element["title"],
- element["content"],
- element["author"],
- element["published_at"])
- .widget),
- );
- readList.add(element["id"]);
- prefs.setString("SZread", jsonEncode(readList));
- setState(() {
- color = Colors.transparent;
- });
- },
- child: Card(
- color: color,
- child: Padding(
- padding:
- const EdgeInsets.fromLTRB(10, 10, 10, 10),
- child: FutureBuilder(
- future: Future.delayed(
- const Duration(seconds: 0)),
- builder: (context, snapshot) {
- if (element["summary"] != null &&
- (element["summary"] as String)
- .isNotEmpty) {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- subtitle: Text(
- element["summary"],
- overflow: TextOverflow.ellipsis,
- maxLines: 2,
- softWrap: true,
- ),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- } else {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- }
- },
- )),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(15),
- )),
- );
- } else {
- return GestureDetector(
- onTap: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => Article.fromData(
- element["title"],
- element["content"],
- element["author"],
- element["published_at"])
- .widget),
- );
- },
- child: Card(
- child: Padding(
- padding:
- const EdgeInsets.fromLTRB(10, 10, 10, 10),
- child: FutureBuilder(
- future: Future.delayed(
- const Duration(seconds: 0)),
- builder: (context, snapshot) {
- if (element["summary"] != null &&
- (element["summary"] as String)
- .isNotEmpty) {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- subtitle: Text(
- element["summary"],
- overflow: TextOverflow.ellipsis,
- maxLines: 2,
- softWrap: true,
- ),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- } else {
- return ListTile(
- title: Text(element["title"],
- style: const TextStyle(
- fontWeight: FontWeight.bold)),
- trailing: Text(
- "${DateTime.parse(element["published_at"]).day.toString()}.${DateTime.parse(element["published_at"]).month.toString()}.${DateTime.parse(element["published_at"]).year.toString()}"),
- );
- }
- },
- )),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(15),
- )),
- );
- }
- } else {
- return const LinearProgressIndicator();
- }
- },
- );
- articleTiles.add(card);
- }
- return ListView(
- children: articleTiles.reversed.toList(),
- );
- } else {
- return (const Center(
- child: Text("Uups... Irgendwas ist schief gelaufen")));
- }
+ appBar: AppBar(
+ title: const Text("Schülerzeitung"),
+ centerTitle: true,
+ ),
+ 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 {
- return (const Center(child: CircularProgressIndicator()));
+ factor = 1;
}
- },
- ),
- );
+
+ return Center(
+ heightFactor: 1,
+ child: Container(
+ constraints: BoxConstraints(
+ maxWidth: MediaQuery.of(context).size.width / factor,
+ ),
+ child: FutureBuilder(
+ future: getArticles(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ int statusCode = snapshot.data!.statusCode;
+ if (statusCode == 200) {
+ String data = utf8.decode(snapshot.data!.bodyBytes);
+ List articles = jsonDecode(data)["data"];
+ List articleTiles = [];
+ for (var element in articles) {
+ int id = element["id"];
+ element = element["attributes"];
+ Color color = Colors.white70;
+ Widget card = FutureBuilder(
+ future: getSZread(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ List readList =
+ snapshot.data! as List;
+ if (!readList.contains(id)) {
+ return GestureDetector(
+ onTap: () async {
+ SharedPreferences prefs =
+ await SharedPreferences.getInstance();
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ Article.fromData(
+ element["title"],
+ element["content"],
+ element["author"],
+ element["publish_date"])
+ .widget),
+ );
+ readList.add(id);
+ prefs.setString(
+ "SZread", jsonEncode(readList));
+ setState(() {
+ color = Colors.transparent;
+ });
+ },
+ child: Card(
+ color: color,
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(
+ 10, 10, 10, 10),
+ child: FutureBuilder(
+ future: Future.delayed(
+ const Duration(seconds: 0)),
+ builder: (context, snapshot) {
+ if (element["summary"] != null &&
+ (element["summary"] as String)
+ .isNotEmpty) {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ subtitle: Text(
+ element["summary"],
+ overflow:
+ TextOverflow.ellipsis,
+ maxLines: 2,
+ softWrap: true,
+ ),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ } else {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ }
+ },
+ )),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ )),
+ );
+ } else {
+ return GestureDetector(
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ Article.fromData(
+ element["title"],
+ element["content"],
+ element["author"],
+ element["publish_date"])
+ .widget),
+ );
+ },
+ child: Card(
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(
+ 10, 10, 10, 10),
+ child: FutureBuilder(
+ future: Future.delayed(
+ const Duration(seconds: 0)),
+ builder: (context, snapshot) {
+ if (element["summary"] != null &&
+ (element["summary"] as String)
+ .isNotEmpty) {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ subtitle: Text(
+ element["summary"],
+ overflow:
+ TextOverflow.ellipsis,
+ maxLines: 2,
+ softWrap: true,
+ ),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ } else {
+ return ListTile(
+ title: Text(element["title"],
+ style: const TextStyle(
+ fontWeight:
+ FontWeight.bold)),
+ trailing: Text(
+ "${DateTime.parse(element["publish_date"]).day.toString()}.${DateTime.parse(element["publish_date"]).month.toString()}.${DateTime.parse(element["publish_date"]).year.toString()}"),
+ );
+ }
+ },
+ )),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ )),
+ );
+ }
+ } else {
+ return const LinearProgressIndicator();
+ }
+ },
+ );
+ articleTiles.add(card);
+ }
+ return ListView(
+ children: articleTiles.reversed.toList(),
+ );
+ } else {
+ return (const Center(
+ child:
+ Text("Uups... Irgendwas ist schief gelaufen")));
+ }
+ } else {
+ return (const Center(child: CircularProgressIndicator()));
+ }
+ },
+ ),
+ ),
+ );
+ }));
}
}
@@ -216,7 +254,14 @@ class Article {
title: Text(
"${DateTime.parse(publishDate).day.toString()}.${DateTime.parse(publishDate).month.toString()}.${DateTime.parse(publishDate).year.toString()}"),
),
- MarkdownBody(data: content)
+ MarkdownBody(
+ data: content,
+ onTapLink: (text, url, title) {
+ launch(url!);
+ },
+ extensionSet: md.ExtensionSet.commonMark,
+ imageDirectory: "https://cms.mein.cantorgymnasium.de",
+ )
],
)));
}
diff --git a/lib/schulbibliothek.dart b/lib/schulbibliothek.dart
index 81c4912..5073a90 100644
--- a/lib/schulbibliothek.dart
+++ b/lib/schulbibliothek.dart
@@ -1,4 +1,3 @@
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SB extends StatelessWidget {
diff --git a/lib/schulcomputer.dart b/lib/schulcomputer.dart
index e5d7f97..7f754c5 100644
--- a/lib/schulcomputer.dart
+++ b/lib/schulcomputer.dart
@@ -1,4 +1,3 @@
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SC extends StatelessWidget {
diff --git a/lib/timetable.dart b/lib/timetable.dart
index 681c00b..b62c255 100644
--- a/lib/timetable.dart
+++ b/lib/timetable.dart
@@ -3,7 +3,6 @@ import 'package:meincantor/presets/subjects.dart';
import 'package:meincantor/presets/colors.dart';
import 'package:flutter/material.dart';
-import 'package:flutter/cupertino.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -25,8 +24,10 @@ class ClassTimetableBuilder {
onTap: () {
showModalBottomSheet(
isScrollControlled: true,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(25.0),
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(25.0),
+ topRight: Radius.circular(25.0)),
),
context: context,
builder: (BuildContext context) {
@@ -35,6 +36,8 @@ class ClassTimetableBuilder {
child: ListView(
children: [
ListTile(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(25.0)),
title: const Text("Informationen",
style: TextStyle(fontWeight: FontWeight.bold)),
leading: const Icon(Icons.arrow_back),
@@ -90,15 +93,15 @@ class LessonsListBuilder {
title: Text(element.count.toString() + '.' + ' ' + element.name,
style: TextStyle(color: element.fontColor)),
subtitle: Row(children: [
- Icon(CupertinoIcons.person, color: element.fontColor),
+ Icon(Icons.person_outline, color: element.fontColor),
const SizedBox(width: 5),
Text(element.teacher, style: TextStyle(color: element.fontColor)),
const Spacer(),
- Icon(CupertinoIcons.home, color: element.fontColor),
+ Icon(MdiIcons.door, color: element.fontColor),
const SizedBox(width: 5),
Text(element.room, style: TextStyle(color: element.fontColor))
]),
- leading: Icon(CupertinoIcons.time, color: element.fontColor)));
+ leading: Icon(MdiIcons.clockOutline, color: element.fontColor)));
if (element.info != '') {
cardChildren.add(ListTile(
title: Text(element.info,
@@ -150,7 +153,7 @@ class TimetableInfo {
}
class ClassTimetable {
- final List timetable;
+ final List timetable;
ClassTimetable({required this.timetable});
factory ClassTimetable.fromJson(Map json) {
List lessons = [];
@@ -201,11 +204,10 @@ class ClassTimetable {
lessons.add(TimetableLesson(
value['St'],
- value["Nr"],
- subjects[subject] ?? subject.toString(),
+ value["Nr"] ?? 0,
+ subject == ' ' ? "---" : subjects[subject] ?? subject.toString(),
teachers[teacher] ?? teacher.toString(),
room.toString(),
- value['If'].toString(),
lessonColor,
fontColor,
info));
@@ -221,10 +223,9 @@ class TimetableLesson {
final String name;
final String teacher;
final String room;
- final String comment;
final Future color;
final Color fontColor;
final String info;
const TimetableLesson(this.count, this.id, this.name, this.teacher, this.room,
- this.comment, this.color, this.fontColor, this.info);
+ this.color, this.fontColor, this.info);
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 4bd95bc..c183dfd 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-version: 0.8.0-dev
+version: 1.0.0
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -31,7 +31,7 @@ dependencies:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
- cupertino_icons: ^1.0.2
+ # cupertino_icons: ^1.0.2
shared_preferences: ^2.0.6
http: ^0.13.3
google_fonts: ^2.1.0
@@ -45,7 +45,7 @@ dependencies:
url_launcher: ^6.0.17
flutter_linkify: ^5.0.2
flutter_svg: ^1.0.0
- webview_flutter: ^3.0.0
+ webviewx: ^0.2.1
flutter_local_notifications: ^10.0.0-dev.1
background_fetch: ^1.0.3
@@ -83,6 +83,8 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/meincantor_r.png
+ - assets/images/meincantor-big.png
+ - assets/images/meincantor-big-dark.png
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see