add notification for messages

This commit is contained in:
hihihaha 2023-08-29 14:32:40 +02:00
parent bc4e4e9b5a
commit e280227ee1
9 changed files with 141 additions and 17 deletions

View File

@ -20,7 +20,7 @@ const settingsDB = DatabaseStruct("settings", {
"grade_color4": int, "grade_color5": int, // grade colors "grade_color4": int, "grade_color5": int, // grade colors
"vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int, "vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int,
"notifications": int, "notifications_bitfield": int, "notifications": int, "notifications_bitfield": int,
"notification_poll_interval": int, "notifications_grades":int, "notifications_absences":int, // notifications "notification_poll_interval": int, "notifications_grades":int, "notifications_absences":int, "notifications_messages": int, // notifications
"x_filc_id": String, "graph_class_avg": int, "presentation_mode": int, "x_filc_id": String, "graph_class_avg": int, "presentation_mode": int,
"bell_delay": int, "bell_delay_enabled": int, "bell_delay": int, "bell_delay_enabled": int,
"grade_opening_fun": int, "icon_pack": String, "premium_scopes": String, "grade_opening_fun": int, "icon_pack": String, "premium_scopes": String,

View File

@ -11,8 +11,10 @@ import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/absence.dart'; import 'package:filcnaplo_kreta_api/models/absence.dart';
import 'package:filcnaplo_kreta_api/models/grade.dart'; import 'package:filcnaplo_kreta_api/models/grade.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart' hide Message;
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:filcnaplo_kreta_api/models/message.dart';
class NotificationsHelper { class NotificationsHelper {
late DatabaseProvider database; late DatabaseProvider database;
@ -63,6 +65,7 @@ class NotificationsHelper {
kretaClient.refreshLogin(); kretaClient.refreshLogin();
if(settingsProvider.notificationsGradesEnabled) gradeNotification(); if(settingsProvider.notificationsGradesEnabled) gradeNotification();
if(settingsProvider.notificationsAbsencesEnabled) absenceNotification(); if(settingsProvider.notificationsAbsencesEnabled) absenceNotification();
messageNotification();
} }
} }
@ -133,13 +136,13 @@ class NotificationsHelper {
if(absenceJson == null) { if(absenceJson == null) {
return; return;
} }
// format api absences to correct format while preserving hasSeen value // format api absences to correct format while preserving isSeen value
List<Absence> absences = absenceJson.map((e) { List<Absence> absences = absenceJson.map((e) {
Absence apiAbsence = Absence.fromJson(e); Absence apiAbsence = Absence.fromJson(e);
Absence storedAbsence = storedAbsences.firstWhere( Absence storedAbsence = storedAbsences.firstWhere(
(stored) => stored.id == apiAbsence.id, (stored) => stored.id == apiAbsence.id,
orElse: () => apiAbsence); orElse: () => apiAbsence);
apiAbsence.hasSeen = storedAbsence.hasSeen; apiAbsence.isSeen = storedAbsence.isSeen;
return apiAbsence; return apiAbsence;
}).toList(); }).toList();
List<Absence> modifiedAbsences = []; List<Absence> modifiedAbsences = [];
@ -147,8 +150,8 @@ class NotificationsHelper {
// remove absences that are not new // remove absences that are not new
absences.removeWhere((element) => storedAbsences.contains(element)); absences.removeWhere((element) => storedAbsences.contains(element));
for(Absence absence in absences) { for(Absence absence in absences) {
if(!absence.hasSeen) { if(!absence.isSeen) {
absence.hasSeen = true; absence.isSeen = true;
modifiedAbsences.add(absence); modifiedAbsences.add(absence);
const AndroidNotificationDetails androidNotificationDetails = const AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails('ABSENCES', 'Hiányzások', AndroidNotificationDetails('ABSENCES', 'Hiányzások',
@ -195,4 +198,71 @@ class NotificationsHelper {
); );
await database.userStore.storeAbsences(combinedAbsences, userId: userProvider.id!); await database.userStore.storeAbsences(combinedAbsences, userId: userProvider.id!);
} }
void messageNotification() async {
// get messages from api
List? messageJson = await kretaClient.getAPI(KretaAPI.messages("beerkezett"));
List<Message> storedmessages = await database.userQuery.getMessages(userId: userProvider.id!);
if(messageJson == null) {
return;
}
// format api messages to correct format while preserving isSeen value
// Parse messages
List<Message> messages = [];
await Future.wait(List.generate(messageJson.length, (index) {
return () async {
Map message = messageJson!.cast<Map>()[index];
Map? innerMessageJson = await kretaClient.getAPI(KretaAPI.message(message["azonosito"].toString()));
if (innerMessageJson != null) messages.add(Message.fromJson(innerMessageJson, forceType: MessageType.inbox));
}();
}));
for(Message message in messages) {
for(Message storedMessage in storedmessages) {
if(message.id == storedMessage.id) {
message.isSeen = storedMessage.isSeen;
}
}
}
List<Message> modifiedmessages = [];
if(messages != storedmessages) {
// remove messages that are not new
messages.removeWhere((element) => storedmessages.contains(element));
for(Message message in messages) {
if(!message.isSeen) {
message.isSeen = true;
modifiedmessages.add(message);
const AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails('MESSAGES', 'Üzenetek',
channelDescription: 'Értesítés kapott üzenetekkor',
importance: Importance.max,
priority: Priority.max,
color: const Color(0xFF3D7BF4),
ticker: 'Üzenetek');
const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails);
if(userProvider.getUsers().length == 1) {
await flutterLocalNotificationsPlugin.show(
message.id.hashCode,
message.author,
message.content.replaceAll(RegExp(r'<[^>]*>'), ''),
notificationDetails);
} else {
await flutterLocalNotificationsPlugin.show(
message.id.hashCode,
"(${userProvider.displayName!}) ${message.author}",
message.content.replaceAll(RegExp(r'<[^>]*>'), ''),
notificationDetails);
}
}
}
}
// combine modified messages and storedmessages list and save them to the database
List<Message> combinedmessages = combineLists(
modifiedmessages,
storedmessages,
(Message message) => message.id,
);
await database.userStore.storeMessages(combinedmessages, userId: userProvider.id!);
}
} }

View File

@ -17,7 +17,7 @@ extension Localization on String {
"body_grade_multiuser": "%s tanuló %s-st kapott %s tantárgyból", "body_grade_multiuser": "%s tanuló %s-st kapott %s tantárgyból",
"title_absence": "Új hiányzás", "title_absence": "Új hiányzás",
"body_absence": "Új hiányzást kaptál %s napon %s tantárgyból", "body_absence": "Új hiányzást kaptál %s napon %s tantárgyból",
"body_absence_multiuser": "%s tanuló új hiányzást kapott %s napon %s tantárgyból" "body_absence_multiuser": "%s tanuló új hiányzást kapott %s napon %s tantárgyból",
}, },
"de_de": { "de_de": {
"title_grade": "Neue Note", "title_grade": "Neue Note",
@ -25,7 +25,7 @@ extension Localization on String {
"body_grade_multiuser": "%s hast eine %s in %s", "body_grade_multiuser": "%s hast eine %s in %s",
"title_absence": "Abwesenheit aufgezeichnet", "title_absence": "Abwesenheit aufgezeichnet",
"body_absence": "Auf %s für %s wurde eine Abwesenheit aufgezeichnet", "body_absence": "Auf %s für %s wurde eine Abwesenheit aufgezeichnet",
"body_absence_multiuser": "Für %s wurde am %s für das Thema Mathematik eine Abwesenheit aufgezeichnet" "body_absence_multiuser": "Für %s wurde am %s für das Thema Mathematik eine Abwesenheit aufgezeichnet",
}, },
}; };

View File

@ -33,6 +33,7 @@ class SettingsProvider extends ChangeNotifier {
bool _notificationsEnabled; bool _notificationsEnabled;
bool _notificationsGradesEnabled; bool _notificationsGradesEnabled;
bool _notificationsAbsencesEnabled; bool _notificationsAbsencesEnabled;
bool _notificationsMessagesEnabled;
/* /*
notificationsBitfield values: notificationsBitfield values:
@ -88,6 +89,7 @@ class SettingsProvider extends ChangeNotifier {
required bool notificationsEnabled, required bool notificationsEnabled,
required bool notificationsGradesEnabled, required bool notificationsGradesEnabled,
required bool notificationsAbsencesEnabled, required bool notificationsAbsencesEnabled,
required bool notificationsMessagesEnabled,
required int notificationsBitfield, required int notificationsBitfield,
required bool developerMode, required bool developerMode,
required int notificationPollInterval, required int notificationPollInterval,
@ -128,6 +130,7 @@ class SettingsProvider extends ChangeNotifier {
_notificationsEnabled = notificationsEnabled, _notificationsEnabled = notificationsEnabled,
_notificationsGradesEnabled = notificationsGradesEnabled, _notificationsGradesEnabled = notificationsGradesEnabled,
_notificationsAbsencesEnabled = notificationsAbsencesEnabled, _notificationsAbsencesEnabled = notificationsAbsencesEnabled,
_notificationsMessagesEnabled = notificationsMessagesEnabled,
_notificationsBitfield = notificationsBitfield, _notificationsBitfield = notificationsBitfield,
_developerMode = developerMode, _developerMode = developerMode,
_notificationPollInterval = notificationPollInterval, _notificationPollInterval = notificationPollInterval,
@ -186,6 +189,7 @@ class SettingsProvider extends ChangeNotifier {
notificationsEnabled: map["notifications"] == 1, notificationsEnabled: map["notifications"] == 1,
notificationsGradesEnabled: map["notifications_grades"] == 1, notificationsGradesEnabled: map["notifications_grades"] == 1,
notificationsAbsencesEnabled: map["notifications_absences"] == 1, notificationsAbsencesEnabled: map["notifications_absences"] == 1,
notificationsMessagesEnabled: map["notifications_messages"] == 1,
notificationsBitfield: map["notifications_bitfield"], notificationsBitfield: map["notifications_bitfield"],
notificationPollInterval: map["notification_poll_interval"], notificationPollInterval: map["notification_poll_interval"],
developerMode: map["developer_mode"] == 1, developerMode: map["developer_mode"] == 1,
@ -230,6 +234,7 @@ class SettingsProvider extends ChangeNotifier {
"notifications": _notificationsEnabled ? 1 : 0, "notifications": _notificationsEnabled ? 1 : 0,
"notifications_grades": _notificationsGradesEnabled ? 1 : 0, "notifications_grades": _notificationsGradesEnabled ? 1 : 0,
"notifications_absences": _notificationsAbsencesEnabled ? 1 : 0, "notifications_absences": _notificationsAbsencesEnabled ? 1 : 0,
"notifications_messages": _notificationsMessagesEnabled ? 1 : 0,
"notifications_bitfield": _notificationsBitfield, "notifications_bitfield": _notificationsBitfield,
"developer_mode": _developerMode ? 1 : 0, "developer_mode": _developerMode ? 1 : 0,
"grade_color1": _gradeColors[0].value, "grade_color1": _gradeColors[0].value,
@ -285,6 +290,7 @@ class SettingsProvider extends ChangeNotifier {
notificationsEnabled: true, notificationsEnabled: true,
notificationsGradesEnabled: true, notificationsGradesEnabled: true,
notificationsAbsencesEnabled: true, notificationsAbsencesEnabled: true,
notificationsMessagesEnabled: true,
notificationsBitfield: 255, notificationsBitfield: 255,
developerMode: false, developerMode: false,
notificationPollInterval: 1, notificationPollInterval: 1,
@ -328,6 +334,7 @@ class SettingsProvider extends ChangeNotifier {
bool get notificationsEnabled => _notificationsEnabled; bool get notificationsEnabled => _notificationsEnabled;
bool get notificationsGradesEnabled => _notificationsGradesEnabled; bool get notificationsGradesEnabled => _notificationsGradesEnabled;
bool get notificationsAbsencesEnabled => _notificationsAbsencesEnabled; bool get notificationsAbsencesEnabled => _notificationsAbsencesEnabled;
bool get notificationsMessagesEnabled => _notificationsMessagesEnabled;
int get notificationsBitfield => _notificationsBitfield; int get notificationsBitfield => _notificationsBitfield;
bool get developerMode => _developerMode; bool get developerMode => _developerMode;
int get notificationPollInterval => _notificationPollInterval; int get notificationPollInterval => _notificationPollInterval;
@ -373,6 +380,7 @@ class SettingsProvider extends ChangeNotifier {
bool? notificationsEnabled, bool? notificationsEnabled,
bool? notificationsGradesEnabled, bool? notificationsGradesEnabled,
bool? notificationsAbsencesEnabled, bool? notificationsAbsencesEnabled,
bool? notificationsMessagesEnabled,
int? notificationsBitfield, int? notificationsBitfield,
bool? developerMode, bool? developerMode,
int? notificationPollInterval, int? notificationPollInterval,
@ -432,6 +440,10 @@ class SettingsProvider extends ChangeNotifier {
notificationsAbsencesEnabled != _notificationsAbsencesEnabled) { notificationsAbsencesEnabled != _notificationsAbsencesEnabled) {
_notificationsAbsencesEnabled = notificationsAbsencesEnabled; _notificationsAbsencesEnabled = notificationsAbsencesEnabled;
} }
if (notificationsMessagesEnabled != null &&
notificationsMessagesEnabled != _notificationsMessagesEnabled) {
_notificationsMessagesEnabled = notificationsMessagesEnabled;
}
if (notificationsBitfield != null && if (notificationsBitfield != null &&
notificationsBitfield != _notificationsBitfield) { notificationsBitfield != _notificationsBitfield) {
_notificationsBitfield = notificationsBitfield; _notificationsBitfield = notificationsBitfield;

View File

@ -192,6 +192,7 @@ class GradeValueWidget extends StatelessWidget {
this.outline = false, this.outline = false,
this.complemented = false, this.complemented = false,
this.nocolor = false, this.nocolor = false,
this.color,
}) : super(key: key); }) : super(key: key);
final GradeValue value; final GradeValue value;
@ -202,6 +203,7 @@ class GradeValueWidget extends StatelessWidget {
final bool outline; final bool outline;
final bool complemented; final bool complemented;
final bool nocolor; final bool nocolor;
final Color? color;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -209,7 +211,7 @@ class GradeValueWidget extends StatelessWidget {
bool isSubjectView = SubjectGradesContainer.of(context) != null; bool isSubjectView = SubjectGradesContainer.of(context) != null;
Color color = Color color =
gradeColor(context: context, value: value.value, nocolor: nocolor); this.color ?? gradeColor(context: context, value: value.value, nocolor: nocolor);
Widget valueText; Widget valueText;
final percentage = value.percentage; final percentage = value.percentage;

View File

@ -18,7 +18,7 @@ class Absence {
DateTime lessonEnd; DateTime lessonEnd;
int? lessonIndex; int? lessonIndex;
String group; String group;
bool hasSeen; bool isSeen;
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
@ -43,7 +43,7 @@ class Absence {
this.lessonIndex, this.lessonIndex,
required this.group, required this.group,
this.json, this.json,
this.hasSeen = false, this.isSeen = false,
}); });
factory Absence.fromJson(Map json) { factory Absence.fromJson(Map json) {
@ -89,7 +89,7 @@ class Absence {
lessonIndex: lessonIndex, lessonIndex: lessonIndex,
group: group:
json["OsztalyCsoport"] != null ? json["OsztalyCsoport"]["Uid"] : "", json["OsztalyCsoport"] != null ? json["OsztalyCsoport"]["Uid"] : "",
hasSeen: false, isSeen: false,
json: json, json: json,
); );
} }

View File

@ -16,6 +16,7 @@ class Message {
MessageType? type; MessageType? type;
List<Recipient> recipients; List<Recipient> recipients;
List<Attachment> attachments; List<Attachment> attachments;
bool isSeen;
Message({ Message({
required this.id, required this.id,
@ -32,7 +33,15 @@ class Message {
this.replyId, this.replyId,
this.conversationId, this.conversationId,
this.json, this.json,
this.isSeen = false,
}); });
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Message && runtimeType == other.runtimeType && id == other.id;
@override
int get hashCode => id.hashCode;
factory Message.fromJson(Map json, {MessageType? forceType}) { factory Message.fromJson(Map json, {MessageType? forceType}) {
Map message = json["uzenet"]; Map message = json["uzenet"];
@ -69,6 +78,7 @@ class Message {
replyId: message["elozoUzenetAzonosito"], replyId: message["elozoUzenetAzonosito"],
conversationId: message["beszelgetesAzonosito"], conversationId: message["beszelgetesAzonosito"],
json: json, json: json,
isSeen: false,
); );
} }

View File

@ -74,7 +74,8 @@ class NotificationsScreen extends StatelessWidget {
onChanged: (v) => {settings.update(notificationsGradesEnabled: v)}, onChanged: (v) => {settings.update(notificationsGradesEnabled: v)},
title: Row( title: Row(
children: [ children: [
GradeValueWidget(GradeValue(5, "", "", 100), fill: true, size: 30, nocolor: !settings.notificationsGradesEnabled,), GradeValueWidget(GradeValue(5, "", "", 100), fill: true, size: 30, color: settings.gradeColors[4].withOpacity(
settings.notificationsGradesEnabled ? 1.0 : .5)),
const SizedBox(width: 14.0), const SizedBox(width: 14.0),
Expanded( Expanded(
child: Text( child: Text(
@ -101,7 +102,7 @@ class NotificationsScreen extends StatelessWidget {
: Icon(FeatherIcons.clock, : Icon(FeatherIcons.clock,
color: color:
AppColors.of(context).text.withOpacity(.25)), AppColors.of(context).text.withOpacity(.25)),
const SizedBox(width: 14.0), const SizedBox(width: 23.0),
Expanded( Expanded(
child: Text( child: Text(
"absences".i18n, "absences".i18n,
@ -115,6 +116,32 @@ class NotificationsScreen extends StatelessWidget {
), ),
], ],
), ),
),
SwitchListTile(
value: settings.notificationsMessagesEnabled,
onChanged: (v) => {settings.update(notificationsMessagesEnabled: v)},
title: Row(
children: [
const SizedBox(width: 8),
settings.notificationsMessagesEnabled
? const Icon(FeatherIcons.messageSquare)
: Icon(FeatherIcons.messageSquare,
color:
AppColors.of(context).text.withOpacity(.25)),
const SizedBox(width: 23.0),
Expanded(
child: Text(
"messages".i18n,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16.0,
color: AppColors.of(context).text.withOpacity(
settings.notificationsMessagesEnabled ? 1.0 : .5),
),
),
),
],
),
) )
]), ]),
)))); ))));

View File

@ -6,18 +6,21 @@ extension SettingsLocalization on String {
"en_en": { "en_en": {
"notifications_screen": "Notifications", "notifications_screen": "Notifications",
"grades": "Grades", "grades": "Grades",
"absences": "Absences" "absences": "Absences",
"messages": "Messages",
}, },
"hu_hu": { "hu_hu": {
"notifications_screen": "Értesítések", "notifications_screen": "Értesítések",
"grades": "Jegyek", "grades": "Jegyek",
"absences": "Hiányzások" "absences": "Hiányzások",
"messages": "Üzenetek",
}, },
"de_de": { "de_de": {
"notifications_screen": "Mitteilung", "notifications_screen": "Mitteilung",
"grades": "Noten", "grades": "Noten",
"absences": "Fehlen" "absences": "Fehlen",
"messages": "Nachrichten"
}, },
}; };