diff --git a/.idea/naplo.iml b/.idea/naplo.iml index d6ebd480..ab2f4821 100644 --- a/.idea/naplo.iml +++ b/.idea/naplo.iml @@ -2,7 +2,65 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_notification.png b/filcnaplo/android/app/src/main/res/drawable/ic_notification.png new file mode 100644 index 00000000..67fd3709 Binary files /dev/null and b/filcnaplo/android/app/src/main/res/drawable/ic_notification.png differ diff --git a/filcnaplo/lib/helpers/notification_helper.dart b/filcnaplo/lib/helpers/notification_helper.dart new file mode 100644 index 00000000..a281b17a --- /dev/null +++ b/filcnaplo/lib/helpers/notification_helper.dart @@ -0,0 +1,59 @@ +import 'dart:math'; +import 'dart:ui'; + +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/database/init.dart'; +import 'package:filcnaplo/models/settings.dart'; +import 'package:filcnaplo/helpers/notification_helper.i18n.dart'; +import 'package:filcnaplo/theme/colors/accent.dart'; +import 'package:filcnaplo_kreta_api/client/client.dart'; +import 'package:filcnaplo_kreta_api/models/category.dart'; +import 'package:filcnaplo_kreta_api/models/grade.dart'; +import 'package:filcnaplo_kreta_api/models/subject.dart'; +import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +class NotificationsHelper { + void backgroundJob() async { + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + DatabaseProvider database = DatabaseProvider(); + var db = await initDB(database); + await database.init(); + SettingsProvider settingsProvider = + await database.query.getSettings(database); + UserProvider userProvider = await database.query.getUsers(settingsProvider); + final status = StatusProvider(); + final kretaClient = KretaClient( + user: userProvider, settings: settingsProvider, status: status); + kretaClient.refreshLogin(); + GradeProvider gradeProvider = GradeProvider( + settings: settingsProvider, + user: userProvider, + database: database, + kreta: kretaClient); + gradeProvider.fetch(); + List grades = + await database.userQuery.getGrades(userId: userProvider.id ?? ""); + DateTime lastSeenGrade = + await database.userQuery.lastSeenGrade(userId: userProvider.id ?? ""); + for (Grade grade in grades) { + if (grade.seenDate.isAfter(lastSeenGrade)) { + const AndroidNotificationDetails androidNotificationDetails = + AndroidNotificationDetails('GRADES', 'Jegyek', + channelDescription: 'Értesítés jegyek beírásakor', + importance: Importance.max, + priority: Priority.max, + color: const Color(0xFF3D7BF4), + ticker: 'ticker'); + const NotificationDetails notificationDetails = + NotificationDetails(android: androidNotificationDetails); + await flutterLocalNotificationsPlugin.show( + Random().nextInt(432234*2), "title".i18n, "body".i18n.fill([grade.value.value.toString(), grade.subject.name.toString()]), notificationDetails); + + } + } + } +} diff --git a/filcnaplo/lib/helpers/notification_helper.i18n.dart b/filcnaplo/lib/helpers/notification_helper.i18n.dart new file mode 100644 index 00000000..5c964882 --- /dev/null +++ b/filcnaplo/lib/helpers/notification_helper.i18n.dart @@ -0,0 +1,24 @@ +import 'package:i18n_extension/i18n_extension.dart'; + +extension Localization on String { + static final _t = Translations.byLocale("hu_hu") + + { + "en_en": { + "title": "New grade", + "body": "You got a %s in %s" + }, + "hu_hu": { + "title": "Új jegy", + "body": "%s-st kaptál %s tantárgyból" + }, + "de_de": { + "title": "Neue Note", + "body": "Du hast eine %s in %s" + }, + }; + + String get i18n => localize(this, _t); + String fill(List params) => localizeFill(this, params); + String plural(int value) => localizePlural(value, this, _t); + String version(Object modifier) => localizeVersion(modifier, this, _t); +} diff --git a/filcnaplo/lib/main.dart b/filcnaplo/lib/main.dart index 70323131..bd87738a 100644 --- a/filcnaplo/lib/main.dart +++ b/filcnaplo/lib/main.dart @@ -2,13 +2,16 @@ import 'package:background_fetch/background_fetch.dart'; import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/database/init.dart'; +import 'package:filcnaplo/helpers/notification_helper.dart'; import 'package:filcnaplo/models/settings.dart'; +import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:filcnaplo/app.dart'; import 'package:flutter/services.dart'; import 'package:filcnaplo_mobile_ui/screens/error_screen.dart'; import 'package:filcnaplo_mobile_ui/screens/error_report_screen.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; void main() async { // Initalize @@ -43,6 +46,53 @@ class Startup { await database.init(); settings = await database.query.getSettings(database); user = await database.query.getUsers(settings); + + // Notifications setup + initPlatformState(); + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + + // Get permission to show notifications + flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>()! + .requestPermission(); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + IOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions( + alert: false, + badge: true, + sound: true, + ); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + MacOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions( + alert: false, + badge: true, + sound: true, + ); + + // Platform specific settings + final DarwinInitializationSettings initializationSettingsDarwin = + DarwinInitializationSettings( + requestSoundPermission: true, + requestBadgePermission: true, + requestAlertPermission: false, + ); + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('ic_notification'); + final InitializationSettings initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsDarwin, + macOS: initializationSettingsDarwin + ); + + // Initialize notifications + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + ); } } @@ -71,9 +121,38 @@ Widget errorBuilder(FlutterErrorDetails details) { return Container(); }); } +// Platform messages are asynchronous, so we initialize in an async method. + Future initPlatformState() async { + // Configure BackgroundFetch. + int status = await BackgroundFetch.configure(BackgroundFetchConfig( + minimumFetchInterval: 15, + stopOnTerminate: false, + enableHeadless: true, + requiresBatteryNotLow: false, + requiresCharging: false, + requiresStorageNotLow: false, + requiresDeviceIdle: false, + requiredNetworkType: NetworkType.ANY + ), (String taskId) async { // <-- Event handler + // This is the fetch-event callback. + print("[BackgroundFetch] Event received $taskId"); + NotificationsHelper().backgroundJob(); + + // IMPORTANT: You must signal completion of your task or the OS can punish your app + // for taking too long in the background. + BackgroundFetch.finish(taskId); + }, (String taskId) async { // <-- Task timeout handler. + // This task has exceeded its allowed running-time. You must stop what you're doing and immediately .finish(taskId) + print("[BackgroundFetch] TASK TIMEOUT taskId: $taskId"); + BackgroundFetch.finish(taskId); + }); + print('[BackgroundFetch] configure success: $status'); + + } @pragma('vm:entry-point') void backgroundHeadlessTask(HeadlessTask task) { print('[BackgroundFetch] Headless event received.'); + NotificationsHelper().backgroundJob(); BackgroundFetch.finish(task.taskId); } diff --git a/filcnaplo/linux/flutter/generated_plugin_registrant.cc b/filcnaplo/linux/flutter/generated_plugin_registrant.cc index 0fcfb275..4894d346 100644 --- a/filcnaplo/linux/flutter/generated_plugin_registrant.cc +++ b/filcnaplo/linux/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include @@ -15,9 +14,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) dynamic_color_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); - g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); - file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) flutter_acrylic_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAcrylicPlugin"); flutter_acrylic_plugin_register_with_registrar(flutter_acrylic_registrar); diff --git a/filcnaplo/linux/flutter/generated_plugins.cmake b/filcnaplo/linux/flutter/generated_plugins.cmake index c5541e6e..c8808fea 100644 --- a/filcnaplo/linux/flutter/generated_plugins.cmake +++ b/filcnaplo/linux/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST dynamic_color - file_selector_linux flutter_acrylic url_launcher_linux ) diff --git a/filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift b/filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift index 53df988b..c6b190d7 100644 --- a/filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,7 +7,6 @@ import Foundation import connectivity_plus import dynamic_color -import file_selector_macos import flutter_local_notifications import macos_window_utils import package_info_plus @@ -19,7 +18,6 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) - FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))