Skip to content

Commit

Permalink
Ci/aggressive linter (#863)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdmendes authored Aug 1, 2023
2 parents 82e9f33 + a5e9160 commit 9bb7333
Show file tree
Hide file tree
Showing 214 changed files with 6,759 additions and 5,254 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

[![Build badge](https://img.shields.io/github/actions/workflow/status/NIAEFEUP/uni/format_lint_test.yaml?style=for-the-badge)](https://github.com/NIAEFEUP/uni/actions)
[![Deploy badge](https://img.shields.io/github/actions/workflow/status/NIAEFEUP/uni/deploy.yaml?label=Deploy&style=for-the-badge)](https://github.com/NIAEFEUP/uni/actions)

[![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg?style=for-the-badge)](https://pub.dev/packages/very_good_analysis)
[![License badge](https://img.shields.io/github/license/NIAEFEUP/uni?style=for-the-badge)](https://github.com/NIAEFEUP/uni/blob/develop/LICENSE)

<a href='https://play.google.com/store/apps/details?id=pt.up.fe.ni.uni&hl=pt_PT&gl=US&pli=1&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img style="width: 135px;" alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a>
Expand Down
44 changes: 11 additions & 33 deletions uni/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
include: package:very_good_analysis/analysis_options.yaml

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
# Exclude auto-generated files from dart analysis
exclude:
- '**.g.dart'
- '**.freezed.dart'

# Custom linter rules. A list of all rules can be found at
# https://dart-lang.github.io/linter/lints/options/options.html
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
always_use_package_imports: true
prefer_final_locals: true

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
public_member_api_docs: false
avoid_equals_and_hash_code_on_mutable_classes: false
one_member_abstracts: false

analyzer:
errors:
# allow for asset_does_not_exist
unrecognized_error_code: ignore
# ignore this in pubspec.yaml
asset_directory_does_not_exist: ignore
20 changes: 11 additions & 9 deletions uni/lib/controller/background_workers/background_callback.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ import 'package:workmanager/workmanager.dart';
/// the bool is all functions that are ran by backgroundfetch in iOS
/// (they must not take any arguments, not checked)
const taskMap = {
"pt.up.fe.ni.uni.notificationworker":
'pt.up.fe.ni.uni.notificationworker':
Tuple2(NotificationManager.updateAndTriggerNotifications, true)
};

@pragma('vm:entry-point')
// This function is android only and only executes when the app is complety terminated
void workerStartCallback() async {
// This function is android only and only executes
// when the app is completely terminated
Future<void> workerStartCallback() async {
Workmanager().executeTask((taskName, inputData) async {
try {
Logger().d("""[$taskName]: Start executing job...""");
Logger().d('''[$taskName]: Start executing job...''');

//iOSBackgroundTask is a special task, that iOS runs whenever it deems necessary
//and will run all tasks with the flag true
//NOTE: keep the total execution time under 30s to avoid being punished by the iOS scheduler.
// iOSBackgroundTask is a special task, that iOS runs whenever
// it deems necessary and will run all tasks with the flag true
// NOTE: keep the total execution time under 30s to avoid being punished
// by the iOS scheduler.
if (taskName == Workmanager.iOSBackgroundTask) {
taskMap.forEach((key, value) async {
if (value.item2) {
Logger().d("""[$key]: Start executing job...""");
Logger().d('''[$key]: Start executing job...''');
await value.item1();
}
});
Expand All @@ -34,7 +36,7 @@ void workerStartCallback() async {
//to not be punished by the scheduler in future runs.
await taskMap[taskName]!.item1();
} catch (err, stackstrace) {
Logger().e("Error while running $taskName job:", err, stackstrace);
Logger().e('Error while running $taskName job:', err, stackstrace);
return false;
}
return true;
Expand Down
134 changes: 77 additions & 57 deletions uni/lib/controller/background_workers/notifications.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,49 @@ import 'package:uni/model/entities/session.dart';
import 'package:workmanager/workmanager.dart';

///
/// Stores all notifications that will be checked and displayed in the background.
/// Stores notifications that will be checked and displayed in the background.
/// Add your custom notification here, because it will NOT be added at runtime.
/// (due to background worker limitations).
///
Map<Type, Notification Function()> notificationMap = {
TuitionNotification: () => TuitionNotification(),
TuitionNotification: TuitionNotification.new,
};

abstract class Notification {
Notification(this.uniqueID, this.timeout);

String uniqueID;
Duration timeout;

Notification(this.uniqueID, this.timeout);

Future<Tuple2<String, String>> buildNotificationContent(Session session);

Future<bool> shouldDisplay(Session session);

void displayNotification(Tuple2<String, String> content,
FlutterLocalNotificationsPlugin localNotificationsPlugin);
void displayNotification(
Tuple2<String, String> content,
FlutterLocalNotificationsPlugin localNotificationsPlugin,
);

Future<void> displayNotificationIfPossible(Session session,
FlutterLocalNotificationsPlugin localNotificationsPlugin) async {
Future<void> displayNotificationIfPossible(
Session session,
FlutterLocalNotificationsPlugin localNotificationsPlugin,
) async {
if (await shouldDisplay(session)) {
displayNotification(
await buildNotificationContent(session), localNotificationsPlugin);
await buildNotificationContent(session),
localNotificationsPlugin,
);
}
}
}

class NotificationManager {
factory NotificationManager() {
return _notificationManager;
}

NotificationManager._internal();

static final NotificationManager _notificationManager =
NotificationManager._internal();

Expand All @@ -55,103 +67,111 @@ class NotificationManager {

static const Duration _notificationWorkerPeriod = Duration(hours: 1);

factory NotificationManager() {
return _notificationManager;
}

static Future<void> updateAndTriggerNotifications() async {
final userInfo = await AppSharedPreferences.getPersistentUserInfo();
final faculties = await AppSharedPreferences.getUserFaculties();

final Session? session = await NetworkRouter.login(
userInfo.item1, userInfo.item2, faculties, false);
final session = await NetworkRouter.login(
userInfo.item1,
userInfo.item2,
faculties,
persistentSession: false,
);

if (session == null) {
return;
}

// Get the .json file that contains the last time that the notification has ran
_initFlutterNotificationsPlugin();
// Get the .json file that contains the last time that the
// notification has ran
await _initFlutterNotificationsPlugin();
final notificationStorage = await NotificationTimeoutStorage.create();

for (Notification Function() value in notificationMap.values) {
final Notification notification = value();
final DateTime lastRan = notificationStorage
for (final value in notificationMap.values) {
final notification = value();
final lastRan = notificationStorage
.getLastTimeNotificationExecuted(notification.uniqueID);
if (lastRan.add(notification.timeout).isBefore(DateTime.now())) {
await notification.displayNotificationIfPossible(
session, _localNotificationsPlugin);
session,
_localNotificationsPlugin,
);
await notificationStorage.addLastTimeNotificationExecuted(
notification.uniqueID, DateTime.now());
notification.uniqueID,
DateTime.now(),
);
}
}
}

void initializeNotifications() async {
// guarantees that the execution is only done once in the lifetime of the app.
Future<void> initializeNotifications() async {
// guarantees that the execution is only done
// once in the lifetime of the app.
if (_initialized) return;
_initialized = true;
_initFlutterNotificationsPlugin();
_buildNotificationWorker();
await _initFlutterNotificationsPlugin();
await _buildNotificationWorker();
}

static void _initFlutterNotificationsPlugin() async {
const AndroidInitializationSettings initializationSettingsAndroid =
static Future<void> _initFlutterNotificationsPlugin() async {
const initializationSettingsAndroid =
AndroidInitializationSettings('ic_notification');

//request for notifications immediatly on iOS
const DarwinInitializationSettings darwinInitializationSettings =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestCriticalPermission: true);

const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: darwinInitializationSettings,
macOS: darwinInitializationSettings);
const darwinInitializationSettings = DarwinInitializationSettings(
requestCriticalPermission: true,
);

const initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: darwinInitializationSettings,
macOS: darwinInitializationSettings,
);

await _localNotificationsPlugin.initialize(initializationSettings);

//specific to android 13+, 12 or lower permission is requested when the first notification channel opens
// specific to android 13+, 12 or lower permission is requested when
// the first notification channel opens
if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin androidPlugin =
_localNotificationsPlugin.resolvePlatformSpecificImplementation()!;
final androidPlugin =
_localNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()!;
try {
final bool? permissionGranted = await androidPlugin.requestPermission();
final permissionGranted = await androidPlugin.requestPermission();
if (permissionGranted != true) {
return;
}
} on PlatformException catch (_) {}
}
}

NotificationManager._internal();

static void _buildNotificationWorker() async {
static Future<void> _buildNotificationWorker() async {
if (Platform.isAndroid) {
Workmanager().cancelByUniqueName(
"pt.up.fe.ni.uni.notificationworker"); //stop task if it's already running
Workmanager().registerPeriodicTask(
"pt.up.fe.ni.uni.notificationworker",
"pt.up.fe.ni.uni.notificationworker",
await Workmanager().cancelByUniqueName(
'pt.up.fe.ni.uni.notificationworker',
); //stop task if it's already running
await Workmanager().registerPeriodicTask(
'pt.up.fe.ni.uni.notificationworker',
'pt.up.fe.ni.uni.notificationworker',
constraints: Constraints(networkType: NetworkType.connected),
frequency: _notificationWorkerPeriod,
);
} else if (Platform.isIOS || kIsWeb) {
//This is to guarentee that the notification will be run at least the app starts.
//NOTE (luisd): This is not an isolate because we can't register plugins in a isolate, in the current version of flutter
// so we just do it after login
Logger().d("Running notification worker on main isolate...");
// This is to guarantee that the notification
// will be run at least once the app starts.
// NOTE (luisd): This is not an isolate because we can't register plugins
// in a isolate, in the current version of flutter
// so we just do it after login
Logger().d('Running notification worker on main isolate...');
await updateAndTriggerNotifications();
Timer.periodic(_notificationWorkerPeriod, (timer) {
Logger().d("Running notification worker on periodic timer...");
Logger().d('Running notification worker on periodic timer...');
updateAndTriggerNotifications();
});
} else {
throw PlatformException(
code: "WorkerManager is only supported in iOS and android...");
code: 'WorkerManager is only supported in iOS and android...',
);
}
}
}
Loading

0 comments on commit 9bb7333

Please sign in to comment.