Phase 3.1 WS2: FCM fallback Flutter + CC, unread badges, dynamic ping

- Control center: add mitra ping config UI (require ping toggle + interval)
- Mitra app StatusNotifier: honor require_ping and ping_interval_seconds
  from API; skip heartbeat when ping not required
- Both apps: update notification services for FCM deep-linking
  - mitra_app: handle chat_request (open_accept), session_closing
  - client_app: handle session_closing, paired
- Unread badge providers:
  - mitra_app: UnreadSessions provider (polls active-with-unread, badge
    on active sessions button)
  - client_app: UnreadCount provider (polls active-with-unread, badge
    on _ActiveSessionCard)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 14:29:06 +08:00
parent ed765d230c
commit 229f889551
10 changed files with 261 additions and 21 deletions

View File

@@ -84,12 +84,17 @@ class NotificationService {
}
static void _navigateFromMessage(Map<String, dynamic> data) {
if (_router == null) return;
final sessionId = data['session_id'] as String?;
if (sessionId == null || _router == null) return;
final type = data['type'] as String?;
if (type == 'chat_message' || type == 'chat_request') {
_router!.push('/chat/session/$sessionId');
if (type == 'session_closing' || type == 'session_expired') {
// Navigate to the chat session — closure UI will show
if (sessionId != null) {
_router!.push('/chat/session/$sessionId', extra: 'Bestie');
}
} else if ((type == 'chat_message' || type == 'paired') && sessionId != null) {
_router!.push('/chat/session/$sessionId', extra: 'Bestie');
}
}
}