Merge branch 'master' into development_haroon

merge-requests/155/head
haroon amjad 2 years ago
commit e0d02554b1

@ -8,6 +8,14 @@
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CAMERA" />
<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
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/generated/codegen_loader.g.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/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/provider/eit_provider_model.dart';
@ -27,7 +28,6 @@ Logger logger = Logger(
// output: null, // U
);
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
@ -69,7 +69,10 @@ Future<void> main() async {
),
ChangeNotifierProvider<MarathonProvider>(
create: (_) => MarathonProvider(),
)
),
// ChangeNotifierProvider<ChatCallProvider>(
// create: (_) => ChatCallProvider(),
// ),
],
child: const MyApp(),
),
@ -261,4 +264,3 @@ class MyApp extends StatelessWidget {
// });
// }
// }

@ -7,127 +7,191 @@ import 'dart:convert';
class CallDataModel {
CallDataModel({
this.callerId,
this.callReceiverID,
this.notificationForeground,
this.message,
this.callerDetails,
this.receiverId,
this.receiverDetails,
this.title,
this.type,
this.identity,
this.name,
this.isCall,
this.isWebrtc,
this.contant,
this.contantNo,
this.chatEventId,
this.fileTypeId,
this.currentUserId,
this.chatSource,
this.userChatHistoryLineRequestList,
this.server,
this.calltype,
});
String? callerId;
String? callReceiverID;
String? notificationForeground;
String? message;
String? title;
String? type;
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;
CallerDetails? callerDetails;
String? receiverId;
ReceiverDetails? receiverDetails;
dynamic title;
String? calltype;
factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory CallDataModel.fromJson(Map<String, dynamic> json) => CallDataModel(
callerId: json["callerID"] == null ? null : json["callerID"],
callReceiverID: json["callReceiverID"] == null ? null : json["callReceiverID"],
notificationForeground: json["notification_foreground"] == null ? null : json["notification_foreground"],
message: json["message"] == null ? null : json["message"],
title: json["title"] == null ? null : json["title"],
type: json["type"] == null ? null : json["type"],
identity: json["identity"] == null ? null : json["identity"],
name: json["name"] == null ? null : json["name"],
isCall: json["is_call"] == null ? null : json["is_call"],
isWebrtc: json["is_webrtc"] == null ? null : json["is_webrtc"],
contant: json["contant"] == null ? null : json["contant"],
contantNo: json["contantNo"] == null ? null : json["contantNo"],
chatEventId: json["chatEventId"] == null ? null : json["chatEventId"],
fileTypeId: json["fileTypeId"],
currentUserId: json["currentUserId"] == null ? null : json["currentUserId"],
chatSource: json["chatSource"] == null ? null : json["chatSource"],
userChatHistoryLineRequestList: json["userChatHistoryLineRequestList"] == null
? null
: List<UserChatHistoryLineRequestList>.from(
json["userChatHistoryLineRequestList"].map(
(x) => UserChatHistoryLineRequestList.fromJson(x),
),
),
server: json["server"] == null ? null : json["server"],
callerId: json["callerID"],
callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]),
receiverId: json["receiverID"],
receiverDetails: json["receiverDetails"] == null ? null : ReceiverDetails.fromJson(json["receiverDetails"]),
title: json["title"],
calltype: json["calltype"],
);
Map<String, dynamic> toJson() => {
"callerID": callerId,
"callerDetails": callerDetails?.toJson(),
"receiverID": receiverId,
"receiverDetails": receiverDetails?.toJson(),
"title": title,
"calltype": calltype,
};
}
class CallerDetails {
CallerDetails({
this.response,
this.errorResponses,
});
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() => {
"callerID": callerId == null ? null : callerId,
"callReceiverID": callReceiverID == null ? null : callReceiverID,
"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,
"response": response?.toJson(),
"errorResponses": errorResponses,
};
}
class UserChatHistoryLineRequestList {
UserChatHistoryLineRequestList({
this.isSeen,
this.isDelivered,
this.targetUserId,
this.targetUserStatus,
class Response {
Response({
this.id,
this.userName,
this.email,
this.phone,
this.title,
this.token,
this.isDomainUser,
this.isActiveCode,
this.encryptedUserId,
this.encryptedUserName,
});
bool? isSeen;
bool? isDelivered;
int? targetUserId;
int? targetUserStatus;
int? id;
String? userName;
String? email;
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(
isSeen: json["isSeen"] == null ? null : json["isSeen"],
isDelivered: json["isDelivered"] == null ? null : json["isDelivered"],
targetUserId: json["targetUserId"] == null ? null : json["targetUserId"],
targetUserStatus: json["targetUserStatus"] == null ? null : json["targetUserStatus"],
factory ReceiverDetails.fromJson(Map<String, dynamic> json) => ReceiverDetails(
id: json["id"],
userName: json["userName"],
email: json["email"],
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() => {
"isSeen": isSeen == null ? null : isSeen,
"isDelivered": isDelivered == null ? null : isDelivered,
"targetUserId": targetUserId == null ? null : targetUserId,
"targetUserStatus": targetUserStatus == null ? null : targetUserStatus,
"id": id,
"userName": userName,
"email": email,
"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 = [];
Material.TextDirection textDirection = Material.TextDirection.ltr;
bool isRTL = false;
String msgText = "";
//Chat Home Page Counter
int chatUConvCounter = 0;
@ -77,6 +79,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
List<ChatUser>? chatUsersList = [];
int pageNo = 1;
bool disbaleChatForThisUser = false;
Future<void> getUserAutoLoginToken() async {
userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
if (userLoginResponse.response != null) {
@ -86,6 +90,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Utils.showToast(
userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr",
);
disbaleChatForThisUser = true;
notifyListeners();
}
}
@ -117,6 +123,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
// chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
if (kDebugMode) {
logger.i("All listeners registered");
}
@ -1007,6 +1014,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
void disposeData() {
if (!disbaleChatForThisUser) {
search.clear();
isChatScreenActive = false;
receiverID = 0;
@ -1025,6 +1033,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
chatHubConnection.stop();
AppState().chatDetails = null;
}
}
void deleteData() {
List<ChatUser> exists = [], unique = [];
@ -1407,17 +1416,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void inputBoxDirection(String val) {
if (val.isNotEmpty) {
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 {
isTextMsg = false;
}
msgText = val;
notifyListeners();
}
void onDirectionChange(bool val) {
isRTL = val;
notifyListeners();
}
Material.TextDirection getTextDirection(String v) {
@ -1451,18 +1459,19 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
void openChatByNoti(BuildContext context) async {
SingleUserChatModel nUser = SingleUserChatModel();
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");
logger.w(jsonEncode(nUser));
Future.delayed(const Duration(seconds: 2));
for (ChatUser user in searchedChats!) {
if (user.id == nUser.targetUserId) {
Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false));
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/main.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 {
CallDataModel OutGoingCallData;
bool? isVideoCall;
CallDataModel outGoingCallData;
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
_OutGoingCallState createState() => _OutGoingCallState();
@ -23,22 +25,24 @@ class OutGoingCall extends StatefulWidget {
class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderStateMixin {
AnimationController? _animationController;
CameraController? _controller;
late CameraController controller;
late List<CameraDescription> _cameras;
Future<void>? _initializeControllerFuture;
bool isCameraReady = false;
bool isMicOff = false;
bool isLoudSpeaker = false;
bool isCamOff = false;
late ChatCallProvider callProviderd;
@override
void initState() {
callProviderd = Provider.of<ChatCallProvider>(context, listen: false);
_animationController = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 500,
),
);
logger.d(jsonEncode(widget.OutGoingCallData));
// _runAnimation();
// connectSignaling();
WidgetsBinding.instance.addPostFrameCallback(
@ -58,13 +62,10 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
return Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (widget.isVideoCall!)
if (widget.isVideoCall)
Positioned.fill(
child: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: CameraPreview(
_controller!,
),
controller,
),
),
Positioned.fill(
@ -74,7 +75,7 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
child: Container(
decoration: BoxDecoration(
color: MyColors.grey57Color.withOpacity(
0.7,
0.3,
),
),
child: Column(
@ -105,9 +106,9 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
fit: BoxFit.cover,
),
10.height,
const Text(
"Aamir Saleem Ahmad",
style: TextStyle(
Text(
widget.outGoingCallData.title,
style: const TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
color: MyColors.white,
@ -179,7 +180,7 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
if (widget.isVideoCall!)
if (widget.isVideoCall)
RawMaterialButton(
onPressed: () {
_camOff();
@ -267,13 +268,10 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
}
void _runAnimation() async {
List<CameraDescription> cameras = await availableCameras();
CameraDescription firstCamera = cameras[1];
_controller = CameraController(
firstCamera,
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller!.initialize();
_cameras = await availableCameras();
CameraDescription firstCamera = _cameras[1];
controller = CameraController(firstCamera, ResolutionPreset.medium);
_initializeControllerFuture = controller.initialize();
setState(() {});
// setAudioFile();
for (int i = 0; i < 100; i++) {
@ -304,7 +302,7 @@ class _OutGoingCallState extends State<OutGoingCall> with SingleTickerProviderSt
try {
// backToHome();
// final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity);
await _controller?.dispose();
await controller?.dispose();
// changeCallStatusAPI(4);

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:easy_localization/easy_localization.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/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_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/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/chat_bubble.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
@ -41,8 +45,10 @@ class ChatDetailScreen extends StatefulWidget {
class _ChatDetailScreenState extends State<ChatDetailScreen> {
final RefreshController _rc = RefreshController(initialRefresh: false);
late ChatProviderModel data;
late ChatCallProvider callPro;
ChatDetailedScreenParams? params;
var textDirection = TextDirection.RTL;
// var textDirection = TextDirection.RTL;
void getMoreChat() async {
if (params != null) {
@ -72,6 +78,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
Widget build(BuildContext context) {
params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams;
data = Provider.of<ChatProviderModel>(context, listen: false);
// callPro = Provider.of<ChatCallProvider>(context, listen: false);
if (params != null) {
data.getSingleUserChatHistory(
senderUID: AppState().chatDetails!.response!.id!.toInt(),
@ -92,11 +99,11 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
chatUser: params!.chatUser,
actions: [
// SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() {
// // makeCall(callType: "AUDIO", con: hubConnection);
// makeCall(callType: "AUDIO");
// }),
// 24.width,
// SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() {
// // makeCall(callType: "VIDEO", con: hubConnection);
// makeCall(callType: "VIDEO");
// }),
// 21.width,
],
@ -252,14 +259,15 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
if (!m.isRecoding)
Row(
children: [
TextField(
textDirection: m.textDirection,
CustomAutoDirection(
onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL),
text: m.msgText,
child: TextField(
// textDirection: m.textDirection,
controller: m.message,
decoration: InputDecoration(
hintTextDirection: m.textDirection,
hintText: m.isAttachmentMsg
? m.selectedFile.path.split("/").last
: m.textDirection.name == "rtl" ? "اكتب هنا للرد" :LocaleKeys.typeheretoreply.tr(),
hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
border: 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!);
},
).expanded,
),
if (m.sFileType.isNotEmpty)
Row(
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 ============================");
Map<String, dynamic> json = {
"callerID": AppState().chatDetails!.response!.id!.toString(),
"callReceiverID": params!.chatUser!.id.toString(),
"notification_foreground": "true",
"message": "Aamir is calling",
"title": "Video Call",
"type": 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",
"callerDetails": AppState().chatDetails!.toJson(),
"receiverID": params!.chatUser!.id.toString(),
"receiverDetails": params!.chatUser!.toJson(),
"title": params!.chatUser!.userName!.replaceAll(".", " "),
"calltype": callType == "VIDEO" ? "Video" : "Audio",
};
logger.w(json);
CallDataModel callData = CallDataModel.fromJson(json);
await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => OutGoingCall(
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) {
data.isLoading = true;
data.getUserRecentChats().whenComplete(() async {
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
String notificationData = await Utils.getStringFromPrefs("notificationData");
if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") {
data.openChatByNoti(context);
}
// String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
// String notificationData = await Utils.getStringFromPrefs("notificationData");
// if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") {
// 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() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
if (!cProvider.disbaleChatForThisUser) {
chatHubConnection.stop();
}
}
void _bHubCon() {
cProvider.getUserAutoLoginToken().whenComplete(() async {
if (!cProvider.disbaleChatForThisUser) {
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");
if (isAppOpendByChat != null && isAppOpendByChat == "true") {
Utils.showLoading(context);
@ -105,6 +108,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!);
});
}
}
});
}
@ -139,7 +143,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchMenuEntries();
data.getCategoryOffersListAPI(context);
marathonProvider.getMarathonDetailsFromApi();
if (!isFromInit) checkHubCon();
if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted();
}
@ -555,7 +559,11 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
children: [
SvgPicture.asset(
"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),
Consumer<ChatProviderModel>(
builder: (BuildContext cxt, ChatProviderModel data, Widget? child) {
@ -565,7 +573,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
child: Container(
padding: const EdgeInsets.only(left: 4, right: 4),
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),
),
);
@ -592,8 +600,10 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
} else if (index == 3) {
Navigator.pushNamed(context, AppRoutes.itemsForSale);
} else if (index == 4) {
if (!cProvider.disbaleChatForThisUser) {
Navigator.pushNamed(context, AppRoutes.chat);
}
}
},
),
),

@ -169,7 +169,6 @@ class MarathonScreen extends StatelessWidget {
],
)
: const SizedBox(),
34.height,
if (provider.selectedWinners != null) ...<Widget>[
provider.selectedWinners!.length == 1
? Column(
@ -310,7 +309,7 @@ class MarathonScreen extends StatelessWidget {
else ...<Widget>[
MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21),
],
if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...<Widget>[
if (provider.questionCardStatus == QuestionCardStatus.findingWinner && !provider.isUserOutOfGame) ...<Widget>[
getNameContainer(context),
],
QuestionCardBuilder(
@ -337,7 +336,7 @@ class MarathonScreen extends StatelessWidget {
subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor, isCentered: true),
),
onFindingWinner: (BuildContext context) => CustomStatusWidget(
asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false),
asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false, repeat: true),
title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor),
subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor, isCentered: true),
),

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

Loading…
Cancel
Save