Call native code android & ios

development_aamir
Aamir Muhammad 2 years ago
parent 28d977017e
commit 7c980cc353

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#F15642;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M121.408,384.016c-4.096-2.32-6.656-6.912-4.096-12.288l36.72-71.76
c3.456-6.784,12.656-7.04,15.856,0l36.08,71.76c5.248,9.968-10.24,17.904-14.848,7.92l-5.632-11.248h-47.2l-5.488,11.264
C130.752,384.016,126.016,384.912,121.408,384.016z M176.416,351.52l-14.464-31.6l-15.728,31.6H176.416z"/>
<path style="fill:#FFFFFF;" d="M241.6,378.256l-33.776-70.736c-4.992-10.112,10.112-18.416,15.728-7.808l11.392,25.712
l14.704,33.76l14.448-33.76l11.392-25.712c5.12-9.712,19.952-3.584,15.616,7.04l-32.624,71.504
C255.536,386.32,246.448,388.24,241.6,378.256z"/>
<path style="fill:#FFFFFF;" d="M306.88,303.152c0-10.48,16.896-10.88,16.896,0v73.04c0,10.624-16.896,10.88-16.896,0V303.152z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#F7B84E;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M133.312,312.096v20.336h32.624c4.608,0,9.216,4.608,9.216,9.088c0,4.224-4.608,7.664-9.216,7.664
h-32.624v26.864c0,4.48-3.184,7.936-7.664,7.936c-5.632,0-9.072-3.456-9.072-7.936v-72.656c0-4.608,3.456-7.936,9.072-7.936h44.912
c5.632,0,8.96,3.328,8.96,7.936c0,4.096-3.328,8.688-8.96,8.688h-37.248V312.096z"/>
<path style="fill:#FFFFFF;" d="M195.072,303.152c0-4.224,3.584-7.808,8.064-7.808c4.096,0,7.552,3.6,7.552,7.808v64.096h34.8
c12.528,0,12.8,16.752,0,16.752h-42.336c-4.48,0-8.064-3.184-8.064-7.808v-73.04H195.072z"/>
<path style="fill:#FFFFFF;" d="M286.88,378.256l-33.776-70.752c-4.992-10.112,10.112-18.416,15.728-7.808l11.392,25.712
l14.704,33.776l14.448-33.776l11.392-25.712c5.12-9.712,19.952-3.584,15.616,7.04l-32.624,71.52
C300.816,386.32,291.728,388.224,286.88,378.256z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
<path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
<polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
<path style="fill:#50BEE8;" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16
V416z"/>
<g>
<path style="fill:#FFFFFF;" d="M96.928,327.84v47.328c0,5.648-4.608,8.832-9.216,8.832c-4.096,0-7.68-3.184-7.68-8.832v-72.016
c0-6.656,5.632-8.848,7.68-8.848c3.696,0,5.872,2.192,8.064,4.624l28.128,37.984l29.168-39.408c4.24-5.232,14.592-3.2,14.592,5.648
v72.016c0,5.648-3.568,8.832-7.664,8.832c-4.608,0-8.192-3.184-8.192-8.832V327.84l-21.248,26.864
c-4.592,5.648-10.352,5.648-14.576,0L96.928,327.84z"/>
<path style="fill:#FFFFFF;" d="M234.096,385.28c-23.664,1.024-48.24-14.72-48.24-46.064c0-31.472,24.56-46.944,48.24-46.944
c22.384,1.136,45.792,16.624,45.792,46.944C279.888,369.552,256.48,385.28,234.096,385.28z M232.688,308.912
c-14.336,0-29.936,10.112-29.936,30.32c0,20.096,15.616,30.336,29.936,30.336c14.72,0,30.448-10.24,30.448-30.336
C263.136,319.008,247.408,308.912,232.688,308.912z"/>
<path style="fill:#FFFFFF;" d="M323.664,378.256l-33.776-70.752c-4.992-10.112,10.112-18.416,15.728-7.808l11.392,25.712
l14.704,33.776l14.448-33.776l11.392-25.712c5.12-9.712,19.952-3.584,15.616,7.04l-32.624,71.52
C337.6,386.32,328.512,388.224,323.664,378.256z"/>
</g>
<path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="448" height="512" viewBox="0 0 448 512">
<g id="mp3" transform="translate(-32)">
<path id="Path_5167" data-name="Path 5167" d="M128,0A32.094,32.094,0,0,0,96,32V480a32.084,32.084,0,0,0,32,32H448a32.084,32.084,0,0,0,32-32V128L352,0Z" fill="#e2e5e7"/>
<path id="Path_5168" data-name="Path 5168" d="M384,128h96L352,0V96A32.094,32.094,0,0,0,384,128Z" fill="#b0b7bd"/>
<path id="Path_5169" data-name="Path 5169" d="M480,224l-96-96h96Z" fill="#cad1d8"/>
<path id="Path_5170" data-name="Path 5170" d="M416,416a16.047,16.047,0,0,1-16,16H48a16.047,16.047,0,0,1-16-16V256a16.047,16.047,0,0,1,16-16H400a16.047,16.047,0,0,1,16,16Z" fill="#50bee8"/>
<g id="Group_8310" data-name="Group 8310">
<path id="Path_5171" data-name="Path 5171" d="M117.184,327.84v47.344c0,5.632-4.592,8.832-9.216,8.832-4.1,0-7.664-3.2-7.664-8.832V303.152a8.527,8.527,0,0,1,7.664-8.832c3.712,0,5.888,2.192,8.064,4.608l28.16,38,29.152-39.408c4.24-5.248,14.592-3.2,14.592,5.632v72.032c0,5.632-3.6,8.832-7.68,8.832-4.592,0-8.192-3.2-8.192-8.832V327.84l-21.232,26.88c-4.592,5.632-10.352,5.632-14.576,0Z" fill="#fff"/>
<path id="Path_5172" data-name="Path 5172" d="M210.288,303.152a8.807,8.807,0,0,1,8.7-8.832h29.552c16.64,0,31.616,11.136,31.616,32.5,0,20.224-14.976,31.472-31.616,31.472h-21.36v16.9c0,5.632-3.584,8.832-8.192,8.832a8.647,8.647,0,0,1-8.7-8.832V303.152Zm16.88,7.3V342.3h21.36c8.576,0,15.36-7.552,15.36-15.488,0-8.96-6.784-16.368-15.36-16.368Z" fill="#fff"/>
<text id="_4" data-name="4" transform="translate(287 383)" fill="#fff" font-size="120" font-family="Poppins-SemiBold, Poppins" font-weight="600" letter-spacing="-0.03em"><tspan x="0" y="0">4</tspan></text>
</g>
<path id="Path_5174" data-name="Path 5174" d="M400,432H96v16H400a16.047,16.047,0,0,0,16-16V416A16.047,16.047,0,0,1,400,432Z" fill="#cad1d8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -199,6 +199,7 @@ class ChatApiClient {
"${ApiConsts.getGroupByUserId}${AppState().chatDetails!.response!.id}",
token: AppState().chatDetails!.response!.token,
);
if (!kReleaseMode) {
logger.i("res: " + response.body);
}
@ -354,7 +355,13 @@ class ChatApiClient {
String id = "";
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.oneSignalCall}players",
{"app_id": ApiConsts.oneSignalAppID, "identifier": value, "device_type": 0, "test_type": !kReleaseMode ? 1 : 0},
{
"app_id": ApiConsts.oneSignalAppID,
"identifier": value,
"device_type": 0,
"test_type": !kReleaseMode ? 1 : 0
// 1
},
);
Map<String, dynamic> values = jsonDecode(response.body) as Map<String, dynamic>;

@ -209,4 +209,12 @@ class AppState {
set setisUserOnline(bool value) {
_isUserOnline = value;
}
bool _isBackgroundCall = false;
bool get isBackgroundCall => _isBackgroundCall;
set isBackgroundCall(bool value) {
_isBackgroundCall = value;
}
}

@ -1,7 +1,6 @@
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/services.dart';
import 'package:flutter_callkit_incoming/entities/entities.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
@ -29,7 +28,6 @@ class ChatVoipCall {
dynamic inCallData;
bool isUserOnline = false;
dynamic callData;
static const platform = MethodChannel('com.example.httpchannel/http');
Future<void> showCallkitIncoming({required String uuid, RemoteMessage? data, CallDataModel? incomingCallData, bool background = false}) async {
await FlutterCallkitIncoming.endAllCalls();
@ -78,7 +76,7 @@ class ChatVoipCall {
backgroundUrl: 'assets/test.png',
actionColor: '#4CAF50',
),
ios: IOSParams(
ios: const IOSParams(
iconName: 'Mohemm',
handleType: '',
supportsVideo: true,
@ -149,11 +147,14 @@ class ChatVoipCall {
// logger.log(Level.error, "API-EVENT-END");
}
Future<void> voipDeclineCall(IosCallPayload? _iosCallPayload) async {
Future<void> voipDeclineCall(IosCallPayload? iosCallPayload) async {
try {
ALM.UserAutoLoginModel model = await ChatApiClient().getUserCallToken(userid: _iosCallPayload!.incomingCallReciverId.toString());
dynamic Res = await ChatApiClient()
.callDecline(cUserID: int.parse(_iosCallPayload!.incomingCallerId!), tUserID: int.parse(_iosCallPayload!.incomingCallReciverId.toString()), targetUsertoken: model.response!.token!);
print("DeclineVia Flutter");
print(iosCallPayload!.toRawJson());
IosCallPayload _iosCallPayload = IosCallPayload(incomingCallerId: iosCallPayload.incomingCallerId!.split("-")[0], incomingCallReciverId: iosCallPayload.incomingCallerId!.split("-")[1]);
ALM.UserAutoLoginModel model = await ChatApiClient().getUserCallToken(userid: iosCallPayload.incomingCallerId!.split("-")[1]);
await ChatApiClient()
.callDecline(cUserID: int.parse(_iosCallPayload.incomingCallerId!), tUserID: int.parse(_iosCallPayload.incomingCallReciverId.toString()), targetUsertoken: model.response!.token!);
} catch (err) {
print(err);
}

@ -21,7 +21,7 @@ import 'package:provider/single_child_widget.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:sizer/sizer.dart';
late HubConnection chatHubConnection;
HubConnection? chatHubConnection;
// test uat account
// username 199067

@ -15,7 +15,6 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da
import 'package:mohem_flutter_app/models/chat/webrtc_payloads.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/call/chat_incoming_call_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:signalr_netcore/hub_connection.dart';
class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
@ -48,20 +47,19 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
late BuildContext providerContext;
List<MediaDeviceInfo> devices = [];
var _videoDeviceId;
void initCallListeners({required BuildContext context}) {
providerContext = context;
if (kDebugMode) {
print("=================== Call Listeners Registered =======================");
}
chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection.on("OnOfferAsync", onOfferAsync);
chatHubConnection.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection.on("OnHangUpAsync", onHangUpAsync);
chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync);
// chatHubConnection.on("OnIncomingCallAsync", OnIncomingCallAsync);
chatHubConnection!.on("OnCallAcceptedAsync", onCallAcceptedAsync);
chatHubConnection!.on("OnIceCandidateAsync", onIceCandidateAsync);
chatHubConnection!.on("OnOfferAsync", onOfferAsync);
chatHubConnection!.on("OnAnswerOffer", onAnswerOffer);
chatHubConnection!.on("OnHangUpAsync", onHangUpAsync);
chatHubConnection!.on("OnCallDeclinedAsync", onCallDeclinedAsync);
// chatHubConnection!.on("OnIncomingCallAsync", OnIncomingCallAsync);
}
// Audio Constraints
@ -95,7 +93,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
void connectOutgoing() {
isOutGoingCall = true;
notifyListeners();
// notifyListeners();
}
Future<void> startCall({required String callType, required BuildContext context}) async {
@ -149,13 +147,11 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
if (isCallStarted) {
isIncomingCallLoader = false;
isOutGoingCall = true;
Navigator.push(
Navigator.pushReplacement(
providerContext,
MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(),
)).then((value) {
Navigator.of(providerContext).pop();
});
));
}
}
}
@ -187,7 +183,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
Future<bool> endCall({required bool isUserOnline}) async {
if (isIncomingCall) {
logger.i("-----------------------Endeddddd By Me---------------------------");
if (chatHubConnection.state == HubConnectionState.Connected) {
if (chatHubConnection!.state == HubConnectionState.Connected) {
await invoke(invokeMethod: "HangUpAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 0);
await invoke(invokeMethod: "UpdateUserStatusAsync", currentUserID: AppState().chatDetails!.response!.id!, targetUserID: incomingCallData.targetUserId!, userStatus: 1);
}
@ -202,7 +198,9 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
if (isCallConnected) {
if (_pc.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateConnected) {
print("------------------ PC Stopped ----------------------------");
if (kDebugMode) {
print("------------------ PC Stopped ----------------------------");
}
_pc.close();
_pc.dispose();
}
@ -221,7 +219,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
_localStream = null;
}
if (chatHubConnection != null && !isUserOnline) {
chatHubConnection.stop();
chatHubConnection!.stop();
}
await FlutterCallkitIncoming.endAllCalls();
return true;
@ -281,13 +279,26 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
}
void onHangUpAsync(List<Object?>? params) {
print("--------------------- onHangUp ---------------------------------------");
print("--------------------- onHangUp ASYNC ---------------------------------------");
dynamic items = params!.toList();
if (kDebugMode) {
logger.i("res: " + items.toString());
}
endCall(isUserOnline: isUserOnline).then((bool value) {
if (isCallConnected) {
Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
if (isCallConnected && !AppState().isBackgroundCall) {
// Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil((route) => false);
Navigator.of(AppRoutes.navigatorKey.currentContext!).popUntil(ModalRoute.withName(AppRoutes.chatDetailed));
isCallConnected = false;
}
if (items[0]["id"] != AppState().chatDetails!.response!.id && !AppState().isBackgroundCall) {
if (kDebugMode) {
print("Popped Due to Another User");
}
Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
}
if (AppState().isBackgroundCall) {
Navigator.of(AppRoutes.navigatorKey.currentContext!).pop();
}
isCallEnded = true;
});
}
@ -385,17 +396,17 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
args = [debugData];
}
try {
await chatHubConnection.invoke("$invokeMethod", args: args);
await chatHubConnection!.invoke("$invokeMethod", args: args);
} catch (e) {
logger.w(e);
}
}
void stopListeners() async {
chatHubConnection.off('OnCallDeclinedAsync');
chatHubConnection.off('OnCallAcceptedAsync');
chatHubConnection.off('OnIceCandidateAsync');
chatHubConnection.off('OnAnswerOffer');
chatHubConnection!.off('OnCallDeclinedAsync');
chatHubConnection!.off('OnCallAcceptedAsync');
chatHubConnection!.off('OnIceCandidateAsync');
chatHubConnection!.off('OnAnswerOffer');
}
void playRingtone() async {
@ -439,15 +450,18 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
},
'optional': []
};
RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints);
await pc!.addStream(_localStream!);
pc?.onConnectionState = (RTCPeerConnectionState state) {};
pc?.onAddStream = (MediaStream stream) {
// await pc.addStream(_localStream!);
//Changed By Aamir
_localStream?.getTracks().forEach((track) {
pc.addTrack(track, _localStream!);
});
pc.onConnectionState = (RTCPeerConnectionState state) {};
pc.onAddStream = (MediaStream stream) {
remoteRenderer!.srcObject = stream;
notifyListeners();
};
pc!.onIceCandidate = (RTCIceCandidate e) async {
pc.onIceCandidate = (RTCIceCandidate e) async {
if (isIncomingCall) {
if (e.candidate != null) {
var payload = {"target": incomingCallData.targetUserId, "candidate": e.toMap()};
@ -471,7 +485,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
// remoteStream.addTrack(element);
// });
// };
pc!.onSignalingState = (RTCSignalingState state) {
pc.onSignalingState = (RTCSignalingState state) {
logger.i("signaling state: " + state.name);
// invoke(
// invokeMethod: "InvokeMobile",
@ -479,14 +493,15 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
// targetUserID: incomingCallData.targetUserId!,
// debugData: {"location": "Signaling", "parms": state.name});
};
pc!.onIceGatheringState = (RTCIceGatheringState state) {
pc.onIceGatheringState = (RTCIceGatheringState state) {
logger.i("rtc ice gathering state: " + state.name);
};
pc!.onIceConnectionState = (RTCIceConnectionState state) {
pc.onIceConnectionState = (RTCIceConnectionState state) {
if (RTCIceConnectionState.RTCIceConnectionStateFailed == state ||
RTCIceConnectionState.RTCIceConnectionStateDisconnected == state ||
RTCIceConnectionState.RTCIceConnectionStateClosed == state) {
logger.i("Ice Connection State:" + state.name);
// endCall().then((value) {
// notifyListeners();
// });
@ -515,7 +530,7 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
// }
Future<RTCSessionDescription> _createOffer() async {
RTCSessionDescription description = await _pc!.createOffer();
RTCSessionDescription description = await _pc.createOffer();
// _offer = true;
return description;
}
@ -573,68 +588,92 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
Future<void> initStreams() async {
List<MediaDeviceInfo> devices = await navigator.mediaDevices.enumerateDevices();
localVideoRenderer = RTCVideoRenderer();
remoteRenderer = RTCVideoRenderer();
localVideoRenderer ??= RTCVideoRenderer();
await localVideoRenderer!.initialize();
_localStream ??= await navigator.mediaDevices.getUserMedia(isVideoCall
// ? Platform.isIOS
// ? // iOS media constraints for maximum quality camera
// {
// 'audio': true,
// 'video': {
// 'facingMode': 'user', // Use 'user' for front camera, 'environment' for back camera
// 'width': {
// 'ideal': 1080, // Set the ideal width (maximum quality)
// },
// 'height': {
// 'ideal': 1920, // Set the ideal height (maximum quality)
// },
// 'frameRate': {
// 'ideal': 30, // Set the ideal frame rate (adjust as needed)
// },
// },
// }
// : // Android media constraints for maximum quality camera
// {
// 'audio': true,
// 'video': {
// 'facingMode': 'user', // Use 'user' for front camera, 'environment' for back camera
// 'width': {
// 'ideal': 1920, // Set the ideal width (maximum quality)
// },
// 'height': {
// 'ideal': 1080, // Set the ideal height (maximum quality)
// },
// 'frameRate': {
// 'ideal': 30, // Set the ideal frame rate (adjust as needed)
// },
// },
// }
? {
"video": {
"mandatory": {
"width": {"min": 1080},
"height": {"min": 1920}
},
"optional": [
{'sourceId': devices[1].deviceId},
{
"width": {"max": 1080}
},
{"frameRate": 30},
{"facingMode": "user"}
]
},
"frameRate": 30,
"width": 1080, //420,//640,//1280,
"height": 1920, //240//480//720
"audio": true,
}
: audioConstraints);
localVideoRenderer!.srcObject = _localStream;
try {
_localStream = await navigator.mediaDevices.getUserMedia({
'audio': false,
'video': {
'mandatory': {
'minWidth': '640', // Provide your own width, height and frame rate here
'minHeight': '480',
'minFrameRate': '30',
},
'facingMode': 'user',
'optional': [],
}
});
if (kDebugMode) {
print(_localStream..toString());
}
localVideoRenderer!.srcObject = _localStream;
localVideoRenderer!.value = (const RTCVideoValue(width: 200, height: 200, renderVideo: true));
print("Working localStream");
} catch (e) {
print("Failed to get user media: $e");
}
// _localStream = await navigator.mediaDevices.getUserMedia(isVideoCall
// ? Platform.isIOS
// ? {
// 'audio': true,
// 'video': {
// 'facingMode': 'user', // Use 'user' for front camera, 'environment' for back camera
// 'width': {
// 'ideal': 1080, // Set the ideal width (maximum quality)
// },
// 'height': {
// 'ideal': 1920, // Set the ideal height (maximum quality)
// },
// 'frameRate': {
// 'ideal': 30, // Set the ideal frame rate (adjust as needed)
// },
// },
// }
// : {
// 'audio': true,
// 'video': {
// 'facingMode': 'user', // Use 'user' for front camera, 'environment' for back camera
// 'width': {
// 'ideal': 1920, // Set the ideal width (maximum quality)
// },
// 'height': {
// 'ideal': 1080, // Set the ideal height (maximum quality)
// },
// 'frameRate': {
// 'ideal': 30, // Set the ideal frame rate (adjust as needed)
// },
// },
// }
//
// // ? {
// // "video": {
// // "mandatory": {
// // "width": {"min": 1080},
// // "height": {"min": 1920}
// // },
// // "optional": Platform.isAndroid
// // ? [
// // {'sourceId': devices[1].deviceId},
// // {
// // "width": {"max": 1080}
// // },
// // {"frameRate": 30},
// // {"facingMode": "user"}
// // ]
// // : [
// // {"frameRate": 30},
// // {"facingMode": "user"}
// // ]
// // },
// // "frameRate": 30,
// // "width": 1080, //420,//640,//1280,
// // "height": 1920, //240//480//720
// // "audio": true,
// // }
// : audioConstraints);
// localVideoRenderer.srcObject = _localStream;
await remoteRenderer!.initialize();
notifyListeners();
}
@ -661,4 +700,38 @@ class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners();
}
MediaRecorder? mobileRecoder;
// void startRecording() async {
// print("=-=-=-=-=-=-= Call Recoding Started -=-=-=-=-=-=-=-=-==-=");
// if (_localStream == null) throw Exception('Stream is not initialized');
// if (Platform.isIOS) {
// print('Recording is not available on iOS');
// return;
// }
// Directory appDirectory = await getApplicationDocumentsDirectory();
// String dirPath = '${appDirectory.path}/webrtc_sample';
// if (!await Directory(dirPath).exists()) {
// await Directory(dirPath).create();
// await File('$dirPath/.nomedia').create();
// }
// if (appDirectory == null) throw Exception('Can\'t find storagePath');
// String filePath = dirPath + '/mobile.mp4';
// mobileRecoder = MediaRecorder();
// notifyListeners();
// MediaStreamTrack videoTrack = _localStream!.getVideoTracks().firstWhere((track) => track.kind == 'video');
// await mobileRecoder!.start(filePath, videoTrack: videoTrack);
//
// Future.delayed(Duration(minutes: 1), () {
// stopRecording();
// });
// }
//
// void stopRecording() async {
// print("=-=-=-=-=-=-= Call Recoding Stopped -=-=-=-=-=-=-=-=-==-=");
// await mobileRecoder!.stop();
// mobileRecoder = null;
// notifyListeners();
// }
}

@ -92,6 +92,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
bool isUserOnline = false;
bool isCall = false;
userLoginToken.UserAutoLoginModel userLoginData = userLoginToken.UserAutoLoginModel();
Future<void> getUserAutoLoginToken() async {
try {
userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
@ -132,16 +133,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} catch (e) {
Utils.showToast(e.toString());
}
await chatHubConnection.start();
await chatHubConnection!.start();
if (kDebugMode) {
logger.i("Hub Conn: Startedddddddd");
}
chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion);
chatHubConnection!.on("OnDeliveredChatUserAsync", onMsgReceived);
chatHubConnection!.on("OnGetChatConversationCount", onNewChatConversion);
//group On message
chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived);
chatHubConnection!.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived);
ccProvider.initCallListeners(context: context);
}
@ -155,17 +156,17 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
void registerEvents() {
chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus);
// chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived);
chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync);
chatHubConnection.on("OnUserTypingAsync", onUserTyping);
chatHubConnection.on("OnUserCountAsync", userCountAsync);
// chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus);
chatHubConnection.on("OnAddGroupChatHistoryAsync", groupChatHistoryAsync);
chatHubConnection!.on("OnUpdateUserStatusAsync", changeStatus);
// chatHubConnection!.on("OnDeliveredChatUserAsync", onMsgReceived);
chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync);
chatHubConnection!.on("OnUserTypingAsync", onUserTyping);
chatHubConnection!.on("OnUserCountAsync", userCountAsync);
// chatHubConnection!.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow);
chatHubConnection!.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered);
chatHubConnection!.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus);
chatHubConnection!.on("OnGetGroupUserStatusAsync", getGroupUserStatus);
chatHubConnection!.on("OnAddGroupChatHistoryAsync", groupChatHistoryAsync);
//
// {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]}
@ -203,7 +204,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async {
await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]);
await chatHubConnection!.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]);
return "";
}
@ -272,7 +273,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void updateUserChatHistoryStatusAsync(List data) {
try {
chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]);
chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]);
} catch (e) {
throw e;
}
@ -280,7 +281,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
void updateUserChatHistoryOnMsg(List data) {
try {
chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]);
chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]);
} catch (e) {
throw e;
}
@ -773,7 +774,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
String chatData =
'{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}';
await chatHubConnection.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]);
await chatHubConnection!.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]);
}
//groupChatMessage
@ -849,7 +850,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
String chatData =
'{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}';
await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: <Object>[json.decode(chatData)]);
await chatHubConnection!.invoke("AddGroupChatHistoryAsync", args: <Object>[json.decode(chatData)]);
}
void sendGroupChatMessage(
@ -1286,7 +1287,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
bool checkFileSize(String path) {
int fileSizeLimit = 1024;
int fileSizeLimit = 5000;
File f = File(path);
double fileSizeInKB = f.lengthSync() / 5000;
double fileSizeInMB = fileSizeInKB / 5000;
@ -1328,7 +1329,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
case ".aac":
return "assets/icons/chat/aac.svg";
case ".mp3":
return "assets/icons/chat/zip.mp3";
return "assets/icons/chat/mp3.svg";
case ".mp4":
return "assets/icons/chat/mp4.svg";
case ".flv":
return "assets/icons/chat/flv.svg";
case ".avi":
return "assets/icons/chat/avi.svg";
case ".mov":
return "assets/icons/chat/mov.svg";
default:
return "assets/images/thumb.svg";
}
@ -1471,7 +1480,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
uGroups?.clear();
searchGroup?.clear();
// callP.stopListeners();
chatHubConnection.stop();
chatHubConnection!.stop();
AppState().chatDetails = null;
}
}
@ -1603,17 +1612,17 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
Future invokeChatCounter({required int userId}) async {
await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]);
await chatHubConnection!.invoke("GetChatCounversationCount", args: [userId]);
return "";
}
void userTypingInvoke({required int currentUser, required int reciptUser}) async {
await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]);
await chatHubConnection!.invoke("UserTypingAsync", args: [reciptUser, currentUser]);
}
void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async {
var data = json.decode(json.encode(groupDetails.groupUserList));
await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]);
await chatHubConnection!.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]);
}
//////// Audio Recoding Work ////////////////////

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:core';
import 'dart:io';
import 'dart:ui';
import 'package:draggable_widget/draggable_widget.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -11,7 +12,6 @@ import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:mohem_flutter_app/api/chat/chat_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
@ -26,14 +26,15 @@ import 'package:provider/provider.dart';
bool isCallConnected = false;
class StartCallPage extends StatefulWidget {
IosCallPayload? payload;
StartCallPage({this.payload});
@override
_StartCallPageState createState() => _StartCallPageState();
}
class _StartCallPageState extends State<StartCallPage> {
DragController dragController = DragController();
bool isOutGoingCall = false;
bool isIncomingCall = false;
late ChatCallProvider cProv;
late ChatProviderModel provider;
@ -52,21 +53,25 @@ class _StartCallPageState extends State<StartCallPage> {
dynamic calls = await FlutterCallkitIncoming.activeCalls();
if (calls.isNotEmpty) {
sessionData = IncomingCallModel.fromRawJson(jsonEncode(calls[0]));
print(sessionData.toRawJson());
if (kDebugMode) {
print(sessionData.toRawJson());
}
if (provider.isUserOnline) {
AppState().isBackgroundCall = true;
cProv.isUserOnline = provider.isUserOnline;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
}
await cProv.startIncomingCallViaKit(inCallData: sessionData!.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
await cProv.startIncomingCallViaKit(inCallData: sessionData.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
cProv.init();
isCallConnected = true;
} else {
AppState().isBackgroundCall = true;
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
cProv.isUserOnline = provider.isUserOnline;
await cProv.startIncomingCallViaKit(inCallData: sessionData!.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
await cProv.startIncomingCallViaKit(inCallData: sessionData.extra!.callerDetails!.toJson(), isVCall: sessionData.extra!.callType == "video" ? true : false);
try {
AppState().setchatUserDetails = UserAutoLoginModel(response: Response.fromJson(sessionData.extra!.loginDetails!.toJson()), errorResponses: null);
await provider.buildHubConnection(context: context, ccProvider: cProv).whenComplete(() {
@ -78,20 +83,23 @@ class _StartCallPageState extends State<StartCallPage> {
}
}
}
// cProv.startRecording();
}
void startIosCall() async {
print(await Utils.getStringFromPrefs("iosCallPayload"));
IosCallPayload _iosCallPayload = IosCallPayload.fromRawJson(await Utils.getStringFromPrefs("iosCallPayload"));
var userID = _iosCallPayload!.incomingCallReciverId;
var callType = _iosCallPayload!.incomingCallType;
// IosCallPayload? iosCallPayload = IosCallPayload.fromRawJson(await Utils.getStringFromPrefs("iosCallPayload"));
IosCallPayload? iosCallPayload = widget.payload;
var userID = iosCallPayload!.incomingCallReciverId;
var callType = iosCallPayload.incomingCallType;
SingleUserChatModel inCallData = SingleUserChatModel(
targetUserName: _iosCallPayload.incomingCallerName,
targetUserName: iosCallPayload.incomingCallerName,
chatEventId: 3,
targetUserId: int.parse(_iosCallPayload.incomingCallerId!),
targetUserId: int.parse(iosCallPayload.incomingCallerId!),
currentUserId: int.parse(userID.toString()),
);
if (provider.isUserOnline) {
AppState().isBackgroundCall = true;
cProv.isUserOnline = provider.isUserOnline;
if (kDebugMode) {
print("====== Processing Incoming Call in Online State =========");
@ -103,6 +111,7 @@ class _StartCallPageState extends State<StartCallPage> {
if (kDebugMode) {
print("====== Processing Incoming Call =========");
}
AppState().isBackgroundCall = true;
cProv.isUserOnline = provider.isUserOnline;
UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserCallToken(userid: userID.toString());
if (userLoginResponse.response != null) {
@ -127,22 +136,25 @@ class _StartCallPageState extends State<StartCallPage> {
Widget build(BuildContext context) {
cProv = context.read<ChatCallProvider>();
provider = context.read<ChatProviderModel>();
if (Platform.isAndroid) {
startCall();
} else if (Platform.isIOS) {
startIosCall();
if (!cProv.isOutGoingCall) {
if (Platform.isAndroid) {
startCall();
} else if (Platform.isIOS) {
startIosCall();
}
}
return Scaffold(
extendBody: true,
body: Consumer2<ChatCallProvider, ChatProviderModel>(
builder: (BuildContext context, ChatCallProvider provider, ChatProviderModel cpm, Widget? child) {
return provider.isIncomingCallLoader
builder: (BuildContext context, ChatCallProvider prov, ChatProviderModel cpm, Widget? child) {
return prov.isIncomingCallLoader
? const SizedBox(
width: double.infinity,
height: double.infinity,
child: Center(child: CircularProgressIndicator()),
)
: provider.isIncomingCall
: prov.isIncomingCall
? Container(
width: double.infinity,
height: double.infinity,
@ -150,14 +162,14 @@ class _StartCallPageState extends State<StartCallPage> {
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!provider.isAudioCall && provider.isVideoCall)
if (!prov.isAudioCall && prov.isVideoCall)
RTCVideoView(
provider.remoteRenderer!,
prov.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
// filterQuality: FilterQuality.high,
key: const Key('remote'),
),
if (provider.isVideoCall)
if (prov.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
@ -172,14 +184,14 @@ class _StartCallPageState extends State<StartCallPage> {
height: 200,
width: 140,
child: RTCVideoView(
provider.localVideoRenderer!,
prov.localVideoRenderer!,
mirror: true,
// filterQuality: FilterQuality.high,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
if (!prov.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
@ -219,7 +231,7 @@ class _StartCallPageState extends State<StartCallPage> {
),
10.height,
Text(
provider.incomingCallData.targetUserName!,
prov.incomingCallData.targetUserName!,
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
@ -273,10 +285,10 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.loudOn();
prov.loudOn();
},
elevation: 2.0,
fillColor: provider.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
fillColor: prov.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
@ -290,16 +302,16 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
prov.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : Colors.grey,
fillColor: prov.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
prov.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
@ -307,16 +319,16 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.switchCamera();
prov.switchCamera();
},
elevation: 2.0,
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.textMixColor,
fillColor: prov.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
prov.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
@ -324,16 +336,16 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.micOff();
prov.micOff();
},
elevation: 2.0,
fillColor: provider.isMicOff ? MyColors.textMixColor : Colors.grey,
fillColor: prov.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isMicOff ? Icons.mic_off : Icons.mic,
prov.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
@ -341,10 +353,10 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
prov.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
// print("Reintiiiiiiitttiiiiiiii");
// print("Reintiiiiiiitttiiiiiiii");
// provider.initStreams();
}
});
@ -368,7 +380,7 @@ class _StartCallPageState extends State<StartCallPage> {
],
),
)
: provider.isOutGoingCall
: prov.isOutGoingCall
? Container(
width: double.infinity,
height: double.infinity,
@ -376,13 +388,13 @@ class _StartCallPageState extends State<StartCallPage> {
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
if (!provider.isAudioCall && provider.isVideoCall)
if (!prov.isAudioCall && prov.isVideoCall)
RTCVideoView(
provider.remoteRenderer!,
prov.remoteRenderer!,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain,
key: const Key('remote'),
),
if (provider.isVideoCall)
if (prov.isVideoCall)
DraggableWidget(
bottomMargin: 20,
topMargin: 40,
@ -397,13 +409,13 @@ class _StartCallPageState extends State<StartCallPage> {
height: 200,
width: 140,
child: RTCVideoView(
provider.localVideoRenderer!,
prov.localVideoRenderer!,
mirror: true,
objectFit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
),
),
if (!provider.isVideoCall)
if (!prov.isVideoCall)
Positioned.fill(
child: ClipRect(
child: BackdropFilter(
@ -443,7 +455,7 @@ class _StartCallPageState extends State<StartCallPage> {
),
10.height,
Text(
provider.outGoingCallData.receiverName!,
prov.outGoingCallData.receiverName!,
style: const TextStyle(
fontSize: 21,
decoration: TextDecoration.none,
@ -497,10 +509,10 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.loudOn();
prov.loudOn();
},
elevation: 2.0,
fillColor: provider.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
fillColor: prov.isLoudSpeaker ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
@ -514,16 +526,16 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.camOff();
prov.camOff();
},
elevation: 2.0,
fillColor: provider.isCamOff ? MyColors.textMixColor : Colors.grey,
fillColor: prov.isCamOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isCamOff ? Icons.videocam_off : Icons.videocam,
prov.isCamOff ? Icons.videocam_off : Icons.videocam,
color: MyColors.white,
size: 30.0,
),
@ -531,16 +543,16 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.switchCamera();
prov.switchCamera();
},
elevation: 2.0,
fillColor: provider.isFrontCamera ? Colors.grey : MyColors.textMixColor,
fillColor: prov.isFrontCamera ? Colors.grey : MyColors.textMixColor,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
prov.isFrontCamera ? Icons.switch_camera_outlined : Icons.switch_camera,
color: MyColors.white,
size: 30.0,
),
@ -548,16 +560,16 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.micOff();
prov.micOff();
},
elevation: 2.0,
fillColor: provider.isMicOff ? MyColors.textMixColor : Colors.grey,
fillColor: prov.isMicOff ? MyColors.textMixColor : Colors.grey,
padding: const EdgeInsets.all(
10.0,
),
shape: const CircleBorder(),
child: Icon(
provider.isMicOff ? Icons.mic_off : Icons.mic,
prov.isMicOff ? Icons.mic_off : Icons.mic,
color: MyColors.white,
size: 30.0,
),
@ -565,7 +577,7 @@ class _StartCallPageState extends State<StartCallPage> {
RawMaterialButton(
constraints: const BoxConstraints(),
onPressed: () {
provider.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
prov.endCall(isUserOnline: cpm.isUserOnline).then((bool value) {
if (value) {
Navigator.of(context).pop();
}

@ -1,7 +1,5 @@
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
@ -35,6 +33,14 @@ class _OutGoingCallState extends State<OutGoingCall> {
Future<void> init() async {
widget.isVideoCall ? callProvider.isVideoCall = true : callProvider.isVideoCall = false;
callProvider.isOutGoingCall = true;
// IosCallPayload payload = IosCallPayload(
// incomingCallerId: widget.outGoingCallData.callerId.toString(),
// incomingCallerName: widget.outGoingCallData.callerName,
// incomingCallReciverId: widget.outGoingCallData.receiverId.toString(),
// incomingCallType: widget.outGoingCallData.callType,
// uuid: "",
// callData: widget.outGoingCallData.toRawJson());
// await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(payload));
await callProvider.initLocalCamera(chatProvmodel: chatProvider, callData: widget.outGoingCallData, context: context);
loader = false;
}

@ -1,5 +1,4 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -18,9 +17,9 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';
import 'package:video_player/video_player.dart';
class ChatBubble extends StatelessWidget {
ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
@ -82,7 +81,8 @@ class ChatBubble extends StatelessWidget {
}
} else {
Utils.showLoading(context);
Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""), fileSource:1);
Uint8List encodedString =
await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 1);
// try {
File sFile = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
if (sFile.path.isEmpty) {
@ -195,20 +195,26 @@ class ChatBubble extends StatelessWidget {
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
currentWaveBubble(context, cItem)
if (fileTypeID == 13 && cItem.voiceController != null) currentWaveBubble(context, cItem),
if (fileTypeID == 16)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
showVideoThumb(context, cItem),
Row(
children: [
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2
)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, size: 16)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, size: 16)
],
),
Align(
@ -300,20 +306,26 @@ class ChatBubble extends StatelessWidget {
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
recipetWaveBubble(context, cItem)
if (fileTypeID == 13 && cItem.voiceController != null) recipetWaveBubble(context, cItem),
if (fileTypeID == 16)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
showVideoThumb(context, cItem),
Row(
children: [
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2
)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, color: Colors.white, size: 16)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, color: Colors.white, size: 16)
],
),
Align(
@ -324,11 +336,7 @@ class ChatBubble extends StatelessWidget {
),
],
),
).paddingOnly(right: MediaQuery.of(context).size.width * 0.3);
}
Widget voiceMsg(BuildContext context) {
return Container();
).paddingOnly(right: MediaQuery.of(context).size.width * 0.33);
}
Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) {
@ -342,7 +350,7 @@ class ChatBubble extends StatelessWidget {
);
} else {
return FutureBuilder<Uint8List>(
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource:1),
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource: 1),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
if (snapshot.data == null) {
@ -470,4 +478,50 @@ class ChatBubble extends StatelessWidget {
},
);
}
Widget showVideoThumb(BuildContext context, SingleUserChatModel data) {
return LoadVideo(data: data);
}
}
class LoadVideo extends StatefulWidget {
final SingleUserChatModel data;
const LoadVideo({Key? key, required this.data}) : super(key: key);
@override
State<LoadVideo> createState() => _LoadVideoState();
}
class _LoadVideoState extends State<LoadVideo> {
late VideoPlayerController videoController;
@override
void initState() {
videoController = VideoPlayerController.networkUrl(Uri.parse('https://apiderichat.hmg.com/attachments/${widget.data.fileTypeResponse?.fileName}'))..initialize().then((_) {});
super.initState();
}
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: AspectRatio(
aspectRatio: videoController.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(videoController),
Align(
alignment: Alignment.center,
child: Icon(
Icons.play_arrow,
color: Colors.white.withOpacity(.7),
size: 56,
),
)
],
),
));
}
}

@ -76,7 +76,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);
callPro = Provider.of<ChatCallProvider>(context, listen: false);
if (params != null) {
data.getSingleUserChatHistory(
senderUID: AppState().chatDetails!.response!.id!.toInt(),
@ -95,34 +95,34 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
showHomeButton: false,
showTyping: true,
chatUser: params!.chatUser,
// actions: [
// // if (Platform.isAndroid)
// SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() async {
// Future<PermissionStatus> micPer = Permission.microphone.request();
// if (await micPer.isGranted) {
// makeCall(callType: "AUDIO");
// } else {
// Permission.microphone.request().isGranted.then((value) {
// makeCall(callType: "AUDIO");
// });
// }
// }),
// // if (Platform.isAndroid)
// 24.width,
// // if (Platform.isAndroid)
// SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() async {
// Future<PermissionStatus> camPer = Permission.camera.request();
// if (await camPer.isGranted) {
// makeCall(callType: "VIDEO");
// } else {
// Permission.camera.request().isGranted.then((value) {
// makeCall(callType: "VIDEO");
// });
// }
// }),
// // if (Platform.isAndroid)
// 21.width,
// ],
actions: [
// if (Platform.isAndroid)
SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() async {
Future<PermissionStatus> micPer = Permission.microphone.request();
if (await micPer.isGranted) {
makeCall(callType: "AUDIO");
} else {
Permission.microphone.request().isGranted.then((value) {
makeCall(callType: "AUDIO");
});
}
}),
// if (Platform.isAndroid)
24.width,
// if (Platform.isAndroid)
SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() async {
Future<PermissionStatus> camPer = Permission.camera.request();
if (await camPer.isGranted) {
makeCall(callType: "VIDEO");
} else {
Permission.camera.request().isGranted.then((value) {
makeCall(callType: "VIDEO");
});
}
}),
// if (Platform.isAndroid)
21.width,
],
),
body: SafeArea(
child: Consumer<ChatProviderModel>(
@ -168,14 +168,16 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
// logger.w(m.userChatHistory[i].toJson());
if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) {
if (m.userChatHistory[i].fileTypeId! == 1 ||
m.userChatHistory[i].fileTypeId! == 5 ||
m.userChatHistory[i].fileTypeId! == 7 ||
m.userChatHistory[i].fileTypeId! == 6 ||
m.userChatHistory[i].fileTypeId! == 8
// || m.userChatHistory[i].fileTypeId! == 2
) {
m.userChatHistory[i].fileTypeId! == 5 ||
m.userChatHistory[i].fileTypeId! == 7 ||
m.userChatHistory[i].fileTypeId! == 6 ||
m.userChatHistory[i].fileTypeId! == 8 ||
m.userChatHistory[i].fileTypeId! == 16) {
m.getChatMedia(context,
fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!, fileSource:1);
fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "",
fileTypeID: m.userChatHistory[i].fileTypeId!,
fileName: m.userChatHistory[i].contant!,
fileSource: 1);
}
}
});

@ -2,7 +2,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.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/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
@ -14,7 +13,6 @@ import 'package:mohem_flutter_app/ui/chat/chat_home_screen.dart';
import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat.dart';
import 'package:mohem_flutter_app/ui/chat/my_team_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:provider/provider.dart';
import 'package:signalr_netcore/signalr_client.dart';
@ -48,18 +46,16 @@ class _ChatHomeState extends State<ChatHome> {
}
void fetchAgain() {
if (chatHubConnection.state != HubConnectionState.Connected) {
if (chatHubConnection!.state != HubConnectionState.Connected) {
data.getUserAutoLoginToken().whenComplete(() async {
await data.buildHubConnection(context: context, ccProvider: callProvider);
data.getUserRecentChats();
});
return;
}
if (data.searchedChats == null || data.searchedChats!.isEmpty) {
data.isLoading = true;
data.getUserRecentChats().whenComplete(() async {
});
data.getUserRecentChats().whenComplete(() async {});
}
}
@ -68,7 +64,6 @@ class _ChatHomeState extends State<ChatHome> {
fetchAgain();
return Scaffold(
backgroundColor: MyColors.white,
appBar: AppBarWidget(context, title: LocaleKeys.chat.tr(), showHomeButton: true, isBackButton: false),
body: Column(
children: <Widget>[
@ -92,7 +87,7 @@ class _ChatHomeState extends State<ChatHome> {
child: Row(
children: <Widget>[
myTab(LocaleKeys.mychats.tr(), 0),
myTab(LocaleKeys.group.tr(), 1),
myTab(LocaleKeys.group.tr(), 1),
myTab(LocaleKeys.favorite.tr(), 2),
AppState().getempStatusIsManager ? myTab(LocaleKeys.myTeam.tr(), 3) : const SizedBox(),
],
@ -108,7 +103,7 @@ class _ChatHomeState extends State<ChatHome> {
},
children: <Widget>[
ChatHomeScreen(),
GropChatHomeScreen(),
GropChatHomeScreen(),
ChatFavoriteUsersScreen(),
AppState().getempStatusIsManager ? const MyTeamScreen() : const SizedBox(),
],

@ -1,7 +1,5 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
@ -15,7 +13,6 @@ import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class ChatHomeScreen extends StatefulWidget {
const ChatHomeScreen({Key? key}) : super(key: key);
@ -154,16 +151,9 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
alignment: Alignment.center,
width: 18,
height: 18,
decoration: const BoxDecoration(
color: MyColors.redColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: (m.searchedChats![index].unreadMessageCount!.toString())
.toText10(
color: MyColors.white,
)
decoration: const BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.all(Radius.circular(22))),
child: (m.searchedChats![index].unreadMessageCount! >= 10 ? "10+" : m.searchedChats![index].unreadMessageCount!.toString())
.toText10(color: MyColors.white)
.center,
).paddingOnly(right: 10).center,
Icon(
@ -172,22 +162,14 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
).onPress(
() {
if (m.searchedChats![index].isFav == null || m.searchedChats![index].isFav == false) {
m.favoriteUser(
userID: AppState().chatDetails!.response!.id!,
targetUserID: m.searchedChats![index].id!,
fromSearch: false
);
m.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: m.searchedChats![index].id!, fromSearch: false);
} else if (m.searchedChats![index].isFav == true) {
m.unFavoriteUser(
userID: AppState().chatDetails!.response!.id!,
targetUserID: m.searchedChats![index].id!,
);
} else {
m.favoriteUser(
userID: AppState().chatDetails!.response!.id!,
targetUserID: m.searchedChats![index].id!,
fromSearch: false
);
m.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: m.searchedChats![index].id!, fromSearch: false);
}
},
).center
@ -217,10 +199,10 @@ class _ChatHomeScreenState extends State<ChatHomeScreen> {
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
//shape: BoxShape.circle,
gradient:const LinearGradient(
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,

@ -1,28 +1,20 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.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/get_group_chat_history.dart';
import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart';
import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/ui/chat/create_group.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart';
import 'package:mohem_flutter_app/ui/chat/manage_group.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class GropChatHomeScreen extends StatefulWidget {
const GropChatHomeScreen({Key? key}) : super(key: key);
@ -59,26 +51,17 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
children: <Widget>[
TextField(
controller: m.searchGroup,
style: const TextStyle(
color: MyColors.darkTextColor,
fontWeight: FontWeight.w500,
fontSize: 12),
style: const TextStyle(color: MyColors.darkTextColor, fontWeight: FontWeight.w500, fontSize: 12),
onChanged: (String val) {
m.filterGroups(val);
},
decoration: InputDecoration(
border: fieldBorder(radius: 5, color: 0xFFE5E5E5),
focusedBorder:
fieldBorder(radius: 5, color: 0xFFE5E5E5),
enabledBorder:
fieldBorder(radius: 5, color: 0xFFE5E5E5),
focusedBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5),
enabledBorder: fieldBorder(radius: 5, color: 0xFFE5E5E5),
contentPadding: const EdgeInsets.all(11),
hintText: LocaleKeys.searchGroup.tr(),
hintStyle: const TextStyle(
color: MyColors.lightTextColor,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w500,
fontSize: 12),
hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic, fontWeight: FontWeight.w500, fontSize: 12),
filled: true,
fillColor: MyColors.greyF7Color,
suffixIconConstraints: const BoxConstraints(),
@ -112,70 +95,53 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
border: Border.all(
width: 1, color: Colors.black),
border: Border.all(width: 1, color: Colors.black),
),
child: SvgPicture.asset(
"assets/images/chat-group.svg",
)),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
(m.uGroups![index]
.groupName!
.toText14(
color: MyColors.darkTextColor)
.paddingOnly(left: 11, top: 16))!,
]),
Column(mainAxisAlignment: MainAxisAlignment.start, children: [
(m.uGroups![index].groupName!.toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 16)),
]),
Align(
alignment: Alignment.centerRight,
child: PopupMenuButton(
onSelected: (String value){
goToSelected(m.uGroups![index], m, value);
},
itemBuilder: (context) => [
PopupMenuItem<String>(
value: '1',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.edit
.tr()
.toText14(color: m.userGroups?.groupresponse![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '2',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.delete
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '3',
enabled: m.uGroups![index].isAdmin ?? false,
onTap: () {
},
child: (LocaleKeys.manage
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor: MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '4',
child: (LocaleKeys.members
.tr()
.toText14(color: MyColors.darkTextColor)
.paddingOnly(left: 11, top: 16))),
],
)
)
.expanded
alignment: Alignment.centerRight,
child: PopupMenuButton(
onSelected: (String value) {
goToSelected(m.uGroups![index], m, value);
},
itemBuilder: (context) => [
PopupMenuItem<String>(
value: '1',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.edit
.tr()
.toText14(color: m.userGroups.groupresponse![index].isAdmin == true ? MyColors.darkTextColor : MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '2',
enabled: m.uGroups![index].isAdmin ?? false,
child: (LocaleKeys.delete
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor : MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(
value: '3',
enabled: m.uGroups![index].isAdmin ?? false,
onTap: () {},
child: (LocaleKeys.manage
.tr()
.toText14(color: m.uGroups![index].isAdmin == true ? MyColors.darkTextColor : MyColors.lightGreyColor)
.paddingOnly(left: 11, top: 16))),
PopupMenuItem<String>(value: '4', child: (LocaleKeys.members.tr().toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 16))),
],
)).expanded
],
),
).onPress(() {
chatDetails(m.uGroups![index], m,);
chatDetails(
m.uGroups![index],
m,
);
// Navigator.pushNamed(
// context,
// AppRoutes.chatDetailed,
@ -187,9 +153,7 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
// });
});
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(color: MyColors.black)
.paddingOnly(left: 59),
separatorBuilder: (BuildContext context, int index) => const Divider(color: MyColors.black).paddingOnly(left: 59),
).expanded,
],
).paddingOnly(left: 21, right: 21);
@ -199,10 +163,10 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
// shape: BoxShape.circle,
gradient:const LinearGradient(
// shape: BoxShape.circle,
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
@ -219,16 +183,15 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
),
),
onPressed: () async {
showMyBottomSheet(
context,
callBackFunc: () {},
child: CreateGroupBottomSheet(
title:LocaleKeys.addUsers.tr(),
title: LocaleKeys.addUsers.tr(),
apiMode: LocaleKeys.delegate.tr(),
fromChat: true,
onSelectEmployee: (ReplacementList _selectedEmployee) {},
groupDetails:GroupResponse(),
groupDetails: GroupResponse(),
),
);
},
@ -245,30 +208,32 @@ class _GropChatHomeScreenState extends State<GropChatHomeScreen> {
);
}
void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value) {
switch(value) {
case '1':
void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value) {
switch (value) {
case '1':
editGroup(groupDetails, m);
break;
case '2':
deleteGroup(groupDetails, m, context);
break;
case '3':
Navigator.pushNamed(context,
case '2':
deleteGroup(groupDetails, m, context);
break;
case '3':
Navigator.pushNamed(
context,
AppRoutes.manageGroup,
arguments: groupDetails ,
);
break;
case '4':
Navigator.pushNamed(context,
AppRoutes.groupMembers,
arguments: groupDetails!.groupUserList,
);
break;
}
arguments: groupDetails,
);
break;
case '4':
Navigator.pushNamed(
context,
AppRoutes.groupMembers,
arguments: groupDetails!.groupUserList,
);
break;
}
}
void deleteGroup(
GroupResponse? groupDetails, ChatProviderModel m, BuildContext context) {
void deleteGroup(GroupResponse? groupDetails, ChatProviderModel m, BuildContext context) {
groupDetails!.groupUserList;
Utils.confirmDialog(
context,
@ -281,28 +246,22 @@ void goToSelected(GroupResponse? groupDetails, ChatProviderModel m, String value
}
Future<void> chatDetails(GroupResponse? groupDetails, ChatProviderModel m) async {
// await m.getGroupChatHistory(groupDetails!);
// await m.getGroupChatHistory(groupDetails!);
Navigator.pushNamed(context,
AppRoutes.groupChatDetailed,
arguments:
GroupChatDetailedScreenParams(
groupDetails,
false));
Navigator.pushNamed(context, AppRoutes.groupChatDetailed, arguments: GroupChatDetailedScreenParams(groupDetails, false));
}
Future<void> editGroup(GroupResponse? groupDetails, ChatProviderModel m) async {
showMyBottomSheet(
context,
callBackFunc: () {},
child: CreateGroupBottomSheet(
title:LocaleKeys.editGroups.tr(),
title: LocaleKeys.editGroups.tr(),
apiMode: LocaleKeys.delegate.tr(),
fromChat: true,
onSelectEmployee: (ReplacementList _selectedEmployee) {},
groupDetails: groupDetails!,
),
);
}
}

@ -1,5 +1,4 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -19,14 +18,12 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';
import 'package:video_player/video_player.dart';
class GroupChatBubble extends StatelessWidget {
GroupChatBubble({Key? key, required this.dateTime, required this.cItem})
: super(key: key);
GroupChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key);
final String dateTime;
final GetGroupChatHistoryAsync cItem;
@ -53,27 +50,15 @@ class GroupChatBubble extends StatelessWidget {
late Offset screenOffset;
void makeAssign() {
isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id
? true
: false;
isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id ? true : false;
isSeen = cItem.isSeen == true ? true : false;
isReplied = cItem.groupChatReplyResponse != null ? true : false;
// isVoice = cItem.fileTypeId == 13 && cItem.voiceController != null ? true : false;
fileTypeID = cItem.fileTypeId;
fileTypeName = cItem.fileTypeResponse != null
? cItem.fileTypeResponse!.fileTypeName
: "";
fileTypeDescription = cItem.fileTypeResponse != null
? cItem.fileTypeResponse!.fileTypeDescription
: "";
isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id &&
cItem.isDelivered == true
? true
: false;
userName = AppState().chatDetails!.response!.userName ==
cItem.currentUserName.toString()
? "You"
: cItem.currentUserName.toString();
fileTypeName = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeName : "";
fileTypeDescription = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeDescription : "";
isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && cItem.isDelivered == true ? true : false;
userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString();
}
void playVoice(
@ -82,8 +67,7 @@ class GroupChatBubble extends StatelessWidget {
}) async {
if (data.voice != null && data.voice!.existsSync()) {
if (Platform.isIOS) {
Duration? duration = await data.voiceController!
.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
Duration? duration = await data.voiceController!.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
await data.voiceController!.seek(duration);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.setVolume(1.0);
@ -98,13 +82,10 @@ class GroupChatBubble extends StatelessWidget {
}
} else {
Utils.showLoading(context);
Uint8List encodedString = await ChatApiClient().downloadURL(
fileName: data.contant!,
fileTypeDescription: provider.getFileTypeDescription(
data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 2);
Uint8List encodedString =
await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 2);
// try {
File sFile = await provider.downChatVoice(
encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
File sFile = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data);
if (sFile.path.isEmpty) {
logger.d("Path Is Emptyyyyyyy");
} else {
@ -113,8 +94,7 @@ class GroupChatBubble extends StatelessWidget {
data.voice = sFile;
if (Platform.isIOS) {
logger.d("isIOS");
Duration? duration = await data.voiceController!
.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
Duration? duration = await data.voiceController!.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync()));
await data.voiceController!.seek(duration);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.setVolume(1.0);
@ -122,8 +102,7 @@ class GroupChatBubble extends StatelessWidget {
Utils.hideLoading(context);
data.voiceController!.play();
} else {
Duration? duration =
await data.voiceController!.setFilePath(sFile.path);
Duration? duration = await data.voiceController!.setFilePath(sFile.path);
await data.voiceController!.setLoopMode(LoopMode.off);
await data.voiceController!.seek(duration);
Utils.hideLoading(context);
@ -132,8 +111,7 @@ class GroupChatBubble extends StatelessWidget {
}
}
void pausePlaying(BuildContext context,
{required SingleUserChatModel data}) async {
void pausePlaying(BuildContext context, {required SingleUserChatModel data}) async {
await data.voiceController!.pause();
}
@ -144,14 +122,8 @@ class GroupChatBubble extends StatelessWidget {
}
}
Stream<PositionData> get _positionDataStream =>
Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(
cItem.voiceController!.positionStream,
cItem.voiceController!.bufferedPositionStream,
cItem.voiceController!.durationStream,
(Duration position, Duration bufferedPosition, Duration? duration) =>
PositionData(
position, bufferedPosition, duration ?? Duration.zero));
Stream<PositionData> get _positionDataStream => Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(cItem.voiceController!.positionStream, cItem.voiceController!.bufferedPositionStream,
cItem.voiceController!.durationStream, (Duration position, Duration bufferedPosition, Duration? duration) => PositionData(position, bufferedPosition, duration ?? Duration.zero));
@override
Widget build(BuildContext context) {
@ -173,49 +145,26 @@ class GroupChatBubble extends StatelessWidget {
width: double.infinity,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color: isCurrentUser
? MyColors.gradiantStartColor
: MyColors.white),
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(userName)
.toText12(
color: MyColors.gradiantStartColor, isBold: false)
.paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
(userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
Directionality(
textDirection: provider.getTextDirection(
cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: ""),
child: (cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: "")
.toText10(
color: isCurrentUser
? MyColors.grey71Color
: MyColors.white.withOpacity(0.5),
isBold: false,
maxlines: 4)
textDirection: provider.getTextDirection(cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : ""),
child: (cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : "")
.toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4)
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
),
],
).expanded,
if (cItem.groupChatReplyResponse != null)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 ||
cItem.groupChatReplyResponse!.fileTypeId == 3 ||
cItem.groupChatReplyResponse!.fileTypeId == 4)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 || cItem.groupChatReplyResponse!.fileTypeId == 3 || cItem.groupChatReplyResponse!.fileTypeId == 4)
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: SizedBox(
@ -223,13 +172,8 @@ class GroupChatBubble extends StatelessWidget {
width: 32,
child: showImage(
isReplyPreview: false,
fileName:
cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem
.groupChatReplyResponse!
.fileTypeResponse!
.fileTypeDescription ??
"image/jpg")),
fileName: cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem.groupChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg")),
).paddingOnly(left: 10, right: 10, bottom: 16, top: 16),
],
),
@ -246,52 +190,36 @@ class GroupChatBubble extends StatelessWidget {
child: showImage(
isReplyPreview: false,
fileName: cItem.contant!,
fileTypeDescription: cItem.fileTypeResponse != null &&
cItem.fileTypeResponse!.fileTypeDescription !=
null
? cItem.fileTypeResponse!.fileTypeDescription
: cItem.fileTypeResponse!.fileTypeName)
fileTypeDescription:
cItem.fileTypeResponse != null && cItem.fileTypeResponse!.fileTypeDescription != null ? cItem.fileTypeResponse!.fileTypeDescription : cItem.fileTypeResponse!.fileTypeName)
.onPress(() {
showDialog(
context: context,
anchorPoint: screenOffset,
builder: (BuildContext context) => ChatImagePreviewScreen(
imgTitle: cItem.contant!, img: cItem.image!),
builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!),
);
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
currentWaveBubble(context, cItem),
if (fileTypeID == 13 && cItem.voiceController != null) currentWaveBubble(context, cItem),
if (fileTypeID == 16)
showVideoThumb(context, cItem)
Column(
children: [
showVideoThumb(context, cItem),
Row(
children: [
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
],
),
],
)
else
Row(
children: [
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""),
height: 30,
width: 22,
alignment: Alignment.center,
fit: BoxFit.cover)
.paddingOnly(left: 0, right: 10),
Directionality(
textDirection: provider.getTextDirection(cItem.contant ?? ""),
child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, size: 16)
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, size: 16)
],
),
Align(
@ -303,32 +231,24 @@ class GroupChatBubble extends StatelessWidget {
color: MyColors.grey41Color.withOpacity(.5),
),
7.width,
Icon(isDelivered ? Icons.done_all : Icons.done_all,
color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor,
size: 14),
Icon(isDelivered ? Icons.done_all : Icons.done_all, color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, size: 14),
],
),
),
],
)
.paddingOnly(top: 11, left: 13, right: 13, bottom: 5)
.objectContainerView(disablePadding: true)
.paddingOnly(left: MediaQuery.of(context).size.width * 0.3);
).paddingOnly(top: 11, left: 13, right: 13, bottom: 5).objectContainerView(disablePadding: true).paddingOnly(left: MediaQuery.of(context).size.width * 0.3);
}
Widget receiptUser(BuildContext context) {
return Container(
padding: const EdgeInsets.only(top: 5, left: 8, right: 13, bottom: 5),
padding: const EdgeInsets.only(top: 11, left: 13, right: 13, bottom: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: const LinearGradient(
transform: GradientRotation(.83),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: <Color>[
MyColors.gradiantEndColor,
MyColors.gradiantStartColor
],
colors: <Color>[MyColors.gradiantEndColor, MyColors.gradiantStartColor],
),
),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
@ -338,51 +258,25 @@ class GroupChatBubble extends StatelessWidget {
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color: isCurrentUser
? MyColors.gradiantStartColor
: MyColors.white)),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
border: Border(left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white)),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(userName)
.toText12(
color: MyColors.gradiantStartColor,
isBold: false)
.paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
(userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5),
Directionality(
textDirection: provider.getTextDirection(
cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: ""),
child: (cItem.groupChatReplyResponse != null
? cItem.groupChatReplyResponse!.contant
.toString()
: "")
.toText10(
color: isCurrentUser
? MyColors.grey71Color
: MyColors.white.withOpacity(0.5),
isBold: false,
maxlines: 4)
.paddingOnly(
right: 5, top: 5, bottom: 8, left: 5),
textDirection: provider.getTextDirection(cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : ""),
child: (cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant.toString() : "")
.toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4)
.paddingOnly(right: 5, top: 5, bottom: 8, left: 5),
),
],
).expanded,
if (cItem.groupChatReplyResponse != null)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 ||
cItem.groupChatReplyResponse!.fileTypeId == 3 ||
cItem.groupChatReplyResponse!.fileTypeId == 4)
if (cItem.groupChatReplyResponse!.fileTypeId == 12 || cItem.groupChatReplyResponse!.fileTypeId == 3 || cItem.groupChatReplyResponse!.fileTypeId == 4)
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: SizedBox(
@ -390,13 +284,8 @@ class GroupChatBubble extends StatelessWidget {
width: 32,
child: showImage(
isReplyPreview: true,
fileName:
cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem
.groupChatReplyResponse!
.fileTypeResponse!
.fileTypeDescription ??
"image/jpg"),
fileName: cItem.groupChatReplyResponse!.contant!,
fileTypeDescription: cItem.groupChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"),
),
).paddingOnly(left: 10, right: 10, bottom: 16, top: 16)
],
@ -411,88 +300,55 @@ class GroupChatBubble extends StatelessWidget {
child: SizedBox(
height: 140,
width: 227,
child: showImage(
isReplyPreview: false,
fileName: cItem.contant ?? "",
fileTypeDescription:
cItem.fileTypeResponse!.fileTypeDescription ??
"image/jpg")
.onPress(() {
child: showImage(isReplyPreview: false, fileName: cItem.contant ?? "", fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription ?? "image/jpg").onPress(() {
showDialog(
context: context,
anchorPoint: screenOffset,
builder: (BuildContext context) => ChatImagePreviewScreen(
imgTitle: cItem.contant ?? "", img: cItem.image!),
builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant ?? "", img: cItem.image!),
);
}),
),
).paddingOnly(bottom: 4),
if (fileTypeID == 13 && cItem.voiceController != null)
recipetWaveBubble(context, cItem),
if (fileTypeID == 13 && cItem.voiceController != null) recipetWaveBubble(context, cItem),
if (fileTypeID == 16)
showVideoThumb(context, cItem)
else
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
cItem.currentUserName!
.toText10(
color: Colors.black,
)
.paddingOnly(bottom: 5),
showVideoThumb(context, cItem),
Row(
children: [
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""),
height: 30,
width: 22,
alignment: Alignment.center,
fit: BoxFit.cover)
.paddingOnly(left: 0, right: 10),
Directionality(
textDirection:
provider.getTextDirection(cItem.contant ?? ""),
child: (cItem.contant ?? "")
.toText12(color: Colors.white)
.expanded),
if (fileTypeID == 1 ||
fileTypeID == 5 ||
fileTypeID == 7 ||
fileTypeID == 6 ||
fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye,
color: Colors.white, size: 16)
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
],
),
Align(
alignment: Alignment.topRight,
child: dateTime
.toText10(
color: Colors.white.withOpacity(.71),
)
.paddingOnly(top: 5),
),
],
)
else
Row(
children: [
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
// || fileTypeID == 2
)
SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10),
Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded),
if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8
//|| fileTypeID == 2
)
const Icon(Icons.remove_red_eye, color: Colors.white, size: 16)
],
),
Align(
alignment: Alignment.centerRight,
child: dateTime.toText10(
color: Colors.white.withOpacity(.71),
),
])).paddingOnly(right: MediaQuery.of(context).size.width * 0.3);
),
])).paddingOnly(right: MediaQuery.of(context).size.width * 0.33);
}
Widget voiceMsg(BuildContext context) {
return Container();
}
Widget showImage(
{required bool isReplyPreview,
required String fileName,
required String fileTypeDescription}) {
Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) {
if (cItem.isImageLoaded != null && cItem.image != null) {
return Image.memory(
cItem.image!,
@ -503,8 +359,7 @@ class GroupChatBubble extends StatelessWidget {
);
} else {
return FutureBuilder<Uint8List>(
future: ChatApiClient().downloadURL(
fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource:2),
future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource: 2),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
if (snapshot.data == null) {
@ -531,20 +386,14 @@ class GroupChatBubble extends StatelessWidget {
}
}
Widget currentWaveBubble(
BuildContext context, GetGroupChatHistoryAsync data) {
Widget currentWaveBubble(BuildContext context, GetGroupChatHistoryAsync data) {
return Container(
margin: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color:
isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
children: [
@ -552,14 +401,12 @@ class GroupChatBubble extends StatelessWidget {
// getPlayer(player: data.voiceController!, modelData: data),
StreamBuilder<PositionData>(
stream: _positionDataStream,
builder:
(BuildContext context, AsyncSnapshot<PositionData> snapshot) {
builder: (BuildContext context, AsyncSnapshot<PositionData> snapshot) {
PositionData? positionData = snapshot.data;
return SeekBar(
duration: positionData?.duration ?? Duration.zero,
position: positionData?.position ?? Duration.zero,
bufferedPosition:
positionData?.bufferedPosition ?? Duration.zero,
bufferedPosition: positionData?.bufferedPosition ?? Duration.zero,
onChangeEnd: data.voiceController!.seek,
).expanded;
},
@ -570,24 +417,17 @@ class GroupChatBubble extends StatelessWidget {
}
Widget showVideoThumb(BuildContext context, GetGroupChatHistoryAsync data) {
return LoadVideo(data: data);
return LoadVideo(data: data);
}
Widget recipetWaveBubble(
BuildContext context, GetGroupChatHistoryAsync data) {
Widget recipetWaveBubble(BuildContext context, GetGroupChatHistoryAsync data) {
return Container(
margin: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 6,
color:
isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white),
),
color: isCurrentUser
? MyColors.black.withOpacity(0.10)
: MyColors.black.withOpacity(0.30),
color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30),
),
child: Row(
mainAxisSize: MainAxisSize.max,
@ -596,14 +436,12 @@ class GroupChatBubble extends StatelessWidget {
//getPlayer(player: data.voiceController!, modelData: data),
StreamBuilder<PositionData>(
stream: _positionDataStream,
builder:
(BuildContext context, AsyncSnapshot<PositionData> snapshot) {
builder: (BuildContext context, AsyncSnapshot<PositionData> snapshot) {
PositionData? positionData = snapshot.data;
return SeekBar(
duration: positionData?.duration ?? Duration.zero,
position: positionData?.position ?? Duration.zero,
bufferedPosition:
positionData?.bufferedPosition ?? Duration.zero,
bufferedPosition: positionData?.bufferedPosition ?? Duration.zero,
onChangeEnd: data.voiceController!.seek,
).expanded;
},
@ -613,16 +451,14 @@ class GroupChatBubble extends StatelessWidget {
).circle(5);
}
Widget getPlayer(
{required AudioPlayer player, required SingleUserChatModel modelData}) {
Widget getPlayer({required AudioPlayer player, required SingleUserChatModel modelData}) {
return StreamBuilder<PlayerState>(
stream: player.playerStateStream,
builder: (BuildContext context, AsyncSnapshot<PlayerState> snapshot) {
PlayerState? playerState = snapshot.data;
ProcessingState? processingState = playerState?.processingState;
bool? playing = playerState?.playing;
if (processingState == ProcessingState.loading ||
processingState == ProcessingState.buffering) {
if (processingState == ProcessingState.loading || processingState == ProcessingState.buffering) {
return Container(
margin: const EdgeInsets.all(8.0),
width: 30.0,
@ -661,6 +497,7 @@ class GroupChatBubble extends StatelessWidget {
class LoadVideo extends StatefulWidget {
final GetGroupChatHistoryAsync data;
const LoadVideo({Key? key, required this.data}) : super(key: key);
@override
@ -672,21 +509,14 @@ class _LoadVideoState extends State<LoadVideo> {
@override
void initState() {
videoController = VideoPlayerController.networkUrl(Uri.parse(
'https://apiderichat.hmg.com/groupattachments/${widget.data.fileTypeResponse?.fileName}'))
..initialize().then((_) {
});
videoController = VideoPlayerController.networkUrl(Uri.parse('https://apiderichat.hmg.com/groupattachments/${widget.data.fileTypeResponse?.fileName}'))..initialize().then((_) {});
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
return ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: AspectRatio(
aspectRatio: videoController.value.aspectRatio,
child: Stack(

@ -142,7 +142,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
WidgetsBinding.instance.removeObserver(this);
super.dispose();
if (!cProvider.disableChatForThisUser) {
chatHubConnection.stop();
chatHubConnection!.stop();
}
}
@ -168,16 +168,16 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
Future<void> checkHubCon() async {
if (chatHubConnection.state == HubConnectionState.Connected) {
await chatHubConnection.stop();
await chatHubConnection.start();
} else if (chatHubConnection.state != HubConnectionState.Connected) {
await chatHubConnection.start();
if (chatHubConnection!.state == HubConnectionState.Connected) {
await chatHubConnection!.stop();
await chatHubConnection!.start();
} else if (chatHubConnection!.state != HubConnectionState.Connected) {
await chatHubConnection!.start();
}
}
void gotoChat(BuildContext context) async {
if (chatHubConnection.state == HubConnectionState.Connected) {
if (chatHubConnection!.state == HubConnectionState.Connected) {
Utils.hideLoading(context);
Navigator.pushNamed(context, AppRoutes.chat);
String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat");

@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -99,7 +98,7 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
voIPKit.getVoIPToken().then((String? value) async {
print('🎈 example: getVoIPToken: $value');
if (value != null) {
AppState().setiosVoipPlayerID = await ChatApiClient().oneSignalVoip(value!);
AppState().setiosVoipPlayerID = await ChatApiClient().oneSignalVoip(value);
print('🎈 example: OneSignal ID: ${AppState().iosVoipPlayerID}');
}
});
@ -113,7 +112,7 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
Map<String, dynamic> payload,
) async {
_iosCallPayload = IosCallPayload.fromJson(payload);
// _timeOut();
_timeOut();
};
voIPKit.onDidRejectIncomingCall = (
@ -130,7 +129,8 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
) async {
await connectCall(uuid: uuid, callDetails: callerId);
voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
voIPKit.callConnected();
voIPKit.callConnected().then((value) => timeOutTimer.cancel());
// Utils.showToast("Timer Cancel", longDuration: true);
};
}
@ -160,17 +160,26 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
_iosCallPayload = IosCallPayload(
uuid: uuid, incomingCallerId: callDetails.split("-")[0], incomingCallReciverId: callDetails.split("-")[1], incomingCallerName: null, incomingCallType: callDetails.split("-").last);
}
// _iosCallPayload = IosCallPayload(uuid: "3423434-423423-43-53-5", incomingCallerId: "266642", incomingCallReciverId: "341682", incomingCallerName: null, incomingCallType: "video");
if (_iosCallPayload!.incomingCallerName == null) {
if (Platform.isIOS) {
Utils.hideLoading(context);
}
await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
MaterialPageRoute pageRoute = await MaterialPageRoute(builder: (BuildContext context) => StartCallPage());
// await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
// Utils.showToast("Name Null", longDuration: true);
MaterialPageRoute pageRoute = await MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(
payload: _iosCallPayload,
));
Navigator.push(context, pageRoute);
} else if (AppState().getisUserOnline) {
await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
// await Utils.saveStringFromPrefs("iosCallPayload", jsonEncode(_iosCallPayload));
BuildContext context = AppRoutes.navigatorKey.currentContext!;
MaterialPageRoute pageRoute = await MaterialPageRoute(builder: (BuildContext context) => StartCallPage());
MaterialPageRoute pageRoute = await MaterialPageRoute(
builder: (BuildContext context) => StartCallPage(
payload: _iosCallPayload,
));
Navigator.push(context, pageRoute);
} else {
FlutterCallkitIncoming.endAllCalls();
@ -491,7 +500,11 @@ class _LoginScreenState extends State<LoginScreen> with WidgetsBindingObserver {
DefaultButton(LocaleKeys.login.tr(), () async {
SystemChannels.textInput.invokeMethod('TextInput.hide');
performLogin();
}).insideContainer
}).insideContainer,
// DefaultButton("Call", () async {
// SystemChannels.textInput.invokeMethod('TextInput.hide');
// connectCall();
// }).insideContainer
],
),
);

@ -85,14 +85,14 @@ dependencies:
cached_network_image: ^3.2.2
#Chat
signalr_netcore: ^1.3.3
signalr_netcore: ^1.3.6
logging: ^1.0.1
swipe_to: ^1.0.5
#flutter_webrtc: ^0.9.34
flutter_webrtc: ^0.9.37
flutter_webrtc: ^0.9.47
draggable_widget: ^2.0.0
flutter_callkit_incoming: ^2.0.0+1
camera: ^0.10.3
camera: ^0.10.5+9
flutter_local_notifications: ^10.0.0
#firebase_analytics: any

Loading…
Cancel
Save