Skip to content

Commit

Permalink
cleaned up logic, added additional comments
Browse files Browse the repository at this point in the history
  • Loading branch information
hjiangsu committed Apr 22, 2024
1 parent 0f4c663 commit 34893f1
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 247 deletions.
14 changes: 9 additions & 5 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@
},
"failedToBlock": "Failed to block: {errorMessage}",
"@failedToBlock": {},
"failedToDisablePushNotifications": "Failed to disable existing push notifications. Will try again when app restarts.",
"failedToDisablePushNotifications": "Failed to disable push notifications",
"@failedToDisablePushNotifications": {
"description": "Error message when failed to disable push notifications."
},
Expand Down Expand Up @@ -1281,14 +1281,18 @@
"@pushNotification": {
"description": "Setting for push notifications"
},
"pushNotificationDescription": "If enabled, Thunder will send your JWT token(s) to the server in order to poll for new notifications. \\n\\n **NOTE:** This will not take effect until the next time the app is launched.",
"pushNotificationDescription": "If enabled, Thunder will send your JWT token(s) to the server in order to poll for new notifications. \n\n **NOTE:** This will not take effect until the next time the app is launched.",
"@pushNotificationDescription": {
"description": "Description of push notification setting"
},
"pushNotificationServer": "Push Notification Server",
"@pushNotificationServer": {},
"pushNotificationServerDescription": "Configure the notification server to use for sending push notifications.",
"@pushNotificationServerDescription": {},
"@pushNotificationServer": {
"description": "Setting for choosing push notification server"
},
"pushNotificationServerDescription": "Configure the push notification server. The server must be properly configured to send push notifications to your device.\n\n **Only enter a server that you trust with your credentials.**",
"@pushNotificationServerDescription": {
"description": "Description of choosing push notification server setting"
},
"reachedTheBottom": "Hmmm. It seems like you've reached the bottom.",
"@reachedTheBottom": {},
"readAll": "Read All",
Expand Down
13 changes: 9 additions & 4 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,18 @@ class _ThunderAppState extends State<ThunderApp> {
SharedPreferences prefs = (await UserPreferences.instance).sharedPreferences;
String? inboxNotificationType = prefs.getString(LocalSettings.inboxNotificationType.name);

if (NotificationType.values.byName(inboxNotificationType ?? NotificationType.none.name) != NotificationType.none) {
// If notification type is null, then don't perform any logic
if (inboxNotificationType == null) return;

if (NotificationType.values.byName(inboxNotificationType) != NotificationType.none) {
// Initialize notification logic
initPushNotificationLogic(controller: notificationsStreamController);
} else if (inboxNotificationType != null && inboxNotificationType == NotificationType.none.name) {
// Attempt to remove tokens from notification server. When inboxNotificationType == NotificationType.none.name, that means at some point in time
// removing the tokens was unsuccessful. When there is a successful removal, the inboxNotificationType will be set to null.
} else {
// Attempt to remove tokens from notification server. When inboxNotificationType == NotificationType.none,
// this indicates that removing token was unsuccessful previously. We will attempt to remove it again.
// When there is a successful removal, the inboxNotificationType will be set to null.
bool success = await deleteAccountFromNotificationServer();

if (success) {
prefs.remove(LocalSettings.inboxNotificationType.name);
debugPrint('Removed tokens from notification server');
Expand Down
13 changes: 6 additions & 7 deletions lib/notification/shared/android_notification.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ const String _inboxMessagesChannelName = 'Inbox Messages';
const String repliesGroupKey = 'replies';

/// Displays a new notification group on Android based on the accounts passed in.
void showNotificationGroups({
List<Account> accounts = const [],
}) async {
///
/// This displays an empty notification which will be used in conjunction with the [showAndroidNotification]
/// to help display a group of notifications on Android.
void showNotificationGroups({List<Account> accounts = const []}) async {
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

for (Account account in accounts) {
Expand Down Expand Up @@ -42,17 +43,15 @@ void showNotificationGroups({
}
}

/// Displays a single push notification on Android
///
/// The notification will be grouped based on the account id.
/// Displays a single push notification on Android. When a notification is displayed, it will be grouped by the account id.
/// This allows us to group notifications for a single account on Android.
void showAndroidNotification({
required int id,
required BigTextStyleInformation bigTextStyleInformation,
Account? account,
String title = '',
String content = '',
String payload = '',
String summaryText = '',
}) async {
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

Expand Down
35 changes: 16 additions & 19 deletions lib/notification/shared/notification_server.dart
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
// Dart imports:
// Dart imports
import 'dart:convert';

// Flutter imports:
// Flutter imports
import 'package:flutter/foundation.dart';

// Package imports:
// Package imports
import 'package:http/http.dart' as http;

// Project imports:
// Project imports
import 'package:thunder/account/models/account.dart';
import 'package:thunder/core/enums/local_settings.dart';
import 'package:thunder/core/singletons/preferences.dart';
import 'package:thunder/notification/enums/notification_type.dart';
import 'package:thunder/utils/constants.dart';

/// Sends a request to the push notification server, including the [NotificationType], [jwt], and [instance].
///
/// The [token] describes the endpoint to send the notification to. This is generally the UnifiedPush endpoint, or device token for APNs.
/// The [instance] and [jwt] are required in order for the push server to act on behalf of the user to poll for notifications.
Future<bool> sendAuthTokenToNotificationServer({
required NotificationType type,
required String token,
required List<String> jwts,
required String jwt,
required String instance,
}) async {
try {
final prefs = (await UserPreferences.instance).sharedPreferences;

String pushNotificationServer = prefs.getString(LocalSettings.pushNotificationServer.name) ?? THUNDER_SERVER_URL;
pushNotificationServer = 'http://192.168.50.195:5100/notifications';

// Send POST request to notification server
http.Response response = await http.post(
Uri.parse(pushNotificationServer),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
headers: {'Content-Type': 'application/json; charset=UTF-8'},
body: jsonEncode({
'type': type.name,
'token': token,
'jwts': jwts,
'jwt': jwt,
'instance': instance,
}),
);
Expand All @@ -49,25 +49,22 @@ Future<bool> sendAuthTokenToNotificationServer({
}
}

/// Sends a request to the push notification server to remove any account tokens from the server. This will remove push notifications for all accounts active on the app.
///
/// This is generally called when the user changes push notification types, or disables all push notifications.
Future<bool> deleteAccountFromNotificationServer() async {
try {
final prefs = (await UserPreferences.instance).sharedPreferences;

String pushNotificationServer = prefs.getString(LocalSettings.pushNotificationServer.name) ?? THUNDER_SERVER_URL;
pushNotificationServer = 'http://192.168.50.195:5100/notifications';

List<Account> accounts = await Account.accounts();
List<String> jwts = accounts.map((Account account) => account.jwt!).toList();

// Send POST request to notification server
http.Response response = await http.delete(
Uri.parse(pushNotificationServer),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode({
'jwts': jwts,
}),
headers: {'Content-Type': 'application/json; charset=UTF-8'},
body: jsonEncode({'jwts': jwts}),
);

// Check if the request was successful
Expand Down
19 changes: 12 additions & 7 deletions lib/notification/utils/apns.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ import 'package:thunder/notification/shared/notification_server.dart';
void initAPNs({required StreamController<NotificationResponse> controller}) async {
const String repliesGroupKey = 'replies';

// Fetch device token for APNs
// We need to send this device token along with the jwt so that the server can poll for new notifications and send them to this device.
// Fetch device token for APNs. We need to send this device token along with the jwt so that the server can poll for new notifications and send them to this device.
String? token = await Push.instance.token;
debugPrint("Device token: $token");

if (token == null) {
debugPrint("No device token, skipping APNs initialization");
debugPrint("No device token found, skipping APNs initialization");
return;
}

Expand All @@ -35,7 +34,7 @@ void initAPNs({required StreamController<NotificationResponse> controller}) asyn

// TODO: Select accounts to enable push notifications
for (Account account in accounts) {
bool success = await sendAuthTokenToNotificationServer(type: NotificationType.apn, token: token, jwts: [account.jwt!], instance: account.instance!);
bool success = await sendAuthTokenToNotificationServer(type: NotificationType.apn, token: token, jwt: account.jwt!, instance: account.instance!);
if (!success) debugPrint("Failed to send device token to server for account ${account.id}. Skipping.");
}

Expand All @@ -49,7 +48,7 @@ void initAPNs({required StreamController<NotificationResponse> controller}) asyn

// TODO: Select accounts to enable push notifications
for (Account account in accounts) {
bool success = await sendAuthTokenToNotificationServer(type: NotificationType.apn, token: token, jwts: [account.jwt!], instance: account.instance!);
bool success = await sendAuthTokenToNotificationServer(type: NotificationType.apn, token: token, jwt: account.jwt!, instance: account.instance!);
if (!success) debugPrint("Failed to send device token to server for account ${account.id}. Skipping.");
}
});
Expand All @@ -59,14 +58,20 @@ void initAPNs({required StreamController<NotificationResponse> controller}) asyn
if (data == null) return;

if (data.containsKey(repliesGroupKey)) {
controller.add(NotificationResponse(payload: data[repliesGroupKey] as String, notificationResponseType: NotificationResponseType.selectedNotification));
controller.add(NotificationResponse(
payload: data[repliesGroupKey] as String,
notificationResponseType: NotificationResponseType.selectedNotification,
));
}
});

/// Handle notification taps. This triggers when the user taps on a notification when the app is on the foreground or background.
Push.instance.onNotificationTap.listen((data) {
if (data.containsKey(repliesGroupKey)) {
controller.add(NotificationResponse(payload: data[repliesGroupKey] as String, notificationResponseType: NotificationResponseType.selectedNotification));
controller.add(NotificationResponse(
payload: data[repliesGroupKey] as String,
notificationResponseType: NotificationResponseType.selectedNotification,
));
}
});
}
1 change: 0 additions & 1 deletion lib/notification/utils/local_notifications.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ Future<void> pollRepliesAndShowNotifications() async {
title: generateUserFullName(null, commentReplyView.creator.name, fetchInstanceNameFromUrl(commentReplyView.creator.actorId), userSeparator: userSeparator),
content: plaintextComment,
payload: '$repliesGroupKey-${commentReplyView.comment.id}',
summaryText: generateUserFullName(null, commentReplyView.recipient.name, fetchInstanceNameFromUrl(commentReplyView.recipient.actorId), userSeparator: userSeparator),
);
}
}
Expand Down
4 changes: 1 addition & 3 deletions lib/notification/utils/unified_push.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void initUnifiedPushNotifications({required StreamController<NotificationRespons

// TODO: Select accounts to enable push notifications
for (Account account in accounts) {
bool success = await sendAuthTokenToNotificationServer(type: NotificationType.unifiedPush, token: endpoint, jwts: [account.jwt!], instance: account.instance!);
bool success = await sendAuthTokenToNotificationServer(type: NotificationType.unifiedPush, token: endpoint, jwt: account.jwt!, instance: account.instance!);
if (!success) debugPrint("Failed to send device token to server for account ${account.id}. Skipping.");
}
},
Expand Down Expand Up @@ -97,7 +97,6 @@ void initUnifiedPushNotifications({required StreamController<NotificationRespons
title: generateUserFullName(null, commentReplyView.creator.name, fetchInstanceNameFromUrl(commentReplyView.creator.actorId), userSeparator: userSeparator),
content: plaintextComment,
payload: '$repliesGroupKey-${commentReplyView.comment.id}',
summaryText: generateUserFullName(null, commentReplyView.recipient.name, fetchInstanceNameFromUrl(commentReplyView.recipient.actorId), userSeparator: userSeparator),
);
}

Expand Down Expand Up @@ -126,7 +125,6 @@ void initUnifiedPushNotifications({required StreamController<NotificationRespons
title: generateUserFullName(null, personMentionView.creator.name, fetchInstanceNameFromUrl(personMentionView.creator.actorId), userSeparator: userSeparator),
content: plaintextComment,
payload: '$repliesGroupKey-${personMentionView.comment.id}',
summaryText: generateUserFullName(null, personMentionView.recipient.name, fetchInstanceNameFromUrl(personMentionView.recipient.actorId), userSeparator: userSeparator),
);
}

Expand Down
Loading

0 comments on commit 34893f1

Please sign in to comment.