71 lines
2.7 KiB
Dart
71 lines
2.7 KiB
Dart
import 'dart:developer';
|
|
|
|
import 'package:eraser/eraser.dart';
|
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_app_badge/flutter_app_badge.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../routing/app_routes.dart';
|
|
import '../state/app/modules/chat_list/bloc/chat_list_bloc.dart';
|
|
import 'notification_service.dart';
|
|
|
|
class NotificationTasks {
|
|
static void updateBadgeCount(RemoteMessage notification) {
|
|
FlutterAppBadge.count(
|
|
int.parse((notification.data['unreadCount'] as String?) ?? '0'),
|
|
);
|
|
}
|
|
|
|
/// Per-chat tag scheme. MUST match the Notify backend, which sets this
|
|
/// value on `AndroidNotification.setTag` AND `apns-collapse-id`.
|
|
static String chatTag(String chatToken) => 'talk_$chatToken';
|
|
|
|
/// Removes tray notifications belonging to [chatToken]. Eraser handles
|
|
/// iOS (where the plugin's `getActiveNotifications` returns null ids
|
|
/// for FCM posts and can't cancel them); the local-notifications sweep
|
|
/// handles Android and acts as a fallback while Eraser's native side
|
|
/// isn't built in yet.
|
|
static Future<void> clearNotificationsForChat(String chatToken) async {
|
|
final tag = chatTag(chatToken);
|
|
try {
|
|
await Eraser.clearAppNotificationsByTag(tag);
|
|
} on MissingPluginException {
|
|
// Eraser native code not yet linked — needs flutter clean + run.
|
|
} on Object catch (e) {
|
|
log('Eraser($tag) failed: $e');
|
|
}
|
|
try {
|
|
final plugin = NotificationService().flutterLocalNotificationsPlugin;
|
|
final actives = await plugin.getActiveNotifications();
|
|
for (final n in actives) {
|
|
final id = n.id;
|
|
if (id == null) continue;
|
|
if (n.tag == tag) await plugin.cancel(id: id, tag: n.tag);
|
|
}
|
|
} on Object catch (e) {
|
|
log('Active-notification sweep failed: $e');
|
|
}
|
|
}
|
|
|
|
/// Refreshes the chat list. Deliberately does NOT touch [ChatBloc] —
|
|
/// the open chat view manages its own state via long-poll, and refreshing
|
|
/// it here would re-fetch the last-opened chat with setReadMarker=on
|
|
/// even if the user has already left.
|
|
static void updateProviders(BuildContext context) {
|
|
context.read<ChatListBloc>().refresh();
|
|
}
|
|
|
|
/// Switches to the Talk tab. If [chatToken] is provided, also schedules
|
|
/// the matching chat to be opened automatically once the chat list view
|
|
/// resolves the token (handled inside [ChatList]).
|
|
static void navigateToTalk(BuildContext context, {String? chatToken}) {
|
|
if (chatToken != null && chatToken.isNotEmpty) {
|
|
AppRoutes.openChatByToken(context, chatToken);
|
|
} else {
|
|
AppRoutes.goToTalkTab(context);
|
|
}
|
|
}
|
|
}
|