diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 1503a2d..326de58 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -9,6 +9,13 @@ + + + + + + @@ -215,7 +222,7 @@ - @@ -282,6 +289,13 @@ + + + + + + @@ -380,6 +394,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -436,6 +506,27 @@ + + + + + + + + + + + + + + + + + + @@ -478,6 +569,13 @@ + + + + + + @@ -600,7 +698,7 @@ - @@ -705,14 +803,14 @@ - - @@ -1006,7 +1104,7 @@ - @@ -1132,7 +1230,7 @@ - @@ -1248,6 +1346,13 @@ + + + + + + @@ -1297,6 +1402,7 @@ + @@ -1326,7 +1432,7 @@ - + @@ -1336,6 +1442,7 @@ + @@ -1349,15 +1456,27 @@ + + + + + + + + + + + + @@ -1375,7 +1494,7 @@ - + @@ -1390,8 +1509,8 @@ - - + + @@ -1431,7 +1550,7 @@ - + @@ -1449,7 +1568,7 @@ - + @@ -1466,6 +1585,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index e848caa..e5ebdb8 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,24 +1,18 @@ - - - - - - - - - - - - + + + + + + @@ -26,19 +20,32 @@ + + + + + + + + + + + + - - + + + diff --git a/android/app/build.gradle b/android/app/build.gradle index 361edbd..0c2fde7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -23,6 +23,7 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'com.google.gms.google-services' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { @@ -39,7 +40,7 @@ android { applicationId "eu.mhsl.marianum.mobile.client" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion + minSdkVersion 19 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..adab10f --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "522850592536", + "project_id": "marmobile-33b10", + "storage_bucket": "marmobile-33b10.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:522850592536:android:9a355c61e6f1b0f0c2606d", + "android_client_info": { + "package_name": "eu.mhsl.marianum.mobile.client" + } + }, + "oauth_client": [ + { + "client_id": "522850592536-5urolovocke0fmr7kpd0hqvfd3gft6qo.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAXo66A3jSBxnAYKgpUIfucidELoHw5W3M" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "522850592536-5urolovocke0fmr7kpd0hqvfd3gft6qo.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java b/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java new file mode 100644 index 0000000..752fc18 --- /dev/null +++ b/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java @@ -0,0 +1,25 @@ +// Generated file. +// +// If you wish to remove Flutter's multidex support, delete this entire file. +// +// Modifications to this file should be done in a copy under a different name +// as this file may be regenerated. + +package io.flutter.app; + +import android.app.Application; +import android.content.Context; +import androidx.annotation.CallSuper; +import androidx.multidex.MultiDex; + +/** + * Extension of {@link android.app.Application}, adding multidex support. + */ +public class FlutterMultiDexApplication extends Application { + @Override + @CallSuper + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(this); + } +} diff --git a/android/build.gradle b/android/build.gradle index 3efffaf..db9efaf 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.15' } } diff --git a/client.iml b/client.iml index fa043b4..2fa4042 100644 --- a/client.iml +++ b/client.iml @@ -3,6 +3,7 @@ + diff --git a/lib/api/mhsl/mhslApi.dart b/lib/api/mhsl/mhslApi.dart index fa9ec02..64f6270 100644 --- a/lib/api/mhsl/mhslApi.dart +++ b/lib/api/mhsl/mhslApi.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:http/http.dart' as http; import '../apiError.dart'; @@ -21,6 +22,10 @@ abstract class MhslApi extends ApiRequest { throw ApiError("Request could not be dispatched!"); } + if(data.statusCode > 299) { + log("Non 200 Status code from mhsl services: $subpath: ${data.statusCode}"); + } + return assemble(utf8.decode(data.bodyBytes)); } } \ No newline at end of file diff --git a/lib/api/mhsl/notify/register/notifyRegister.dart b/lib/api/mhsl/notify/register/notifyRegister.dart new file mode 100644 index 0000000..c614520 --- /dev/null +++ b/lib/api/mhsl/notify/register/notifyRegister.dart @@ -0,0 +1,26 @@ + +import 'dart:convert'; +import 'dart:developer'; + +import 'package:http/http.dart' as http; + +import '../../mhslApi.dart'; +import 'notifyRegisterParams.dart'; + +class NotifyRegister extends MhslApi { + NotifyRegisterParams params; + NotifyRegister(this.params) : super("notify/register/"); + + + @override + void assemble(String raw) { + + } + + @override + Future request(Uri uri) { + String requestString = jsonEncode(params.toJson()); + log(requestString); + return http.post(uri, body: requestString); + } +} \ No newline at end of file diff --git a/lib/api/mhsl/notify/register/notifyRegisterParams.dart b/lib/api/mhsl/notify/register/notifyRegisterParams.dart new file mode 100644 index 0000000..75c7a95 --- /dev/null +++ b/lib/api/mhsl/notify/register/notifyRegisterParams.dart @@ -0,0 +1,19 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'notifyRegisterParams.g.dart'; + +@JsonSerializable() +class NotifyRegisterParams { + String username; + String password; + String fcmToken; + + NotifyRegisterParams({ + required this.username, + required this.password, + required this.fcmToken + }); + + factory NotifyRegisterParams.fromJson(Map json) => _$NotifyRegisterParamsFromJson(json); + Map toJson() => _$NotifyRegisterParamsToJson(this); +} \ No newline at end of file diff --git a/lib/api/mhsl/notify/register/notifyRegisterParams.g.dart b/lib/api/mhsl/notify/register/notifyRegisterParams.g.dart new file mode 100644 index 0000000..0b26d8d --- /dev/null +++ b/lib/api/mhsl/notify/register/notifyRegisterParams.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'notifyRegisterParams.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +NotifyRegisterParams _$NotifyRegisterParamsFromJson( + Map json) => + NotifyRegisterParams( + username: json['username'] as String, + password: json['password'] as String, + fcmToken: json['fcmToken'] as String, + ); + +Map _$NotifyRegisterParamsToJson( + NotifyRegisterParams instance) => + { + 'username': instance.username, + 'password': instance.password, + 'fcmToken': instance.fcmToken, + }; diff --git a/lib/app.dart b/lib/app.dart index 391296b..f77ea5c 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,6 +1,7 @@ import 'dart:async'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; import 'package:provider/provider.dart'; @@ -10,6 +11,9 @@ import 'api/mhsl/breaker/getBreakers/getBreakersResponse.dart'; import 'model/breakers/Breaker.dart'; import 'model/breakers/BreakerProps.dart'; import 'model/chatList/chatListProps.dart'; +import 'notification/notificationController.dart'; +import 'notification/notifyUpdater.dart'; +import 'storage/base/settingsProvider.dart'; import 'view/pages/files/files.dart'; import 'view/pages/more/overhang.dart'; import 'view/pages/talk/chatList.dart'; @@ -42,6 +46,13 @@ class _AppState extends State { }); }); + if(Provider.of(context, listen: false).val().notificationSettings.enabled) { + NotifyUpdater.registerToServer(); + } + + FirebaseMessaging.onMessage.listen((message) => NotificationController.onForegroundMessageHandler(message, context)); + FirebaseMessaging.onBackgroundMessage(NotificationController.onBackgroundMessageHandler); + super.initState(); } diff --git a/lib/main.dart b/lib/main.dart index d0af28b..6268f3c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,10 @@ import 'dart:async'; +import 'dart:developer'; import 'dart:io'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:jiffy/jiffy.dart'; @@ -27,6 +31,8 @@ import 'widget/placeholderView.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(); + log("Firebase token: ${await FirebaseMessaging.instance.getToken() ?? "Error: no Firebase token!"}"); ByteData data = await PlatformAssetBundle().load('assets/ca/lets-encrypt-r3.pem'); SecurityContext.defaultContext.setTrustedCertificatesBytes(data.buffer.asUint8List()); diff --git a/lib/notification/notificationController.dart b/lib/notification/notificationController.dart new file mode 100644 index 0000000..22a6b13 --- /dev/null +++ b/lib/notification/notificationController.dart @@ -0,0 +1,45 @@ +import 'dart:developer'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/cupertino.dart'; + +import '../api/marianumcloud/talk/room/getRoom.dart'; +import '../api/marianumcloud/talk/room/getRoomParams.dart'; +import '../model/accountData.dart'; +import 'notificationService.dart'; + +class NotificationController { + @pragma('vm:entry-point') + static Future onBackgroundMessageHandler(RemoteMessage message) async { + log("Handling a background notification: ${message.messageId}"); + + await Firebase.initializeApp(); + AccountData().waitForPopulation().then((value) { + log("User account status: $value"); + if(value) { + GetRoom( + GetRoomParams( + includeStatus: false, + ), + ).run().then((value) { + var messageCount = value.data.map((e) => e.unreadMessages).reduce((a, b) => a + b); + var chatCount = value.data.map((e) => e.unreadMessages).length; + var people = value.data.where((e) => e.unreadMessages > 0).map((e) => e.displayName.split(" ")[0]); + + final NotificationService service = NotificationService(); + service.initializeNotifications().then((value) { + service.showNotification( + title: "Du hast $messageCount ungelesene Nachrichten!", + body: "In $chatCount Chats, von ${people.join(", ")}" + ); + }); + }); + } + }); + } + + static Future onForegroundMessageHandler(RemoteMessage message, BuildContext context) async { + NotificationService().showToast(message: "Du hast eine neue Talk Nachricht!", context: context); + } +} \ No newline at end of file diff --git a/lib/notification/notificationService.dart b/lib/notification/notificationService.dart new file mode 100644 index 0000000..77fdc8c --- /dev/null +++ b/lib/notification/notificationService.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/provider.dart'; + +import '../model/chatList/chatListProps.dart'; +import '../model/message/messageProps.dart'; + +class NotificationService { + static final NotificationService _instance = NotificationService._internal(); + + factory NotificationService() { + return _instance; + } + + NotificationService._internal(); + + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + + Future initializeNotifications() async { + const AndroidInitializationSettings androidSettings = AndroidInitializationSettings( + '@mipmap/ic_launcher' + ); + + final DarwinInitializationSettings iosSettings = DarwinInitializationSettings( + onDidReceiveLocalNotification: (id, title, body, payload) { + // TODO Navigate to Talk section (This runs when an Notification is tapped) + }, + ); + + + final InitializationSettings initializationSettings = InitializationSettings( + android: androidSettings, + iOS: iosSettings, + ); + + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + ); + } + + Future showNotification({required String title, required String body}) async { + const AndroidNotificationDetails androidPlatformChannelSpecifics = + AndroidNotificationDetails( + 'your_channel_id', + 'Your Channel Name', + importance: Importance.defaultImportance, + priority: Priority.defaultPriority, + ticker: 'ticker', + ); + + const NotificationDetails platformChannelSpecifics = NotificationDetails(android: androidPlatformChannelSpecifics); + + await flutterLocalNotificationsPlugin.show( + 0, + title, + body, + platformChannelSpecifics, + ); + } + + void showToast({required String message, required BuildContext context, ToastGravity gravity = ToastGravity.BOTTOM}) { + Fluttertoast.showToast( + msg: message, + gravity: gravity, + toastLength: Toast.LENGTH_SHORT, + backgroundColor: Theme.of(context).primaryColor, + textColor: Colors.white, + fontSize: 13.0, + ); + + Provider.of(context, listen: false).run(renew: true); + Provider.of(context, listen: false).run(renew: true); + } +} \ No newline at end of file diff --git a/lib/notification/notifyUpdater.dart b/lib/notification/notifyUpdater.dart new file mode 100644 index 0000000..72688de --- /dev/null +++ b/lib/notification/notifyUpdater.dart @@ -0,0 +1,22 @@ + +import 'package:firebase_messaging/firebase_messaging.dart'; + +import '../api/mhsl/notify/register/notifyRegister.dart'; +import '../api/mhsl/notify/register/notifyRegisterParams.dart'; +import '../model/accountData.dart'; + +class NotifyUpdater { + static void registerToServer() async { + String? fcmToken = await FirebaseMessaging.instance.getToken(); + + if(fcmToken == null) throw Exception("Failed to register push notification because there is no FBC token!"); + + NotifyRegister( + NotifyRegisterParams( + username: AccountData().getUsername(), + password: AccountData().getPassword(), + fcmToken: fcmToken, + ), + ).run(); + } +} \ No newline at end of file diff --git a/lib/storage/base/settings.dart b/lib/storage/base/settings.dart index 59aca1c..5f96084 100644 --- a/lib/storage/base/settings.dart +++ b/lib/storage/base/settings.dart @@ -5,6 +5,7 @@ import '../file/fileSettings.dart'; import '../fileView/fileViewSettings.dart'; import '../gradeAverages/gradeAveragesSettings.dart'; import '../holidays/holidaysSettings.dart'; +import '../notification/notificationSettings.dart'; import '../talk/talkSettings.dart'; import '../timetable/timetableSettings.dart'; @@ -25,6 +26,7 @@ class Settings { FileSettings fileSettings; HolidaysSettings holidaysSettings; FileViewSettings fileViewSettings; + NotificationSettings notificationSettings; Settings({ required this.appTheme, @@ -35,6 +37,7 @@ class Settings { required this.fileSettings, required this.holidaysSettings, required this.fileViewSettings, + required this.notificationSettings, }); static String _themeToJson(ThemeMode m) => m.name; diff --git a/lib/storage/base/settings.g.dart b/lib/storage/base/settings.g.dart index 5d04e65..b8ca058 100644 --- a/lib/storage/base/settings.g.dart +++ b/lib/storage/base/settings.g.dart @@ -21,6 +21,8 @@ Settings _$SettingsFromJson(Map json) => Settings( json['holidaysSettings'] as Map), fileViewSettings: FileViewSettings.fromJson( json['fileViewSettings'] as Map), + notificationSettings: NotificationSettings.fromJson( + json['notificationSettings'] as Map), ); Map _$SettingsToJson(Settings instance) => { @@ -32,4 +34,5 @@ Map _$SettingsToJson(Settings instance) => { 'fileSettings': instance.fileSettings.toJson(), 'holidaysSettings': instance.holidaysSettings.toJson(), 'fileViewSettings': instance.fileViewSettings.toJson(), + 'notificationSettings': instance.notificationSettings.toJson(), }; diff --git a/lib/storage/notification/notificationSettings.dart b/lib/storage/notification/notificationSettings.dart new file mode 100644 index 0000000..81607ba --- /dev/null +++ b/lib/storage/notification/notificationSettings.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'notificationSettings.g.dart'; + +@JsonSerializable() +class NotificationSettings { + bool askUsageDismissed; + bool enabled; + + NotificationSettings({required this.askUsageDismissed, required this.enabled}); + + factory NotificationSettings.fromJson(Map json) => _$NotificationSettingsFromJson(json); + Map toJson() => _$NotificationSettingsToJson(this); +} \ No newline at end of file diff --git a/lib/storage/notification/notificationSettings.g.dart b/lib/storage/notification/notificationSettings.g.dart new file mode 100644 index 0000000..d46c15d --- /dev/null +++ b/lib/storage/notification/notificationSettings.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'notificationSettings.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +NotificationSettings _$NotificationSettingsFromJson( + Map json) => + NotificationSettings( + askUsageDismissed: json['askUsageDismissed'] as bool, + enabled: json['enabled'] as bool, + ); + +Map _$NotificationSettingsToJson( + NotificationSettings instance) => + { + 'askUsageDismissed': instance.askUsageDismissed, + 'enabled': instance.enabled, + }; diff --git a/lib/view/pages/more/overhang.dart b/lib/view/pages/more/overhang.dart index 5f9be9d..7b501a6 100644 --- a/lib/view/pages/more/overhang.dart +++ b/lib/view/pages/more/overhang.dart @@ -1,5 +1,4 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; diff --git a/lib/view/pages/talk/chatList.dart b/lib/view/pages/talk/chatList.dart index 0760f9f..acd879d 100644 --- a/lib/view/pages/talk/chatList.dart +++ b/lib/view/pages/talk/chatList.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -26,6 +27,8 @@ class _ChatListState extends State { void initState() { super.initState(); + FirebaseMessaging.instance.requestPermission(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { _query(); }); diff --git a/lib/view/settings/defaultSettings.dart b/lib/view/settings/defaultSettings.dart index 44d9494..1c6bc88 100644 --- a/lib/view/settings/defaultSettings.dart +++ b/lib/view/settings/defaultSettings.dart @@ -7,6 +7,7 @@ import '../../storage/file/fileSettings.dart'; import '../../storage/fileView/fileViewSettings.dart'; import '../../storage/gradeAverages/gradeAveragesSettings.dart'; import '../../storage/holidays/holidaysSettings.dart'; +import '../../storage/notification/notificationSettings.dart'; import '../../storage/talk/talkSettings.dart'; import '../../storage/timetable/timetableSettings.dart'; import '../pages/files/files.dart'; @@ -39,6 +40,10 @@ class DefaultSettings { fileViewSettings: FileViewSettings( alwaysOpenExternally: Platform.isIOS, ), + notificationSettings: NotificationSettings( + askUsageDismissed: false, + enabled: false, + ) ); } } \ No newline at end of file diff --git a/lib/view/settings/settings.dart b/lib/view/settings/settings.dart index 6c221ae..f106da4 100644 --- a/lib/view/settings/settings.dart +++ b/lib/view/settings/settings.dart @@ -7,6 +7,7 @@ import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../model/accountData.dart'; +import '../../notification/notifyUpdater.dart'; import '../../storage/base/settingsProvider.dart'; import '../../theming/appTheme.dart'; import '../../widget/centeredLeading.dart'; @@ -87,9 +88,7 @@ class _SettingsState extends State { ), )).toList(), onChanged: (e) { - setState(() { - settings.val(write: true).appTheme = e!; - }); + settings.val(write: true).appTheme = e!; }, ), ), @@ -102,9 +101,7 @@ class _SettingsState extends State { trailing: Checkbox( value: settings.val().talkSettings.sortFavoritesToTop, onChanged: (e) { - setState(() { - settings.val(write: true).talkSettings.sortFavoritesToTop = e!; - }); + settings.val(write: true).talkSettings.sortFavoritesToTop = e!; }, ), ), @@ -115,9 +112,7 @@ class _SettingsState extends State { trailing: Checkbox( value: settings.val().talkSettings.sortUnreadToTop, onChanged: (e) { - setState(() { - settings.val(write: true).talkSettings.sortUnreadToTop = e!; - }); + settings.val(write: true).talkSettings.sortUnreadToTop = e!; }, ), ), @@ -130,9 +125,7 @@ class _SettingsState extends State { trailing: Checkbox( value: settings.val().fileSettings.sortFoldersToTop, onChanged: (e) { - setState(() { - settings.val(write: true).fileSettings.sortFoldersToTop = e!; - }); + settings.val(write: true).fileSettings.sortFoldersToTop = e!; }, ), ), @@ -152,6 +145,49 @@ class _SettingsState extends State { const Divider(), + ListTile( + leading: const CenteredLeading(Icon(Icons.notifications_active_outlined)), + title: const Text("Push-Benachrichtigungen aktivieren"), + subtitle: const Text("Lange tippen für mehr Informationen"), + trailing: Checkbox( + value: settings.val().notificationSettings.enabled, + onChanged: (e) { + if(e!) { + ConfirmDialog( + title: "Warnung", + icon: Icons.warning_amber, + content: "" + "Die Push-Benachrichtigungen werden durch mhsl.eu versendet.\n\n" + "Durch das aktivieren dieser Funktion wird dein Nutzername, dein Password und eine Geräte-ID von mhsl dauerhaft gespeichert und verarbeitet.\n\n" + "Für mehr Informationen drücke lange auf die Einstellungsoption!", + confirmButton: "Aktivieren", + onConfirm: () { + settings.val(write: true).notificationSettings.enabled = e; + NotifyUpdater.registerToServer(); + }, + ).asDialog(context); + } else { + settings.val(write: true).notificationSettings.enabled = e; + } + }, + ), + onLongPress: () => showDialog(context: context, builder: (context) => AlertDialog( + title: const Text("Info über Push"), + content: const SingleChildScrollView(child: Text("" + "Aufgrund technischer Limitationen müssen Push-nachrichten über einen Externen Server - hier 'mhsl.eu' (Author dieser App) - erfolgen.\n\n" + "Wenn Push aktiviert wird, werden deine Zugangsdaten und ein Token verschlüsselt an den Betreiber gesendet und von ihm unverschlüsselt gespeichert.\n\n" + "Der extene Server verwendet die Zugangsdaten um sich maschinell in Nextcloud Talk anzumelden und via Websockets auf neue Nachrichten zu warten.\n\n" + "Wenn eine neue Nachricht eintrifft wird dein Telefon via FBC-Messaging (Google Firebase Push) vom Externen Server benachrichtigt.\n\n" + "Behalte im Hinterkopf, dass deine Zugangsdaten auf einem Externen Server gespeichert werden und dies trots bester Absichten ein Sicherheitsrisiko sein kann!" + )), + actions: [ + TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text("Zurück")) + ], + )), + ), + + const Divider(), + ListTile( leading: const Icon(Icons.live_help_outlined), title: const Text("Informationen und Lizenzen"), @@ -215,9 +251,7 @@ class _SettingsState extends State { trailing: Checkbox( value: settings.val().devToolsEnabled, onChanged: (state) { - changeView() => setState(() { - settings.val(write: true).devToolsEnabled = state ?? false; - }); + changeView() => settings.val(write: true).devToolsEnabled = state ?? false; if(!state!) { changeView(); @@ -284,9 +318,7 @@ class _SettingsState extends State { content: "Alle Einstellungen gehen verloren! Accountdaten sowie App-Daten sind nicht betroffen.", confirmButton: "Unwiederruflich Löschen", onConfirm: () { - setState(() { - Provider.of(context, listen: false).reset(); - }); + Provider.of(context, listen: false).reset(); }, ).asDialog(context); }, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 9d5f78f..f9e6582 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,6 +7,9 @@ import Foundation import device_info_plus import file_selector_macos +import firebase_core +import firebase_messaging +import flutter_local_notifications import package_info import path_provider_foundation import shared_preferences_foundation @@ -17,6 +20,9 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.yaml b/pubspec.yaml index d124148..ca0a645 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -81,6 +81,11 @@ dependencies: syncfusion_flutter_pdfviewer: ^21.2.8 photo_view: ^0.14.0 uuid: ^3.0.7 + firebase_messaging: ^14.6.5 + firebase_core: ^2.15.0 + firebase_in_app_messaging: ^0.7.3+4 + flutter_local_notifications: ^15.1.0+1 + fluttertoast: ^8.2.2 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 779f0ee..9f7d909 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,12 +7,15 @@ #include "generated_plugin_registrant.h" #include +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("SyncfusionPdfviewerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 3757972..d9d5615 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows + firebase_core syncfusion_pdfviewer_windows url_launcher_windows )