Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ci/aggressive linter #863

Merged
merged 40 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
325d86d
Change linter to very good analysis
bdmendes Jul 21, 2023
8e4b493
Apply automated fixes
bdmendes Jul 21, 2023
a74fda0
Surpress more hints
bdmendes Jul 21, 2023
64bfe9b
Surpress database warnings
bdmendes Jul 21, 2023
051c1ad
Surpress fetcher warnings
bdmendes Jul 21, 2023
213ec8d
Surpress warnings in parsers
bdmendes Jul 21, 2023
47e5203
Surpress warnings from models
bdmendes Jul 21, 2023
1cc4b61
More models and fix startup providers
LuisDuarte1 Jul 22, 2023
60cd7c1
bus_stop and text_field fixed
LuisDuarte1 Jul 22, 2023
eeb9f04
Fix most cards
LuisDuarte1 Jul 22, 2023
493133d
most of the views done
LuisDuarte1 Jul 22, 2023
ffe29a9
all views without errors
LuisDuarte1 Jul 22, 2023
a47b5e7
fix all errors
LuisDuarte1 Jul 28, 2023
965cba5
Fix library parser
LuisDuarte1 Jul 28, 2023
e0b7d49
Make ALL linter suggestions
LuisDuarte1 Jul 28, 2023
1269215
Merge remote-tracking branch 'origin' into ci/aggressive-linter
LuisDuarte1 Jul 28, 2023
3e1fd50
fix main cards list
LuisDuarte1 Jul 28, 2023
b85bcc6
fix formatting
LuisDuarte1 Jul 28, 2023
ec653df
fix linter
LuisDuarte1 Jul 28, 2023
b344ab8
Remove manual print and balance refresh times
bdmendes Jul 28, 2023
6a1324c
Fix parsing of course units json
bdmendes Jul 28, 2023
a38902a
fix api schedule parser
LuisDuarte1 Jul 29, 2023
1dfb8a9
fix relogin logic
LuisDuarte1 Jul 29, 2023
8615891
disable one_member_abstracts
LuisDuarte1 Jul 29, 2023
1d25e27
order pubspec
LuisDuarte1 Jul 29, 2023
e8afc2a
Merge branch 'develop' into ci/aggressive-linter
bdmendes Jul 30, 2023
883c583
Reset providers when logging out
bdmendes Jul 30, 2023
252b93e
Fix course units loading from database
bdmendes Jul 30, 2023
a0876c5
Fix current course units json parsing
bdmendes Jul 30, 2023
ff39ccf
Fix url query parser
bdmendes Jul 30, 2023
b6c206c
Fix empty classes on course unit detail
bdmendes Jul 30, 2023
3b9eef7
Fix empty course unit detail title
bdmendes Jul 30, 2023
755ab8c
Show all course units by default
bdmendes Jul 30, 2023
948b16c
Fix bus stops addition
bdmendes Jul 30, 2023
a15e3f1
Fix fees parser when no limit
bdmendes Jul 30, 2023
1bdf5d4
Fetch new trips after adding bus
bdmendes Jul 30, 2023
456320a
Fix fees parser index
bdmendes Jul 30, 2023
03afef8
Add style badge
bdmendes Jul 30, 2023
0bd7fb3
Fix repeated bug report widgets
bdmendes Jul 30, 2023
a5e9160
fix notification worker
LuisDuarte1 Jul 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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