2026-01-13 11:36:24 +05:30

439 lines
15 KiB
Dart

import 'package:awesome_snackbar_content/awesome_snackbar_content.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:onufitness/constants/asset_constants.dart';
import 'package:onufitness/constants/color_constant.dart';
import 'package:onufitness/constants/text_constant.dart';
import 'package:onufitness/routes/route_constant.dart';
import 'package:onufitness/screens/chat/controllers/chat_controller.dart';
import 'package:onufitness/services/agora/call_services.dart';
import 'package:onufitness/widgets/others/new_custom_sneakbar.dart';
Widget chatAppBar({
required BuildContext context,
required ChatController chatCtrl,
required String userId,
required String receiverName,
String? targetUserAvatarUrl,
bool showOnlineDot = false,
bool isGroupChat = false,
}) {
final agoraCallService = AgoraCallService.instance;
// Function to check if call can be made..............................................................................
void checkAndMakeCall(CallType callType) {
if (agoraCallService.callState.value != CallState.idle) {
AwesomeCustomSnackbar.show(
context: context,
title: 'Call In Progress',
message:
'You are already in a call. Please end the current call first.',
contentType: ContentType.warning,
);
return;
}
if (receiverName.isEmpty && userId.isEmpty) {
AwesomeCustomSnackbar.show(
context: context,
title: 'Invalid User',
message: 'Cannot initiate call. User information is not available.',
contentType: ContentType.warning,
);
return;
}
try {
agoraCallService.makeCall(
context: context,
targetUserId: userId,
targatedUserName: receiverName,
targatedUserProfilePic: targetUserAvatarUrl,
callType: callType,
);
} catch (e) {
AwesomeCustomSnackbar.show(
context: context,
title: 'Call Failed',
message: 'Unable to initiate call. Please try again later.',
contentType: ContentType.warning,
);
}
}
return Column(
children: [
// Call Indicator - Above the AppBar
Obx(() {
if (agoraCallService.callState.value == CallState.connected ||
agoraCallService.callState.value == CallState.calling ||
agoraCallService.callState.value == CallState.ringing) {
return Container(
width: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: _getCallGradientColors(
agoraCallService.callState.value,
),
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
boxShadow: [
BoxShadow(
color: _getCallStatusColor(
agoraCallService.callState.value,
).withValues(alpha: 0.3),
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _navigateToCallScreen(agoraCallService),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 15.w,
vertical: 12.h,
),
child: Row(
children: [
// Call Icon
Container(
padding: EdgeInsets.all(6.sp),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.2),
shape: BoxShape.circle,
),
child: Icon(
agoraCallService.currentCallType.value ==
CallType.video
? Icons.videocam
: Icons.call,
color: Colors.white,
size: 15.sp,
),
),
SizedBox(width: 12.w),
// Call Status and Details
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
_getCallStatusText(agoraCallService),
style: TextStyle(
color: Colors.white,
fontSize: smallSizeText,
fontWeight: FontWeight.w600,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
if (agoraCallService.callState.value ==
CallState.connected)
Obx(
() => Text(
_formatDuration(
agoraCallService.callDuration.value,
),
style: TextStyle(
color: Colors.white.withValues(alpha: 0.9),
fontSize: verySmallSizeText,
fontWeight: FontWeight.w400,
),
),
),
],
),
),
// Action Buttons
Row(
mainAxisSize: MainAxisSize.min,
children: [
// Return to Call Button
_buildActionButton(
icon: Icons.open_in_full,
onTap:
() => _navigateToCallScreen(agoraCallService),
tooltip: 'Return to call',
),
SizedBox(width: 8),
// End Call Button (only show for connected calls)
if (agoraCallService.callState.value ==
CallState.connected)
_buildActionButton(
icon: Icons.call_end,
onTap: () => agoraCallService.endCall(),
tooltip: 'End call',
isDestructive: true,
),
],
),
],
),
),
),
),
);
}
return SizedBox.shrink();
}),
// Main AppBar content
Container(
padding: EdgeInsets.only(top: 15.h, bottom: 10.h),
decoration: BoxDecoration(
color: Color(primaryColor),
image: DecorationImage(
image: AssetImage(AssetConstants.chatAppBarBackgroundImage),
fit: BoxFit.cover,
opacity: 0.5,
),
),
child: Row(
children: [
IconButton(
icon: Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () async {
Get.back();
chatCtrl.selectedUserId.value = "";
await chatCtrl.markAllMessagesAsRead(userId);
await chatCtrl.unsuscribePresence(userId);
},
),
// User Avatar with Online Indicator
Stack(
children: [
CircleAvatar(
radius: 20.r,
backgroundColor: Colors.grey.shade300,
backgroundImage:
(targetUserAvatarUrl != null &&
targetUserAvatarUrl.isNotEmpty)
? NetworkImage(targetUserAvatarUrl)
: null,
child:
(targetUserAvatarUrl == null ||
targetUserAvatarUrl.isEmpty)
? Text(
receiverName.isNotEmpty
? receiverName[0].toUpperCase()
: 'U',
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
)
: null,
),
// if (showOnlineDot && !isGroupChat)
// Positioned(
// right: 2,
// bottom: 2,
// child: Container(
// width: 12,
// height: 12,
// decoration: BoxDecoration(
// color: Colors.green,
// shape: BoxShape.circle,
// border: Border.all(color: Colors.white, width: 2),
// ),
// ),
// ),
],
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
receiverName.isNotEmpty ? receiverName : "Unknown User",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: smallSizeText,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
if (!isGroupChat)
Text(
showOnlineDot ? "Online" : "Last seen recently",
style: TextStyle(
fontSize: verySmallSizeText,
color: showOnlineDot ? Colors.green : Colors.grey,
fontWeight: FontWeight.w400,
),
),
],
),
),
// Action Buttons
Obx(() {
bool isCallActive =
agoraCallService.callState.value != CallState.idle;
return Padding(
padding: EdgeInsets.only(right: 15.sp),
child: Row(
children: [
if (!isGroupChat && chatCtrl.isMyFriend.value)
AppBarAction(
icon: Icons.call,
onPressed: () => checkAndMakeCall(CallType.voice),
isEnabled: showOnlineDot && !isCallActive,
),
if (!isGroupChat && chatCtrl.isMyFriend.value)
AppBarAction(
icon: Icons.videocam,
onPressed: () => checkAndMakeCall(CallType.video),
isEnabled: showOnlineDot && !isCallActive,
),
],
),
);
}),
],
),
),
],
);
}
// Helper function to navigate to appropriate call screen
void _navigateToCallScreen(AgoraCallService agoraCallService) {
final callState = agoraCallService.callState.value;
if (callState == CallState.connected) {
Get.toNamed(RouteConstant.activeCallScreen);
} else if (callState == CallState.calling) {
Get.toNamed(RouteConstant.outgoingCallScreen);
} else if (callState == CallState.ringing) {
Get.toNamed(RouteConstant.incomingCallScreen);
}
}
// Helper function to get call gradient colors
List<Color> _getCallGradientColors(CallState callState) {
switch (callState) {
case CallState.connected:
return [Color(0xFF4CAF50), Color(0xFF66BB6A)];
case CallState.calling:
return [Color(0xFFFF9800), Color(0xFFFFB74D)];
case CallState.ringing:
return [Color(0xFF2196F3), Color(0xFF64B5F6)];
default:
return [Colors.grey, Colors.grey.shade400];
}
}
// Helper function to get call status color
Color _getCallStatusColor(CallState callState) {
switch (callState) {
case CallState.connected:
return Color(0xFF4CAF50);
case CallState.calling:
return Color(0xFFFF9800);
case CallState.ringing:
return Color(0xFF2196F3);
default:
return Colors.grey;
}
}
// Helper function to build action buttons
Widget _buildActionButton({
required IconData icon,
required VoidCallback onTap,
required String tooltip,
bool isDestructive = false,
}) {
return Tooltip(
message: tooltip,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(20),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color:
isDestructive
? Colors.red.withValues(alpha: 0.2)
: Colors.white.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(20),
),
child: Icon(
icon,
color: isDestructive ? Colors.red.shade100 : Colors.white,
size: 15.sp,
),
),
),
);
}
// Helper function to get call status text
String _getCallStatusText(AgoraCallService agoraCallService) {
switch (agoraCallService.callState.value) {
case CallState.calling:
return 'Calling ${agoraCallService.callerName.value}...';
case CallState.ringing:
return 'Incoming call from ${agoraCallService.callerName.value}';
case CallState.connected:
return 'On call with ${agoraCallService.callerName.value}';
default:
return '';
}
}
// Helper function to format call duration
String _formatDuration(int seconds) {
int hours = seconds ~/ 3600;
int minutes = (seconds % 3600) ~/ 60;
int remainingSeconds = seconds % 60;
if (hours > 0) {
return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}';
}
return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}';
}
// App Bar Action Widget
class AppBarAction extends StatelessWidget {
final IconData icon;
final VoidCallback onPressed;
final bool isEnabled;
const AppBarAction({
super.key,
required this.icon,
required this.onPressed,
this.isEnabled = true,
});
@override
Widget build(BuildContext context) {
return IconButton(
// icon: Icon(icon, color: isEnabled ? Colors.black : Colors.grey.shade500),
icon: Icon(icon, color: Colors.black),
onPressed: onPressed,
);
}
}
//............................................................................................................................