TKK_E32230502/lib/widgets/whatsapp_notification.dart

143 lines
5.2 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_auth/firebase_auth.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
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<dynamic, dynamic>?;
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<Offset>(
tween: Tween<Offset>(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();
}
});
}
}