From 68939f6256c1305c19c523da47314172e0acf5d0 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Wed, 16 Nov 2022 12:07:13 +0300 Subject: [PATCH 01/19] Chat Call UI --- lib/models/chat/call.dart | 117 ++++++++ lib/ui/chat/call/chat_call_screen.dart | 379 +++++++++++++++++++++++++ lib/ui/chat/chat_detailed_screen.dart | 116 +++++++- lib/widgets/app_bar_widget.dart | 29 +- pubspec.yaml | 2 + 5 files changed, 614 insertions(+), 29 deletions(-) create mode 100644 lib/models/chat/call.dart create mode 100644 lib/ui/chat/call/chat_call_screen.dart diff --git a/lib/models/chat/call.dart b/lib/models/chat/call.dart new file mode 100644 index 0000000..eacdd03 --- /dev/null +++ b/lib/models/chat/call.dart @@ -0,0 +1,117 @@ +class IncomingCallData { + String? callerID; + String? receiverID; + String? msgID; + String? notfID; + String? notificationForeground; + String? count; + String? message; + String? appointmentNo; + String? title; + String? projectID; + String? notificationType; + String? background; + String? doctorname; + String? clinicname; + String? speciality; + String? appointmentdate; + String? appointmenttime; + String? type; + String? sessionId; + String? identity; + String? name; + String? videoUrl; + String? picture; + String? token; + String? isCall; + String? sound; + String? server; + String? isWebRTC; + + IncomingCallData( + {this.msgID, + this.notfID, + this.notificationForeground, + this.count, + this.message, + this.appointmentNo, + this.title, + this.projectID, + this.notificationType, + this.background, + this.doctorname, + this.clinicname, + this.speciality, + this.appointmentdate, + this.appointmenttime, + this.type, + this.sessionId, + this.identity, + this.name, + this.videoUrl, + this.picture, + this.isCall, + this.sound}); + + IncomingCallData.fromJson(Map json) { + callerID = json['callerID']; + receiverID = json['PatientID']; + msgID = json['msgID']; + notfID = json['notfID']; + notificationForeground = json['notification_foreground']; + count = json['count']; + message = json['message']; + appointmentNo = json['AppointmentNo']; + title = json['title']; + projectID = json['ProjectID']; + notificationType = json['NotificationType']; + background = json['background']; + doctorname = json['doctorname']; + clinicname = json['clinicname']; + speciality = json['speciality']; + appointmentdate = json['appointmentdate']; + appointmenttime = json['appointmenttime']; + type = json['type']; + sessionId = json['session_id']; + token = json['token']; + identity = json['identity']; + name = json['name']; + videoUrl = json['videoUrl']; + picture = json['picture']; + isCall = json['is_call']; + sound = json['sound']; + server = json['server']; + isWebRTC = json['is_webrtc'] ?? "true"; + } + + Map toJson() { + Map data = Map(); + data['msgID'] = this.msgID; + data['notfID'] = this.notfID; + data['notification_foreground'] = this.notificationForeground; + data['count'] = this.count; + data['message'] = this.message; + data['AppointmentNo'] = this.appointmentNo; + data['title'] = this.title; + data['ProjectID'] = this.projectID; + data['NotificationType'] = this.notificationType; + data['background'] = this.background; + data['doctorname'] = this.doctorname; + data['clinicname'] = this.clinicname; + data['speciality'] = this.speciality; + data['appointmentdate'] = this.appointmentdate; + data['appointmenttime'] = this.appointmenttime; + data['type'] = this.type; + data['session_id'] = this.sessionId; + data['token'] = this.token; + data['identity'] = this.identity; + data['name'] = this.name; + data['videoUrl'] = this.videoUrl; + data['picture'] = this.picture; + data['is_call'] = this.isCall; + data['sound'] = this.sound; + data['server'] = this.server; + data['is_webrtc'] = this.isWebRTC; + return data; + } +} diff --git a/lib/ui/chat/call/chat_call_screen.dart b/lib/ui/chat/call/chat_call_screen.dart new file mode 100644 index 0000000..0bec1f0 --- /dev/null +++ b/lib/ui/chat/call/chat_call_screen.dart @@ -0,0 +1,379 @@ +import 'dart:ui'; + +import 'package:camera/camera.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:just_audio/just_audio.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/models/chat/call.dart'; + +class IncomingCall extends StatefulWidget { + IncomingCallData incomingCallData; + bool? isVideoCall; + + IncomingCall({Key? key, required this.incomingCallData, this.isVideoCall}) : super(key: key); + + @override + _IncomingCallState createState() => _IncomingCallState(); +} + +class _IncomingCallState extends State with SingleTickerProviderStateMixin { + AnimationController? _animationController; + CameraController? _controller; + Future? _initializeControllerFuture; + bool isCameraReady = 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: [ + Container( + margin: const EdgeInsets.all(21.0), + child: Row( + children: [ + Image.asset( + "assets/images/logos/main_mohemm_logo.png", + height: 70, + width: 70, + ), + Container( + margin: const EdgeInsets.only( + left: 10.0, + right: 10.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: const [ + Text( + "Aamir Saleem Ahmad", + style: TextStyle( + fontSize: 21, + fontWeight: FontWeight.bold, + color: MyColors.white, + letterSpacing: -1.26, + height: 23 / 12, + ), + ), + Text( + "Calling...", + 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.incomingCallData.appointmentdate + widget.incomingCallData.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.incomingCallData.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: [ + RotationTransition( + turns: Tween( + begin: 0.0, + end: -.1, + ) + .chain( + CurveTween( + curve: Curves.elasticIn, + ), + ) + .animate( + _animationController!, + ), + child: RawMaterialButton( + onPressed: () { + _submit(); + }, + elevation: 2.0, + fillColor: MyColors.green2DColor, + padding: const EdgeInsets.all( + 15.0, + ), + shape: const CircleBorder(), + child: const Icon( + Icons.call, + 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(); + } + } + + Future _submit() async { + try { + // backToHome(); + // final roomModel = RoomModel(name: widget.incomingCallData.name, token: widget.incomingCallData.sessionId, identity: widget.incomingCallData.identity); + await _controller?.dispose(); + // changeCallStatusAPI(4); + + // if (_session != null && _signaling != null) { + // await Navigator.of(context).pushReplacement( + // MaterialPageRoute( + // // fullscreenDialog: true, + // builder: (BuildContext context) { + // // if (widget.incomingCallData.isWebRTC == "true") { + // return StartVideoCall(signaling: _signaling, session: _session); + // + // // else { + // // return OpenTokConnectCallPage(apiKey: OPENTOK_API_KEY, sessionId: widget.incomingCallData.sessionId, token: widget.incomingCallData.token); + // // } + // + // // return VideoCallWebPage(receiverId: widget.incomingCallData.receiverID, callerId: widget.incomingCallData.callerID); // Web WebRTC VideoCall + // + // // return CallHomePage(receiverId: widget.incomingCallData.receiverID, callerId: widget.incomingCallData.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.incomingCallData.sessionId, sessionStatus, context).then((res) {}).catchError((err) { + // print(err); + // }); + // } + + void backToHome() async { + // final connected = await signaling.declineCall(widget.incomingCallData.callerID, widget.incomingCallData.receiverID); + // LandingPage.isOpenCallPage = false; + // _signaling + // 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.incomingCallData.callerID; + // var receiver = widget.incomingCallData.receiverID; + // var host = widget.incomingCallData.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_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 782e4e2..6ddd19e 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -9,6 +9,8 @@ import 'package:mohem_flutter_app/classes/colors.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/chat_bubble.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; @@ -16,15 +18,18 @@ import 'package:provider/provider.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:swipe_to/swipe_to.dart'; -class ChatDetailScreen extends StatelessWidget { +class ChatDetailScreen extends StatefulWidget { // ignore: prefer_const_constructors_in_immutables ChatDetailScreen({Key? key}) : super(key: key); - dynamic userDetails; + @override + State createState() => _ChatDetailScreenState(); +} +class _ChatDetailScreenState extends State { + dynamic userDetails; late ChatProviderModel data; - - final RefreshController _refreshController = RefreshController(initialRefresh: false); + final RefreshController _rc = RefreshController(initialRefresh: false); void getMoreChat() async { if (userDetails != null) { @@ -32,19 +37,54 @@ class ChatDetailScreen extends StatelessWidget { data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: true, isNewChat: false); } await Future.delayed(const Duration(milliseconds: 1000)); - _refreshController.loadComplete(); + _rc.loadComplete(); } @override - Widget build(BuildContext context) { - userDetails = ModalRoute.of(context)!.settings.arguments; + void initState() { + super.initState(); data = Provider.of(context, listen: false); if (userDetails != null) - data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: false, isNewChat: userDetails["isNewChat"]); - data.scrollController.addListener(data.scrollListener); + data.getSingleUserChatHistory( + senderUID: AppState().chatDetails!.response!.id.toString(), + receiverUID: userDetails["targetUser"].id, + loadMore: false, + isNewChat: userDetails["isNewChat"], + ); + //data.scrollController.addListener(data.scrollListener); + } + + @override + Widget build(BuildContext context) { + userDetails = ModalRoute.of(context)!.settings.arguments; return Scaffold( backgroundColor: const Color(0xFFF8F8F8), - appBar: AppBarWidget(context, title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach, showHomeButton: false, image: userDetails["targetUser"].image), + appBar: AppBarWidget(context, + title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach, + showHomeButton: false, + image: userDetails["targetUser"].image, + actions: [ + IconButton( + onPressed: () { + makeCall("AUDIO"); + }, + icon: SvgPicture.asset( + "assets/images/call.svg", + width: 25, + height: 25, + ), + ), + IconButton( + onPressed: () { + makeCall("VIDEO"); + }, + icon: SvgPicture.asset( + "assets/images/call.svg", + width: 25, + height: 25, + ), + ), + ]), body: Consumer( builder: (BuildContext context, ChatProviderModel m, Widget? child) { return (m.isLoading @@ -62,7 +102,7 @@ class ChatDetailScreen extends StatelessWidget { header: const MaterialClassicHeader( color: MyColors.gradiantEndColor, ), - controller: _refreshController, + controller: _rc, reverse: true, child: ListView.builder( controller: m.scrollController, @@ -136,11 +176,11 @@ class ChatDetailScreen extends StatelessWidget { margin: EdgeInsets.zero, elevation: 0, child: Padding( - padding: const EdgeInsets.only(left: 20.0, right: 20, top: 20, bottom: 0), + padding: const EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 0), child: Card( margin: EdgeInsets.zero, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0.0), + borderRadius: BorderRadius.circular(0), ), elevation: 0, child: Container( @@ -267,4 +307,54 @@ class ChatDetailScreen extends StatelessWidget { ), ); } + + void makeCall(String callType) async { + // final server = await SelectionDialog( + // context, + // title: "Select Server", + // items: ["https://livecareturn.hmg.com:8086", "https://104.197.179.1:8086"] + // ).show(); + + Map json = { + "callerID": "9920", + "PatientID": "1231755", + "msgID": "123", + "notfID": "123", + "notification_foreground": "true", + "count": "1", + "message": "Doctor is calling ", + "AppointmentNo": "123", + "title": "Rayyan Hospital", + "ProjectID": "123", + "NotificationType": "10", + "background": "1", + "doctorname": "Dr Sulaiman Al Habib", + "clinicname": "ENT Clinic", + "speciality": "Speciality", + "appointmentdate": "Sun, 15th Dec, 2019", + "appointmenttime": "09:00", + "type": "video", + "session_id": + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0eSI6InR3aWxpby1mcGE7dj0xIn0.eyJqdGkiOiJTS2I2NjYyOWMzN2ZhOTM3YjFjNDI2Zjg1MTgyNWFmN2M0LTE1OTg3NzQ1MDYiLCJpc3MiOiJTS2I2NjYyOWMzN2ZhOTM3YjFjNDI2Zjg1MTgyNWFmN2M0Iiwic3ViIjoiQUNhYWQ1YTNmOGM2NGZhNjczNTY3NTYxNTc0N2YyNmMyYiIsImV4cCI6MTU5ODc3ODEwNiwiZ3JhbnRzIjp7ImlkZW50aXR5IjoiSGFyb29uMSIsInZpZGVvIjp7InJvb20iOiJTbWFsbERhaWx5U3RhbmR1cCJ9fX0.7XUS5uMQQJfkrBZu9EjQ6STL6R7iXkso6BtO1HmrQKk", + "identity": "Haroon1", + "name": "SmallDailyStandup", + "videoUrl": "video", + "picture": "video", + "is_call": "true", + "is_webrtc": "true", + // "server": "https://192.168.8.163:8086", + "server": "https://livecareturn.hmg.com:8086", + }; + + IncomingCallData incomingCallData = IncomingCallData.fromJson(json); + await Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => IncomingCall( + incomingCallData: incomingCallData, + isVideoCall: callType == "VIDEO" ? true : false, + ), + ), + ); + } } diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 745dedf..d3e7c97 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -7,11 +7,7 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; AppBar AppBarWidget(BuildContext context, - {required String title, - bool showHomeButton = true, - bool showNotificationButton = false, - bool showMemberButton = false, - String? image}) { + {required String title, bool showHomeButton = true, bool showNotificationButton = false, bool showMemberButton = false, String? image, bool, List? actions}) { return AppBar( leadingWidth: 0, // leading: GestureDetector( @@ -24,17 +20,16 @@ AppBar AppBarWidget(BuildContext context, children: [ GestureDetector( behavior: HitTestBehavior.opaque, - onTap: - Feedback.wrapForTap(() => Navigator.maybePop(context), context), - child: - const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + onTap: Feedback.wrapForTap(() => Navigator.maybePop(context), context), + child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), ), 4.width, - if (image != null) SvgPicture.asset( - image, - height: 40, - width: 40, - ), + if (image != null) + SvgPicture.asset( + image, + height: 40, + width: 40, + ), if (image != null) 14.width, title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, ], @@ -46,8 +41,7 @@ AppBar AppBarWidget(BuildContext context, if (showHomeButton) IconButton( onPressed: () { - Navigator.popUntil( - context, ModalRoute.withName(AppRoutes.dashboard)); + Navigator.popUntil(context, ModalRoute.withName(AppRoutes.dashboard)); }, icon: const Icon(Icons.home, color: MyColors.darkIconColor), ), @@ -65,6 +59,9 @@ AppBar AppBarWidget(BuildContext context, }, icon: const Icon(Icons.people, color: MyColors.textMixColor), ), + + + ...actions??[] ], ); } diff --git a/pubspec.yaml b/pubspec.yaml index 8947c12..5a7c1c5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,6 +91,8 @@ dependencies: signalr_netcore: ^1.3.3 logging: ^1.0.1 swipe_to: ^1.0.2 + flutter_webrtc: ^0.9.16 + camera: ^0.10.0+4 From 00dee97bca969b495a5568fcbc96022f287f2904 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Wed, 16 Nov 2022 16:44:46 +0300 Subject: [PATCH 02/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/api/chat/chat_provider_model.dart | 42 +++++++--- lib/api/dashboard_api_client.dart | 10 ++- lib/classes/consts.dart | 4 +- .../chat/chat_count_conversation_model.dart | 25 ++++++ .../chat/get_user_login_token_model.dart | 81 ++++++++++++------- lib/provider/dashboard_provider_model.dart | 22 ++++- lib/ui/chat/call/chat_call_screen.dart | 2 + lib/ui/chat/chat_detailed_screen.dart | 28 ++++--- lib/ui/chat/chat_home.dart | 9 ++- lib/ui/landing/dashboard_screen.dart | 33 ++++++-- .../search_employee_bottom_sheet.dart | 2 +- 11 files changed, 191 insertions(+), 67 deletions(-) create mode 100644 lib/models/chat/chat_count_conversation_model.dart diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index ead29d7..cedc158 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -7,6 +7,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:logger/logger.dart' as L; +import 'package:logging/logging.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; @@ -27,6 +28,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? pChatHistory, searchedChats; late HubConnection hubConnection; L.Logger logger = L.Logger(); + bool hubConInitialized = false; bool isLoading = true; bool isChatScreenActive = false; @@ -43,13 +45,27 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool _shouldAutoscroll = false; Future getUserAutoLoginToken() async { - String userName = AppState().memberInformationList!.eMPLOYEEEMAILADDRESS!.split("@").first.toString(); - //userName - Response response = - await ApiClient().postJsonForResponse("${ApiConsts.chatServerBaseApiUrl}user/desktopuserlogin", {"userName": userName, "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", "loginType": 2}); - login.UserAutoLoginModel userLoginResponse = login.userAutoLoginModelFromJson(response.body); - AppState().setchatUserDetails = userLoginResponse; - await buildHubConnection(); + Response response = await ApiClient().postJsonForResponse( + "${ApiConsts.chatServerBaseApiUrl}user/externaluserlogin", + { + "employeeNumber": int.parse( + AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + ), + "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG" + }, + ); + login.UserAutoLoginModel userLoginResponse = login.userAutoLoginModelFromJson( + response.body, + ); + + if (userLoginResponse.response != null) { + hubConInitialized = true; + AppState().setchatUserDetails = userLoginResponse; + await buildHubConnection(); + } else { + Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr"); + return; + } } Future?> getChatMemberFromSearch(String sName, int cUserId) async { @@ -95,6 +111,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void getSingleUserChatHistory({required String senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { isLoading = true; + if (isNewChat) userChatHistory = []; if (!loadMore) paginationVal = 0; isChatScreenActive = true; Response response = await ApiClient().getJsonForResponse( @@ -151,8 +168,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { hubConnection = HubConnectionBuilder() .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Web&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) .withAutomaticReconnect( - retryDelays: [2000, 5000, 10000, 20000], - ).build(); + retryDelays: [2000, 5000, 10000, 20000], + ) + .configureLogging(Logger("Loggin")) + .build(); hubConnection.onclose( ({Exception? error}) {}, ); @@ -173,6 +192,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + } } @@ -215,9 +235,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateChatHistoryWindow(List? args) { dynamic items = args!.toList(); - if (kDebugMode) { - print("---------------------------------Update Chat History Windows Async -------------------------------------"); - } + print("---------------------------------Update Chat History Windows Async -------------------------------------"); logger.d(items); // for (var user in searchedChats!) { // if (user.id == items.first["id"]) { diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index cce2207..9747e5c 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -1,10 +1,12 @@ import 'dart:async'; import 'dart:convert'; +import 'package:http/http.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/date_uitl.dart'; +import 'package:mohem_flutter_app/models/chat/chat_count_conversation_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; @@ -15,7 +17,6 @@ import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:uuid/uuid.dart'; - class DashboardApiClient { static final DashboardApiClient _instance = DashboardApiClient._internal(); @@ -178,4 +179,11 @@ class DashboardApiClient { return responseData; }, url, postParams); } + + Future getChatCount() async { + Response response = await ApiClient().getJsonForResponse( + "${ApiConsts.chatServerBaseApiUrl}user/unreadconversationcount/${AppState().getUserName}", + ); + return chatUnreadCovnCountModelFromJson(response.body); + } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index ede22e3..c5788f9 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/models/chat/chat_count_conversation_model.dart b/lib/models/chat/chat_count_conversation_model.dart new file mode 100644 index 0000000..e584d32 --- /dev/null +++ b/lib/models/chat/chat_count_conversation_model.dart @@ -0,0 +1,25 @@ +import 'dart:convert'; + +ChatUnreadCovnCountModel chatUnreadCovnCountModelFromJson(String str) => ChatUnreadCovnCountModel.fromJson(json.decode(str)); + +String chatUnreadCovnCountModelToJson(ChatUnreadCovnCountModel data) => json.encode(data.toJson()); + +class ChatUnreadCovnCountModel { + ChatUnreadCovnCountModel({ + this.singleChatCount, + this.groupChatCount, + }); + + int? singleChatCount; + int? groupChatCount; + + factory ChatUnreadCovnCountModel.fromJson(Map json) => ChatUnreadCovnCountModel( + singleChatCount: json["singleChatCount"] == null ? null : json["singleChatCount"], + groupChatCount: json["groupChatCount"] == null ? null : json["groupChatCount"], + ); + + Map toJson() => { + "singleChatCount": singleChatCount == null ? null : singleChatCount, + "groupChatCount": groupChatCount == null ? null : groupChatCount, + }; +} diff --git a/lib/models/chat/get_user_login_token_model.dart b/lib/models/chat/get_user_login_token_model.dart index 8afd3a9..8d55461 100644 --- a/lib/models/chat/get_user_login_token_model.dart +++ b/lib/models/chat/get_user_login_token_model.dart @@ -1,4 +1,3 @@ - import 'dart:convert'; UserAutoLoginModel userAutoLoginModelFromJson(String str) => UserAutoLoginModel.fromJson(json.decode(str)); @@ -7,22 +6,22 @@ String userAutoLoginModelToJson(UserAutoLoginModel data) => json.encode(data.toJ class UserAutoLoginModel { UserAutoLoginModel({ - this.response, + this.response, this.errorResponses, }); Response? response; - dynamic? errorResponses; + List? errorResponses; factory UserAutoLoginModel.fromJson(Map json) => UserAutoLoginModel( - response: json["response"] == null ? null : Response.fromJson(json["response"]), - errorResponses: json["errorResponses"], - ); + response: json["response"] == null ? null : Response.fromJson(json["response"]), + errorResponses: json["errorResponses"] == null ? null : List.from(json["errorResponses"].map((x) => ErrorResponse.fromJson(x))), + ); Map toJson() => { - "response": response == null ? null : response!.toJson(), - "errorResponses": errorResponses, - }; + "response": response == null ? null : response!.toJson(), + "errorResponses": errorResponses == null ? null : List.from(errorResponses!.map((x) => x.toJson())), + }; } class Response { @@ -51,28 +50,48 @@ class Response { String? encryptedUserName; factory Response.fromJson(Map json) => Response( - id: json["id"] == null ? null : json["id"], - userName: json["userName"] == null ? null : json["userName"], - email: json["email"] == null ? null : json["email"], - phone: json["phone"] == null ? null : json["phone"], - title: json["title"] == null ? null : json["title"], - token: json["token"] == null ? null : json["token"], - isDomainUser: json["isDomainUser"] == null ? null : json["isDomainUser"], - isActiveCode: json["isActiveCode"] == null ? null : json["isActiveCode"], - encryptedUserId: json["encryptedUserId"] == null ? null : json["encryptedUserId"], - encryptedUserName: json["encryptedUserName"] == null ? null : json["encryptedUserName"], - ); + id: json["id"] == null ? null : json["id"], + userName: json["userName"] == null ? null : json["userName"], + email: json["email"] == null ? null : json["email"], + phone: json["phone"] == null ? null : json["phone"], + title: json["title"] == null ? null : json["title"], + token: json["token"] == null ? null : json["token"], + isDomainUser: json["isDomainUser"] == null ? null : json["isDomainUser"], + isActiveCode: json["isActiveCode"] == null ? null : json["isActiveCode"], + encryptedUserId: json["encryptedUserId"] == null ? null : json["encryptedUserId"], + encryptedUserName: json["encryptedUserName"] == null ? null : json["encryptedUserName"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "userName": userName == null ? null : userName, + "email": email == null ? null : email, + "phone": phone == null ? null : phone, + "title": title == null ? null : title, + "token": token == null ? null : token, + "isDomainUser": isDomainUser == null ? null : isDomainUser, + "isActiveCode": isActiveCode == null ? null : isActiveCode, + "encryptedUserId": encryptedUserId == null ? null : encryptedUserId, + "encryptedUserName": encryptedUserName == null ? null : encryptedUserName, + }; +} + +class ErrorResponse { + ErrorResponse({ + this.fieldName, + this.message, + }); + + String? fieldName; + String? message; + + factory ErrorResponse.fromJson(Map json) => ErrorResponse( + fieldName: json["fieldName"] == null ? null : json["fieldName"], + message: json["message"] == null ? null : json["message"], + ); Map toJson() => { - "id": id == null ? null : id, - "userName": userName == null ? null : userName, - "email": email == null ? null : email, - "phone": phone == null ? null : phone, - "title": title == null ? null : title, - "token": token == null ? null : token, - "isDomainUser": isDomainUser == null ? null : isDomainUser, - "isActiveCode": isActiveCode == null ? null : isActiveCode, - "encryptedUserId": encryptedUserId == null ? null : encryptedUserId, - "encryptedUserName": encryptedUserName == null ? null : encryptedUserName, - }; + "fieldName": fieldName == null ? null : fieldName, + "message": message == null ? null : message, + }; } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 5b9f8f1..b38536c 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -7,6 +7,7 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/main.dart'; +import 'package:mohem_flutter_app/models/chat/chat_count_conversation_model.dart'; import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; @@ -34,6 +35,10 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool isWorkListLoading = true; int workListCounter = 0; + //Chat + bool isChatCounterLoding = true; + int chatUConvCounter = 0; + //Misssing Swipe bool isMissingSwipeLoading = true; int missingSwipeCounter = 0; @@ -91,6 +96,9 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { accrualList = null; leaveBalanceAccrual = null; + isChatCounterLoding = true; + chatUConvCounter = 0; + ticketBalance = 0; isServicesMenusLoading = true; homeMenus = null; @@ -266,7 +274,19 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return res; } - + void fetchChatCounts() async { + print("----------------------- Fetch Count ____________________________________"); + try { + ChatUnreadCovnCountModel response = await DashboardApiClient().getChatCount(); + chatUConvCounter = response.singleChatCount!; + isChatCounterLoding = false; + notifyListeners(); + } catch (ex) { + logger.wtf(ex); + notifyListeners(); + Utils.handleException(ex, null, null); + } + } void notify() { notifyListeners(); diff --git a/lib/ui/chat/call/chat_call_screen.dart b/lib/ui/chat/call/chat_call_screen.dart index 0bec1f0..3fce65b 100644 --- a/lib/ui/chat/call/chat_call_screen.dart +++ b/lib/ui/chat/call/chat_call_screen.dart @@ -255,6 +255,7 @@ class _IncomingCallState extends State with SingleTickerProviderSt // backToHome(); // final roomModel = RoomModel(name: widget.incomingCallData.name, token: widget.incomingCallData.sessionId, identity: widget.incomingCallData.identity); await _controller?.dispose(); + // changeCallStatusAPI(4); // if (_session != null && _signaling != null) { @@ -300,6 +301,7 @@ class _IncomingCallState extends State with SingleTickerProviderSt // final connected = await signaling.declineCall(widget.incomingCallData.callerID, widget.incomingCallData.receiverID); // LandingPage.isOpenCallPage = false; // _signaling + _animationController!.dispose(); // player.stop(); // changeCallStatusAPI(3); // _signaling.bye(_session, callRejected: true); diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 6ddd19e..2ef61f0 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -34,15 +34,25 @@ class _ChatDetailScreenState extends State { void getMoreChat() async { if (userDetails != null) { data.paginationVal = data.paginationVal + 10; - data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: true, isNewChat: false); + if (userDetails != null) + data.getSingleUserChatHistory( + senderUID: AppState().chatDetails!.response!.id.toString(), + receiverUID: userDetails["targetUser"].id, + loadMore: true, + isNewChat: false, + ); } - await Future.delayed(const Duration(milliseconds: 1000)); + await Future.delayed( + const Duration( + milliseconds: 1000, + ), + ); _rc.loadComplete(); } @override - void initState() { - super.initState(); + Widget build(BuildContext context) { + userDetails = ModalRoute.of(context)!.settings.arguments; data = Provider.of(context, listen: false); if (userDetails != null) data.getSingleUserChatHistory( @@ -51,12 +61,6 @@ class _ChatDetailScreenState extends State { loadMore: false, isNewChat: userDetails["isNewChat"], ); - //data.scrollController.addListener(data.scrollListener); - } - - @override - Widget build(BuildContext context) { - userDetails = ModalRoute.of(context)!.settings.arguments; return Scaffold( backgroundColor: const Color(0xFFF8F8F8), appBar: AppBarWidget(context, @@ -66,7 +70,7 @@ class _ChatDetailScreenState extends State { actions: [ IconButton( onPressed: () { - makeCall("AUDIO"); + // makeCall("AUDIO"); }, icon: SvgPicture.asset( "assets/images/call.svg", @@ -76,7 +80,7 @@ class _ChatDetailScreenState extends State { ), IconButton( onPressed: () { - makeCall("VIDEO"); + // makeCall("VIDEO"); }, icon: SvgPicture.asset( "assets/images/call.svg", diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 738fc17..744188f 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -1,6 +1,9 @@ +import 'dart:convert'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -31,7 +34,7 @@ class _ChatHomeState extends State { // TODO: implement initState super.initState(); data = Provider.of(context, listen: false); - data.getUserAutoLoginToken().then((value) { + data.getUserAutoLoginToken().then((Object? value) { data.getUserRecentChats(); }); } @@ -39,7 +42,9 @@ class _ChatHomeState extends State { @override void dispose() { data.clearAll(); - data.hubConnection.stop(); + if (data.hubConInitialized) { + data.hubConnection.stop(); + } super.dispose(); } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index d342072..7453603 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -71,6 +71,7 @@ class _DashboardScreenState extends State { data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); + data.fetchChatCounts(); _refreshController.refreshCompleted(); } @@ -268,7 +269,7 @@ class _DashboardScreenState extends State { ).onPress(() { showMyBottomSheet( context, - callBackFunc: (){}, + callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true), ); }), @@ -469,10 +470,32 @@ class _DashboardScreenState extends State { label: LocaleKeys.itemsForSale.tr(), ), BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/chat/chat.svg", - color: currentIndex == 4 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset( + "assets/icons/chat/chat.svg", + color: currentIndex == 4 ? MyColors.grey3AColor : MyColors.grey98Color, + ).paddingAll(4), + Consumer( + builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { + if (data.chatUConvCounter == 0) { + return const SizedBox(); + } + return Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); + }, + ), + ], + ), label: LocaleKeys.chat.tr(), ), ], diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index a30b33d..b88b96f 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -236,7 +236,7 @@ class _SearchEmployeeBottomSheetState extends State { arguments: {"targetUser": chatUsersList![index], "isNewChat": true}, ); }, - onLongPress: () {}, + ), ); }, From d7c0ef7bfbaef8afb6f82eb21fc7d44634091a82 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Wed, 16 Nov 2022 16:50:34 +0300 Subject: [PATCH 03/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/ui/chat/chat_home.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 744188f..ed6b155 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -34,8 +34,11 @@ class _ChatHomeState extends State { // TODO: implement initState super.initState(); data = Provider.of(context, listen: false); - data.getUserAutoLoginToken().then((Object? value) { + data.getUserAutoLoginToken().then((value) { data.getUserRecentChats(); + // var datae = [int.parse(AppState().memberInformationList!.eMPLOYEENUMBER.toString())]; + + // data.hubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [int.parse(AppState().memberInformationList!.eMPLOYEENUMBER.toString())]); }); } From 44d76f068781e7ef22665d39fd16f3146025daeb Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 09:26:11 +0300 Subject: [PATCH 04/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/api/chat/chat_provider_model.dart | 46 ++++++++++++++++++++++----- lib/ui/chat/chat_detailed_screen.dart | 5 +-- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index cedc158..b336ace 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -109,7 +109,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } - void getSingleUserChatHistory({required String senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { + Future GetUserChatHistoryNotDeliveredAsync(int userId) async { + await hubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); + return ""; + } + + void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { isLoading = true; if (isNewChat) userChatHistory = []; if (!loadMore) paginationVal = 0; @@ -134,9 +139,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } isLoading = false; + await GetUserChatHistoryNotDeliveredAsync(senderUID); notifyListeners(); } + void updateUserChatHistoryStatusAsync(List data) { + hubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + } + List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); ChatUserModel userToList(String str) => ChatUserModel.fromJson(json.decode(str)); @@ -170,7 +180,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { .withAutomaticReconnect( retryDelays: [2000, 5000, 10000, 20000], ) - .configureLogging(Logger("Loggin")) + .configureLogging( + Logger("Loggin"), + ) .build(); hubConnection.onclose( ({Exception? error}) {}, @@ -188,11 +200,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // hubConnection.on("OnSeenChatUserAsync", onChatSeen); //hubConnection.on("OnUserTypingAsync", onUserTyping); - // hubConnection.on("OnUserCountAsync", userCountAsync); + hubConnection.on("OnUserCountAsync", userCountAsync); hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); - } } @@ -223,6 +234,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void userCountAsync(List? args) { dynamic items = args!.toList(); + // logger.d(items); //logger.d("---------------------------------User Count Async -------------------------------------"); //logger.d(items); // for (var user in searchedChats!) { @@ -247,10 +259,17 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void chatNotDelivered(List? args) { dynamic items = args!.toList(); - if (kDebugMode) { - print("--------------------------------- Chat Not Delivered Windows Async -------------------------------------"); + for (dynamic item in items[0]) { + dynamic data = [ + { + "userChatHistoryId": item["userChatHistoryId"], + "TargetUserId": item["targetUserId"], + "isDelivered": true, + "isSeen": true, + } + ]; + updateUserChatHistoryStatusAsync(data); } - logger.d(items); // for (var user in searchedChats!) { // if (user.id == items.first["id"]) { // user.userStatus = items.first["userStatus"]; @@ -289,7 +308,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } Future onMsgReceived(List? parameters) async { - print("msg Received"); List data = []; List temp = []; for (dynamic msg in parameters!) { @@ -307,6 +325,18 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // element.unreadMessageCount = val! + 1; // } // }); + logger.d(jsonEncode(data)); + + var list = [ + { + "userChatHistoryId": data.first.userChatHistoryId, + "TargetUserId": data.first.targetUserId, + "isDelivered": true, + "isSeen": isChatScreenActive ? true : false, + } + ]; + updateUserChatHistoryStatusAsync(list); + notifyListeners(); // if (isChatScreenActive) scrollToBottom(); } diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 2ef61f0..71a95b5 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -36,7 +36,7 @@ class _ChatDetailScreenState extends State { data.paginationVal = data.paginationVal + 10; if (userDetails != null) data.getSingleUserChatHistory( - senderUID: AppState().chatDetails!.response!.id.toString(), + senderUID: AppState().chatDetails!.response!.id!.toInt(), receiverUID: userDetails["targetUser"].id, loadMore: true, isNewChat: false, @@ -56,11 +56,12 @@ class _ChatDetailScreenState extends State { data = Provider.of(context, listen: false); if (userDetails != null) data.getSingleUserChatHistory( - senderUID: AppState().chatDetails!.response!.id.toString(), + senderUID: AppState().chatDetails!.response!.id!.toInt(), receiverUID: userDetails["targetUser"].id, loadMore: false, isNewChat: userDetails["isNewChat"], ); + return Scaffold( backgroundColor: const Color(0xFFF8F8F8), appBar: AppBarWidget(context, From 5aa56450d9db89aa4660e38802cca8ba0ded2ba3 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 15 Nov 2022 16:04:19 +0300 Subject: [PATCH 05/19] Chat Fixes --- lib/api/chat/chat_provider_model.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index b336ace..bf4c33a 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -270,6 +270,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { ]; updateUserChatHistoryStatusAsync(data); } + logger.d(items); // for (var user in searchedChats!) { // if (user.id == items.first["id"]) { // user.userStatus = items.first["userStatus"]; @@ -308,6 +309,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } Future onMsgReceived(List? parameters) async { + print("msg Received"); List data = []; List temp = []; for (dynamic msg in parameters!) { @@ -428,11 +430,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future sendChatToServer( {required int chatEventId, required fileTypeId, required int targetUserId, required String targetUserName, required chatReplyId, required bool isAttachment, required bool isReply}) async { Uuid uuid = const Uuid(); - String msg = message.text; SingleUserChatModel data = SingleUserChatModel( chatEventId: chatEventId, chatSource: 1, - contant: msg, + contant: message.text, contantNo: uuid.v4(), conversationId: uuid.v4(), createdDate: DateTime.now(), From 33609ea773dd77c2123b02b0a8fadd0688426d89 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 17 Nov 2022 09:49:31 +0300 Subject: [PATCH 06/19] Chat Fixes --- lib/api/chat/chat_provider_model.dart | 4 +++- lib/ui/chat/chat_detailed_screen.dart | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index bf4c33a..ff02c4d 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -50,6 +50,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { { "employeeNumber": int.parse( AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + // "" ), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG" }, @@ -430,10 +431,11 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future sendChatToServer( {required int chatEventId, required fileTypeId, required int targetUserId, required String targetUserName, required chatReplyId, required bool isAttachment, required bool isReply}) async { Uuid uuid = const Uuid(); + var msg = message.text; SingleUserChatModel data = SingleUserChatModel( chatEventId: chatEventId, chatSource: 1, - contant: message.text, + contant: msg, contantNo: uuid.v4(), conversationId: uuid.v4(), createdDate: DateTime.now(), diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 71a95b5..ff661f1 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -71,7 +71,7 @@ class _ChatDetailScreenState extends State { actions: [ IconButton( onPressed: () { - // makeCall("AUDIO"); + makeCall("AUDIO"); }, icon: SvgPicture.asset( "assets/images/call.svg", @@ -81,7 +81,7 @@ class _ChatDetailScreenState extends State { ), IconButton( onPressed: () { - // makeCall("VIDEO"); + makeCall("VIDEO"); }, icon: SvgPicture.asset( "assets/images/call.svg", From 3cac5eebbc7fbc92f675600b7596a890b96d8c45 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 17 Nov 2022 10:49:37 +0300 Subject: [PATCH 07/19] Chat Fixes --- assets/icons/chat/call.svg | 3 + assets/icons/chat/video_call.svg | 6 + lib/api/chat/chat_provider_model.dart | 4 +- lib/classes/consts.dart | 4 +- lib/provider/dashboard_provider_model.dart | 1 - ...en.dart => chat_incoming_call_screen.dart} | 1 + .../chat/call/chat_outgoing_call_screen.dart | 470 ++++++++++++++++++ lib/ui/chat/chat_bubble.dart | 12 +- lib/ui/chat/chat_detailed_screen.dart | 22 +- 9 files changed, 502 insertions(+), 21 deletions(-) create mode 100644 assets/icons/chat/call.svg create mode 100644 assets/icons/chat/video_call.svg rename lib/ui/chat/call/{chat_call_screen.dart => chat_incoming_call_screen.dart} (99%) create mode 100644 lib/ui/chat/call/chat_outgoing_call_screen.dart 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, ), ), ); From 451b381acf34370470ac8636c96c29f6e7e8051b Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 10:52:08 +0300 Subject: [PATCH 08/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/api/chat/chat_provider_model.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index f5d896c..bf69d58 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -49,8 +49,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { "${ApiConsts.chatServerBaseApiUrl}user/externaluserlogin", { "employeeNumber": int.parse( - //AppState().memberInformationList!.eMPLOYEENUMBER.toString(), - "210919" + AppState().memberInformationList!.eMPLOYEENUMBER.toString(), ), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG" }, From 5ec6fbdf421fb5304cbcf2172817d9de29b25601 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 17 Nov 2022 11:07:43 +0300 Subject: [PATCH 09/19] Chat Fixes --- .gitignore | 1 - lib/api/chat/chat_provider_model.dart | 4 ++-- lib/classes/consts.dart | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 034a5be..a841580 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ pubspec.lock /build/ # Web related -lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index f5d896c..7227c99 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(), - "210919" + AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + //"210919" ), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG" }, diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index ede22e3..c5788f9 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/"; From c6cd550dbced3b1462a69d247be0687556d925c3 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 17 Nov 2022 11:32:10 +0300 Subject: [PATCH 10/19] Chat Fixes --- ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- lib/ui/chat/chat_detailed_screen.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..ac88fca 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -40,7 +40,7 @@ { actions: [ IconButton( onPressed: () { - makeCall("AUDIO"); + // makeCall("AUDIO"); }, icon: SvgPicture.asset( "assets/icons/chat/call.svg", @@ -82,7 +82,7 @@ class _ChatDetailScreenState extends State { ), IconButton( onPressed: () { - makeCall("VIDEO"); + // makeCall("VIDEO"); }, icon: SvgPicture.asset( "assets/icons/chat/video_call.svg", From 2546fb52a9100987b2ffe40033f4da1dba7b4646 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 11:32:24 +0300 Subject: [PATCH 11/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/classes/consts.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index ede22e3..c5788f9 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/"; From 5913452a439d135dec80841635c821ec60f88afc Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 11:34:54 +0300 Subject: [PATCH 12/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/api/chat/chat_provider_model.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index 7227c99..7439b98 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -50,7 +50,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { { "employeeNumber": int.parse( AppState().memberInformationList!.eMPLOYEENUMBER.toString(), - //"210919" ), "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG" }, @@ -310,7 +309,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } Future onMsgReceived(List? parameters) async { - print("msg Received"); List data = []; List temp = []; for (dynamic msg in parameters!) { @@ -328,7 +326,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // element.unreadMessageCount = val! + 1; // } // }); - logger.d(jsonEncode(data)); var list = [ { From efce6dbd0f0e7b1142737a043e9fed1b39dffb84 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 11:50:37 +0300 Subject: [PATCH 13/19] Chat Count Api / Chat Token Updates / Chat Call UI --- ios/Runner/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2ac7a44..2797543 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -44,6 +44,8 @@ This App requires access to your location to mark your attendance. NSPhotoLibraryUsageDescription This app requires photo library access to select image as document & upload it. + NSMicrophoneUsageDescription + This app requires microphone access to for call. UIBackgroundModes remote-notification From 4d35767784b2d1264bdf3125883c09e00e2dcf50 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 12:37:03 +0300 Subject: [PATCH 14/19] Revert "Chat Count Api / Chat Token Updates / Chat Call UI" This reverts commit 826c39bafc72f27eceb7a2fbb975740e2a18c7db. --- ios/Runner/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2ac7a44..2797543 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -44,6 +44,8 @@ This App requires access to your location to mark your attendance. NSPhotoLibraryUsageDescription This app requires photo library access to select image as document & upload it. + NSMicrophoneUsageDescription + This app requires microphone access to for call. UIBackgroundModes remote-notification From e2a1eb3c812686767225f3e59cdf958da6d90466 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 15:05:49 +0300 Subject: [PATCH 15/19] Chat Count Api / Chat Token Updates / Chat Call UI --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a841580..4a374d7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +/ios/ From 8cb5d9a0610f397ea0dcb8a3d9e563f6ccb928e5 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 15:15:33 +0300 Subject: [PATCH 16/19] Chat Count Api / Chat Token Updates / Chat Call UI --- lib/ui/chat/chat_detailed_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index be34d7a..2c8b2d8 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -72,7 +72,7 @@ class _ChatDetailScreenState extends State { actions: [ IconButton( onPressed: () { - // makeCall("AUDIO"); + makeCall("AUDIO"); }, icon: SvgPicture.asset( "assets/icons/chat/call.svg", @@ -82,7 +82,7 @@ class _ChatDetailScreenState extends State { ), IconButton( onPressed: () { - // makeCall("VIDEO"); + makeCall("VIDEO"); }, icon: SvgPicture.asset( "assets/icons/chat/video_call.svg", From 42287f24d18b4a63377c0d62a09a17334de1bfc4 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 17 Nov 2022 15:16:16 +0300 Subject: [PATCH 17/19] Chat Count Api / Chat Token Updates / Chat Call UI --- ios/Runner/Info.plist | 2 -- 1 file changed, 2 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2797543..2ac7a44 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -44,8 +44,6 @@ This App requires access to your location to mark your attendance. NSPhotoLibraryUsageDescription This app requires photo library access to select image as document & upload it. - NSMicrophoneUsageDescription - This app requires microphone access to for call. UIBackgroundModes remote-notification From 1fcb6250f5264612c7062c3c9a9f13a234dd12a0 Mon Sep 17 00:00:00 2001 From: Aamir Saleem Ahmad Date: Thu, 17 Nov 2022 12:22:59 +0000 Subject: [PATCH 18/19] Revert "Chat Fixes" This reverts commit c6cd550dbced3b1462a69d247be0687556d925c3 --- ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ac88fca..c87d15a 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -40,7 +40,7 @@ Date: Thu, 17 Nov 2022 12:24:46 +0000 Subject: [PATCH 19/19] Revert "Chat Count Api / Chat Token Updates / Chat Call UI" This reverts commit 42287f24d18b4a63377c0d62a09a17334de1bfc4 --- ios/Runner/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2ac7a44..2797543 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -44,6 +44,8 @@ This App requires access to your location to mark your attendance. NSPhotoLibraryUsageDescription This app requires photo library access to select image as document & upload it. + NSMicrophoneUsageDescription + This app requires microphone access to for call. UIBackgroundModes remote-notification