import 'dart:async'; import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_auth/firebase_auth.dart'; final GlobalKey navigatorKey = GlobalKey(); class WhatsAppNotificationService { static final WhatsAppNotificationService _instance = WhatsAppNotificationService._internal(); factory WhatsAppNotificationService() => _instance; WhatsAppNotificationService._internal(); StreamSubscription? _subscription; int _initTime = DateTime.now().millisecondsSinceEpoch; bool _isListening = false; void startListening() { if (_isListening) return; _isListening = true; _initTime = DateTime.now().millisecondsSinceEpoch; final db = FirebaseDatabase.instance.ref(); _subscription = db.child("notifikasi").orderByChild("timestamp").startAt(_initTime).onChildAdded.listen((event) { final data = event.snapshot.value as Map?; if (data != null && data['timestamp'] != null) { // Ensure it's strictly newer than initTime to avoid immediate trigger if (data['timestamp'] > _initTime) { if (navigatorKey.currentContext != null) { _showNotification(navigatorKey.currentContext!, data['title'] ?? 'Pemberitahuan', data['message'] ?? ''); } } } }); } void stopListening() { _subscription?.cancel(); _isListening = false; } void showNotification(BuildContext context, String title, String message) { _showNotification(context, title, message); } void _showNotification(BuildContext context, String title, String message) { final overlay = navigatorKey.currentState?.overlay ?? Overlay.of(context); late OverlayEntry overlayEntry; overlayEntry = OverlayEntry( builder: (overlayContext) => Positioned( top: MediaQuery.of(overlayContext).padding.top + 10, left: 10, right: 10, child: Material( color: Colors.transparent, child: TweenAnimationBuilder( tween: Tween(begin: const Offset(0, -1), end: Offset.zero), duration: const Duration(milliseconds: 400), curve: Curves.easeOutBack, builder: (overlayContext, offset, child) { return FractionalTranslation( translation: offset, child: child, ); }, child: GestureDetector( onVerticalDragUpdate: (details) { if (details.primaryDelta! < -5) { overlayEntry.remove(); } }, onTap: () { overlayEntry.remove(); Navigator.pushNamed(context, '/notifikasi'); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 15, offset: const Offset(0, 5), ) ] ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: title.toLowerCase().contains("bahaya") ? Colors.red.withOpacity(0.1) : const Color(0xFF2E7D5B).withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( title.toLowerCase().contains("bahaya") ? Icons.warning_rounded : Icons.info_outline, color: title.toLowerCase().contains("bahaya") ? Colors.red : const Color(0xFF2E7D5B), size: 24, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ), const SizedBox(height: 4), Text( message, style: const TextStyle(color: Colors.black87, fontSize: 13), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ), ), ), ), ), ); overlay.insert(overlayEntry); // Auto remove after 4 seconds Future.delayed(const Duration(seconds: 4), () { if (overlayEntry.mounted) { overlayEntry.remove(); } }); } }