Rename everything filcnaplo-related to refilc
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/helpers/storage_helper.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/client.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/attachment.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/homework.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:open_file/open_file.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
extension AttachmentHelper on Attachment {
|
||||
Future<String> download(BuildContext context, {bool overwrite = false}) async {
|
||||
String downloads = await StorageHelper.downloadsPath();
|
||||
|
||||
if (!overwrite && await File("$downloads/$name").exists()) return "$downloads/$name";
|
||||
|
||||
Uint8List data = await Provider.of<KretaClient>(context, listen: false).getAPI(downloadUrl, rawResponse: true);
|
||||
if (!await StorageHelper.write("$downloads/$name", data)) return "";
|
||||
|
||||
return "$downloads/$name";
|
||||
}
|
||||
|
||||
Future<bool> open(BuildContext context) async {
|
||||
String downloads = await StorageHelper.downloadsPath();
|
||||
|
||||
if (!await File("$downloads/$name").exists()) await download(context);
|
||||
var result = await OpenFile.open("$downloads/$name");
|
||||
return result.type == ResultType.done;
|
||||
}
|
||||
}
|
||||
|
||||
extension HomeworkAttachmentHelper on HomeworkAttachment {
|
||||
Future<String> download(BuildContext context, {bool overwrite = false}) async {
|
||||
String downloads = await StorageHelper.downloadsPath();
|
||||
|
||||
if (!overwrite && await File("$downloads/$name").exists()) return "$downloads/$name";
|
||||
|
||||
String url = downloadUrl(Provider.of<UserProvider>(context, listen: false).instituteCode ?? "");
|
||||
Uint8List data = await Provider.of<KretaClient>(context, listen: false).getAPI(url, rawResponse: true);
|
||||
if (!await StorageHelper.write("$downloads/$name", data)) return "";
|
||||
|
||||
return "$downloads/$name";
|
||||
}
|
||||
|
||||
Future<bool> open(BuildContext context) async {
|
||||
String downloads = await StorageHelper.downloadsPath();
|
||||
|
||||
if (!await File("$downloads/$name").exists()) await download(context);
|
||||
var result = await OpenFile.open("$downloads/$name");
|
||||
return result.type == ResultType.done;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
|
||||
class AverageHelper {
|
||||
static double averageEvals(List<Grade> grades, {bool finalAvg = false}) {
|
||||
double average = 0.0;
|
||||
|
||||
List<String> ignoreInFinal = ["5,SzorgalomErtek", "4,MagatartasErtek"];
|
||||
|
||||
if (finalAvg) {
|
||||
grades.removeWhere((e) => (e.value.value == 0) || (ignoreInFinal.contains(e.gradeType?.id)));
|
||||
}
|
||||
|
||||
for (var e in grades) {
|
||||
average += e.value.value * ((finalAvg ? 100 : e.value.weight) / 100);
|
||||
}
|
||||
|
||||
average = average / grades.map((e) => (finalAvg ? 100 : e.value.weight) / 100).fold(0.0, (a, b) => a + b);
|
||||
|
||||
return average.isNaN ? 0.0 : average;
|
||||
}
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
import 'package:filcnaplo/api/providers/database_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/status_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/helpers/notification_helper.i18n.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/api.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/client.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/absence.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/lesson.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart'
|
||||
hide Message;
|
||||
import 'package:i18n_extension/i18n_widget.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/message.dart';
|
||||
|
||||
class NotificationsHelper {
|
||||
late DatabaseProvider database;
|
||||
late SettingsProvider settingsProvider;
|
||||
late UserProvider userProvider;
|
||||
late KretaClient kretaClient;
|
||||
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
List<T> combineLists<T, K>(
|
||||
List<T> list1,
|
||||
List<T> list2,
|
||||
K Function(T) keyExtractor,
|
||||
) {
|
||||
Set<K> uniqueKeys = <K>{};
|
||||
List<T> combinedList = [];
|
||||
|
||||
for (T item in list1) {
|
||||
K key = keyExtractor(item);
|
||||
if (!uniqueKeys.contains(key)) {
|
||||
uniqueKeys.add(key);
|
||||
combinedList.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
for (T item in list2) {
|
||||
K key = keyExtractor(item);
|
||||
if (!uniqueKeys.contains(key)) {
|
||||
uniqueKeys.add(key);
|
||||
combinedList.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return combinedList;
|
||||
}
|
||||
|
||||
String dayTitle(DateTime date) {
|
||||
try {
|
||||
return DateFormat("EEEE", I18n.locale.languageCode).format(date);
|
||||
} catch (e) {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void backgroundJob() async {
|
||||
// initialize providers
|
||||
database = DatabaseProvider();
|
||||
await database.init();
|
||||
settingsProvider = await database.query.getSettings(database);
|
||||
userProvider = await database.query.getUsers(settingsProvider);
|
||||
|
||||
if (userProvider.id != null && settingsProvider.notificationsEnabled) {
|
||||
// refresh kreta login
|
||||
final status = StatusProvider();
|
||||
kretaClient = KretaClient(
|
||||
user: userProvider, settings: settingsProvider, status: status);
|
||||
kretaClient.refreshLogin();
|
||||
if (settingsProvider.notificationsGradesEnabled) gradeNotification();
|
||||
if (settingsProvider.notificationsAbsencesEnabled) absenceNotification();
|
||||
if (settingsProvider.notificationsMessagesEnabled) messageNotification();
|
||||
if (settingsProvider.notificationsLessonsEnabled) lessonNotification();
|
||||
}
|
||||
}
|
||||
|
||||
void gradeNotification() async {
|
||||
// fetch grades
|
||||
GradeProvider gradeProvider = GradeProvider(
|
||||
settings: settingsProvider,
|
||||
user: userProvider,
|
||||
database: database,
|
||||
kreta: kretaClient);
|
||||
gradeProvider.fetch();
|
||||
List<Grade> grades =
|
||||
await database.userQuery.getGrades(userId: userProvider.id ?? "");
|
||||
DateTime lastSeenGrade =
|
||||
await database.userQuery.lastSeenGrade(userId: userProvider.id ?? "");
|
||||
|
||||
// loop through grades and see which hasn't been seen yet
|
||||
for (Grade grade in grades) {
|
||||
// if grade is not a normal grade (1-5), don't show it
|
||||
if ([1, 2, 3, 4, 5].contains(grade.value.value)) {
|
||||
// if the grade was added over a week ago, don't show it to avoid notification spam
|
||||
if (grade.seenDate.isAfter(lastSeenGrade) &&
|
||||
grade.date.difference(DateTime.now()).inDays * -1 < 7) {
|
||||
// send notificiation about new grade
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'GRADES',
|
||||
'Jegyek',
|
||||
channelDescription: 'Értesítés jegyek beírásakor',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
color: settingsProvider.customAccentColor,
|
||||
ticker: 'Jegyek',
|
||||
);
|
||||
NotificationDetails notificationDetails =
|
||||
NotificationDetails(android: androidNotificationDetails);
|
||||
if (userProvider.getUsers().length == 1) {
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
grade.id.hashCode,
|
||||
"title_grade".i18n,
|
||||
"body_grade".i18n.fill(
|
||||
[
|
||||
grade.value.value.toString(),
|
||||
grade.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsEnabled
|
||||
? grade.subject.renamedTo!
|
||||
: grade.subject.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
} else {
|
||||
// multiple users are added, also display student name
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
grade.id.hashCode,
|
||||
"title_grade".i18n,
|
||||
"body_grade_multiuser".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
grade.value.value.toString(),
|
||||
grade.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsEnabled
|
||||
? grade.subject.renamedTo!
|
||||
: grade.subject.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// set grade seen status
|
||||
gradeProvider.seenAll();
|
||||
}
|
||||
|
||||
void absenceNotification() async {
|
||||
// get absences from api
|
||||
List? absenceJson = await kretaClient
|
||||
.getAPI(KretaAPI.absences(userProvider.instituteCode ?? ""));
|
||||
List<Absence> storedAbsences =
|
||||
await database.userQuery.getAbsences(userId: userProvider.id!);
|
||||
if (absenceJson == null) {
|
||||
return;
|
||||
}
|
||||
// format api absences to correct format while preserving isSeen value
|
||||
List<Absence> absences = absenceJson.map((e) {
|
||||
Absence apiAbsence = Absence.fromJson(e);
|
||||
Absence storedAbsence = storedAbsences.firstWhere(
|
||||
(stored) => stored.id == apiAbsence.id,
|
||||
orElse: () => apiAbsence);
|
||||
apiAbsence.isSeen = storedAbsence.isSeen;
|
||||
return apiAbsence;
|
||||
}).toList();
|
||||
List<Absence> modifiedAbsences = [];
|
||||
if (absences != storedAbsences) {
|
||||
// remove absences that are not new
|
||||
absences.removeWhere((element) => storedAbsences.contains(element));
|
||||
for (Absence absence in absences) {
|
||||
if (!absence.isSeen) {
|
||||
absence.isSeen = true;
|
||||
modifiedAbsences.add(absence);
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'ABSENCES',
|
||||
'Hiányzások',
|
||||
channelDescription: 'Értesítés hiányzások beírásakor',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
color: settingsProvider.customAccentColor,
|
||||
ticker: 'Hiányzások',
|
||||
);
|
||||
NotificationDetails notificationDetails =
|
||||
NotificationDetails(android: androidNotificationDetails);
|
||||
if (userProvider.getUsers().length == 1) {
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
absence.id.hashCode,
|
||||
"title_absence".i18n,
|
||||
"body_absence".i18n.fill(
|
||||
[
|
||||
DateFormat("yyyy-MM-dd").format(absence.date),
|
||||
absence.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsEnabled
|
||||
? absence.subject.renamedTo!
|
||||
: absence.subject.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
} else {
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
absence.id.hashCode,
|
||||
"title_absence".i18n,
|
||||
"body_absence_multiuser".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
DateFormat("yyyy-MM-dd").format(absence.date),
|
||||
absence.subject.isRenamed &&
|
||||
settingsProvider.renamedSubjectsEnabled
|
||||
? absence.subject.renamedTo!
|
||||
: absence.subject.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// combine modified absences and storedabsences list and save them to the database
|
||||
List<Absence> combinedAbsences = combineLists(
|
||||
modifiedAbsences,
|
||||
storedAbsences,
|
||||
(Absence absence) => absence.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);
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'MESSAGES',
|
||||
'Üzenetek',
|
||||
channelDescription: 'Értesítés kapott üzenetekkor',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
color: settingsProvider.customAccentColor,
|
||||
ticker: 'Üzenetek',
|
||||
);
|
||||
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!);
|
||||
}
|
||||
|
||||
void lessonNotification() async {
|
||||
// get lesson from api
|
||||
TimetableProvider timetableProvider = TimetableProvider(
|
||||
user: userProvider, database: database, kreta: kretaClient);
|
||||
List<Lesson> storedlessons =
|
||||
timetableProvider.lessons[Week.current()] ?? [];
|
||||
List? apilessons = timetableProvider.getWeek(Week.current()) ?? [];
|
||||
for (Lesson lesson in apilessons) {
|
||||
for (Lesson storedLesson in storedlessons) {
|
||||
if (lesson.id == storedLesson.id) {
|
||||
lesson.isSeen = storedLesson.isSeen;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Lesson> modifiedlessons = [];
|
||||
if (apilessons != storedlessons) {
|
||||
// remove lessons that are not new
|
||||
apilessons.removeWhere((element) => storedlessons.contains(element));
|
||||
for (Lesson lesson in apilessons) {
|
||||
if (!lesson.isSeen && lesson.isChanged) {
|
||||
lesson.isSeen = true;
|
||||
modifiedlessons.add(lesson);
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'LESSONS',
|
||||
'Órák',
|
||||
channelDescription:
|
||||
'Értesítés órák elmaradásáról, helyettesítésről',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
color: settingsProvider.customAccentColor,
|
||||
ticker: 'Órák',
|
||||
);
|
||||
NotificationDetails notificationDetails =
|
||||
NotificationDetails(android: androidNotificationDetails);
|
||||
if (userProvider.getUsers().length == 1) {
|
||||
if (lesson.status?.name == "Elmaradt") {
|
||||
switch (I18n.localeStr) {
|
||||
case "en_en":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_canceled".i18n.fill(
|
||||
[
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date)
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "hu_hu":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_canceled".i18n.fill(
|
||||
[
|
||||
dayTitle(lesson.date),
|
||||
lesson.lessonIndex,
|
||||
lesson.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_canceled".i18n.fill(
|
||||
[
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date)
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (lesson.substituteTeacher?.name != "") {
|
||||
switch (I18n.localeStr) {
|
||||
case "en_en":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_substituted".i18n.fill(
|
||||
[
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date),
|
||||
lesson.substituteTeacher!.isRenamed
|
||||
? lesson.substituteTeacher!.renamedTo!
|
||||
: lesson.substituteTeacher!.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "hu_hu":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_substituted".i18n.fill(
|
||||
[
|
||||
dayTitle(lesson.date),
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
lesson.substituteTeacher!.isRenamed
|
||||
? lesson.substituteTeacher!.renamedTo!
|
||||
: lesson.substituteTeacher!.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_substituted".i18n.fill(
|
||||
[
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date),
|
||||
lesson.substituteTeacher!.isRenamed
|
||||
? lesson.substituteTeacher!.renamedTo!
|
||||
: lesson.substituteTeacher!.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lesson.status?.name == "Elmaradt") {
|
||||
switch (I18n.localeStr) {
|
||||
case "en_en":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_canceled".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date)
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "hu_hu":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_canceled".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
dayTitle(lesson.date),
|
||||
lesson.lessonIndex,
|
||||
lesson.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_canceled".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date)
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (lesson.substituteTeacher?.name != "") {
|
||||
switch (I18n.localeStr) {
|
||||
case "en_en":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_substituted".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date),
|
||||
lesson.substituteTeacher!.isRenamed
|
||||
? lesson.substituteTeacher!.renamedTo!
|
||||
: lesson.substituteTeacher!.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "hu_hu":
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_substituted".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
dayTitle(lesson.date),
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
lesson.substituteTeacher!.isRenamed
|
||||
? lesson.substituteTeacher!.renamedTo!
|
||||
: lesson.substituteTeacher!.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
lesson.id.hashCode,
|
||||
"title_lesson".i18n,
|
||||
"body_lesson_substituted".i18n.fill(
|
||||
[
|
||||
userProvider.displayName!,
|
||||
lesson.lessonIndex,
|
||||
lesson.name,
|
||||
dayTitle(lesson.date),
|
||||
lesson.substituteTeacher!.isRenamed
|
||||
? lesson.substituteTeacher!.renamedTo!
|
||||
: lesson.substituteTeacher!.name
|
||||
],
|
||||
),
|
||||
notificationDetails,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// combine modified lesson and storedlesson list and save them to the database
|
||||
List<Lesson> combinedlessons = combineLists(
|
||||
modifiedlessons,
|
||||
storedlessons,
|
||||
(Lesson message) => message.id,
|
||||
);
|
||||
Map<Week, List<Lesson>> timetableLessons = timetableProvider.lessons;
|
||||
timetableLessons[Week.current()] = combinedlessons;
|
||||
await database.userStore
|
||||
.storeLessons(timetableLessons, userId: userProvider.id!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import 'package:i18n_extension/i18n_extension.dart';
|
||||
|
||||
extension Localization on String {
|
||||
static final _t = Translations.byLocale("hu_hu") +
|
||||
{
|
||||
"en_en": {
|
||||
"title_grade": "New grade",
|
||||
"body_grade": "You got a %s in %s",
|
||||
"body_grade_multiuser": "%s got a %s in %s",
|
||||
"title_absence": "Absence recorded",
|
||||
"body_absence": "An absence was recorded on %s for %s",
|
||||
"body_absence_multiuser": "An absence was recorded for %s on %s for the subject %s",
|
||||
"title_lesson": "Timetable modified",
|
||||
"body_lesson_canceled": "Lesson #%s (%s) has been canceled on %s",
|
||||
"body_lesson_canceled_multiuser": "(%s) Lesson #%s (%s) has been canceled on %s",
|
||||
"body_lesson_substituted": "Lesson #%s (%s) on %s will be substituted by %s",
|
||||
"body_lesson_substituted_multiuser": "(%s) Lesson #%s (%s) on %s will be substituted by %s"
|
||||
},
|
||||
"hu_hu": {
|
||||
"title_grade": "Új jegy",
|
||||
"body_grade": "%s-st kaptál %s tantárgyból",
|
||||
"body_grade_multiuser": "%s tanuló %s-st kapott %s tantárgyból",
|
||||
"title_absence": "Új hiányzás",
|
||||
"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",
|
||||
"title_lesson": "Órarend szerkesztve",
|
||||
"body_lesson_canceled": "%s-i %s. óra (%s) elmarad",
|
||||
"body_lesson_canceled_multiuser": "(%s) %s-i %s. óra (%s) elmarad",
|
||||
"body_lesson_substituted": "%s-i %s. (%s) órát %s helyettesíti",
|
||||
"body_lesson_substituted_multiuser": "(%s) %s-i %s. (%s) órát %s helyettesíti"
|
||||
},
|
||||
"de_de": {
|
||||
"title_grade": "Neue Note",
|
||||
"body_grade": "Du hast eine %s in %s",
|
||||
"body_grade_multiuser": "%s hast eine %s in %s",
|
||||
"title_absence": "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",
|
||||
"title_lesson": "Fahrplan geändert",
|
||||
"body_lesson_canceled": "Lektion Nr. %s (%s) wurde am %s abgesagt",
|
||||
"body_lesson_canceled_multiuser": "(%s) Lektion Nr. %s (%s) wurde am %s abgesagt",
|
||||
"body_lesson_substituted": "Lektion Nr. %s (%s) wird am %s durch %s ersetzt",
|
||||
"body_lesson_substituted_multiuser": "(%s) Lektion Nr. %s (%s) wird am %s durch %s ersetzt"
|
||||
},
|
||||
};
|
||||
|
||||
String get i18n => localize(this, _t);
|
||||
String fill(List<Object> params) => localizeFill(this, params);
|
||||
String plural(int value) => localizePlural(value, this, _t);
|
||||
String version(Object modifier) => localizeVersion(modifier, this, _t);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:quick_actions/quick_actions.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/screens.i18n.dart';
|
||||
|
||||
const QuickActions quickActions = QuickActions();
|
||||
|
||||
void setupQuickActions() {
|
||||
quickActions.setShortcutItems(<ShortcutItem>[
|
||||
ShortcutItem(type: 'action_grades', localizedTitle: 'grades'.i18n, icon: 'ic_grades'),
|
||||
ShortcutItem(type: 'action_timetable', localizedTitle: 'timetable'.i18n, icon: 'ic_timetable'),
|
||||
ShortcutItem(type: 'action_messages', localizedTitle: 'messages'.i18n, icon: 'ic_messages'),
|
||||
ShortcutItem(type: 'action_absences', localizedTitle: 'absences'.i18n, icon: 'ic_absences')
|
||||
]);
|
||||
}
|
||||
|
||||
void handleQuickActions(BuildContext context, void Function(String) callback) {
|
||||
quickActions.initialize((shortcutType) {
|
||||
switch (shortcutType) {
|
||||
case 'action_home':
|
||||
callback("home");
|
||||
break;
|
||||
case 'action_grades':
|
||||
callback("grades");
|
||||
break;
|
||||
case 'action_timetable':
|
||||
callback("timetable");
|
||||
break;
|
||||
case 'action_messages':
|
||||
callback("messages");
|
||||
break;
|
||||
case 'action_absences':
|
||||
callback("absences");
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:filcnaplo/helpers/attachment_helper.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/attachment.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class ShareHelper {
|
||||
static Future<void> shareText(String text, {String? subject}) => Share.share(text, subject: subject);
|
||||
// ignore: deprecated_member_use
|
||||
static Future<void> shareFile(String path, {String? text, String? subject}) => Share.shareFiles([path], text: text, subject: subject);
|
||||
|
||||
static Future<void> shareAttachment(Attachment attachment, {required BuildContext context}) async {
|
||||
String path = await attachment.download(context);
|
||||
await shareFile(path);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class StorageHelper {
|
||||
static Future<bool> write(String path, Uint8List data) async {
|
||||
try {
|
||||
if (await Permission.manageExternalStorage.request().isGranted) {
|
||||
await File(path).writeAsBytes(data);
|
||||
return true;
|
||||
} else {
|
||||
if (await Permission.storage.isPermanentlyDenied) {
|
||||
openAppSettings();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
print("ERROR: StorageHelper.write: $error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<String> downloadsPath() async {
|
||||
String downloads;
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
downloads = "/storage/self/primary/Download";
|
||||
} else {
|
||||
downloads = (await getTemporaryDirectory()).path;
|
||||
}
|
||||
|
||||
return downloads;
|
||||
// return (await getTemporaryDirectory()).path;
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
import 'package:filcnaplo/icons/filc_icons.dart';
|
||||
import 'package:filcnaplo/models/icon_pack.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/utils/format.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/subject.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
typedef SubjectIconVariants = Map<IconPack, IconData>;
|
||||
|
||||
class SubjectIconData {
|
||||
final SubjectIconVariants data;
|
||||
final String name; // for iOS live activities compatibilty
|
||||
|
||||
SubjectIconData({
|
||||
this.data = const {
|
||||
IconPack.material: Icons.widgets_outlined,
|
||||
IconPack.cupertino: CupertinoIcons.rectangle_grid_2x2,
|
||||
},
|
||||
this.name = "square.grid.2x2",
|
||||
});
|
||||
}
|
||||
|
||||
SubjectIconVariants createIcon({required IconData material, required IconData cupertino}) {
|
||||
return {
|
||||
IconPack.material: material,
|
||||
IconPack.cupertino: cupertino,
|
||||
};
|
||||
}
|
||||
|
||||
class SubjectIcon {
|
||||
static String resolveName({Subject? subject, String? subjectName}) => _resolve(subject: subject, subjectName: subjectName).name;
|
||||
static IconData resolveVariant({Subject? subject, String? subjectName, required BuildContext context}) =>
|
||||
_resolve(subject: subject, subjectName: subjectName).data[Provider.of<SettingsProvider>(context, listen: false).iconPack]!;
|
||||
|
||||
static SubjectIconData _resolve({Subject? subject, String? subjectName}) {
|
||||
assert(!(subject == null && subjectName == null));
|
||||
|
||||
String name = (subject?.name ?? subjectName ?? "").toLowerCase().specialChars().trim();
|
||||
String category = subject?.category.description.toLowerCase().specialChars() ?? "";
|
||||
|
||||
// todo: check for categories
|
||||
if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.function, material: Icons.calculate_outlined), name: "function");
|
||||
} else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.textformat_alt, material: Icons.spellcheck_outlined), name: "textformat.alt");
|
||||
} else if (RegExp("irodalom").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.book, material: Icons.menu_book_outlined), name: "book");
|
||||
} else if (RegExp("tor(i|tenelem)").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.compass, material: Icons.hourglass_empty_outlined), name: "safari");
|
||||
} else if (RegExp("foldrajz").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.map, material: Icons.public_outlined), name: "map");
|
||||
} else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.paintbrush, material: Icons.palette_outlined), name: "paintbrush");
|
||||
} else if (RegExp("fizika").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.lightbulb, material: Icons.emoji_objects_outlined), name: "lightbulb");
|
||||
} else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.music_note, material: Icons.music_note_outlined), name: "music.note");
|
||||
} else if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.sportscourt, material: Icons.sports_soccer_outlined), name: "sportscourt");
|
||||
} else if (RegExp("kemia").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.lab_flask, material: Icons.science_outlined), name: "testtube.2");
|
||||
} else if (RegExp("biologia").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.paw, material: Icons.pets_outlined), name: "pawprint");
|
||||
} else if (RegExp("kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret").hasMatch(name)) {
|
||||
return SubjectIconData(
|
||||
data: createIcon(cupertino: CupertinoIcons.arrow_3_trianglepath, material: Icons.eco_outlined), name: "arrow.3.trianglepath");
|
||||
} else if (RegExp("(hit|erkolcs)tan|vallas|etika").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.heart, material: Icons.favorite_border_outlined), name: "heart");
|
||||
} else if (RegExp("penzugy").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.money_dollar, material: Icons.savings_outlined), name: "dollarsign");
|
||||
} else if (RegExp("informatika|szoftver|iroda|digitalis").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.device_laptop, material: Icons.computer_outlined), name: "laptopcomputer");
|
||||
} else if (RegExp("prog").hasMatch(name)) {
|
||||
return SubjectIconData(
|
||||
data: createIcon(cupertino: CupertinoIcons.chevron_left_slash_chevron_right, material: Icons.code_outlined),
|
||||
name: "chevron.left.forwardslash.chevron.right");
|
||||
} else if (RegExp("halozat").hasMatch(name)) {
|
||||
return SubjectIconData(
|
||||
data: createIcon(cupertino: CupertinoIcons.antenna_radiowaves_left_right, material: Icons.wifi_tethering_outlined),
|
||||
name: "antenna.radiowaves.left.and.right");
|
||||
} else if (RegExp("szinhaz").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.hifispeaker, material: Icons.theater_comedy_outlined), name: "hifispeaker");
|
||||
} else if (RegExp("film|media").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.film, material: Icons.theaters_outlined), name: "film");
|
||||
} else if (RegExp("elektro(tech)?nika").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.bolt, material: Icons.electrical_services_outlined), name: "bolt");
|
||||
} else if (RegExp("gepesz|mernok|ipar").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.wrench, material: Icons.precision_manufacturing_outlined), name: "wrench");
|
||||
} else if (RegExp("technika").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.hammer, material: Icons.build_outlined), name: "hammer");
|
||||
} else if (RegExp("tanc").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.music_mic, material: Icons.speaker_outlined), name: "music.mic");
|
||||
} else if (RegExp("filozofia").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.bubble_left, material: Icons.psychology_outlined), name: "bubble.left");
|
||||
} else if (RegExp("osztaly(fonoki|kozosseg)").hasMatch(name) || name == "ofo") {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.group, material: Icons.groups_outlined), name: "person.3");
|
||||
} else if (RegExp("gazdasag").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.chart_pie, material: Icons.account_balance_outlined), name: "chart.pie");
|
||||
} else if (RegExp("szorgalom").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.checkmark_seal, material: Icons.verified_outlined), name: "checkmark.seal");
|
||||
} else if (RegExp("magatartas").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.smiley, material: Icons.emoji_people_outlined), name: "face.smiling");
|
||||
} else if (RegExp("angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.globe, material: Icons.translate_outlined), name: "globe");
|
||||
} else if (RegExp("linux").hasMatch(name)) {
|
||||
return SubjectIconData(data: createIcon(material: FilcIcons.linux, cupertino: FilcIcons.linux));
|
||||
}
|
||||
|
||||
return SubjectIconData();
|
||||
}
|
||||
}
|
||||
|
||||
class ShortSubject {
|
||||
static String resolve({Subject? subject, String? subjectName}) {
|
||||
assert(!(subject == null && subjectName == null));
|
||||
|
||||
String name = (subject?.name ?? subjectName ?? "").toLowerCase().specialChars().trim();
|
||||
// String category = subject?.category.description.toLowerCase().specialChars() ?? "";
|
||||
|
||||
if (RegExp("magyar irodalom").hasMatch(name)) {
|
||||
return "Irodalom";
|
||||
} else if (RegExp("magyar nyelv").hasMatch(name)) {
|
||||
return "Nyelvtan";
|
||||
} else if (RegExp("matematika").hasMatch(name)) {
|
||||
return "Matek";
|
||||
} else if (RegExp("digitalis kultura").hasMatch(name)) {
|
||||
return "Dig. kult.";
|
||||
} else if (RegExp("testneveles").hasMatch(name)) {
|
||||
return "Tesi";
|
||||
} else if (RegExp("tortenelem").hasMatch(name)) {
|
||||
return "Töri";
|
||||
} else if (RegExp("(angol|nemet|francia|olasz|orosz|spanyol|latin|kinai) nyelv").hasMatch(name)) {
|
||||
return (subject?.name ?? subjectName ?? "?").replaceAll(" nyelv", "");
|
||||
} else if (RegExp("informatika").hasMatch(name)) {
|
||||
return "Infó";
|
||||
} else if (RegExp("osztalyfonoki").hasMatch(name)) {
|
||||
return "Ofő";
|
||||
}
|
||||
|
||||
return subject?.name.capital() ?? subjectName?.capital() ?? "?";
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:filcnaplo/api/client.dart';
|
||||
import 'package:filcnaplo/helpers/storage_helper.dart';
|
||||
import 'package:filcnaplo/models/release.dart';
|
||||
import 'package:open_file/open_file.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
enum UpdateState { none, preparing, downloading, installing }
|
||||
|
||||
typedef UpdateCallback = Function(double progress, UpdateState state);
|
||||
|
||||
// ignore: todo
|
||||
// TODO: cleanup old apk files
|
||||
|
||||
extension UpdateHelper on Release {
|
||||
Future<void> install({UpdateCallback? updateCallback}) async {
|
||||
updateCallback!(-1, UpdateState.preparing);
|
||||
|
||||
String downloads = await StorageHelper.downloadsPath();
|
||||
File apk = File("$downloads/refilc-v$version.apk");
|
||||
|
||||
if (!await apk.exists()) {
|
||||
updateCallback(-1, UpdateState.downloading);
|
||||
|
||||
var bytes = await download(updateCallback: updateCallback);
|
||||
if (!await StorageHelper.write(apk.path, bytes)) {
|
||||
throw "failed to write apk: permission denied";
|
||||
}
|
||||
}
|
||||
|
||||
updateCallback(-1, UpdateState.installing);
|
||||
|
||||
var installPerms =
|
||||
(await Permission.manageExternalStorage.request().isGranted &&
|
||||
await Permission.requestInstallPackages.request().isGranted);
|
||||
if (installPerms) {
|
||||
var result = await OpenFile.open(apk.path);
|
||||
|
||||
if (result.type != ResultType.done) {
|
||||
// ignore: avoid_print
|
||||
print("ERROR: installUpdate.openFile: ${result.message}");
|
||||
throw result.message;
|
||||
}
|
||||
}
|
||||
|
||||
updateCallback(-1, UpdateState.none);
|
||||
}
|
||||
|
||||
Future<Uint8List> download({UpdateCallback? updateCallback}) async {
|
||||
var response = await FilcAPI.downloadRelease(downloads.first);
|
||||
|
||||
List<List<int>> chunks = [];
|
||||
int downloaded = 0;
|
||||
|
||||
var completer = Completer<Uint8List>();
|
||||
|
||||
response?.stream.listen((List<int> chunk) {
|
||||
updateCallback!(
|
||||
downloaded / (response.contentLength ?? 0), UpdateState.downloading);
|
||||
|
||||
chunks.add(chunk);
|
||||
downloaded += chunk.length;
|
||||
}, onDone: () {
|
||||
// Save the file
|
||||
final Uint8List bytes = Uint8List(response.contentLength ?? 0);
|
||||
int offset = 0;
|
||||
for (List<int> chunk in chunks) {
|
||||
bytes.setRange(offset, offset + chunk.length, chunk);
|
||||
offset += chunk.length;
|
||||
}
|
||||
|
||||
completer.complete(bytes);
|
||||
});
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user