some time its show again same call when user pick or decline the call , i also check the call length and firebase message coming time ,why its happened can you resolve this ?
my code is
// ignore_for_file: use_build_context_synchronously
import 'dart:convert';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State createState() => _HomePageState();
}
class _HomePageState extends State with WidgetsBindingObserver {
int _currentIndex = 0;
final JwtRepoImpl _jwtRepoImpl = JwtRepoImpl();
final PageController _pageController = PageController(initialPage: 0);
CollectionReference callRef = FirebaseFirestore.instance.collection("calls");
late final Uuid _uuid;
String? currentUuid;
// Set to store notification IDs that have been displayed
Set<String?> shownNotificationForegroundIds = {};
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
// debugPrint('User granted permission');
} else if (settings.authorizationStatus ==
AuthorizationStatus.provisional) {
// debugPrint('User granted provisional permission');
} else {
// debugPrint('User declined or has not accepted permission');
}
// when user tap on msg fron terminated state
FirebaseMessaging.instance.getInitialMessage().then((message) async {
// debugPrint("RemoteMessage ${message?.data}");
// Generate a unique notification ID
String? notificationId = message?.messageId;
// Check if the notification ID has already been shown
if (shownNotificationForegroundIds.contains(notificationId)) {
// If the ID has already been shown, do not process the notification
return;
}
// Add the notification ID to the set of shown notification IDs
shownNotificationForegroundIds.add(notificationId);
if (message != null) {
bool iscallling =
await NotificationData.checkcallState(message.data['channel_id']);
if (message.data['type'] == 'Call' && iscallling) {
debugPrint("how much time called background");
NotificationData.showCallkitIncoming(
message.data['channel_id'],
message.data['senderName'],
message.notification?.body,
message.data['senderPicture'],
message.data['duration'],
message.data['time'],
currentUuid!);
} else if (message.data['type'] == 'Call' && !iscallling) {
Navigator.pushReplacementNamed(context, AppPaths.home,
arguments: "notification");
} else {
MapMarkersModel second = MapMarkersModel(
name: message.data['senderName'],
picture: message.data['senderPicture'],
userId: message.data['userId'],
deviceName: message.data['device']);
String? jwTtoken = await _jwtRepoImpl.fetchJwtToken();
var result = await UserDetailsImpl().userDetails(token: jwTtoken);
final currentUser = UserModel.fromJson(result);
Provider.of<UserProvider>(context, listen: false).mainUser =
currentUser;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatPage(
fromMap: false,
currentUser:
Provider.of<UserProvider>(context, listen: false)
.mainUser!,
second: second,
)));
}
} else {}
});
// when user tap on notification in background state
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
debugPrint("background mode ${message.data['channel_id']}");
// Generate a unique notification ID
String? notificationId = message.messageId;
// Check if the notification ID has already been shown
if (shownNotificationForegroundIds.contains(notificationId)) {
// If the ID has already been shown, do not process the notification
return;
}
// Add the notification ID to the set of shown notification IDs
shownNotificationForegroundIds.add(notificationId);
bool iscallling =
await NotificationData.checkcallState(message.data['channel_id']);
if (message.data['type'] == 'Call' && iscallling) {
debugPrint("how much time called background opened");
NotificationData.showCallkitIncoming(
message.data['channel_id'],
message.data['senderName'],
message.notification?.body,
message.data['senderPicture'],
message.data['duration'],
message.data['time'],
currentUuid!);
// Handle the call based on the call type
} else if (message.data['type'] == 'Call' && !iscallling) {
Navigator.pushReplacementNamed(context, AppPaths.home,
arguments: "notification");
} else {
MapMarkersModel second = MapMarkersModel(
name: message.data['senderName'],
picture: message.data['senderPicture'],
userId: message.data['userId'],
deviceName: message.data['device']);
debugPrint("notification data is ${second.userId}");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatPage(
fromMap: false,
currentUser:
Provider.of<UserProvider>(context, listen: false)
.mainUser!,
second: second,
)));
}
});
// when app is opened
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
debugPrint("foreground mode ${message.data['channel_id']}");
debugPrint(
'Message title: ${message.notification?.title}, body: ${message.notification?.body}, data: ${message.data}');
// Generate a unique notification ID
String? notificationId = message.messageId;
// Check if the notification ID has already been shown
if (shownNotificationForegroundIds.contains(notificationId)) {
// If the ID has already been shown, do not process the notification
return;
}
// Add the notification ID to the set of shown notification IDs
shownNotificationForegroundIds.add(notificationId);
if (message.data['type'] == 'Call') {
debugPrint("how much time called foreground");
NotificationData.showCallkitIncoming(
message.data['channel_id'],
message.data['senderName'],
message.notification?.body,
message.data['senderPicture'],
message.data['duration'],
message.data['time'],
currentUuid!);
} else {
ForegroundNotification.showForegroundNotification(message, context);
}
});
Future getCurrentCall() async {
//check current call from pushkit if possible
var calls = await FlutterCallkitIncoming.activeCalls();
debugPrint('calls$calls');
if (calls is List) {
if (calls.isNotEmpty) {
debugPrint("call length is ${calls.length}");
currentUuid = calls[0]['id'];
return calls[0];
} else {
currentUuid = "";
return;
}
}
}
// add your page for calling in bottom navigation bar
some time its show again same call when user pick or decline the call , i also check the call length and firebase message coming time ,why its happened can you resolve this ? my code is // ignore_for_file: use_build_context_synchronously import 'dart:convert';
import 'package:agora_uikit/agora_uikit.dart'; import 'package:bspotz/app/modules/authentication/datasource/models/main_user.dart'; import 'package:bspotz/app/modules/authentication/presentation/providers/user_provider.dart'; import 'package:bspotz/app/modules/explore/datasource/model/map_markers_model.dart'; import 'package:bspotz/app/modules/explore/presentation/pages/explore_map.dart'; import 'package:bspotz/app/modules/home/presentation/pages/main_events_page.dart'; import 'package:bspotz/app/modules/profile/presentation/pages/user_profile.dart'; import 'package:bspotz/app/modules/subscribedevent/presentation/pages/subscribed_events_page.dart'; import 'package:bspotz/app/modules/userDetails/presentation/bloc/user_details_bloc.dart'; import 'package:bspotz/app/modules/wallet/presentation/pages/wallet_details_screen.dart'; import 'package:bspotz/app/widgets/custom_snackbar.dart'; import 'package:bspotz/core/routes/app_paths.dart'; import 'package:bspotz/core/utils/foreground_notification.dart'; import 'package:bspotz/core/utils/show_case_repo.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_callkit_incoming/entities/call_event.dart'; import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; import 'package:provider/provider.dart'; import 'package:uuid/uuid.dart';
// ignore: depend_on_referenced_packages import '../../../calling/presentation/pages/call.dart'; import '../../../chat/datasource/firebase_messeging_repo.dart'; import '../../../chat/presentation/screens/chat_page.dart'; import '../../../explore/presentation/bloc/fetch_location_bloc.dart'; import '../../../registration/datasource/repo/jwt_repo.dart'; import '../../../userDetails/datasource/repo/user_details_repo.dart'; import '../../datasource/repo/notification.dart'; import '../widgets/bottom_navigation.dart';
@pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
debugPrint("Handling a background message: ${message.messageId}");
if (message.data['type'] == 'Call') { NotificationData.showCallkitIncoming( message.data['channel_id'], message.data['senderName'], message.notification?.body, message.data['senderPicture'], message.data['duration'], message.data['time'], const Uuid().v4(), ); } }
var fcmInstance = FirebaseMessaging.instance;
class HomePage extends StatefulWidget { const HomePage({super.key});
@override State createState() => _HomePageState();
}
class _HomePageState extends State with WidgetsBindingObserver {
int _currentIndex = 0;
final JwtRepoImpl _jwtRepoImpl = JwtRepoImpl();
final PageController _pageController = PageController(initialPage: 0);
CollectionReference callRef = FirebaseFirestore.instance.collection("calls");
late final Uuid _uuid;
String? currentUuid;
// Set to store notification IDs that have been displayed
Set<String?> shownNotificationForegroundIds = {};
@override void initState() { _uuid = const Uuid(); currentUuid = ""; context.read().add(RequestUserDetails());
WidgetsBinding.instance.addObserver(this);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}
@override void dispose() { WidgetsBinding.instance.removeObserver(this); _pageController.dispose();
}
initFirebase(BuildContext context) async { await Firebase.initializeApp(); await fcmInstance.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true); currentUuid = _uuid.v4(); NotificationSettings settings = await fcmInstance.requestPermission( alert: true, announcement: false, badge: true, carPlay: false, criticalAlert: false, provisional: false, sound: true, );
}
String textEvents = ""; onEvent(event) { if (!mounted) return; setState(() { textEvents += "${event.toString()}\n"; }); }
// For listening event fron callkit incoming Future listenerEvent(Function? callback) async {
try {
FlutterCallkitIncoming.onEvent.listen((event) async {
debugPrint('HOME: $event');
}
// For checking user has granted notification permission or not Future checkNotificationPermission() async {
NotificationSettings settings = await fcmInstance.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
}
// When user pick the call from terminated state
checkAndNavigationCallingPageFromTerminated() async { var currentCall = await getCurrentCall(); bool isPermissionallowed = await checkNotificationPermission();
}
// when user pick the call from opened app or background to navigate on call screen
Future checkAndNavigationCallingPage(
String channelId, String callType, String callDurationInSec) async {
var currentCall = await getCurrentCall();
if (currentCall != null) {
Map<String, dynamic> callTimeMap = Map<String, dynamic>.from(
json.decode(currentCall['extra']['callTime']));
DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(callTimeMap['_seconds'] * 1000);
if (DateTime.now().difference(dateTime).inSeconds >= 0 &&
DateTime.now().difference(dateTime).inSeconds <= 20) {
debugPrint('call not expired');
await callRef.doc(channelId).update({'response': "Pickup"});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CallPage(
currentUuid: currentUuid!,
imageurl: currentCall['avatar'],
callDurationInSec: int.parse(callDurationInSec),
callType: callType,
channelName: channelId,
role: ClientRoleType.clientRoleAudience,
)));
} else {
debugPrint('call expired');
await callRef
.doc(currentCall['extra']['channelId'])
.update({'response': 'Not-answer'});
await FlutterCallkitIncoming.endCall(currentCall['id']);
await FlutterCallkitIncoming.endAllCalls();
}
} else {
debugPrint('call null');
}
}
Future getCurrentCall() async {
//check current call from pushkit if possible
var calls = await FlutterCallkitIncoming.activeCalls();
debugPrint('calls$calls');
if (calls is List) {
if (calls.isNotEmpty) {
debugPrint("call length is ${calls.length}");
currentUuid = calls[0]['id'];
return calls[0];
} else {
currentUuid = "";
return;
}
}
}
// add your page for calling in bottom navigation bar
final List _pages = [
AllEventsPage(
searchShowCase: ShowCaseRepo.searchShowCase,
languageShowCase: ShowCaseRepo.languageShowCase,
drawerShowCase: ShowCaseRepo.drawerShowCase,
),
const EventListPage(),
ExploreScreen(
searchUserKey: ShowCaseRepo.searchUserShowCase,
),
WalletDetailScreen(
walletrefreshCase: ShowCaseRepo.walletRefershCase,
paybuttonShowCase: ShowCaseRepo.paybuttonShowCase,
),
const UserProfileScreen()
];
// for handing and changing page content ontap of tab
void onTabTapped(int index) async { switch (index) { case 0: WidgetsBinding.instance.addPostFrameCallback(() { ShowCaseRepo.callShowCase( context: context, showcaseKey: "homePage", widgetIds: [ ShowCaseRepo.drawerShowCase, ShowCaseRepo.searchShowCase, ShowCaseRepo.languageShowCase ]); });
}
@override Widget build(BuildContext context) { return BlocListener<UserDetailsBloc, UserDetailsState>( listener: (context, state) { if (state is UserDetailsSuccess) { final currentUser = UserModel.fromJson(state.result); Provider.of(context, listen: false).mainUser =
currentUser;
bool isEnabled = Provider.of(context, listen: false)
.mainUser
?.showOnMap ??
false;
if (isEnabled) {
context.read().add(ListenLocationStream());
}
debugPrint(" user id is ${UserModel.fromJson(state.result).userId}");
fcmInstance.getToken().then((token) async {
// debugPrint('token $token');
try {
if (!currentUser.fcmTokens.contains(token)) {
String? jwTtoken = await _jwtRepoImpl.fetchJwtToken();
await FCMRepositoryImpl().updateFCMToken(
token: jwTtoken!, body: {'fcmToken': token});
debugPrint('Device Token FCM: $token');
}
} catch (e) {
debugPrint(e.toString());
}
});
}
if (state is UserDetailsFailed) {
CustomSnackbar.showSnackBar(state.msg, context);
}
},
child: PopScope(
canPop: false,
child: Scaffold(
body: IndexedStack(
index: _currentIndex,
children: _pages,
),
bottomNavigationBar: CustomBottomNavigationBar(
currentIndex: _currentIndex,
onTabTapped: _onTabTapped,
),
),
),
);
}
}