From 43702e5ba07580d41f7f41b2e50c94c82084b781 Mon Sep 17 00:00:00 2001 From: Lea Date: Sun, 5 Feb 2023 18:43:19 +0100 Subject: [PATCH] Open relevant post when notification is clicked Closes #7 --- lib/api/api.dart | 5 +++ lib/main.dart | 6 ++- lib/notifications/tasks.dart | 79 +++++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/lib/api/api.dart b/lib/api/api.dart index 043cbea..3dc1f35 100644 --- a/lib/api/api.dart +++ b/lib/api/api.dart @@ -141,6 +141,11 @@ class APIRequestBuilder { return this; } + APIRequestBuilder withIds(List ids) { + _addArg('with_ids=${ids.join(',')}'); + return this; + } + /// Executes the API request and returns the JSON data Future> fetch() async { if (api.apiKey == null || api.apiUrl == null) { diff --git a/lib/main.dart b/lib/main.dart index 5bc3b80..f9f8aa2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,13 +16,16 @@ import 'api/api.dart'; // fetching a large list const FETCH_MAX_POSTS = 1000; +// Store these globally so our notification handler can access them +BuildContext? globalContext; +final api = FeverAPI(); + void main() { setupBackgroundTasks(); runApp(MyApp()); } class MyApp extends StatelessWidget { - final api = FeverAPI(); SharedPreferences? prefs; MyApp({super.key}); @@ -60,6 +63,7 @@ class MyApp extends StatelessWidget { themeMode: ThemeMode.system, home: FutureBuilder( builder: (context, snapshot) { + globalContext = context; if (snapshot.hasData && prefs != null) { return MyHomePage(title: 'Feet', api: api, prefs: prefs!); } diff --git a/lib/notifications/tasks.dart b/lib/notifications/tasks.dart index 830c820..fe04424 100644 --- a/lib/notifications/tasks.dart +++ b/lib/notifications/tasks.dart @@ -1,6 +1,8 @@ import 'dart:math'; import 'package:feet/api/api.dart'; +import 'package:feet/main.dart'; +import 'package:feet/pages/article.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; @@ -79,9 +81,11 @@ void callbackDispatcher() { } await FlutterLocalNotificationsPlugin().show( - Random().nextInt(10000000), // Can't use the post ID here because FreshRSS's IDs are too large + Random().nextInt( + 10000000), // Can't use the post ID here because FreshRSS's IDs are too large feed != null ? 'New post - ${feed.title}' : 'New post', item.title, + payload: 'item/${item.id}', NotificationDetails( android: AndroidNotificationDetails( 'new_posts', @@ -117,6 +121,35 @@ void setupBackgroundTasks() async { await Permission.notification.request(); + await FlutterLocalNotificationsPlugin().initialize( + const InitializationSettings( + android: AndroidInitializationSettings('@mipmap/ic_launcher'), + ), + onSelectNotification: handleNotificationClick, + ); + + var launchDetails = + await FlutterLocalNotificationsPlugin().getNotificationAppLaunchDetails(); + + if (launchDetails?.payload != null && launchDetails!.payload!.isNotEmpty) { + handleNotificationClick(launchDetails.payload); + } + + // Test notification + //if (kDebugMode) { + // await FlutterLocalNotificationsPlugin().show( + // Random().nextInt(1000000), + // "Test Notification", + // "Test Notification Body", + // const NotificationDetails( + // android: AndroidNotificationDetails( + // 'new_posts', + // 'New posts', + // ), + // ), + // payload: "item/1675609277381551"); + //} + // Runs every 15 minutes await Workmanager().registerPeriodicTask( 'fetch_notifications', @@ -125,3 +158,47 @@ void setupBackgroundTasks() async { initialDelay: const Duration(seconds: 60), ); } + +Future handleNotificationClick(String? payload) async { + print("Notification click: $payload"); + if (globalContext == null) { + print("Global context not available."); + return; + } + if (payload == null) { + print("Didn't receive a payload"); + return; + } + + try { + if (payload.startsWith('item/')) { + if (!api.loggedIn()) { + print("API client is not logged in"); + return; + } + + var id = toInt(payload.split('/')[1]); + var item = api.cache.items.get(id); + if (item == null) { + var res = await api.request().withItems().withIds([id]).execute(); + item = api.cache.items.get(id); + if (item == null) throw 'Didn\'t receive item $id from API: $res'; + } + + Navigator.of(globalContext!).push( + MaterialPageRoute( + builder: (context) => ArticlePage(article: item!), + ), + ); + + if (!item.isRead) { + await api + .request() + .markItem(item, ItemMarkType.read) + .execute(); + } + } + } catch (e) { + print("Error while handling notification click: $e"); + } +}