import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/modules/cx_module/chat/model/call_session.dart'; import 'package:test_sa/modules/cx_module/chat/call/video_call_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; class AudioCallPage extends StatefulWidget { const AudioCallPage({Key? key}) : super(key: key); @override State createState() => _AudioCallPageState(); } class _AudioCallPageState extends State { @override void initState() { super.initState(); // Initialize call on page load WidgetsBinding.instance.addPostFrameCallback((_) { // Will be implemented when connecting to provider }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.backgroundTabBarDark, appBar: const DefaultAppBar( backgroundColor: Colors.transparent, arrowBackColor: AppColor.white10, ), body: SafeArea( child: Selector( selector: (_, provider) => provider.currentCall, builder: (context, session, _) { if (session == null) { return const Center(child: Text('No active call')); } return Column( children: [ const Spacer(flex: 2), _buildContactInfo(context, session), 8.height, _buildCallStatusOrDuration(context), const Spacer(flex: 4), _buildControls(context, session), 32.height, ], ); }, ), ), ); } Widget _buildContactInfo(BuildContext context, CallSession session) { return Column( children: [ Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( shape: BoxShape.circle, color: AppColor.whiteF8d, //TODO need to check opacity border: Border.all(color: AppColor.white10.withOpacity(0.2), width: 1), ), child: ClipOval( child: session.peerAvatar != null ? CachedNetworkImage( imageUrl: session.peerAvatar!, fit: BoxFit.cover, placeholder: (context, url) => Center( child: CircularProgressIndicator( color: Colors.white.withOpacity(0.5), ), ), errorWidget: (context, url, error) => 'call_user_avatar'.toSvgAsset(height: 48, width: 48), ) : 'call_user_avatar'.toSvgAsset(height: 48, width: 48), ), ), 24.height, Text( session.peerName, style: AppTextStyles.heading2.copyWith( color: Colors.white, fontWeight: FontWeight.w600, ), textAlign: TextAlign.center, ), ], ); } Widget _buildCallStatusOrDuration(BuildContext context) { return Selector( selector: (_, provider) => provider.callStatus, builder: (context, status, _) { String statusText; switch (status) { case CallStatus.outgoingRinging: statusText = 'Calling...'; break; case CallStatus.incomingRinging: statusText = 'Incoming call...'; break; case CallStatus.connecting: statusText = 'Connecting...'; break; case CallStatus.connected: return _buildDuration(context); default: statusText = ''; } return Text( statusText, style: AppTextStyles.heading5.copyWith( color: AppColor.neutral100, ), ); }, ); } Widget _buildDuration(BuildContext context) { return Selector( selector: (_, provider) => provider.callDuration, builder: (context, duration, _) { if (duration.inSeconds == 0) { return const SizedBox.shrink(); } String twoDigits(int n) => n.toString().padLeft(2, '0'); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white.withAlpha(51), borderRadius: BorderRadius.circular(20), ), child: Text( '$minutes:$seconds', style: AppTextStyles.heading5.copyWith( color: AppColor.neutral100, fontWeight: FontWeight.w400, ), ), ); }, ); } Widget _buildControls(BuildContext context, CallSession session) { final chatProvider = context.read(); return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Selector( selector: (_, provider) => provider.isMuted, builder: (context, isMuted, _) { return _buildControlButton( icon: isMuted ? 'mic_disable' : 'mic_enable', label: isMuted ? 'Unmute' : 'Mute', isActive: isMuted, onPressed: () { chatProvider.toggleMute(); }, ); }, ), _buildControlButton( icon: 'video_call_icon', label: 'Video', isActive: false, onPressed: () { // Switch to video call view Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => const VideoCallPage(), ), ); }, ), Selector( selector: (_, provider) => provider.isSpeakerOn, builder: (context, isSpeakerOn, _) { return _buildControlButton( icon: 'speaker_enable', label: 'Speaker', isActive: isSpeakerOn, onPressed: () { chatProvider.toggleSpeaker(); }, ); }, ), ], ), 48.height, _buildEndCallButton(context, chatProvider), ], ); } Widget _buildControlButton({ required String icon, required String label, required bool isActive, required VoidCallback onPressed, }) { return Column( children: [ Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration(color: isActive ? AppColor.primary10 : AppColor.black2E, shape: BoxShape.circle, border: BoxBorder.all(color: AppColor.white10.withOpacity(0.2))), child: icon.toSvgAsset(width: 24, height: 24, color: AppColor.white10), ).onPress(() { onPressed(); }), 8.height, Text( label, style: AppTextStyles.heading5.copyWith(color: AppColor.neutral100, fontWeight: FontWeight.w400), ), ], ); } Widget _buildEndCallButton(BuildContext context, ChatProvider provider) { return Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( color: AppColor.red30, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), alignment: Alignment.center, child: 'end_call'.toSvgAsset(height: 32, width: 32, color: AppColor.white10), ).onPress(() async { await provider.hangUp(); if (mounted) { Navigator.pop(context); } }); } }