Working push-Notifications for Android

This commit is contained in:
2023-09-03 19:18:14 +02:00
parent 376472ab53
commit cbf049f6cd
23 changed files with 329 additions and 239 deletions

View File

@ -161,7 +161,7 @@ class _FileElementState extends State<FileElement> {
content: "Das Element wird unwiederruflich gelöscht.",
onConfirm: () {
WebdavApi.webdav
.then((value) => value.delete(widget.file.path))
.then((value) => value.delete(Uri.parse(widget.file.path)))
.then((value) => widget.refetch());
}
));

View File

@ -43,7 +43,7 @@ class _FileUploadDialogState extends State<FileUploadDialog> {
setState(() {
state = FileUploadState.checkConflict;
});
List<WebDavResponse> result = (await webdavClient.propfind(widget.remotePath.join("/"))).responses;
List<WebDavResponse> result = (await webdavClient.propfind(Uri.parse(widget.remotePath.join("/")))).responses;
if(result.any((element) => element.href!.endsWith("/$targetFileName"))) {
setState(() {
state = FileUploadState.conflict;
@ -56,7 +56,7 @@ class _FileUploadDialogState extends State<FileUploadDialog> {
}
}
Future<HttpClientResponse> uploadTask = webdavClient.putFile(File(widget.localPath), FileStat.statSync(widget.localPath), fullRemotePath); // TODO use onProgress from putFile
Future<HttpClientResponse> uploadTask = webdavClient.putFile(File(widget.localPath), FileStat.statSync(widget.localPath), Uri.parse(fullRemotePath)); // TODO use onProgress from putFile
uploadTask.then((value) => Future<HttpClientResponse?>.value(value)).catchError((e) {
setState(() {
state = FileUploadState.error;

View File

@ -189,7 +189,7 @@ class _FilesState extends State<Files> {
}, child: const Text("Abbrechen")),
TextButton(onPressed: () {
WebdavApi.webdav.then((webdav) {
webdav.mkcol("${widget.path.join("/")}/${inputController.text}").then((value) => _query());
webdav.mkcol(Uri.parse("${widget.path.join("/")}/${inputController.text}")).then((value) => _query());
});
Navigator.of(context).pop();
}, child: const Text("Ordner erstellen")),

View File

@ -147,7 +147,7 @@ class _HolidaysState extends State<Holidays> {
subtitle: Text(Jiffy.parse(holiday.start).fromNow()),
),
),
DebugTile(holiday.toJson()).asTile(context),
DebugTile(context).jsonData(holiday.toJson()),
],
)),
trailing: const Icon(Icons.arrow_right),

View File

@ -1,8 +1,17 @@
import 'dart:convert';
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import 'package:fast_rsa/fast_rsa.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
import '../../../model/endpointData.dart';
import '../../../widget/ListItem.dart';
import '../../../widget/debug/debugTile.dart';
import '../../settings/settings.dart';
import 'gradeAverages/gradeAverage.dart';
import 'holidays/holidays.dart';
@ -22,11 +31,46 @@ class Overhang extends StatelessWidget {
],
),
body: ListView(
children: const [
ListItemNavigator(icon: Icons.newspaper, text: "Marianum Message", target: Message()),
ListItemNavigator(icon: Icons.room, text: "Raumplan", target: Roomplan()),
ListItemNavigator(icon: Icons.calculate, text: "Notendurschnittsrechner", target: GradeAverage()),
ListItemNavigator(icon: Icons.calendar_month, text: "Schulferien", target: Holidays()),
children: [
const ListItemNavigator(icon: Icons.newspaper, text: "Marianum Message", target: Message()),
const ListItemNavigator(icon: Icons.room, text: "Raumplan", target: Roomplan()),
const ListItemNavigator(icon: Icons.calculate, text: "Notendurschnittsrechner", target: GradeAverage()),
const ListItemNavigator(icon: Icons.calendar_month, text: "Schulferien", target: Holidays()),
DebugTile(context, onlyInDebug: true).callback(onTab: () async {
log("Starting");
log("Generate keys");
final rsaKey = await RSA.generate(2048);
final devicePrivateKey = rsaKey.privateKey.toString();
final devicePublicKey = rsaKey.publicKey.toString();
log("Private: \n$devicePrivateKey");
log("Public: \n$devicePublicKey");
final pushToken = await FirebaseMessaging.instance.getToken();
log("PushToken: $pushToken}");
final pushTokenHash = sha512.convert(utf8.encode(pushToken!));
log("PushTokenHash: $pushTokenHash");
final requestMap = {
"format": "json",
"pushTokenHash": pushTokenHash.toString(),
"devicePublicKey": devicePublicKey.toString(),
"proxyServer": "https://push-notifications.nextcloud.com/devices"
};
log(jsonEncode(requestMap));
http.post(
//${AccountData().buildHttpAuthString()}@
Uri.parse("https://${EndpointData().nextcloud().full()}/ocs/v2.php/apps/notifications/api/v2/push"),
headers: {
"OCS-APIRequest": "true",
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer Fv3g7g9jW91FXNjZLaJmyprClfy8pX1jEM3hJGbXjPEFcx4oGIEVcpwEnuT4mPs39D9xT063"
},
body: jsonEncode(requestMap),
).then((response) {
log("Response: ${response.statusCode}\n${response.body}");
});
}),
],
),
);

View File

@ -255,7 +255,7 @@ class _ChatBubbleState extends State<ChatBubble> {
},
),
),
DebugTile(widget.bubbleData.toJson()).asTile(context),
DebugTile(context).jsonData(widget.bubbleData.toJson()),
],
);
});

View File

@ -41,7 +41,7 @@ class _ChatTextfieldState extends State<ChatTextfield> {
String filename = "${path.split("/").last.split(".").first}-${const Uuid().v4()}.${path.split(".").last}";
String shareFolder = "MarianumMobile";
WebdavApi.webdav.then((webdav) {
webdav.mkcol("/$shareFolder");
webdav.mkcol(Uri.parse("/$shareFolder"));
});
showDialog(context: context, builder: (context) => FileUploadDialog(

View File

@ -172,7 +172,7 @@ class _ChatTileState extends State<ChatTile> {
).asDialog(context);
},
),
DebugTile(widget.data.toJson()).asTile(context),
DebugTile(context).jsonData(widget.data.toJson()),
],
));
},

View File

@ -92,7 +92,7 @@ class AppointmentDetails {
leading: const Icon(Icons.people),
title: Text("Klasse(n): ${timetableData.kl.map((e) => e.name).join(", ")}"),
),
DebugTile(timetableData.toJson()).asTile(context),
DebugTile(context).jsonData(timetableData.toJson()),
],
),
)

View File

@ -1,4 +1,6 @@
import 'dart:io';
import 'package:filesize/filesize.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -145,45 +147,48 @@ class _SettingsState extends State<Settings> {
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!"
Visibility(
visible: Platform.isAndroid,
child: 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"))
],
)),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text("Zurück"))
],
)),
),
),
const Divider(),