63 lines
2.2 KiB
Dart
63 lines
2.2 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
|
|
import 'push_actions.dart';
|
|
import 'push_target.dart';
|
|
|
|
/// Routes foreground notification interactions from the single
|
|
/// flutter_local_notifications response callback. Action responses (reply /
|
|
/// mark-read) are dispatched straight to [PushActions]; a plain tap publishes
|
|
/// its target via [pendingTarget] for [App] to navigate to.
|
|
class PushTapRouter {
|
|
PushTapRouter._();
|
|
|
|
/// Target of the most recently tapped notification, or null. [App] listens
|
|
/// to this and navigates, then resets it to null.
|
|
static final ValueNotifier<PushTarget?> pendingTarget = ValueNotifier(null);
|
|
|
|
static void handleResponse(NotificationResponse response) {
|
|
final actionId = response.actionId;
|
|
if (actionId == kTalkReplyActionId || actionId == kTalkMarkReadActionId) {
|
|
// Reuse the isolate-safe action dispatch for foreground actions too.
|
|
PushActions.handleBackgroundResponse(response);
|
|
return;
|
|
}
|
|
final map = _payloadMap(response.payload);
|
|
if (map == null) return;
|
|
final target = resolvePushTarget(map);
|
|
if (target != null) pendingTarget.value = target;
|
|
}
|
|
|
|
static bool _launchHandled = false;
|
|
|
|
/// Routes the tap that cold-started the app. The plugin reports such a tap
|
|
/// only through its launch details, never through the response callback;
|
|
/// the details stay set for the whole process, hence the one-shot guard.
|
|
static Future<void> handleAppLaunch(
|
|
FlutterLocalNotificationsPlugin plugin,
|
|
) async {
|
|
if (_launchHandled) return;
|
|
_launchHandled = true;
|
|
try {
|
|
final details = await plugin.getNotificationAppLaunchDetails();
|
|
final response = details?.notificationResponse;
|
|
if (details?.didNotificationLaunchApp != true || response == null) return;
|
|
handleResponse(response);
|
|
} on Object catch (e) {
|
|
log('Reading the notification launch details failed: $e');
|
|
}
|
|
}
|
|
|
|
static Map<String, dynamic>? _payloadMap(String? payload) {
|
|
if (payload == null || payload.isEmpty) return null;
|
|
try {
|
|
return jsonDecode(payload) as Map<String, dynamic>;
|
|
} on Object {
|
|
return null;
|
|
}
|
|
}
|
|
}
|