Skip to content

Commit

Permalink
Merge pull request #78 from LEIC-ES-2021-22/dev
Browse files Browse the repository at this point in the history
Iteration 3 integration
  • Loading branch information
Francisco Oliveira authored Jun 7, 2022
2 parents c1a2440 + 82c89a0 commit 68ec310
Show file tree
Hide file tree
Showing 28 changed files with 745 additions and 295 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: FLutter_Tests

on:
push:
branches: [ dev, main ]
pull_request:
branches: [ dev, main ]

jobs:
tests:
runs-on: ubuntu-latest

steps:
- name: Checkout Code from PR/Commit
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}

- name: Install and set Flutter version
uses: subosito/flutter-action@v2.0.1
with:
flutter-version: '2.0.1'

- name: Restore packages
run: |
cd app/
flutter pub get
- name: Run tests
run: |
cd app/
flutter test --coverage
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class AppLectureNotificationPreferencesDatabase extends AppDatabase {
/// Replaces all of the data in this database with [preferences].
saveNewLectureNotificationPreferences(
List<LectureNotificationPreference> preferences) async {
Logger().i('Saving new lecture preferences: ${preferences}');
await deleteLectureNotificationPreferences();
await _insertLectureNotificationPreferences(preferences);
}
Expand All @@ -37,7 +38,24 @@ class AppLectureNotificationPreferencesDatabase extends AppDatabase {
for (Lecture l in lectures) {
preferences.add(LectureNotificationPreference(l.id, true));
}
this.saveNewLectureNotificationPreferences(preferences);
await this.saveNewLectureNotificationPreferences(preferences);
}

Future<void> setNotificationPreference(
int lectureId, bool activationValue) async {
final Database db = await this.getDatabase();
Logger()
.i('Updating lecture preference: ${lectureId} - ${activationValue}');
await db.update(
'lectureNotificationPreferences', {'isActive': activationValue},
where: 'id = ?', whereArgs: [lectureId]);
}

Future<bool> getNotificationPreference(int lectureId) async {
final Database db = await this.getDatabase();
var preference = await db.query('lectureNotificationPreferences',
columns: ['isActive'], where: 'id = ?', whereArgs: [lectureId]);
return preference[0]['isActive'] == 1 ? true : false;
}

/// Returns a list containing all of the lectures stored in this database.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import 'dart:async';
import 'package:logger/logger.dart';
import 'package:uni/controller/local_storage/app_database.dart';
import 'package:sqflite/sqflite.dart';
import 'package:uni/model/entities/notification_data.dart';
import 'package:uni/model/entities/notification_preference.dart';
import 'package:uni/model/notifications/notification.dart';

/// Manages the app's Notifications Data database.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:logger/logger.dart';
import 'package:uni/controller/local_storage/app_database.dart';
import 'package:sqflite/sqflite.dart';
import 'package:uni/model/entities/notification_preference.dart';
import 'package:uni/utils/constants.dart';

/// Manages the app's Notification Preferences database.
///
Expand All @@ -22,6 +23,7 @@ class AppNotificationPreferencesDatabase extends AppDatabase {

/// Replaces all of the data in this database with [preferences].
saveNewPreferences(List<NotificationPreference> preferences) async {
Logger().i('Saving new preferences: ${preferences}');
await deletePreferences();
await _insertPreferences(preferences);
}
Expand Down Expand Up @@ -56,6 +58,28 @@ class AppNotificationPreferencesDatabase extends AppDatabase {
}
}

Future<NotificationPreference> getPreference(NotificationType type) async {
final Database db = await this.getDatabase();

// This list only contains more than one element if primary key is broken
final List<Map<String, dynamic>> rawPreferences = await db.query(
'notification_preferences',
where: 'notificationType = ?',
whereArgs: [type.typeName]);

final wantedPreference = rawPreferences[0];
return NotificationPreference.fromHtml(wantedPreference['isActive'],
wantedPreference['antecedence'], wantedPreference['notificationType']);
}

Future<void> replacePreference(NotificationPreference preference) async {
final Database db = await this.getDatabase();
Logger().i('Updating preference: ${preference.toMap()}');
await db.update('notification_preferences', preference.toMap(),
where: 'notificationType = ?',
whereArgs: [preference.notificationType]);
}

/// Deletes all of the data stored in this database.
Future<void> deletePreferences() async {
// Get a reference to the database
Expand Down
7 changes: 6 additions & 1 deletion app/lib/controller/logout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import 'package:uni/controller/local_storage/app_bus_stop_database.dart';
import 'package:uni/controller/local_storage/app_courses_database.dart';
import 'package:uni/controller/local_storage/app_exams_database.dart';
import 'package:uni/controller/local_storage/app_last_user_info_update_database.dart';
import 'package:uni/controller/local_storage/app_lecture_notification_preferences_database.dart';
import 'package:uni/controller/local_storage/app_lectures_database.dart';
import 'package:uni/controller/local_storage/app_notification_preferences_database.dart';
import 'package:uni/controller/local_storage/app_refresh_times_database.dart';
import 'package:uni/controller/local_storage/app_user_database.dart';
import 'package:uni/controller/notifications/notification_setup.dart';
import 'package:uni/model/app_state.dart';
import 'package:uni/redux/action_creators.dart';
import 'package:uni/view/Pages/general_page_view.dart';
Expand All @@ -23,7 +25,10 @@ Future logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();

AppNotificationPreferencesDatabase().deletePreferences();
await AppLectureNotificationPreferencesDatabase()
.deleteLectureNotificationPreferences();
await AppNotificationPreferencesDatabase().deletePreferences();
await deleteNotifications();
AppLecturesDatabase().deleteLectures();
AppExamsDatabase().deleteExams();
AppCoursesDatabase().deleteCourses();
Expand Down
49 changes: 32 additions & 17 deletions app/lib/controller/notifications/notification_scheduler.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:logger/logger.dart';
import 'package:redux/redux.dart';
import 'package:uni/model/app_state.dart';
import 'package:uni/model/entities/notification_preference.dart';
import 'package:uni/utils/constants.dart';
import 'package:uni/model/notifications/notification.dart';
import 'package:timezone/timezone.dart' as tz;

class NotificationScheduler {
final Store<AppState> _store;
static var _notificationPlugin = null;

NotificationScheduler(this._store);
static get notificationPlugin {
return _notificationPlugin;
}

NotificationScheduler() {
if (_notificationPlugin == null) {
throw Exception(
'Instantiated Notification Scheduler without initializing it');
}
}

static init() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('mipmap/ic_launcher');
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
);
_notificationPlugin = FlutterLocalNotificationsPlugin();
await _notificationPlugin.initialize(initializationSettings);
}

static NotificationDetails _buildPlatformChannelSpecifics(
Notification notification) {
Expand All @@ -23,26 +40,24 @@ class NotificationScheduler {
return NotificationDetails(android: androidPlatformChannelSpecifics);
}

Future<void> unscheduleAll() async {
Logger().i('Unscheduling all notifications');
NotificationScheduler._notificationPlugin.cancelAll();
}

Future<void> schedule(
Notification notification, tz.TZDateTime scheduledTime) async {
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
this._store.state.content['flutterLocalNotificationsPlugin'];
Logger()
.i('LocalNotifPlugin:' + flutterLocalNotificationsPlugin.toString());
await flutterLocalNotificationsPlugin.zonedSchedule(
Logger().i(
"Scheduled Notification '${notification.toString()}' to '${scheduledTime.toString()}' ");
await _notificationPlugin.zonedSchedule(
notification.id,
notification.title,
notification.body,
scheduledTime,
_buildPlatformChannelSpecifics(notification),
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
androidAllowWhileIdle: true);
}

Future<void> scheduleAll() async {
final List<NotificationPreference> preferences =
await this._store.state.content['userNotificationPreferences'];
Logger().i('Preferences:' + preferences.toString());
androidAllowWhileIdle: true,
matchDateTimeComponents: DateTimeComponents.dayOfWeekAndTime);
}
}
58 changes: 39 additions & 19 deletions app/lib/controller/notifications/notification_setup.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import 'package:logger/logger.dart';
import 'package:redux/redux.dart';
import 'package:tuple/tuple.dart';
import 'package:uni/controller/local_storage/app_lecture_notification_preferences_database.dart';
import 'package:uni/controller/local_storage/app_lectures_database.dart';
import 'package:uni/controller/local_storage/app_notification_data_database.dart';
import 'package:uni/controller/local_storage/app_notification_preferences_database.dart';
import 'package:uni/controller/local_storage/app_shared_preferences.dart';
import 'package:uni/controller/notifications/notification_scheduler.dart';
import 'package:uni/model/app_state.dart';
import 'package:uni/model/entities/lecture.dart';
import 'package:uni/model/entities/lecture_notification_preference.dart';
import 'package:uni/model/entities/notification_data.dart';
Expand All @@ -25,57 +23,78 @@ Future<List<NotificationPreference>> notificationPreferences() async {
NotificationPreference(
isActive: true,
antecedence: NotificationPreference.DEFAULT_ANTECEDENCE,
notificationType: NotificationType.classNotif.typeName
)
notificationType: NotificationType.classNotif.typeName)
];
await db.saveNewPreferences(preferences);
}
return preferences;
}

Future<List<NotificationData>> notificationsData() async {
return AppNotificationDataDatabase().notificationsData();
return await AppNotificationDataDatabase().notificationsData();
}

Future<List<LectureNotificationPreference>>
lectureNotificationPreferences() async {
return AppLectureNotificationPreferencesDatabase().preferences();
final AppLecturesDatabase lecturesDb = AppLecturesDatabase();
final AppLectureNotificationPreferencesDatabase
lecturesNotificationPreferencesDb =
AppLectureNotificationPreferencesDatabase();
List<Lecture> lectures = await lecturesDb.lectures();
final List<LectureNotificationPreference> lectureNotificationPreferences =
await lecturesNotificationPreferencesDb.preferences();
// While lectures have not been saved in database from remote
while (lectures.isEmpty) {
await Future.delayed(const Duration(milliseconds: 100));
lectures = await lecturesDb.lectures();
}
if (lectures.length > lectureNotificationPreferences.length) {
await lecturesNotificationPreferencesDb
.saveNewPreferencesThroughLectures(lectures);
}
return await AppLectureNotificationPreferencesDatabase().preferences();
}

Future<void> deleteNotifications() async {
NotificationScheduler().unscheduleAll();
await AppNotificationDataDatabase().deleteNotificationsData();
}

Future<void> resetNotifications() async {
await deleteNotifications();
await notificationSetUp();
}

Future<void> notificationSetUp(Store<AppState> store) async {
Logger().i('Getting here');
Future<void> notificationSetUp() async {
final Tuple2<String, String> userPersistentInfo =
await AppSharedPreferences.getPersistentUserInfo();
if (userPersistentInfo.item1 == '' || userPersistentInfo.item2 == '') return;

final List<NotificationPreference> preferences =
await notificationPreferences();
Logger().i('Preferences:' + preferences.toString());
for (NotificationPreference preference in preferences) {
if (preference.notificationType == NotificationType.classNotif.typeName &&
preference.isActive) {
classNotificationSetUp(store, preference.antecedence);
classNotificationSetUp(preference.antecedence);
}
}
}

Future<void> classNotificationSetUp(
Store<AppState> store, int antecedence) async {
Future<void> classNotificationSetUp(int antecedence) async {
final preferences = await lectureNotificationPreferences();
Logger().i('Lecture preferences:' + preferences.toString());
final alreadyScheduled = await notificationsData();
Logger().i('Notification data:' + alreadyScheduled.toString());
final List<Lecture> lectures = await AppLecturesDatabase().lectures();
for (Lecture lecture in lectures) {
if (shouldScheduleClass(lecture, alreadyScheduled, preferences)) {
if (!shouldScheduleClass(lecture, alreadyScheduled, preferences)) {
Logger().i(
'Notification Already Scheduled: ${lecture.subject}-${lecture.day}');
continue;
}
final Notification notification =
ClassNotificationFactory().buildNotification(lecture);
alreadyScheduled.add(NotificationData(
notification.id, lecture.id, NotificationType.classNotif.typeName));
NotificationScheduler(store).schedule(
ClassNotificationFactory().buildNotification(lecture),
NotificationScheduler().schedule(notification,
ClassNotificationFactory().calculateTime(lecture, antecedence));
}
AppNotificationDataDatabase().saveNewNotificationData(alreadyScheduled);
Expand All @@ -86,11 +105,12 @@ bool shouldScheduleClass(
List<NotificationData> notificationsData,
List<LectureNotificationPreference> preferences) {
try {
return NotificationData.listContainsModelId(
return !NotificationData.listContainsModelId(
notificationsData, lecture.id) &&
LectureNotificationPreference.idIsActive(preferences, lecture.id);
} catch (e) {
Logger().e('Error: ' + e.cause);
Logger().e(
'Error: ${e.cause}/${lecture.subject}-${lecture.typeClass}-${lecture.day}');
}
return false;
}
Loading

0 comments on commit 68ec310

Please sign in to comment.