diff --git a/assets/icons/chat/call.svg b/assets/icons/chat/call.svg new file mode 100644 index 0000000..843daf4 --- /dev/null +++ b/assets/icons/chat/call.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/chat/video_call.svg b/assets/icons/chat/video_call.svg new file mode 100644 index 0000000..2fceee6 --- /dev/null +++ b/assets/icons/chat/video_call.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index ff02c4d..f5d896c 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -49,8 +49,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { "${ApiConsts.chatServerBaseApiUrl}user/externaluserlogin", { "employeeNumber": int.parse( - AppState().memberInformationList!.eMPLOYEENUMBER.toString(), - // "" + //AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + "210919" ), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG" }, diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index c5788f9..ede22e3 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,7 +1,7 @@ class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server - //static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server + //static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index b38536c..948e5b4 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -275,7 +275,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void fetchChatCounts() async { - print("----------------------- Fetch Count ____________________________________"); try { ChatUnreadCovnCountModel response = await DashboardApiClient().getChatCount(); chatUConvCounter = response.singleChatCount!; diff --git a/lib/ui/chat/call/chat_call_screen.dart b/lib/ui/chat/call/chat_incoming_call_screen.dart similarity index 99% rename from lib/ui/chat/call/chat_call_screen.dart rename to lib/ui/chat/call/chat_incoming_call_screen.dart index 3fce65b..923a4bd 100644 --- a/lib/ui/chat/call/chat_call_screen.dart +++ b/lib/ui/chat/call/chat_incoming_call_screen.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:ui'; import 'package:camera/camera.dart'; diff --git a/lib/ui/chat/call/chat_outgoing_call_screen.dart b/lib/ui/chat/call/chat_outgoing_call_screen.dart new file mode 100644 index 0000000..b5a47a6 --- /dev/null +++ b/lib/ui/chat/call/chat_outgoing_call_screen.dart @@ -0,0 +1,470 @@ +import 'dart:ui'; + +import 'package:camera/camera.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/models/chat/call.dart'; + +class OutGoingCall extends StatefulWidget { + IncomingCallData OutGoingCallData; + bool? isVideoCall; + + OutGoingCall({Key? key, required this.OutGoingCallData, this.isVideoCall}) : super(key: key); + + @override + _OutGoingCallState createState() => _OutGoingCallState(); +} + +class _OutGoingCallState extends State with SingleTickerProviderStateMixin { + AnimationController? _animationController; + CameraController? _controller; + Future? _initializeControllerFuture; + bool isCameraReady = false; + bool isMicOff = false; + bool isLoudSpeaker = false; + bool isCamOff = false; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: const Duration( + milliseconds: 500, + ), + ); + //_runAnimation(); + // connectSignaling(); + WidgetsBinding.instance.addPostFrameCallback( + (_) => _runAnimation(), + ); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: FutureBuilder( + future: _initializeControllerFuture, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return Stack( + alignment: FractionalOffset.center, + children: [ + if (widget.isVideoCall!) + Positioned.fill( + child: AspectRatio( + aspectRatio: _controller!.value.aspectRatio, + child: CameraPreview( + _controller!, + ), + ), + ), + Positioned.fill( + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Container( + decoration: BoxDecoration( + color: MyColors.grey57Color.withOpacity( + 0.7, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + 40.height, + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + margin: const EdgeInsets.all(21.0), + child: Container( + margin: const EdgeInsets.only( + left: 10.0, + right: 10.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + SvgPicture.asset( + "assets/images/user.svg", + height: 70, + width: 70, + fit: BoxFit.cover, + ), + 10.height, + Text( + "Aamir Saleem Ahmad", + style: TextStyle( + fontSize: 21, + fontWeight: FontWeight.bold, + color: MyColors.white, + letterSpacing: -1.26, + height: 23 / 12, + ), + ), + Text( + "Ringing...", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color( + 0xffC6C6C6, + ), + letterSpacing: -0.48, + height: 23 / 24, + ), + ), + SizedBox( + height: 2, + ), + ], + ), + ), + ), + ], + ), + // Container( + // margin: const EdgeInsets.all(21.0), + // width: MediaQuery.of(context).size.width, + // decoration: cardRadius(15.0, color: MyColors.black, elevation: null), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // Container( + // padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 6.0), + // child: Text( + // "TranslationBase.of(context).appoInfo", + // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: MyColors.white, letterSpacing: -0.64, height: 23 / 12), + // ), + // ), + // Container( + // padding: const EdgeInsets.only(left: 16.0, right: 16.0), + // child: Text( + // "widget.OutGoingCallData.appointmentdate + widget.OutGoingCallData.appointmenttime", + // style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600), + // ), + // ), + // Container( + // padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 21.0), + // child: Text( + // "widget.OutGoingCallData.clinicname", + // style: TextStyle(fontSize: 12.0, letterSpacing: -0.48, color: Color(0xff8E8E8E), fontWeight: FontWeight.w600), + // ), + // ), + // ], + // ), + // ), + const Spacer(), + Container( + margin: const EdgeInsets.only( + bottom: 70.0, + left: 49, + right: 49, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (widget.isVideoCall!) + RotationTransition( + turns: Tween( + begin: 0.0, + end: -.1, + ) + .chain( + CurveTween( + curve: Curves.elasticIn, + ), + ) + .animate( + _animationController!, + ), + child: RawMaterialButton( + onPressed: () { + _camOff(); + }, + elevation: 2.0, + fillColor: isCamOff ? MyColors.green2DColor : Colors.grey, + padding: const EdgeInsets.all( + 15.0, + ), + shape: const CircleBorder(), + child: Icon( + isCamOff ? Icons.videocam_off : Icons.videocam, + color: MyColors.white, + size: 35.0, + ), + ), + ) + else + RotationTransition( + turns: Tween( + begin: 0.0, + end: -.1, + ) + .chain( + CurveTween( + curve: Curves.elasticIn, + ), + ) + .animate( + _animationController!, + ), + child: RawMaterialButton( + onPressed: () { + _loudOn(); + }, + elevation: 2.0, + fillColor: isLoudSpeaker ? MyColors.green2DColor : Colors.grey, + padding: const EdgeInsets.all( + 15.0, + ), + shape: const CircleBorder(), + child: const Icon( + Icons.volume_up, + color: MyColors.white, + size: 35.0, + ), + ), + ), + RotationTransition( + turns: Tween( + begin: 0.0, + end: -.1, + ) + .chain( + CurveTween( + curve: Curves.elasticIn, + ), + ) + .animate( + _animationController!, + ), + child: RawMaterialButton( + onPressed: () { + _micOff(); + }, + elevation: 2.0, + fillColor: isMicOff ? MyColors.green2DColor : Colors.grey, + padding: const EdgeInsets.all( + 15.0, + ), + shape: const CircleBorder(), + child: Icon( + isMicOff ? Icons.mic_off : Icons.mic, + color: MyColors.white, + size: 35.0, + ), + ), + ), + RawMaterialButton( + onPressed: () { + backToHome(); + }, + elevation: 2.0, + fillColor: MyColors.redA3Color, + padding: const EdgeInsets.all( + 15.0, + ), + shape: const CircleBorder(), + child: const Icon( + Icons.call_end, + color: MyColors.white, + size: 35.0, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ), + ], + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ); + } + + void _runAnimation() async { + List cameras = await availableCameras(); + CameraDescription firstCamera = cameras[1]; + _controller = CameraController( + firstCamera, + ResolutionPreset.medium, + ); + _initializeControllerFuture = _controller!.initialize(); + setState(() {}); + // setAudioFile(); + for (int i = 0; i < 100; i++) { + await _animationController!.forward(); + await _animationController!.reverse(); + } + } + + void _micOff() { + setState(() { + isMicOff = !isMicOff; + }); + } + + void _camOff() { + setState(() { + isCamOff = !isCamOff; + }); + } + + void _loudOn() { + setState(() { + isLoudSpeaker = !isLoudSpeaker; + }); + } + + Future _submit() async { + try { + // backToHome(); + // final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity); + await _controller?.dispose(); + + // changeCallStatusAPI(4); + + // if (_session != null && _signaling != null) { + // await Navigator.of(context).pushReplacement( + // MaterialPageRoute( + // // fullscreenDialog: true, + // builder: (BuildContext context) { + // // if (widget.OutGoingCallData.isWebRTC == "true") { + // return StartVideoCall(signaling: _signaling, session: _session); + // + // // else { + // // return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: widget.OutGoingCallData.sessionId, token: widget.OutGoingCallData.token); + // // } + // + // // return VideoCallWebPage(receiverId: widget.OutGoingCallData.receiverID, callerId: widget.OutGoingCallData.callerID); // Web WebRTC VideoCall + // + // // return CallHomePage(receiverId: widget.OutGoingCallData.receiverID, callerId: widget.OutGoingCallData.callerID); // App WebRTC VideoCall + // }, + // ), + // ); + // } else { + // // Invalid Params/Data + // Utils.showToast("Failed to establish connection with server"); + // } + } catch (err) { + print(err); + // await PlatformExceptionAlertDialog( + // exception: err, + // ).show(context); + + Utils.showToast(err.toString()); + } + } + + // void changeCallStatusAPI(int sessionStatus) { + // LiveCareService service = new LiveCareService(); + // service.endCallAPI(widget.OutGoingCallData.sessionId, sessionStatus, context).then((res) {}).catchError((err) { + // print(err); + // }); + // } + + void backToHome() async { + // final connected = await signaling.declineCall(widget.OutGoingCallData.callerID, widget.OutGoingCallData.receiverID); + // LandingPage.isOpenCallPage = false; + // _signaling + _animationController!.dispose(); + // player.stop(); + // changeCallStatusAPI(3); + // _signaling.bye(_session, callRejected: true); + // _signaling.callDisconnected(_session, callRejected: true); + Navigator.of(context).pop(); + } + + // + // void disposeAudioResources() async { + // await player.dispose(); + // } + // + // void setAudioFile() async { + // player.stop(); + // await player.setVolume(1.0); // full volume + // try { + // await player.setAsset('assets/sounds/ring_60Sec.mp3').then((value) { + // player.setLoopMode(LoopMode.one); // loop ring sound + // player.play(); + // }).catchError((err) { + // print("Error: $err"); + // }); + // } catch (e) { + // print("Error: $e"); + // } + // } + // + // void connectSignaling({@required bool iAmCaller = false}) async { + // print("----------------- + Signaling Connection Started ---------------------------"); + // var caller = widget.OutGoingCallData.callerID; + // var receiver = widget.OutGoingCallData.receiverID; + // var host = widget.OutGoingCallData.server; + // + // var selfRole = iAmCaller ? "Caller" : "Receiver"; + // var selfId = iAmCaller ? caller : receiver; + // var selfUser = SocketUser(id: selfId, name: "$selfRole-$selfId", userAgent: DeviceInfo.userAgent, moreInfo: {}); + // + // var remoteRole = !iAmCaller ? "Caller" : "Receiver"; + // var remoteId = !iAmCaller ? caller : receiver; + // var remoteUser = SocketUser(id: remoteId, name: "$remoteRole-$remoteId", userAgent: DeviceInfo.userAgent, moreInfo: {}); + // + // var sessionId = "$caller-$receiver"; + // _session = SessionOneToOne(id: sessionId, local_user: selfUser, remote_user: remoteUser); + // + // _signaling = Signaling(host, session: _session); + // await _signaling.connect(); + // + // if (_signaling.state == SignalingState.Open) { + // return; + // } + // } + + BoxDecoration cardRadius(double radius, {required Color color, double? elevation}) { + return BoxDecoration( + shape: BoxShape.rectangle, + color: color ?? Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(radius), + ), + boxShadow: [ + BoxShadow( + color: const Color( + 0xff000000, + ).withOpacity( + .05, + ), + //spreadRadius: 5, + blurRadius: elevation ?? 27, + offset: const Offset( + -2, + 3, + ), + ), + ], + ); + } +} diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index c638b34..6dcd6d2 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -91,12 +91,12 @@ class ChatBubble extends StatelessWidget { children: [ dateTime.toText12(color: isCurrentUser ? MyColors.grey41Color.withOpacity(.5) : MyColors.white.withOpacity(0.7),), if (isCurrentUser) 5.width, - if (isCurrentUser) - Icon( - isDelivered ? Icons.done_all : Icons.done_all, - color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, - size: 14, - ), + // if (isCurrentUser) + // Icon( + // isDelivered ? Icons.done_all : Icons.done_all, + // color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, + // size: 14, + // ), ], ), ], diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index ff661f1..2c8b2d8 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -6,11 +6,12 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/chat/call.dart'; -import 'package:mohem_flutter_app/ui/chat/call/chat_call_screen.dart'; +import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart'; import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; @@ -71,12 +72,12 @@ class _ChatDetailScreenState extends State { actions: [ IconButton( onPressed: () { - makeCall("AUDIO"); + makeCall("AUDIO"); }, icon: SvgPicture.asset( - "assets/images/call.svg", - width: 25, - height: 25, + "assets/icons/chat/call.svg", + width: 22, + height: 22, ), ), IconButton( @@ -84,11 +85,12 @@ class _ChatDetailScreenState extends State { makeCall("VIDEO"); }, icon: SvgPicture.asset( - "assets/images/call.svg", - width: 25, - height: 25, + "assets/icons/chat/video_call.svg", + width: 20, + height: 20, ), ), + 10.width, ]), body: Consumer( builder: (BuildContext context, ChatProviderModel m, Widget? child) { @@ -355,9 +357,9 @@ class _ChatDetailScreenState extends State { await Navigator.push( context, MaterialPageRoute( - builder: (BuildContext context) => IncomingCall( - incomingCallData: incomingCallData, + builder: (BuildContext context) => OutGoingCall( isVideoCall: callType == "VIDEO" ? true : false, + OutGoingCallData: incomingCallData, ), ), );