From e6b5594226e525b9066622205ae05427e3285d07 Mon Sep 17 00:00:00 2001 From: rzuasti Date: Mon, 2 Mar 2026 13:59:50 -0500 Subject: [PATCH] Refactored events to notifications on front-end, added prefutils to read shared preferences. --- backend/src/scanner.rs | 2 +- frontend/lib/main.dart | 6 +- .../model/{event.dart => notification.dart} | 6 +- frontend/lib/navigation.dart | 16 +- .../notification_list.dart} | 12 +- frontend/lib/utils/oott_api.dart | 50 +++-- frontend/lib/utils/pref_utils.dart | 40 ++++ .../flutter/generated_plugin_registrant.cc | 4 + .../linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 4 + frontend/pubspec.lock | 184 ++++++++++++++++++ frontend/pubspec.yaml | 2 + .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + 14 files changed, 293 insertions(+), 38 deletions(-) rename frontend/lib/model/{event.dart => notification.dart} (90%) rename frontend/lib/{events/events_list.dart => notifications/notification_list.dart} (85%) create mode 100644 frontend/lib/utils/pref_utils.dart diff --git a/backend/src/scanner.rs b/backend/src/scanner.rs index d51bd25..d4f9aa9 100644 --- a/backend/src/scanner.rs +++ b/backend/src/scanner.rs @@ -44,7 +44,7 @@ pub async fn scan() -> Result<(), Box> { }; } info!( - "Scan finished. Sleeping for {} seconds", + "Scan finished. Sleeping for {}", get_settings().timings.wait_between_scans ); sleep(Duration::from(get_settings().timings.wait_between_scans)).await; diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart index fbdf574..880e668 100644 --- a/frontend/lib/main.dart +++ b/frontend/lib/main.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:frontend/utils/pref_utils.dart'; import 'package:provider/provider.dart'; import 'navigation.dart'; -void main() { +void main() async { + PrefUtil.init(); runApp(const MainApp()); } @@ -17,7 +19,7 @@ final class MainApp extends StatelessWidget { title: 'OOTT', theme: ThemeData( colorScheme: ColorScheme.fromSeed( - seedColor: Colors.green, + seedColor: Colors.deepOrange, brightness: Brightness.dark, ), ), diff --git a/frontend/lib/model/event.dart b/frontend/lib/model/notification.dart similarity index 90% rename from frontend/lib/model/event.dart rename to frontend/lib/model/notification.dart index a49435f..f633b00 100644 --- a/frontend/lib/model/event.dart +++ b/frontend/lib/model/notification.dart @@ -1,6 +1,6 @@ import 'notification_type.dart'; -class Event { +class Notification { int id; String title; String body; @@ -8,7 +8,7 @@ class Event { NotificationType notificationType; DateTime createdOn; - Event({ + Notification({ required this.id, required this.title, required this.body, @@ -17,7 +17,7 @@ class Event { this.isNew = true, }); - Event.fromJson(Map json) + Notification.fromJson(Map json) : id = json['id'] as int, createdOn = DateTime.parse(json['created_on'] as String), notificationType = NotificationType.fromString( diff --git a/frontend/lib/navigation.dart b/frontend/lib/navigation.dart index 0da65f6..5272f19 100644 --- a/frontend/lib/navigation.dart +++ b/frontend/lib/navigation.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'events/events_list.dart'; +import 'notifications/notification_list.dart'; // Routes definitions final GoRouter router = GoRouter( - initialLocation: '/events', + initialLocation: '/notifications', routes: [ ShellRoute( builder: (context, state, child) { @@ -12,9 +12,9 @@ final GoRouter router = GoRouter( }, routes: [ GoRoute( - path: '/events', - name: 'events', - builder: (context, state) => EventsList(), + path: '/notifications', + name: 'notifications', + builder: (context, state) => NotificationList(), ), GoRoute( path: '/devices', @@ -65,7 +65,7 @@ class MainShell extends StatelessWidget { NavigationRailDestination( icon: Icon(Icons.notifications_outlined), selectedIcon: Icon(Icons.notifications), - label: Text('Events'), + label: Text('Notifications'), ), NavigationRailDestination( icon: Icon(Icons.devices_other_outlined), @@ -105,7 +105,7 @@ class MainShell extends StatelessWidget { int _calculateSelectedIndex(BuildContext context) { final location = GoRouterState.of(context).uri.path; - if (location.startsWith('/events')) return 0; + if (location.startsWith('/notifications')) return 0; if (location.startsWith('/devices')) return 1; if (location.startsWith('/settings')) return 2; if (location.startsWith('/about')) return 3; @@ -115,7 +115,7 @@ int _calculateSelectedIndex(BuildContext context) { void _onDestinationSelected(int index, BuildContext context) { switch (index) { case 0: - context.go('/events'); + context.go('/notifications'); break; case 1: context.go('/devices'); diff --git a/frontend/lib/events/events_list.dart b/frontend/lib/notifications/notification_list.dart similarity index 85% rename from frontend/lib/events/events_list.dart rename to frontend/lib/notifications/notification_list.dart index 89e8b3a..4fb8611 100644 --- a/frontend/lib/events/events_list.dart +++ b/frontend/lib/notifications/notification_list.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import '../utils/friendly_date_formatter.dart'; -import '../model/event.dart'; +import '../model/notification.dart' as oott_model; import '../utils/oott_api.dart'; -class EventsList extends StatefulWidget { +class NotificationList extends StatefulWidget { @override - _EventListState createState() => _EventListState(); + _NotificationListState createState() => _NotificationListState(); } -class _EventListState extends State { +class _NotificationListState extends State { bool _isLoading = true; - List? _events; + List? _events; @override void initState() { @@ -27,7 +27,7 @@ class _EventListState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Events')), + appBar: AppBar(title: const Text('Notifications')), body: _isLoading ? const Center(child: CircularProgressIndicator()) : ListView.separated( diff --git a/frontend/lib/utils/oott_api.dart b/frontend/lib/utils/oott_api.dart index 8206bb8..d4640d5 100644 --- a/frontend/lib/utils/oott_api.dart +++ b/frontend/lib/utils/oott_api.dart @@ -1,28 +1,42 @@ -import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:frontend/model/event.dart'; +import 'package:encrypter/encrypter/xor.dart'; +import 'package:frontend/utils/pref_utils.dart'; +import '../model/notification.dart'; class BackendAPI { - BackendAPI._singleton(); + static final BackendAPI _instance = BackendAPI._internal(); - static final BackendAPI instance = BackendAPI._singleton(); + static BackendAPI get instance => _instance; - static final String _baseUrl = 'http://localhost:3000/api'; - static final String _apiKey = 'super_secret'; + BackendAPI._internal() { + // _baseUrl = + // PrefUtil.getValue("base_url", "http://localhost:3000/api") as String; + // _apiKey = XOR().xorDecode(PrefUtil.getValue("api_key", "") as String); - final Dio _dio = Dio( - BaseOptions( - baseUrl: _baseUrl, - headers: { - HttpHeaders.contentTypeHeader: 'application/json', - HttpHeaders.authorizationHeader: 'Bearer $_apiKey', - }, - ), - ); + _baseUrl = "http://localhost:3000/api"; + _apiKey = "super_secret"; - Future> listNotifications() async { + print('Base URL: $_baseUrl'); + print('API KEY $_apiKey'); + + _dio = Dio( + BaseOptions( + baseUrl: _baseUrl, + headers: { + HttpHeaders.contentTypeHeader: 'application/json', + HttpHeaders.authorizationHeader: 'Bearer $_apiKey', + }, + ), + ); + } + + late String _baseUrl; + late String _apiKey; + late Dio _dio; + + Future> listNotifications() async { print('About to call /notifications'); Response response; @@ -33,8 +47,8 @@ class BackendAPI { List list = response.data; print('List contains ' + list.length.toString() + ' items'); - List events = List.from( - list.map((item) => Event.fromJson(item)), + List events = List.from( + list.map((item) => Notification.fromJson(item)), ); print('Parsed ' + events.length.toString() + ' events'); diff --git a/frontend/lib/utils/pref_utils.dart b/frontend/lib/utils/pref_utils.dart new file mode 100644 index 0000000..011faf7 --- /dev/null +++ b/frontend/lib/utils/pref_utils.dart @@ -0,0 +1,40 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class PrefUtil { + static late final SharedPreferences preferences; + static bool _init = false; + static Future init() async { + if (_init) return; + preferences = await SharedPreferences.getInstance(); + _init = true; + return preferences; + } + + static void setValue(String key, Object value) { + switch (value.runtimeType) { + case String: + preferences.setString(key, value as String); + break; + case bool: + preferences.setBool(key, value as bool); + break; + case int: + preferences.setInt(key, value as int); + break; + default: + } + } + + static Object getValue(String key, Object defaultValue) { + switch (defaultValue.runtimeType) { + case String: + return preferences.getString(key) ?? ""; + case bool: + return preferences.getBool(key) ?? false; + case int: + return preferences.getInt(key) ?? 0; + default: + return defaultValue; + } + } +} diff --git a/frontend/linux/flutter/generated_plugin_registrant.cc b/frontend/linux/flutter/generated_plugin_registrant.cc index e71a16d..8a6b329 100644 --- a/frontend/linux/flutter/generated_plugin_registrant.cc +++ b/frontend/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) encrypter_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "EncrypterPlugin"); + encrypter_plugin_register_with_registrar(encrypter_registrar); } diff --git a/frontend/linux/flutter/generated_plugins.cmake b/frontend/linux/flutter/generated_plugins.cmake index 2e1de87..69a8ed8 100644 --- a/frontend/linux/flutter/generated_plugins.cmake +++ b/frontend/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + encrypter ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..cf4d788 100644 --- a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,10 @@ import FlutterMacOS import Foundation +import encrypter +import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + EncrypterPlugin.register(with: registry.registrar(forPlugin: "EncrypterPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index c3e2bc3..dee6669 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -1,6 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" + url: "https://pub.dev" + source: hosted + version: "1.6.5" async: dependency: transitive description: @@ -41,6 +57,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" dio: dependency: "direct main" description: @@ -57,6 +89,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + encrypt: + dependency: transitive + description: + name: encrypt + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" + url: "https://pub.dev" + source: hosted + version: "5.0.3" + encrypter: + dependency: "direct main" + description: + name: encrypter + sha256: "2bc641fa73f86e3d8aa7957236b84d2a47b01b2fe5145440488c326f172a65f9" + url: "https://pub.dev" + source: hosted + version: "2.0.0" fake_async: dependency: transitive description: @@ -65,6 +113,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -112,6 +176,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.2" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" leak_tracker: dependency: transitive description: @@ -200,6 +272,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" provider: dependency: "direct main" description: @@ -208,6 +328,62 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.5+1" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41" + url: "https://pub.dev" + source: hosted + version: "2.4.21" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" sky_engine: dependency: transitive description: flutter @@ -293,6 +469,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" sdks: dart: ">=3.10.8 <4.0.0" flutter: ">=3.35.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 0b1a388..5c3290f 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -13,6 +13,8 @@ dependencies: intl: ^0.20.2 provider: ^6.1.5 dio: ^5.9.1 + encrypter: ^2.0.0 + shared_preferences: ^2.5.4 dev_dependencies: flutter_test: diff --git a/frontend/windows/flutter/generated_plugin_registrant.cc b/frontend/windows/flutter/generated_plugin_registrant.cc index 8b6d468..03aedd9 100644 --- a/frontend/windows/flutter/generated_plugin_registrant.cc +++ b/frontend/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + EncrypterPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("EncrypterPluginCApi")); } diff --git a/frontend/windows/flutter/generated_plugins.cmake b/frontend/windows/flutter/generated_plugins.cmake index b93c4c3..ff6985c 100644 --- a/frontend/windows/flutter/generated_plugins.cmake +++ b/frontend/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + encrypter ) list(APPEND FLUTTER_FFI_PLUGIN_LIST