2023-02-01 21:35:16 +00:00
|
|
|
import 'dart:math';
|
|
|
|
|
|
|
|
import 'package:feet/api/api.dart';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:workmanager/workmanager.dart';
|
|
|
|
|
|
|
|
@pragma('vm:entry-point')
|
|
|
|
void callbackDispatcher() {
|
|
|
|
Workmanager().executeTask((taskName, inputData) async {
|
|
|
|
print("Native called background task: $taskName");
|
|
|
|
|
|
|
|
if (taskName == 'fetchNotifications') {
|
|
|
|
final sharedPreferences = await SharedPreferences.getInstance();
|
|
|
|
|
|
|
|
try {
|
|
|
|
var initialized = await FlutterLocalNotificationsPlugin().initialize(
|
|
|
|
const InitializationSettings(
|
|
|
|
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (initialized == false) {
|
|
|
|
print("Notification plugin did not initialize; cancelling task");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
var apiUrl = sharedPreferences.getString('apiUrl'),
|
|
|
|
apiKey = sharedPreferences.getString('apiKey'),
|
|
|
|
latest = sharedPreferences.getInt('newestKnownPost');
|
|
|
|
|
|
|
|
if (apiUrl == null || apiKey == null) {
|
|
|
|
print("API URL or API key not set; cancelling task");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-02-02 07:02:25 +00:00
|
|
|
if (latest == null || latest == 0) {
|
|
|
|
print("newestKnownPost is not set; cancelling task");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-02-01 21:35:16 +00:00
|
|
|
var api = FeverAPI(
|
|
|
|
apiKey: apiKey,
|
|
|
|
apiUrl: apiUrl,
|
|
|
|
sharedPrefs: sharedPreferences,
|
|
|
|
);
|
|
|
|
|
2023-02-02 07:02:25 +00:00
|
|
|
var response =
|
|
|
|
await api.request().withItems().sinceId(latest).execute();
|
2023-02-01 21:35:16 +00:00
|
|
|
var items =
|
|
|
|
api.cache.items.getAll().values.where((post) => !post.isRead);
|
|
|
|
|
2023-02-02 07:02:25 +00:00
|
|
|
print("Found ${items.length} new unread posts (out of "
|
|
|
|
"${api.cache.items.size} total)");
|
|
|
|
print(response);
|
|
|
|
|
2023-02-01 21:35:16 +00:00
|
|
|
// Only fetch feeds and favicons if necessary to avoid wasting bandwidth
|
|
|
|
if (items.isNotEmpty) {
|
|
|
|
print("New posts found, fetching feeds and favicons");
|
|
|
|
await api.request().withFeeds().withFavicons().execute();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var item in items) {
|
|
|
|
var feed = api.cache.feeds.get(item.feedId);
|
|
|
|
print("Notifying for post: ${item.id}");
|
|
|
|
|
|
|
|
AndroidBitmap<Object>? iconData;
|
|
|
|
var favicon = api.cache.favicons.get(feed?.faviconId ?? -1);
|
|
|
|
if (favicon != null) {
|
|
|
|
try {
|
|
|
|
iconData = ByteArrayAndroidBitmap.fromBase64String(
|
|
|
|
favicon.data.split(',')[1]);
|
|
|
|
} catch (e) {
|
|
|
|
print("Failed to decode favicon: $e - Continuing");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await FlutterLocalNotificationsPlugin().show(
|
2023-02-02 09:55:33 +00:00
|
|
|
Random().nextInt(10000000), // Can't use the post ID here because FreshRSS's IDs are too large
|
2023-02-01 21:35:16 +00:00
|
|
|
feed != null ? 'New post - ${feed.title}' : 'New post',
|
|
|
|
item.title,
|
|
|
|
NotificationDetails(
|
|
|
|
android: AndroidNotificationDetails(
|
|
|
|
'new_posts',
|
|
|
|
'New posts',
|
|
|
|
autoCancel: true,
|
|
|
|
channelShowBadge: true,
|
|
|
|
importance: Importance.low,
|
|
|
|
largeIcon: iconData,
|
2023-02-02 09:17:54 +00:00
|
|
|
when: item.createdOnTime.millisecondsSinceEpoch,
|
|
|
|
showWhen: true,
|
2023-02-01 21:35:16 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
print(e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupBackgroundTasks() async {
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
2023-02-02 07:02:25 +00:00
|
|
|
await Workmanager().initialize(
|
2023-02-01 21:35:16 +00:00
|
|
|
callbackDispatcher,
|
|
|
|
isInDebugMode: kDebugMode,
|
|
|
|
);
|
|
|
|
|
|
|
|
await Permission.notification.request();
|
|
|
|
|
|
|
|
// Runs every 15 minutes
|
2023-02-02 07:02:25 +00:00
|
|
|
await Workmanager().registerPeriodicTask(
|
|
|
|
'fetch_notifications',
|
2023-02-01 21:35:16 +00:00
|
|
|
'fetchNotifications',
|
2023-02-02 07:02:25 +00:00
|
|
|
constraints: Constraints(networkType: NetworkType.connected),
|
|
|
|
initialDelay: const Duration(seconds: 60),
|
2023-02-01 21:35:16 +00:00
|
|
|
);
|
|
|
|
}
|