Merge branch 'development_aamir' into 'master'

Chat  Fix & Web RTC -- Inprogress

See merge request Cloud_Solution/mohemm-flutter-app!154
merge-requests/155/merge
Sikander Saleem 2 years ago
commit 2b35c3d8d6

@ -7,7 +7,15 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Chat Web RTC Calling -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application <application
android:allowBackup="false" android:allowBackup="false"

@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/generated/codegen_loader.g.dart'; import 'package:mohem_flutter_app/generated/codegen_loader.g.dart';
import 'package:mohem_flutter_app/models/post_params_model.dart'; import 'package:mohem_flutter_app/models/post_params_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/provider/eit_provider_model.dart'; import 'package:mohem_flutter_app/provider/eit_provider_model.dart';
@ -27,7 +28,6 @@ Logger logger = Logger(
// output: null, // U // output: null, // U
); );
class MyHttpOverrides extends HttpOverrides { class MyHttpOverrides extends HttpOverrides {
@override @override
HttpClient createHttpClient(SecurityContext? context) { HttpClient createHttpClient(SecurityContext? context) {
@ -69,7 +69,10 @@ Future<void> main() async {
), ),
ChangeNotifierProvider<MarathonProvider>( ChangeNotifierProvider<MarathonProvider>(
create: (_) => MarathonProvider(), create: (_) => MarathonProvider(),
) ),
// ChangeNotifierProvider<ChatCallProvider>(
// create: (_) => ChatCallProvider(),
// ),
], ],
child: const MyApp(), child: const MyApp(),
), ),
@ -261,4 +264,3 @@ class MyApp extends StatelessWidget {
// }); // });
// } // }
// } // }

@ -7,127 +7,191 @@ import 'dart:convert';
class CallDataModel { class CallDataModel {
CallDataModel({ CallDataModel({
this.callerId, this.callerId,
this.callReceiverID, this.callerDetails,
this.notificationForeground, this.receiverId,
this.message, this.receiverDetails,
this.title, this.title,
this.type, this.calltype,
this.identity,
this.name,
this.isCall,
this.isWebrtc,
this.contant,
this.contantNo,
this.chatEventId,
this.fileTypeId,
this.currentUserId,
this.chatSource,
this.userChatHistoryLineRequestList,
this.server,
}); });
String? callerId; String? callerId;
String? callReceiverID; CallerDetails? callerDetails;
String? notificationForeground; String? receiverId;
String? message; ReceiverDetails? receiverDetails;
String? title; dynamic title;
String? type; String? calltype;
String? identity;
String? name;
String? isCall;
String? isWebrtc;
String? contant;
String? contantNo;
String? chatEventId;
dynamic? fileTypeId;
String? currentUserId;
String? chatSource;
List<UserChatHistoryLineRequestList>? userChatHistoryLineRequestList;
String? server;
factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str)); factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());
factory CallDataModel.fromJson(Map<String, dynamic> json) => CallDataModel( factory CallDataModel.fromJson(Map<String, dynamic> json) => CallDataModel(
callerId: json["callerID"] == null ? null : json["callerID"], callerId: json["callerID"],
callReceiverID: json["callReceiverID"] == null ? null : json["callReceiverID"], callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]),
notificationForeground: json["notification_foreground"] == null ? null : json["notification_foreground"], receiverId: json["receiverID"],
message: json["message"] == null ? null : json["message"], receiverDetails: json["receiverDetails"] == null ? null : ReceiverDetails.fromJson(json["receiverDetails"]),
title: json["title"] == null ? null : json["title"], title: json["title"],
type: json["type"] == null ? null : json["type"], calltype: json["calltype"],
identity: json["identity"] == null ? null : json["identity"], );
name: json["name"] == null ? null : json["name"],
isCall: json["is_call"] == null ? null : json["is_call"], Map<String, dynamic> toJson() => {
isWebrtc: json["is_webrtc"] == null ? null : json["is_webrtc"], "callerID": callerId,
contant: json["contant"] == null ? null : json["contant"], "callerDetails": callerDetails?.toJson(),
contantNo: json["contantNo"] == null ? null : json["contantNo"], "receiverID": receiverId,
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], "receiverDetails": receiverDetails?.toJson(),
fileTypeId: json["fileTypeId"], "title": title,
currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], "calltype": calltype,
chatSource: json["chatSource"] == null ? null : json["chatSource"], };
userChatHistoryLineRequestList: json["userChatHistoryLineRequestList"] == null }
? null
: List<UserChatHistoryLineRequestList>.from( class CallerDetails {
json["userChatHistoryLineRequestList"].map( CallerDetails({
(x) => UserChatHistoryLineRequestList.fromJson(x), this.response,
), this.errorResponses,
), });
server: json["server"] == null ? null : json["server"],
Response? response;
dynamic errorResponses;
factory CallerDetails.fromRawJson(String str) => CallerDetails.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory CallerDetails.fromJson(Map<String, dynamic> json) => CallerDetails(
response: json["response"] == null ? null : Response.fromJson(json["response"]),
errorResponses: json["errorResponses"],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"callerID": callerId == null ? null : callerId, "response": response?.toJson(),
"callReceiverID": callReceiverID == null ? null : callReceiverID, "errorResponses": errorResponses,
"notification_foreground": notificationForeground == null ? null : notificationForeground,
"message": message == null ? null : message,
"title": title == null ? null : title,
"type": type == null ? null : type,
"identity": identity == null ? null : identity,
"name": name == null ? null : name,
"is_call": isCall == null ? null : isCall,
"is_webrtc": isWebrtc == null ? null : isWebrtc,
"contant": contant == null ? null : contant,
"contantNo": contantNo == null ? null : contantNo,
"chatEventId": chatEventId == null ? null : chatEventId,
"fileTypeId": fileTypeId,
"currentUserId": currentUserId == null ? null : currentUserId,
"chatSource": chatSource == null ? null : chatSource,
"userChatHistoryLineRequestList": userChatHistoryLineRequestList == null
? null
: List<dynamic>.from(
userChatHistoryLineRequestList!.map(
(x) => x.toJson(),
),
),
"server": server == null ? null : server,
}; };
} }
class UserChatHistoryLineRequestList { class Response {
UserChatHistoryLineRequestList({ Response({
this.isSeen, this.id,
this.isDelivered, this.userName,
this.targetUserId, this.email,
this.targetUserStatus, this.phone,
this.title,
this.token,
this.isDomainUser,
this.isActiveCode,
this.encryptedUserId,
this.encryptedUserName,
}); });
bool? isSeen; int? id;
bool? isDelivered; String? userName;
int? targetUserId; String? email;
int? targetUserStatus; dynamic phone;
String? title;
String? token;
bool? isDomainUser;
bool? isActiveCode;
String? encryptedUserId;
String? encryptedUserName;
factory Response.fromRawJson(String str) => Response.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Response.fromJson(Map<String, dynamic> json) => Response(
id: json["id"],
userName: json["userName"],
email: json["email"],
phone: json["phone"],
title: json["title"],
token: json["token"],
isDomainUser: json["isDomainUser"],
isActiveCode: json["isActiveCode"],
encryptedUserId: json["encryptedUserId"],
encryptedUserName: json["encryptedUserName"],
);
Map<String, dynamic> toJson() => {
"id": id,
"userName": userName,
"email": email,
"phone": phone,
"title": title,
"token": token,
"isDomainUser": isDomainUser,
"isActiveCode": isActiveCode,
"encryptedUserId": encryptedUserId,
"encryptedUserName": encryptedUserName,
};
}
class ReceiverDetails {
ReceiverDetails({
this.id,
this.userName,
this.email,
this.phone,
this.title,
this.userStatus,
this.image,
this.unreadMessageCount,
this.userAction,
this.isPin,
this.isFav,
this.isAdmin,
this.rKey,
this.totalCount,
});
int? id;
String? userName;
String? email;
dynamic phone;
dynamic title;
int? userStatus;
String? image;
int? unreadMessageCount;
dynamic userAction;
bool? isPin;
bool? isFav;
bool? isAdmin;
String? rKey;
int? totalCount;
factory ReceiverDetails.fromRawJson(String str) => ReceiverDetails.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory UserChatHistoryLineRequestList.fromJson(Map<String, dynamic> json) => UserChatHistoryLineRequestList( factory ReceiverDetails.fromJson(Map<String, dynamic> json) => ReceiverDetails(
isSeen: json["isSeen"] == null ? null : json["isSeen"], id: json["id"],
isDelivered: json["isDelivered"] == null ? null : json["isDelivered"], userName: json["userName"],
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], email: json["email"],
targetUserStatus: json["targetUserStatus"] == null ? null : json["targetUserStatus"], phone: json["phone"],
title: json["title"],
userStatus: json["userStatus"],
image: json["image"],
unreadMessageCount: json["unreadMessageCount"],
userAction: json["userAction"],
isPin: json["isPin"],
isFav: json["isFav"],
isAdmin: json["isAdmin"],
rKey: json["rKey"],
totalCount: json["totalCount"],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"isSeen": isSeen == null ? null : isSeen, "id": id,
"isDelivered": isDelivered == null ? null : isDelivered, "userName": userName,
"targetUserId": targetUserId == null ? null : targetUserId, "email": email,
"targetUserStatus": targetUserStatus == null ? null : targetUserStatus, "phone": phone,
"title": title,
"userStatus": userStatus,
"image": image,
"unreadMessageCount": unreadMessageCount,
"userAction": userAction,
"isPin": isPin,
"isFav": isFav,
"isAdmin": isAdmin,
"rKey": rKey,
"totalCount": totalCount,
}; };
} }

@ -0,0 +1,187 @@
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
///////////////////// Web RTC Video Calling //////////////////////
// Video Call
late RTCPeerConnection _peerConnection;
RTCVideoRenderer _localVideoRenderer = RTCVideoRenderer();
final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
MediaStream? _localStream;
MediaStream? _remoteStream;
void initCallListeners() {
chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection.on("OnOfferAsync", onOfferAsync);
chatHubConnection.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection.on("OnHangUpAsync", onHangUpAsync);
chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync);
}
//Video Constraints
var videoConstraints = {
"video": {
"mandatory": {
"width": {"min": 320},
"height": {"min": 180}
},
"optional": [
{
"width": {"max": 1280}
},
{"frameRate": 25},
{"facingMode": "user"}
]
},
"frameRate": 25,
"width": 420, //420,//640,//1280,
"height": 240 //240//480//720
};
// Audio Constraints
var audioConstraints = {
"sampleRate": 8000,
"sampleSize": 16,
"channelCount": 2,
"echoCancellation": true,
"audio": true,
};
Future<RTCPeerConnection> _createPeerConnection() async {
// {"url": "stun:stun.l.google.com:19302"},
Map<String, dynamic> configuration = {
"iceServers": [
{"urls": 'stun:15.185.116.59:3478'},
{"urls": "turn:15.185.116.59:3479", "username": "admin", "credential": "admin"}
]
};
Map<String, dynamic> offerSdpConstraints = {
"mandatory": {
"OfferToReceiveAudio": true,
"OfferToReceiveVideo": true,
},
"optional": [],
};
RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
// if (pc != null) print(pc);
//pc.addStream(widget.localStream);
pc.onIceCandidate = (e) {
if (e.candidate != null) {
print(json.encode({
'candidate': e.candidate.toString(),
'sdpMid': e.sdpMid.toString(),
'sdpMlineIndex': e.sdpMLineIndex,
}));
}
};
pc.onIceConnectionState = (e) {
print(e);
};
pc.onAddStream = (stream) {
print('addStream: ' + stream.id);
_remoteRenderer.srcObject = stream;
};
return pc;
}
void init() {
initRenderers();
_createPeerConnection().then((pc) {
_peerConnection = pc;
// _setRemoteDescription(widget.info);
});
}
void initRenderers() {
_localVideoRenderer.initialize();
_remoteRenderer.initialize();
initLocalCamera();
}
void initLocalCamera() async {
_localStream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true});
_localVideoRenderer.srcObject = _localStream;
// _localVideoRenderer.srcObject = await navigator.mediaDevices
// .getUserMedia({'video': true, 'audio': true});
print('this source Object');
print('this suarce ${_localVideoRenderer.srcObject != null}');
notifyListeners();
}
void startCall({required String callType}) {}
void endCall() {}
void checkCall(Map<String, dynamic> message) {
switch (message["callStatus"]) {
case 'connected':
{}
break;
case 'offer':
{}
break;
case 'accept':
{}
break;
case 'candidate':
{}
break;
case 'bye':
{}
break;
case 'leave':
{}
break;
}
}
//// Listeners Methods ////
void onCallAcceptedAsync(List<Object?>? params) {}
void onIceCandidateAsync(List<Object?>? params) {}
void onOfferAsync(List<Object?>? params) {}
void onAnswerOffer(List<Object?>? params) {}
void onHangUpAsync(List<Object?>? params) {}
void onCallDeclinedAsync(List<Object?>? params) {}
//// Invoke Methods
Future<void> invoke({required String invokeMethod, required String currentUserID, required String targetUserID, bool isVideoCall = false, var data}) async {
List<Object> args = [];
if (invokeMethod == "answerCallAsync") {
args = [currentUserID, targetUserID];
} else if (invokeMethod == "CallUserAsync") {
args = [currentUserID, targetUserID, isVideoCall];
} else if (invokeMethod == "IceCandidateAsync") {
args = [targetUserID, data];
} else if (invokeMethod == "OfferAsync") {
args = [targetUserID, data];
} else if (invokeMethod == "AnswerOfferAsync") {
args = [targetUserID, data];
//json In Data
}
await chatHubConnection.invoke(invokeMethod, args: args);
}
void stopListeners() async {
chatHubConnection.off('OnCallDeclinedAsync');
chatHubConnection.off('OnCallAcceptedAsync');
chatHubConnection.off('OnIceCandidateAsync');
chatHubConnection.off('OnAnswerOffer');
}
}

@ -69,6 +69,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
List<ChatUser> teamMembersList = []; List<ChatUser> teamMembersList = [];
Material.TextDirection textDirection = Material.TextDirection.ltr; Material.TextDirection textDirection = Material.TextDirection.ltr;
bool isRTL = false;
String msgText = "";
//Chat Home Page Counter //Chat Home Page Counter
int chatUConvCounter = 0; int chatUConvCounter = 0;
@ -77,6 +79,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
List<ChatUser>? chatUsersList = []; List<ChatUser>? chatUsersList = [];
int pageNo = 1; int pageNo = 1;
bool disbaleChatForThisUser = false;
Future<void> getUserAutoLoginToken() async { Future<void> getUserAutoLoginToken() async {
userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) { if (userLoginResponse.response != null) {
@ -86,6 +90,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Utils.showToast( Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
); );
disbaleChatForThisUser = true;
notifyListeners();
} }
} }
@ -117,6 +123,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
// chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
if (kDebugMode) { if (kDebugMode) {
logger.i("All listeners registered"); logger.i("All listeners registered");
} }
@ -1007,6 +1014,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void disposeData() { void disposeData() {
if (!disbaleChatForThisUser) {
search.clear(); search.clear();
isChatScreenActive = false; isChatScreenActive = false;
receiverID = 0; receiverID = 0;
@ -1025,6 +1033,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
chatHubConnection.stop(); chatHubConnection.stop();
AppState().chatDetails = null; AppState().chatDetails = null;
} }
}
void deleteData() { void deleteData() {
List<ChatUser> exists = [], unique = []; List<ChatUser> exists = [], unique = [];
@ -1407,17 +1416,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void inputBoxDirection(String val) { void inputBoxDirection(String val) {
if (val.isNotEmpty) { if (val.isNotEmpty) {
isTextMsg = true; isTextMsg = true;
RegExp exp = RegExp("[a-zA-Z]");
if (exp.hasMatch(val.substring(val.length - 1)) && val.substring(val.length - 1) != " ") {
textDirection = Material.TextDirection.ltr;
notifyListeners();
} else if (val.substring(val.length - 1) != " " && !exp.hasMatch(val.substring(val.length - 1))) {
textDirection = Material.TextDirection.rtl;
notifyListeners();
}
} else { } else {
isTextMsg = false; isTextMsg = false;
} }
msgText = val;
notifyListeners();
}
void onDirectionChange(bool val) {
isRTL = val;
notifyListeners();
} }
Material.TextDirection getTextDirection(String v) { Material.TextDirection getTextDirection(String v) {
@ -1451,18 +1459,19 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
void openChatByNoti(BuildContext context) async { void openChatByNoti(BuildContext context) async {
SingleUserChatModel nUser = SingleUserChatModel();
Utils.saveStringFromPrefs("isAppOpendByChat", "false"); Utils.saveStringFromPrefs("isAppOpendByChat", "false");
SingleUserChatModel nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); if (await Utils.getStringFromPrefs("notificationData") != "null") {
nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData")));
Utils.saveStringFromPrefs("notificationData", "null"); Utils.saveStringFromPrefs("notificationData", "null");
logger.w(jsonEncode(nUser));
Future.delayed(const Duration(seconds: 2)); Future.delayed(const Duration(seconds: 2));
for (ChatUser user in searchedChats!) { for (ChatUser user in searchedChats!) {
if (user.id == nUser.targetUserId) { if (user.id == nUser.targetUserId) {
Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false));
return; return;
} else {
openChatByNoti(context);
} }
} }
} }
Utils.saveStringFromPrefs("notificationData", "null");
}
} }

@ -10,12 +10,14 @@ import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart'; import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:provider/provider.dart';
class OutGoingCall extends StatefulWidget { class OutGoingCall extends StatefulWidget {
CallDataModel OutGoingCallData; CallDataModel outGoingCallData;
bool? isVideoCall; bool isVideoCall;
OutGoingCall({Key? key, required this.OutGoingCallData, this.isVideoCall}) : super(key: key); OutGoingCall({Key? key, required this.outGoingCallData, required this.isVideoCall}) : super(key: key);
@override @override
_OutGoingCallState createState() => _OutGoingCallState(); _OutGoingCallState createState() => _OutGoingCallState();
@ -23,23 +25,25 @@ class OutGoingCall extends StatefulWidget {
class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderStateMixin { class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderStateMixin {
AnimationController? _animationController; AnimationController? _animationController;
CameraController? _controller; late CameraController controller;
late List<CameraDescription> _cameras;
Future<void>? _initializeControllerFuture; Future<void>? _initializeControllerFuture;
bool isCameraReady = false; bool isCameraReady = false;
bool isMicOff = false; bool isMicOff = false;
bool isLoudSpeaker = false; bool isLoudSpeaker = false;
bool isCamOff = false; bool isCamOff = false;
late ChatCallProvider callProviderd;
@override @override
void initState() { void initState() {
callProviderd = Provider.of<ChatCallProvider>(context, listen: false);
_animationController = AnimationController( _animationController = AnimationController(
vsync: this, vsync: this,
duration: const Duration( duration: const Duration(
milliseconds: 500, milliseconds: 500,
), ),
); );
logger.d(jsonEncode(widget.OutGoingCallData)); // _runAnimation();
//_runAnimation();
// connectSignaling(); // connectSignaling();
WidgetsBinding.instance.addPostFrameCallback( WidgetsBinding.instance.addPostFrameCallback(
(_) => _runAnimation(), (_) => _runAnimation(),
@ -58,13 +62,10 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
return Stack( return Stack(
alignment: FractionalOffset.center, alignment: FractionalOffset.center,
children: <Widget>[ children: <Widget>[
if (widget.isVideoCall!) if (widget.isVideoCall)
Positioned.fill( Positioned.fill(
child: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: CameraPreview( child: CameraPreview(
_controller!, controller,
),
), ),
), ),
Positioned.fill( Positioned.fill(
@ -74,7 +75,7 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity( color: MyColors.grey57Color.withOpacity(
0.7, 0.3,
), ),
), ),
child: Column( child: Column(
@ -105,9 +106,9 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
10.height, 10.height,
const Text( Text(
"Aamir Saleem Ahmad", widget.outGoingCallData.title,
style: TextStyle( style: const TextStyle(
fontSize: 21, fontSize: 21,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: MyColors.white, color: MyColors.white,
@ -179,7 +180,7 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
if (widget.isVideoCall!) if (widget.isVideoCall)
RawMaterialButton( RawMaterialButton(
onPressed: () { onPressed: () {
_camOff(); _camOff();
@ -267,13 +268,10 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
} }
void _runAnimation() async { void _runAnimation() async {
List<CameraDescription> cameras = await availableCameras(); _cameras = await availableCameras();
CameraDescription firstCamera = cameras[1]; CameraDescription firstCamera = _cameras[1];
_controller = CameraController( controller = CameraController(firstCamera, ResolutionPreset.medium);
firstCamera, _initializeControllerFuture = controller.initialize();
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller!.initialize();
setState(() {}); setState(() {});
// setAudioFile(); // setAudioFile();
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
@ -304,7 +302,7 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
try { try {
// backToHome(); // backToHome();
// final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity); // final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity);
await _controller?.dispose(); await controller?.dispose();
// changeCallStatusAPI(4); // changeCallStatusAPI(4);

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -13,7 +14,10 @@ import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/chat/call.dart'; import 'package:mohem_flutter_app/models/chat/call.dart';
import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart';
import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart';
import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart';
import 'package:mohem_flutter_app/provider/chat_call_provider.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_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/ui/chat/chat_bubble.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart'; import 'package:mohem_flutter_app/ui/chat/common.dart';
@ -41,8 +45,10 @@ class ChatDetailScreen extends StatefulWidget {
class _ChatDetailScreenState extends State<ChatDetailScreen> { class _ChatDetailScreenState extends State<ChatDetailScreen> {
final RefreshController _rc = RefreshController(initialRefresh: false); final RefreshController _rc = RefreshController(initialRefresh: false);
late ChatProviderModel data; late ChatProviderModel data;
late ChatCallProvider callPro;
ChatDetailedScreenParams? params; ChatDetailedScreenParams? params;
var textDirection = TextDirection.RTL;
// var textDirection = TextDirection.RTL;
void getMoreChat() async { void getMoreChat() async {
if (params != null) { if (params != null) {
@ -72,6 +78,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams; params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams;
data = Provider.of<ChatProviderModel>(context, listen: false); data = Provider.of<ChatProviderModel>(context, listen: false);
// callPro = Provider.of<ChatCallProvider>(context, listen: false);
if (params != null) { if (params != null) {
data.getSingleUserChatHistory( data.getSingleUserChatHistory(
senderUID: AppState().chatDetails!.response!.id!.toInt(), senderUID: AppState().chatDetails!.response!.id!.toInt(),
@ -92,11 +99,11 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
chatUser: params!.chatUser, chatUser: params!.chatUser,
actions: [ actions: [
// SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { // SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() {
// // makeCall(callType: "AUDIO", con: hubConnection); // makeCall(callType: "AUDIO");
// }), // }),
// 24.width, // 24.width,
// SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() { // SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() {
// // makeCall(callType: "VIDEO", con: hubConnection); // makeCall(callType: "VIDEO");
// }), // }),
// 21.width, // 21.width,
], ],
@ -252,14 +259,15 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
if (!m.isRecoding) if (!m.isRecoding)
Row( Row(
children: [ children: [
TextField( CustomAutoDirection(
textDirection: m.textDirection, onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL),
text: m.msgText,
child: TextField(
// textDirection: m.textDirection,
controller: m.message, controller: m.message,
decoration: InputDecoration( decoration: InputDecoration(
hintTextDirection: m.textDirection, hintTextDirection: m.textDirection,
hintText: m.isAttachmentMsg hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
? m.selectedFile.path.split("/").last
: m.textDirection.name == "rtl" ? "اكتب هنا للرد" :LocaleKeys.typeheretoreply.tr(),
hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
border: InputBorder.none, border: InputBorder.none,
focusedBorder: InputBorder.none, focusedBorder: InputBorder.none,
@ -283,6 +291,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!); m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!);
}, },
).expanded, ).expanded,
),
if (m.sFileType.isNotEmpty) if (m.sFileType.isNotEmpty)
Row( Row(
children: <Widget>[ children: <Widget>[
@ -342,45 +351,30 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
} }
} }
void makeCall({required String callType, required HubConnection con}) async { void makeCall({required String callType}) async {
callPro.initCallListeners();
print("================== Make call Triggered ============================"); print("================== Make call Triggered ============================");
Map<String, dynamic> json = { Map<String, dynamic> json = {
"callerID": AppState().chatDetails!.response!.id!.toString(), "callerID": AppState().chatDetails!.response!.id!.toString(),
"callReceiverID": params!.chatUser!.id.toString(), "callerDetails": AppState().chatDetails!.toJson(),
"notification_foreground": "true", "receiverID": params!.chatUser!.id.toString(),
"message": "Aamir is calling", "receiverDetails": params!.chatUser!.toJson(),
"title": "Video Call", "title": params!.chatUser!.userName!.replaceAll(".", " "),
"type": callType == "VIDEO" ? "Video" : "Audio", "calltype": callType == "VIDEO" ? "Video" : "Audio",
"identity": AppState().chatDetails!.response!.userName,
"name": AppState().chatDetails!.response!.title,
"is_call": "true",
"is_webrtc": "true",
"contant": "Start video Call ${AppState().chatDetails!.response!.userName}",
"contantNo": "775d1f11-62d9-6fcc-91f6-21f8c14559fb",
"chatEventId": "3",
"fileTypeId": null,
"currentUserId": AppState().chatDetails!.response!.id!.toString(),
"chatSource": "1",
"userChatHistoryLineRequestList": [
{
"isSeen": false,
"isDelivered": false,
"targetUserId": params!.chatUser!.id!,
"targetUserStatus": 4,
}
],
// "server": "https://192.168.8.163:8086",
"server": "https://livecareturn.hmg.com:8086",
}; };
logger.w(json);
CallDataModel callData = CallDataModel.fromJson(json); CallDataModel callData = CallDataModel.fromJson(json);
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (BuildContext context) => OutGoingCall( builder: (BuildContext context) => OutGoingCall(
isVideoCall: callType == "VIDEO" ? true : false, isVideoCall: callType == "VIDEO" ? true : false,
OutGoingCallData: callData, outGoingCallData: callData,
), ),
), ),
); ).then((value) {
print("then");
callPro.stopListeners();
});
} }
} }

@ -52,11 +52,11 @@ class _ChatHomeState extends State<ChatHome> {
if (data.searchedChats == null || data.searchedChats!.isEmpty) { if (data.searchedChats == null || data.searchedChats!.isEmpty) {
data.isLoading = true; data.isLoading = true;
data.getUserRecentChats().whenComplete(() async { data.getUserRecentChats().whenComplete(() async {
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); // String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
String notificationData = await Utils.getStringFromPrefs("notificationData"); // String notificationData = await Utils.getStringFromPrefs("notificationData");
if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { // if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") {
data.openChatByNoti(context); // data.openChatByNoti(context);
} // }
}); });
} }
} }

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
class CustomAutoDirection extends StatefulWidget {
final String text;
final Widget child;
final void Function(bool isRTL)? onDirectionChange;
const CustomAutoDirection({Key? key, required this.text, required this.child, this.onDirectionChange}) : super(key: key);
@override
_CustomAutoDirectionState createState() => _CustomAutoDirectionState();
}
class _CustomAutoDirectionState extends State<CustomAutoDirection> {
late String text;
late Widget childWidget;
@override
Widget build(BuildContext context) {
text = widget.text;
childWidget = widget.child;
return Directionality(textDirection: isRTL(text) ? TextDirection.rtl : TextDirection.ltr, child: childWidget);
}
@override
void didUpdateWidget(CustomAutoDirection oldWidget) {
if (isRTL(oldWidget.text) != isRTL(widget.text)) {
WidgetsBinding.instance.addPostFrameCallback((_) => widget.onDirectionChange?.call(isRTL(widget.text)));
}
super.didUpdateWidget(oldWidget);
}
bool isRTL(String text) {
if (text.isEmpty) return Directionality.of(context) == TextDirection.rtl;
return intl.Bidi.detectRtlDirectionality(text);
}
}

@ -86,11 +86,14 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
super.dispose(); super.dispose();
if (!cProvider.disbaleChatForThisUser) {
chatHubConnection.stop(); chatHubConnection.stop();
} }
}
void _bHubCon() { void _bHubCon() {
cProvider.getUserAutoLoginToken().whenComplete(() async { cProvider.getUserAutoLoginToken().whenComplete(() async {
if (!cProvider.disbaleChatForThisUser) {
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
if (isAppOpendByChat != null && isAppOpendByChat == "true") { if (isAppOpendByChat != null && isAppOpendByChat == "true") {
Utils.showLoading(context); Utils.showLoading(context);
@ -105,6 +108,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!);
}); });
} }
}
}); });
} }
@ -139,7 +143,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchMenuEntries(); data.fetchMenuEntries();
data.getCategoryOffersListAPI(context); data.getCategoryOffersListAPI(context);
marathonProvider.getMarathonDetailsFromApi(); marathonProvider.getMarathonDetailsFromApi();
if (!isFromInit) checkHubCon(); if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted(); _refreshController.refreshCompleted();
} }
@ -555,7 +559,11 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
"assets/icons/chat/chat.svg", "assets/icons/chat/chat.svg",
color: currentIndex == 4 ? MyColors.grey3AColor : MyColors.grey98Color, color: currentIndex == 4
? MyColors.grey3AColor
: cProvider.disbaleChatForThisUser
? MyColors.lightGreyE3Color
: MyColors.grey98Color,
).paddingAll(4), ).paddingAll(4),
Consumer<ChatProviderModel>( Consumer<ChatProviderModel>(
builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { builder: (BuildContext cxt, ChatProviderModel data, Widget? child) {
@ -565,7 +573,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
child: Container( child: Container(
padding: const EdgeInsets.only(left: 4, right: 4), padding: const EdgeInsets.only(left: 4, right: 4),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white), child: data.chatUConvCounter.toString().toText10(color: Colors.white),
), ),
); );
@ -592,8 +600,10 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
} else if (index == 3) { } else if (index == 3) {
Navigator.pushNamed(context, AppRoutes.itemsForSale); Navigator.pushNamed(context, AppRoutes.itemsForSale);
} else if (index == 4) { } else if (index == 4) {
if (!cProvider.disbaleChatForThisUser) {
Navigator.pushNamed(context, AppRoutes.chat); Navigator.pushNamed(context, AppRoutes.chat);
} }
}
}, },
), ),
), ),

@ -91,7 +91,7 @@ dependencies:
logging: ^1.0.1 logging: ^1.0.1
swipe_to: ^1.0.2 swipe_to: ^1.0.2
flutter_webrtc: ^0.9.16 flutter_webrtc: ^0.9.16
camera: ^0.10.0+4 camera: ^0.10.3
flutter_local_notifications: any flutter_local_notifications: any
#firebase_analytics: any #firebase_analytics: any

Loading…
Cancel
Save