From b596b1b61d5bf5dd8e44ce04a98b2323e45197c9 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Tue, 16 Nov 2021 15:07:57 +0300 Subject: [PATCH 01/11] WebRTC and Packages Offer | Merge --- ios/Flutter/.last_build_id | 2 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- .../requests/CreateCustomerRequestModel.dart | 5 +- .../responses/tamara_payment_option.dart | 1 + .../PackagesOffersServices.dart | 1 + .../PackagesOffersViewModel.dart | 17 + lib/main.dart | 3 +- .../conference/web_rtc/call_home_page.dart | 92 ++++-- .../web_rtc/widgets/cam_view_widget.dart | 23 +- .../OfferAndPackagesCartPage.dart | 20 +- lib/pages/webRTC/call_page.dart | 120 +++++--- lib/pages/webRTC/call_page_bkp.dart | 147 +++++++++ lib/pages/webRTC/fcm/FCMSendNotification.dart | 86 ++++++ lib/pages/webRTC/signaling.dart | 291 +++++++----------- lib/pages/webRTC/signaling_bkp.dart | 242 +++++++++++++++ lib/routes.dart | 4 + lib/uitl/SignalRUtil.dart | 162 ++++++++-- lib/uitl/date_uitl.dart | 4 + lib/widgets/drawer/app_drawer_widget.dart | 1 + 19 files changed, 928 insertions(+), 299 deletions(-) create mode 100644 lib/pages/webRTC/call_page_bkp.dart create mode 100644 lib/pages/webRTC/fcm/FCMSendNotification.dart create mode 100644 lib/pages/webRTC/signaling_bkp.dart diff --git a/ios/Flutter/.last_build_id b/ios/Flutter/.last_build_id index 53427e0c..b3315e38 100644 --- a/ios/Flutter/.last_build_id +++ b/ios/Flutter/.last_build_id @@ -1 +1 @@ -3f8c659591fcdd0e47e3895f74af395c \ No newline at end of file +8d8845c5c035b7f87f2849054cdedb69 \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 6c02c983..9bf7caa5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -520,7 +520,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.hmg.smartphone; + PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -659,7 +659,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.hmg.smartphone; + PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -692,7 +692,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.hmg.smartphone; + PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart b/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart index 9cc3d3b9..d5022f0f 100644 --- a/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart +++ b/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart @@ -1,4 +1,5 @@ import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; +import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:flutter/cupertino.dart'; class PackagesCustomerRequestModel { @@ -19,7 +20,9 @@ class PackagesCustomerRequestModel { this.email = user.emailAddress; this.phone = user.mobileNumber; this.national_id = user.patientIdentificationNo; - this.date_of_birth = user.dateofBirth; + + String isoDateTime = DateUtil.getISODateFormat(user.dateofBirthDataTime); + this.date_of_birth = isoDateTime; } Map json() { diff --git a/lib/core/model/packages_offers/responses/tamara_payment_option.dart b/lib/core/model/packages_offers/responses/tamara_payment_option.dart index ad79f5f3..2b694a23 100644 --- a/lib/core/model/packages_offers/responses/tamara_payment_option.dart +++ b/lib/core/model/packages_offers/responses/tamara_payment_option.dart @@ -3,6 +3,7 @@ class TamaraPaymentOption { double minLimit; double maxLimit; int id; + bool enable = true; String fullName() => '$name Months'; diff --git a/lib/core/service/packages_offers/PackagesOffersServices.dart b/lib/core/service/packages_offers/PackagesOffersServices.dart index ae5396a7..6c4e0d24 100644 --- a/lib/core/service/packages_offers/PackagesOffersServices.dart +++ b/lib/core/service/packages_offers/PackagesOffersServices.dart @@ -75,6 +75,7 @@ class OffersAndPackagesServices extends BaseService { Future> getTamaraOptions({@required BuildContext context, @required bool showLoading = true}) async { if (tamaraPaymentOptions != null && tamaraPaymentOptions.isNotEmpty) return tamaraPaymentOptions; + tamaraPaymentOptions.clear(); var url = EXA_CART_API_BASE_URL + PACKAGES_TAMARA_OPT; await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { diff --git a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart index af750eab..b1fcc1d1 100644 --- a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart +++ b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart @@ -2,6 +2,7 @@ import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/tamara_payment_option.dart'; import 'package:diplomaticquarterapp/core/service/packages_offers/PackagesOffersServices.dart'; import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart'; import 'package:diplomaticquarterapp/locator.dart'; @@ -25,6 +26,22 @@ class PackagesViewModel extends BaseViewModel { List get cartItemList => service.cartItemList; List get hospitals => service.hospitals; + List get tamara_options => service.tamaraPaymentOptions; + bool allowTamara = true; + + setTamaraIllegablity(double amount){ + bool illegible = true; + if(tamara_options == null || tamara_options.isEmpty) + illegible = false; + else{ + tamara_options.forEach((element) { + final ill = (amount >= element.minLimit && amount <= element.maxLimit); + element.enable = ill; + illegible = illegible || ill; + }); + } + allowTamara = illegible; + } String _cartItemCount = ""; diff --git a/lib/main.dart b/lib/main.dart index 0dd18a2d..93af691e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -168,7 +168,8 @@ class _MyApp extends State { // ), // ), // ), - initialRoute: SPLASH, + // initialRoute: SPLASH, + initialRoute: CALL_PAGE, // initialRoute: OPENTOK_CALL_PAGE, // initialRoute: PACKAGES_OFFERS, // initialRoute: PACKAGES_ORDER_COMPLETED, diff --git a/lib/pages/conference/web_rtc/call_home_page.dart b/lib/pages/conference/web_rtc/call_home_page.dart index 7153bf92..892871cc 100644 --- a/lib/pages/conference/web_rtc/call_home_page.dart +++ b/lib/pages/conference/web_rtc/call_home_page.dart @@ -2,6 +2,9 @@ import 'dart:async'; import 'package:diplomaticquarterapp/pages/conference/web_rtc/widgets/cam_view_widget.dart'; import 'package:diplomaticquarterapp/pages/conference/widgets/noise_box.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/call_page.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/signaling.dart'; +import 'package:diplomaticquarterapp/uitl/SignalRUtil.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; @@ -9,6 +12,11 @@ import 'package:flutter_webrtc/flutter_webrtc.dart'; import '../conference_button_bar.dart'; class CallHomePage extends StatefulWidget { + final String receiverId; + final String callerId; + + const CallHomePage({Key key, this.receiverId, this.callerId}) : super(key: key); + @override _CallHomePageState createState() => _CallHomePageState(); } @@ -24,33 +32,68 @@ class _CallHomePageState extends State { final StreamController _onButtonBarHeightStreamController = StreamController.broadcast(); //Stream to enable video - MediaStream stream; + MediaStream localMediaStream; + MediaStream remoteMediaStream; + Signaling signaling = Signaling()..init(); @override void initState() { // TODO: implement initState super.initState(); - _localRenderer.initialize(); - _remoteRenderer.initialize(); + startCall(); + } - enableVideo(); + startCall() async{ + await _localRenderer.initialize(); + await _remoteRenderer.initialize(); + final connected = await receivedCall(); } - enableVideo() async { - //Stream to enable video - stream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true}); - // _audioButton.add(false); + + Future receivedCall() async { + //Stream local media + localMediaStream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true}); + _localRenderer.srcObject = localMediaStream; + + final connected = await signaling.acceptCall(widget.callerId, widget.receiverId, localMediaStream: localMediaStream, onRemoteMediaStream: (remoteMediaStream){ + this.remoteMediaStream = remoteMediaStream; + _remoteRenderer.srcObject = remoteMediaStream; + }); + + if(connected){ + signaling.signalR.listen( + onAcceptCall: (arg0){ + print(arg0.toString()); + }, + onCandidate: (candidateJson){ + signaling.addCandidate(candidateJson); + }, + onDeclineCall: (arg0,arg1){ + _onHangup(); + }, + onHangupCall: (arg0){ + _onHangup(); + }, + + onOffer: (offerSdp, callerUser) async{ + print('${offerSdp.toString()} | ${callerUser.toString()}'); + await signaling.answerOffer(offerSdp); + } + ); + } + return connected; } @override void dispose() { // TODO: implement dispose super.dispose(); - _localRenderer.dispose(); - _remoteRenderer.dispose(); - _audioButton.close(); - _videoButton.close(); - stream.dispose(); + _localRenderer?.dispose(); + _remoteRenderer?.dispose(); + _audioButton?.close(); + _videoButton?.close(); + localMediaStream?.dispose(); + remoteMediaStream?.dispose(); _disposeStreamsAndSubscriptions(); } @@ -83,7 +126,6 @@ class _CallHomePageState extends State { CamViewWidget( localRenderer: _localRenderer, remoteRenderer: _remoteRenderer, - stream: stream, constraints: constraints, onButtonBarVisibleStreamController: _onButtonBarVisibleStreamController, onButtonBarHeightStreamController: _onButtonBarHeightStreamController, @@ -130,26 +172,25 @@ class _CallHomePageState extends State { } Function _onAudioEnable() { - bool enabled = stream.getAudioTracks()[0].enabled; - stream.getAudioTracks()[0].enabled = !enabled; - _audioButton.add(!enabled); + final audioTrack = localMediaStream.getAudioTracks()[0]; + final mute = audioTrack.muted; + Helper.setMicrophoneMute(!mute, audioTrack); + _audioButton.add(mute); } Function _onVideoEnabled() { - bool enabled = stream.getVideoTracks()[0].enabled; - stream.getVideoTracks()[0].enabled = !enabled; - _videoButton.add(!enabled); + final videoTrack = localMediaStream.getVideoTracks()[0]; + bool videoEnabled = videoTrack.enabled; + localMediaStream.getVideoTracks()[0].enabled = !videoEnabled; + _videoButton.add(!videoEnabled); } Function _onSwitchCamera() { - // stream.getAudioTracks()[0].enabled = false; - // stream.getVideoTracks()[0].enabled = false; - Helper.switchCamera(stream.getVideoTracks()[0]); + Helper.switchCamera(localMediaStream.getVideoTracks()[0]); } void _onShowBar() { setState(() { - SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom, SystemUiOverlay.top]); }); _onButtonBarVisibleStreamController.add(true); } @@ -166,7 +207,10 @@ class _CallHomePageState extends State { } Future _onHangup() async { + signaling.hangupCall(widget.callerId, widget.receiverId); print('onHangup'); Navigator.of(context).pop(); } + + } diff --git a/lib/pages/conference/web_rtc/widgets/cam_view_widget.dart b/lib/pages/conference/web_rtc/widgets/cam_view_widget.dart index 3db0c74b..d27dad55 100644 --- a/lib/pages/conference/web_rtc/widgets/cam_view_widget.dart +++ b/lib/pages/conference/web_rtc/widgets/cam_view_widget.dart @@ -9,12 +9,12 @@ import 'draggable_cam.dart'; class CamViewWidget extends StatefulWidget { RTCVideoRenderer localRenderer; RTCVideoRenderer remoteRenderer; - MediaStream stream; + MediaStream localStream; BoxConstraints constraints; StreamController onButtonBarVisibleStreamController; StreamController onButtonBarHeightStreamController; - CamViewWidget({this.localRenderer, this.remoteRenderer, this.stream, this.constraints, this.onButtonBarVisibleStreamController, this.onButtonBarHeightStreamController}); + CamViewWidget({this.localRenderer, this.remoteRenderer, this.constraints, this.onButtonBarVisibleStreamController, this.onButtonBarHeightStreamController}); @override _CamViewWidgetState createState() => _CamViewWidgetState(); @@ -24,16 +24,6 @@ class _CamViewWidgetState extends State { @override void initState() { super.initState(); - Future.delayed(const Duration(milliseconds: 300), () { - showCamera(); - }); - } - - showCamera() async { - setState(() async { - widget.localRenderer.srcObject = widget.stream; - widget.remoteRenderer.srcObject = widget.stream; - }); } @override @@ -43,15 +33,18 @@ class _CamViewWidgetState extends State { height: double.infinity, child: Stack( children: [ - Container( - child: RTCVideoView(widget.localRenderer, mirror: true), + FractionallySizedBox( + heightFactor: 1, widthFactor: 1, + child: Container( + child: RTCVideoView(widget.remoteRenderer, mirror: true), + ), ), DraggableCam( key: Key('publisher'), onButtonBarHeight: widget.onButtonBarHeightStreamController.stream, onButtonBarVisible: widget.onButtonBarVisibleStreamController.stream, availableScreenSize: widget.constraints.biggest, - child: RTCVideoView(widget.remoteRenderer), + child: RTCVideoView(widget.localRenderer), ), // Expanded(child: RTCVideoView(widget.remoteRenderer)), ], diff --git a/lib/pages/packages_offers/OfferAndPackagesCartPage.dart b/lib/pages/packages_offers/OfferAndPackagesCartPage.dart index 4b42774b..a15cd4f3 100644 --- a/lib/pages/packages_offers/OfferAndPackagesCartPage.dart +++ b/lib/pages/packages_offers/OfferAndPackagesCartPage.dart @@ -336,13 +336,18 @@ class _PackagesCartPageState extends State with AfterLayoutMix } fetchData() async { - await viewModel.service.cartItems(context: context).then((value) { - subtotal = value['subtotal'] ?? 0.0; - tax = value['tax'] ?? 0.0; - total = value['total'] ?? 0.0; - }).catchError((error) {}); - - setState(() {}); + final cartResponse = await viewModel.service.cartItems(context: context).catchError((error) {}); + if(cartResponse != null){ + subtotal = cartResponse['subtotal'] ?? 0.0; + tax = cartResponse['tax'] ?? 0.0; + total = cartResponse['total'] ?? 0.0; + viewModel.service.getTamaraOptions(context: context, showLoading: true).then((tamara_options){ + if(tamara_options != null || tamara_options.isNotEmpty) { + viewModel.setTamaraIllegablity(total); + setState(() {}); + } + }); + } } paymentClosed({@required int orderId, @required bool withStatus, dynamic data}) async { @@ -355,6 +360,7 @@ class _PackagesCartPageState extends State with AfterLayoutMix debugPrint(error); }); } + } // Widget _payNow(BuildContext context, {double subtotal, double tax, double total, @required VoidCallback onPayNowClick}) { diff --git a/lib/pages/webRTC/call_page.dart b/lib/pages/webRTC/call_page.dart index 4c8ac4f5..0c6caf54 100644 --- a/lib/pages/webRTC/call_page.dart +++ b/lib/pages/webRTC/call_page.dart @@ -1,8 +1,20 @@ +import 'dart:io'; + +import 'package:diplomaticquarterapp/models/LiveCare/IncomingCallData.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; +import 'package:diplomaticquarterapp/pages/livecare/incoming_call.dart'; import 'package:diplomaticquarterapp/pages/webRTC/signaling.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; +final DOCTOR_TOKEN = 'cj2TFgotT6q-F0SCGVFaKR:APA91bFBY0NCY5tlCooYMKS9JWI8TMJQ6YcPLT0T5gNyn-qjfQgFVQWh60QeXDz_aNqL2U3B9qOjpDbaA32e4oBlK1klR-7uUYL0DwWiHKnU1hV_wlW9-Tib16CBVkN3ods7OMlKbPv9'; +String My_ID = '54321'; +String My_Mobile = '0500409598'; +String doctor_ID = '12345'; +String doctor_Mobile = '966500409598'; + class CallPage extends StatefulWidget { @override _CallPageState createState() => _CallPageState(); @@ -20,10 +32,12 @@ class _CallPageState extends State { _localRenderer.initialize(); _remoteRenderer.initialize(); - signaling.onAddRemoteStream = ((stream) { - _remoteRenderer.srcObject = stream; - setState(() {}); - }); + // signaling.onRemoteStream = ((stream) { + // _remoteRenderer.srcObject = stream; + // setState(() {}); + // }); + + fcmConfigure(); super.initState(); } @@ -35,24 +49,13 @@ class _CallPageState extends State { super.dispose(); } - void _getUserMedia() async { - final Map constraints = { - 'audio': 'false', - 'video': {'facingMode': 'user'}, - }; - - MediaStream stream = await navigator.mediaDevices.getUserMedia(constraints); - setState(() { - _localRenderer.srcObject = stream; - }); - } - - void initializeRenderers() async { - _localRenderer.initialize(); - } @override Widget build(BuildContext context) { + FirebaseMessaging().getToken().then((value){ + print('FCM_TOKEN: $value'); + }); + return AppScaffold( isShowAppBar: true, showNewAppBar: true, @@ -64,37 +67,14 @@ class _CallPageState extends State { SizedBox(height: 8), Wrap( children: [ - ElevatedButton( - onPressed: () { - setState(() { - signaling.openUserMedia(_localRenderer, _remoteRenderer); - }); - }, - child: Text("Open camera & microphone"), - ), - SizedBox( - width: 8, - ), - ElevatedButton( - onPressed: () async { - roomId = await signaling.createRoom(_remoteRenderer); - textEditingController.text = roomId; - setState(() {}); - }, - child: Text("Create room"), - ), SizedBox( width: 8, ), ElevatedButton( onPressed: () { - // Add roomId - signaling.joinRoom( - textEditingController.text, - _remoteRenderer, - ); + dummyCall(); }, - child: Text("Join room"), + child: Text("Call"), ), SizedBox( width: 8, @@ -143,5 +123,57 @@ class _CallPageState extends State { ], ), ); + } + + dummyCall() async{ + final json = { + "callerID": "12345", + "receiverID": "54321", + "msgID": "123", + "notfID": "123", + "notification_foreground": "true", + "count": "1", + "message": "Doctor is calling ", + "AppointmentNo": "123", + "title": "Rayyan Hospital", + "ProjectID": "123", + "NotificationType": "10", + "background": "1", + "doctorname": "Dr Sulaiman Al Habib", + "clinicname": "ENT Clinic", + "speciality": "Speciality", + "appointmentdate": "Sun, 15th Dec, 2019", + "appointmenttime": "09:00", + "type": "video", + "session_id": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0eSI6InR3aWxpby1mcGE7dj0xIn0.eyJqdGkiOiJTS2I2NjYyOWMzN2ZhOTM3YjFjNDI2Zjg1MTgyNWFmN2M0LTE1OTg3NzQ1MDYiLCJpc3MiOiJTS2I2NjYyOWMzN2ZhOTM3YjFjNDI2Zjg1MTgyNWFmN2M0Iiwic3ViIjoiQUNhYWQ1YTNmOGM2NGZhNjczNTY3NTYxNTc0N2YyNmMyYiIsImV4cCI6MTU5ODc3ODEwNiwiZ3JhbnRzIjp7ImlkZW50aXR5IjoiSGFyb29uMSIsInZpZGVvIjp7InJvb20iOiJTbWFsbERhaWx5U3RhbmR1cCJ9fX0.7XUS5uMQQJfkrBZu9EjQ6STL6R7iXkso6BtO1HmrQKk", + "identity": "Haroon1", + "name": "SmallDailyStandup", + "videoUrl": "video", + "picture": "video", + "is_call": "true" + }; + + IncomingCallData incomingCallData = IncomingCallData.fromJson(json); + final result = await Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: incomingCallData))); + } + + fcmConfigure(){ + FirebaseMessaging().configure( + onMessage: (message) async{ + print(message.toString()); + + IncomingCallData incomingCallData; + if(Platform.isAndroid) + incomingCallData = IncomingCallData.fromJson(message['data']); + else if(Platform.isIOS) + incomingCallData = IncomingCallData.fromJson(message); + if(incomingCallData != null) + final result = await Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: incomingCallData))); + + } + ); + } + + } diff --git a/lib/pages/webRTC/call_page_bkp.dart b/lib/pages/webRTC/call_page_bkp.dart new file mode 100644 index 00000000..4a31feae --- /dev/null +++ b/lib/pages/webRTC/call_page_bkp.dart @@ -0,0 +1,147 @@ +// import 'package:diplomaticquarterapp/pages/webRTC/signaling_bkp.dart'; +// import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_webrtc/flutter_webrtc.dart'; +// +// class CallPage extends StatefulWidget { +// @override +// _CallPageState createState() => _CallPageState(); +// } +// +// class _CallPageState extends State { +// Signaling signaling = Signaling(); +// RTCVideoRenderer _localRenderer = RTCVideoRenderer(); +// RTCVideoRenderer _remoteRenderer = RTCVideoRenderer(); +// String roomId; +// TextEditingController textEditingController = TextEditingController(text: ''); +// +// @override +// void initState() { +// _localRenderer.initialize(); +// _remoteRenderer.initialize(); +// +// signaling.onAddRemoteStream = ((stream) { +// _remoteRenderer.srcObject = stream; +// setState(() {}); +// }); +// +// super.initState(); +// } +// +// @override +// void dispose() { +// _localRenderer.dispose(); +// _remoteRenderer.dispose(); +// super.dispose(); +// } +// +// void _getUserMedia() async { +// final Map constraints = { +// 'audio': 'false', +// 'video': {'facingMode': 'user'}, +// }; +// +// MediaStream stream = await navigator.mediaDevices.getUserMedia(constraints); +// setState(() { +// _localRenderer.srcObject = stream; +// }); +// } +// +// void initializeRenderers() async { +// _localRenderer.initialize(); +// } +// +// @override +// Widget build(BuildContext context) { +// return AppScaffold( +// isShowAppBar: true, +// showNewAppBar: true, +// showNewAppBarTitle: true, +// isShowDecPage: false, +// appBarTitle: "WebRTC Calling", +// body: Column( +// children: [ +// SizedBox(height: 8), +// Wrap( +// children: [ +// ElevatedButton( +// onPressed: () { +// setState(() { +// signaling.openUserMedia(_localRenderer, _remoteRenderer); +// }); +// }, +// child: Text("Open camera & microphone"), +// ), +// SizedBox( +// width: 8, +// ), +// ElevatedButton( +// onPressed: () async { +// roomId = await signaling.createRoom(_remoteRenderer); +// textEditingController.text = roomId; +// setState(() {}); +// }, +// child: Text("Create room"), +// ), +// SizedBox( +// width: 8, +// ), +// ElevatedButton( +// onPressed: () { +// // Add roomId +// signaling.joinRoom( +// textEditingController.text, +// _remoteRenderer, +// ); +// }, +// child: Text("Join room"), +// ), +// SizedBox( +// width: 8, +// ), +// ElevatedButton( +// onPressed: () { +// signaling.hangUp(_localRenderer); +// }, +// child: Text("Hangup"), +// ) +// ], +// ), +// SizedBox(height: 8), +// Expanded( +// child: Padding( +// padding: const EdgeInsets.all(0.0), +// child: Stack( +// children: [ +// Positioned(top: 0.0, right: 0.0, left: 0.0, bottom: 0.0, child: RTCVideoView(_remoteRenderer)), +// Positioned( +// top: 20.0, +// right: 100.0, +// left: 20.0, +// bottom: 300.0, +// child: RTCVideoView(_localRenderer, mirror: true), +// ), +// ], +// ), +// ), +// ), +// Padding( +// padding: const EdgeInsets.all(8.0), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Text("Join the following Room: "), +// Flexible( +// child: TextFormField( +// controller: textEditingController, +// ), +// ) +// ], +// ), +// ), +// SizedBox(height: 8) +// ], +// ), +// ); +// } +// } diff --git a/lib/pages/webRTC/fcm/FCMSendNotification.dart b/lib/pages/webRTC/fcm/FCMSendNotification.dart new file mode 100644 index 00000000..f67537cf --- /dev/null +++ b/lib/pages/webRTC/fcm/FCMSendNotification.dart @@ -0,0 +1,86 @@ + +import 'dart:convert'; + +import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; +import 'package:http/http.dart' as http; + +const _serverFCMToken = 'ya29.a0ARrdaM9U7fZtxF64ntg2Y1Nve-cd4rPazyGcWN69cQmOsddUqxAL1X8GUQ8V6sW2gWxM8ln1BIbmh0OrzQtCiTGrsmcL3jZlGXoQhZN51nX3O7F3g1AXCW_Zt_pjiworCJEGSRkl7QirxE7RFzlwBONsOuft'; +const doctorID = '12345'; + +class FCM{ + static Future sendCallNotifcationTo(String token, String patientID, String patientMobile) async{ + var headers = { + 'Authorization': 'Bearer $_serverFCMToken', + 'Content-Type': 'application/json' + }; + + final body = { + "message": { + "token": token, + "notification": { + "title": "Dr Sulaiman Al Habib", + "body": "Doctor is calling" + }, + "apns": { + "payload": { + "aps": { + "sound": "ring_30Sec.mp3", + "token": "466e0f16fecf1e32c51f812cccc84fcbc807f958b15eb55675a5fa971a775829", + "badge": 1 + } + }, + "headers": { + "apns-priority": "10", + "apns-expiration": "0", + "apns-collapse-id": "2561368006" + } + }, + "data": { + "callerID" : doctorID, + "receiverID" : patientID, + "receiverMobile" : patientMobile, + "msgID": "123", + "notfID": "123", + "notification_foreground": "true", + "count": "1", + "message": "Doctor is calling ", + "AppointmentNo": "123", + "title": "Rayyan Hospital", + "ProjectID": "123", + "NotificationType": "10", + "background": "1", + "doctorname": "Dr Sulaiman Al Habib", + "clinicname": "ENT Clinic", + "speciality": "Speciality", + "appointmentdate": "Sun, 15th Dec, 2019", + "appointmenttime": "09:00", + "type": "video", + "session_id": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0eSI6InR3aWxpby1mcGE7dj0xIn0.eyJqdGkiOiJTS2I2NjYyOWMzN2ZhOTM3YjFjNDI2Zjg1MTgyNWFmN2M0LTE1OTg3NzQ1MDYiLCJpc3MiOiJTS2I2NjYyOWMzN2ZhOTM3YjFjNDI2Zjg1MTgyNWFmN2M0Iiwic3ViIjoiQUNhYWQ1YTNmOGM2NGZhNjczNTY3NTYxNTc0N2YyNmMyYiIsImV4cCI6MTU5ODc3ODEwNiwiZ3JhbnRzIjp7ImlkZW50aXR5IjoiSGFyb29uMSIsInZpZGVvIjp7InJvb20iOiJTbWFsbERhaWx5U3RhbmR1cCJ9fX0.7XUS5uMQQJfkrBZu9EjQ6STL6R7iXkso6BtO1HmrQKk", + "identity": "Haroon1", + "name": "SmallDailyStandup", + "videoUrl": "video", + "picture": "video", + "is_call": "true" + } + } + }; + + bool success = false; + await BaseAppClient().simplePost('https://fcm.googleapis.com/v1/projects/api-project-815750722565/messages:send', body: body, headers: headers, onSuccess: (data, statusCode){ + success = true; + }, onFailure: (error, statusCode){ + success = false; + }); + + return success; + // final response = await http.post('https://fcm.googleapis.com/v1/projects/api-project-815750722565/messages:send', headers:headers, body: body); + + + } +} + +String toB64(String data){ + var bytes = utf8.encode(data); + var base64Str = base64.encode(bytes); + return base64Str; +} \ No newline at end of file diff --git a/lib/pages/webRTC/signaling.dart b/lib/pages/webRTC/signaling.dart index f987e285..90127e31 100644 --- a/lib/pages/webRTC/signaling.dart +++ b/lib/pages/webRTC/signaling.dart @@ -1,11 +1,45 @@ import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/fcm/FCMSendNotification.dart'; +import 'package:diplomaticquarterapp/uitl/SignalRUtil.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; +import 'call_page.dart'; + typedef void StreamStateCallback(MediaStream stream); +typedef void RTCIceGatheringStateCallback(RTCIceGatheringState state); +typedef void RTCPeerConnectionStateCallback(RTCPeerConnectionState state); +typedef void RTCSignalingStateCallback(RTCSignalingState state); class Signaling { + + dispose(){ + if(peerConnection != null) + peerConnection.dispose(); + signalR.closeConnection(); + } + + init(){ + // Create Peer Connection + createPeerConnection(configuration).then((value){ + peerConnection = value; + registerPeerConnectionListeners(); + }); + } + + + initializeSignalR() async{ + if(signalR != null) + await signalR.closeConnection(); + + signalR = SignalRUtil(hubName: "https://VCallApi.hmg.com/WebRTCHub?source=$My_Mobile&username=$My_ID"); + final connected = await signalR.openConnection(); + if(!connected) + throw 'Failed to connect SignalR'; + } + Map configuration = { 'iceServers': [ { @@ -14,209 +48,96 @@ class Signaling { ] }; + SignalRUtil signalR; + RTCPeerConnection peerConnection; MediaStream localStream; MediaStream remoteStream; - String roomId; - String currentRoomText; - StreamStateCallback onAddRemoteStream; - - Future createRoom(RTCVideoRenderer remoteRenderer) async { - FirebaseFirestore db = FirebaseFirestore.instance; - DocumentReference roomRef = db.collection('rooms').doc(); + RTCDataChannel dataChannel; - print('Create PeerConnection with configuration: $configuration'); + Future call(String patientId, String mobile, {@required RTCVideoRenderer localVideo, @required RTCVideoRenderer remoteVideo}) async { + initializeSignalR(); - peerConnection = await createPeerConnection(configuration); + final isCallPlaced = await FCM.sendCallNotifcationTo(DOCTOR_TOKEN, patientId, mobile); + if(!isCallPlaced) + throw 'Failed to notify target for call'; - registerPeerConnectionListeners(); - - localStream.getTracks().forEach((track) { - peerConnection?.addTrack(track, localStream); - }); - - // Code for collecting ICE candidates below - var callerCandidatesCollection = roomRef.collection('callerCandidates'); - - peerConnection?.onIceCandidate = (RTCIceCandidate candidate) { - print('Got candidate: ${candidate.toMap()}'); - callerCandidatesCollection.add(candidate.toMap()); - }; - // Finish Code for collecting ICE candidate - - // Add code for creating a room - RTCSessionDescription offer = await peerConnection.createOffer(); - await peerConnection.setLocalDescription(offer); - print('Created offer: $offer'); + return isCallPlaced; + } - Map roomWithOffer = {'offer': offer.toMap()}; - await roomRef.set(roomWithOffer); - var roomId = roomRef.id; - print('New room created with SDK offer. Room ID: $roomId'); - currentRoomText = 'Current room is $roomId - You are the caller!'; - // Created a Room + Future acceptCall(String caller, String receiver, {@required MediaStream localMediaStream, @required Function(MediaStream) onRemoteMediaStream}) async{ + await initializeSignalR(); + signalR.setContributors(caller: caller, receiver: receiver); + await signalR.acceptCall(receiver, caller).catchError((e) => throw 'Failed to inform signalR that i accepted a call'); - peerConnection?.onTrack = (RTCTrackEvent event) { - print('Got remote track: ${event.streams[0]}'); + peerConnection.addStream(localMediaStream); - event.streams[0].getTracks().forEach((track) { - print('Add a track to the remoteStream $track'); - remoteStream?.addTrack(track); - }); + peerConnection?.onAddStream = (MediaStream stream) { + remoteStream = stream; + onRemoteMediaStream?.call(stream); }; - // Listening for remote session description below - roomRef.snapshots().listen((snapshot) async { - print('Got updated room: ${snapshot.data()}'); - - Map data = snapshot.data() as Map; - if (peerConnection?.getRemoteDescription() != null && data['answer'] != null) { - var answer = RTCSessionDescription( - data['answer']['sdp'], - data['answer']['type'], - ); - - print("Someone tried to connect"); - await peerConnection?.setRemoteDescription(answer); - } - }); - // Listening for remote session description above - - // Listen for remote Ice candidates below - roomRef.collection('calleeCandidates').snapshots().listen((snapshot) { - snapshot.docChanges.forEach((change) { - if (change.type == DocumentChangeType.added) { - Map data = change.doc.data() as Map; - print('Got new remote ICE candidate: ${jsonEncode(data)}'); - peerConnection.addCandidate( - RTCIceCandidate( - data['candidate'], - data['sdpMid'], - data['sdpMLineIndex'], - ), - ); - } - }); - }); - // Listen for remote ICE candidates above - - return roomId; + return true; } - Future joinRoom(String roomId, RTCVideoRenderer remoteVideo) async { - FirebaseFirestore db = FirebaseFirestore.instance; - DocumentReference roomRef = db.collection('rooms').doc('$roomId'); - var roomSnapshot = await roomRef.get(); - print('Got room ${roomSnapshot.exists}'); - - if (roomSnapshot.exists) { - print('Create PeerConnection with configuration: $configuration'); - peerConnection = await createPeerConnection(configuration); - - registerPeerConnectionListeners(); - - localStream.getTracks().forEach((track) { - peerConnection?.addTrack(track, localStream); - }); - - // Code for collecting ICE candidates below - var calleeCandidatesCollection = roomRef.collection('calleeCandidates'); - peerConnection.onIceCandidate = (RTCIceCandidate candidate) { - if (candidate == null) { - print('onIceCandidate: complete!'); - return; - } - print('onIceCandidate: ${candidate.toMap()}'); - calleeCandidatesCollection.add(candidate.toMap()); - }; - // Code for collecting ICE candidate above - - peerConnection?.onTrack = (RTCTrackEvent event) { - print('Got remote track: ${event.streams[0]}'); - event.streams[0].getTracks().forEach((track) { - print('Add a track to the remoteStream: $track'); - remoteStream?.addTrack(track); - }); - }; - - // Code for creating SDP answer below - var data = roomSnapshot.data() as Map; - print('Got offer $data'); - var offer = data['offer']; - await peerConnection?.setRemoteDescription( - RTCSessionDescription(offer['sdp'], offer['type']), - ); - var answer = await peerConnection.createAnswer(); - print('Created Answer $answer'); - - await peerConnection.setLocalDescription(answer); - - Map roomWithAnswer = { - 'answer': {'type': answer.type, 'sdp': answer.sdp} - }; - - await roomRef.update(roomWithAnswer); - // Finished creating SDP answer - - // Listening for remote ICE candidates below - // roomRef.collection('callerCandidates').snapshots().listen((snapshot) { - // snapshot.docChanges.forEach((document) { - // var data = document.doc.data() as Map; - // print(data); - // print('Got new remote ICE candidate: $data'); - // peerConnection.addCandidate( - // RTCIceCandidate( - // data['candidate'], - // data['sdpMid'], - // data['sdpMLineIndex'], - // ), - // ); - // }); - // }); - } + Future hangupCall(String caller, String receiver) async{ + await signalR.hangupCall(caller, receiver); + dispose(); } - Future openUserMedia( - RTCVideoRenderer localVideo, - RTCVideoRenderer remoteVideo, - ) async { - var stream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': false}); - - localVideo.srcObject = stream; - localStream = stream; + answerOffer(String sdp) async{ + final offer = jsonDecode(sdp); + final caller = offer['caller']; + final receiver = offer['target']; + final offerSdp = offer['sdp']; + peerConnection.setRemoteDescription(rtcSessionDescriptionFrom(offerSdp)) + .then((value) { + return peerConnection.createAnswer(); + }) + .then((anwser) { + return peerConnection.setLocalDescription(anwser); + }) + .then((value) { + return peerConnection.getLocalDescription(); + }) + .then((answer) { + return signalR.answerOffer(answer, caller, receiver); + }); - remoteVideo.srcObject = await createLocalMediaStream('key'); } Future hangUp(RTCVideoRenderer localVideo) async { - List tracks = localVideo.srcObject.getTracks(); - tracks.forEach((track) { - track.stop(); - }); - if (remoteStream != null) { - remoteStream.getTracks().forEach((track) => track.stop()); - } - if (peerConnection != null) peerConnection.close(); + } - if (roomId != null) { - var db = FirebaseFirestore.instance; - var roomRef = db.collection('rooms').doc(roomId); - var calleeCandidates = await roomRef.collection('calleeCandidates').get(); - calleeCandidates.docs.forEach((document) => document.reference.delete()); + Future createSdpAnswer(String toOfferSdp) async { + final offerSdp = rtcSessionDescriptionFrom(jsonDecode(toOfferSdp)); + peerConnection.setRemoteDescription(offerSdp); - var callerCandidates = await roomRef.collection('callerCandidates').get(); - callerCandidates.docs.forEach((document) => document.reference.delete()); + final answer = await peerConnection.createAnswer(); + var answerSdp = json.encode(answer); // Send SDP via Push or any channel + return answerSdp; + } - await roomRef.delete(); - } + Future createSdpOffer() async { + final offer = await peerConnection.createOffer(); + await peerConnection.setLocalDescription(offer); + final map = offer.toMap(); + var offerSdp = json.encode(map); // Send SDP via Push or any channel + return offerSdp; + } - localStream.dispose(); - remoteStream?.dispose(); + addCandidate(String candidateJson){ + peerConnection.addCandidate(rtcIceCandidateFrom(candidateJson)); } void registerPeerConnectionListeners() { + peerConnection.onIceCandidate = (RTCIceCandidate candidate){ + print(json.encode(candidate.toMap())); + signalR.addIceCandidate(json.encode(candidate.toMap())); + }; + peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { print('ICE gathering state changed: $state'); }; @@ -228,15 +149,17 @@ class Signaling { peerConnection?.onSignalingState = (RTCSignalingState state) { print('Signaling state change: $state'); }; + } +} - peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { - print('ICE connection state change: $state'); - }; - peerConnection?.onAddStream = (MediaStream stream) { - print("Add remote stream"); - onAddRemoteStream?.call(stream); - remoteStream = stream; - }; - } +rtcSessionDescriptionFrom(Map sdp){ + return RTCSessionDescription( + sdp['sdp'],sdp['type'], + ); +} + +rtcIceCandidateFrom(String json){ + final map = jsonDecode(json)['candidate']; + return RTCIceCandidate(map['candidate'], map['sdpMid'], map['sdpMLineIndex']); } diff --git a/lib/pages/webRTC/signaling_bkp.dart b/lib/pages/webRTC/signaling_bkp.dart new file mode 100644 index 00000000..f987e285 --- /dev/null +++ b/lib/pages/webRTC/signaling_bkp.dart @@ -0,0 +1,242 @@ +import 'dart:convert'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter_webrtc/flutter_webrtc.dart'; + +typedef void StreamStateCallback(MediaStream stream); + +class Signaling { + Map configuration = { + 'iceServers': [ + { + 'urls': ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'] + } + ] + }; + + RTCPeerConnection peerConnection; + MediaStream localStream; + MediaStream remoteStream; + String roomId; + String currentRoomText; + StreamStateCallback onAddRemoteStream; + + Future createRoom(RTCVideoRenderer remoteRenderer) async { + FirebaseFirestore db = FirebaseFirestore.instance; + DocumentReference roomRef = db.collection('rooms').doc(); + + print('Create PeerConnection with configuration: $configuration'); + + peerConnection = await createPeerConnection(configuration); + + registerPeerConnectionListeners(); + + localStream.getTracks().forEach((track) { + peerConnection?.addTrack(track, localStream); + }); + + // Code for collecting ICE candidates below + var callerCandidatesCollection = roomRef.collection('callerCandidates'); + + peerConnection?.onIceCandidate = (RTCIceCandidate candidate) { + print('Got candidate: ${candidate.toMap()}'); + callerCandidatesCollection.add(candidate.toMap()); + }; + // Finish Code for collecting ICE candidate + + // Add code for creating a room + RTCSessionDescription offer = await peerConnection.createOffer(); + await peerConnection.setLocalDescription(offer); + print('Created offer: $offer'); + + Map roomWithOffer = {'offer': offer.toMap()}; + + await roomRef.set(roomWithOffer); + var roomId = roomRef.id; + print('New room created with SDK offer. Room ID: $roomId'); + currentRoomText = 'Current room is $roomId - You are the caller!'; + // Created a Room + + peerConnection?.onTrack = (RTCTrackEvent event) { + print('Got remote track: ${event.streams[0]}'); + + event.streams[0].getTracks().forEach((track) { + print('Add a track to the remoteStream $track'); + remoteStream?.addTrack(track); + }); + }; + + // Listening for remote session description below + roomRef.snapshots().listen((snapshot) async { + print('Got updated room: ${snapshot.data()}'); + + Map data = snapshot.data() as Map; + if (peerConnection?.getRemoteDescription() != null && data['answer'] != null) { + var answer = RTCSessionDescription( + data['answer']['sdp'], + data['answer']['type'], + ); + + print("Someone tried to connect"); + await peerConnection?.setRemoteDescription(answer); + } + }); + // Listening for remote session description above + + // Listen for remote Ice candidates below + roomRef.collection('calleeCandidates').snapshots().listen((snapshot) { + snapshot.docChanges.forEach((change) { + if (change.type == DocumentChangeType.added) { + Map data = change.doc.data() as Map; + print('Got new remote ICE candidate: ${jsonEncode(data)}'); + peerConnection.addCandidate( + RTCIceCandidate( + data['candidate'], + data['sdpMid'], + data['sdpMLineIndex'], + ), + ); + } + }); + }); + // Listen for remote ICE candidates above + + return roomId; + } + + Future joinRoom(String roomId, RTCVideoRenderer remoteVideo) async { + FirebaseFirestore db = FirebaseFirestore.instance; + DocumentReference roomRef = db.collection('rooms').doc('$roomId'); + var roomSnapshot = await roomRef.get(); + print('Got room ${roomSnapshot.exists}'); + + if (roomSnapshot.exists) { + print('Create PeerConnection with configuration: $configuration'); + peerConnection = await createPeerConnection(configuration); + + registerPeerConnectionListeners(); + + localStream.getTracks().forEach((track) { + peerConnection?.addTrack(track, localStream); + }); + + // Code for collecting ICE candidates below + var calleeCandidatesCollection = roomRef.collection('calleeCandidates'); + peerConnection.onIceCandidate = (RTCIceCandidate candidate) { + if (candidate == null) { + print('onIceCandidate: complete!'); + return; + } + print('onIceCandidate: ${candidate.toMap()}'); + calleeCandidatesCollection.add(candidate.toMap()); + }; + // Code for collecting ICE candidate above + + peerConnection?.onTrack = (RTCTrackEvent event) { + print('Got remote track: ${event.streams[0]}'); + event.streams[0].getTracks().forEach((track) { + print('Add a track to the remoteStream: $track'); + remoteStream?.addTrack(track); + }); + }; + + // Code for creating SDP answer below + var data = roomSnapshot.data() as Map; + print('Got offer $data'); + var offer = data['offer']; + await peerConnection?.setRemoteDescription( + RTCSessionDescription(offer['sdp'], offer['type']), + ); + var answer = await peerConnection.createAnswer(); + print('Created Answer $answer'); + + await peerConnection.setLocalDescription(answer); + + Map roomWithAnswer = { + 'answer': {'type': answer.type, 'sdp': answer.sdp} + }; + + await roomRef.update(roomWithAnswer); + // Finished creating SDP answer + + // Listening for remote ICE candidates below + // roomRef.collection('callerCandidates').snapshots().listen((snapshot) { + // snapshot.docChanges.forEach((document) { + // var data = document.doc.data() as Map; + // print(data); + // print('Got new remote ICE candidate: $data'); + // peerConnection.addCandidate( + // RTCIceCandidate( + // data['candidate'], + // data['sdpMid'], + // data['sdpMLineIndex'], + // ), + // ); + // }); + // }); + } + } + + Future openUserMedia( + RTCVideoRenderer localVideo, + RTCVideoRenderer remoteVideo, + ) async { + var stream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': false}); + + localVideo.srcObject = stream; + localStream = stream; + + remoteVideo.srcObject = await createLocalMediaStream('key'); + } + + Future hangUp(RTCVideoRenderer localVideo) async { + List tracks = localVideo.srcObject.getTracks(); + tracks.forEach((track) { + track.stop(); + }); + + if (remoteStream != null) { + remoteStream.getTracks().forEach((track) => track.stop()); + } + if (peerConnection != null) peerConnection.close(); + + if (roomId != null) { + var db = FirebaseFirestore.instance; + var roomRef = db.collection('rooms').doc(roomId); + var calleeCandidates = await roomRef.collection('calleeCandidates').get(); + calleeCandidates.docs.forEach((document) => document.reference.delete()); + + var callerCandidates = await roomRef.collection('callerCandidates').get(); + callerCandidates.docs.forEach((document) => document.reference.delete()); + + await roomRef.delete(); + } + + localStream.dispose(); + remoteStream?.dispose(); + } + + void registerPeerConnectionListeners() { + peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { + print('ICE gathering state changed: $state'); + }; + + peerConnection?.onConnectionState = (RTCPeerConnectionState state) { + print('Connection state change: $state'); + }; + + peerConnection?.onSignalingState = (RTCSignalingState state) { + print('Signaling state change: $state'); + }; + + peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { + print('ICE connection state change: $state'); + }; + + peerConnection?.onAddStream = (MediaStream stream) { + print("Add remote stream"); + onAddRemoteStream?.call(stream); + remoteStream = stream; + }; + } +} diff --git a/lib/routes.dart b/lib/routes.dart index 72599bb2..9525bc96 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -21,6 +21,8 @@ import 'package:diplomaticquarterapp/pages/symptom-checker/info.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/select-gender.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/symtom-checker.dart'; import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/call_page.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/call_page_bkp.dart'; import 'package:diplomaticquarterapp/splashPage.dart'; const String INIT_ROUTE = '/'; @@ -48,6 +50,7 @@ const String PACKAGES_ORDER_COMPLETED = 'packages-offers-cart'; const String TEST_PAGE = 'test-page'; const String OPENTOK_CALL_PAGE = 'OPENTOK_CALL_PAGE'; const String CART_ORDER_PAGE = 'cart-order-page'; +const String CALL_PAGE = 'CALL_PAGE'; const String HEALTH_WEATHER = 'health-weather'; const APP_UPDATE = 'app-update'; @@ -76,6 +79,7 @@ var routes = { APP_UPDATE: (_) => AppUpdatePage(), SETTINGS: (_) => Settings(), CART_ORDER_PAGE: (_) => CartOrderPage(), + CALL_PAGE: (_) => CallPage(), OPENTOK_CALL_PAGE: (_) => OpenTokConnectCallPage( apiKey: '46209962', sessionId: '1_MX40NjIwOTk2Mn5-MTYzNDY0ODM3NDY2Nn5PcnpnNGM0R1Q3ODZ6UXlFQ01lMDF5YWJ-fg', diff --git a/lib/uitl/SignalRUtil.dart b/lib/uitl/SignalRUtil.dart index a1a411e0..d46a2ea8 100644 --- a/lib/uitl/SignalRUtil.dart +++ b/lib/uitl/SignalRUtil.dart @@ -1,36 +1,57 @@ +import 'dart:convert'; import 'dart:io'; import 'package:flutter/cupertino.dart'; +import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:http/io_client.dart'; import 'package:signalr_core/signalr_core.dart'; class SignalRUtil { String hubName; - BuildContext context; - SignalRUtil({@required this.hubName, @required this.context}); + String sourceUser; + String destinationUser; + setContributors({@required String caller, @required String receiver}){ + this.sourceUser = caller; + this.destinationUser = receiver; + } + + Function(bool) onConnected; + SignalRUtil({@required this.hubName}); + - HubConnection connectionBuilder; + HubConnection connectionHub; - void startSignalRConnection() async { - connectionBuilder = HubConnectionBuilder() + closeConnection() async{ + if(connectionHub != null) { + connectionHub.off('OnIncomingCallAsync'); + connectionHub.off('OnCallDeclinedAsync'); + connectionHub.off('OnCallAcceptedAsync'); + connectionHub.off('nHangUpAsync'); + connectionHub.off('OnIceCandidateAsync'); + connectionHub.off('OnOfferAsync'); + await connectionHub.stop(); + } + } + + Future openConnection() async { + connectionHub = HubConnectionBuilder() .withUrl( - hubName, - HttpConnectionOptions( - client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true), - logging: (level, message) => print(message), - )) - .build(); + hubName, + HttpConnectionOptions( + logMessageContent: true, + client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true), + logging: (level, message) => print(message), + )).build(); - await connectionBuilder.start(); + await connectionHub.start(); + await Future.delayed(Duration(seconds: 1)); - connectionBuilder.on('ReceiveMessage', (message) { + connectionHub.on('ReceiveMessage', (message) { handleIncomingMessage(message); }); - } - void closeSignalRConnection() { - connectionBuilder.stop(); + return getConnectionState(); } void handleIncomingMessage(List message) { @@ -38,11 +59,114 @@ class SignalRUtil { } void sendMessage(List args) async { - await connectionBuilder.invoke('SendMessage', args: args); //['Bob', 'Says hi!'] + await connectionHub.invoke('SendMessage', args: args); //['Bob', 'Says hi!'] + } + + listen({Function(CallUser) onAcceptCall, Function(CallUser) onHangupCall, Function(String, CallUser) onDeclineCall, Function(String, CallUser) onOffer, Function(String) onCandidate}){ + + connectionHub.on('OnIncomingCallAsync', (arguments) { + print('OnIncomingCallAsync: ${arguments.toString()}'); + }); + + connectionHub.on('OnCallDeclinedAsync', (arguments) { + print('OnCallDeclinedAsync: ${arguments.toString()}'); + onDeclineCall(arguments.first, CallUser.from(arguments.last)); + }); + + connectionHub.on('OnCallAcceptedAsync', (arguments) { + print('OnCallAcceptedAsync: ${arguments.toString()}'); + }); + + connectionHub.on('OnHangUpAsync', (arguments) { + print('nHangUpAsync: ${arguments.toString()}'); + onHangupCall(CallUser.from(arguments.first)); + }); + + connectionHub.on('OnIceCandidateAsync', (arguments) { + print('OnIceCandidateAsync: ${arguments.toString()}'); + onCandidate(arguments.first); + }); + + connectionHub.on('OnOfferAsync', (arguments) { + print('OnOfferAsync: ${arguments.toString()}'); + onOffer(arguments.first, CallUser.from(arguments.last)); + }); + } + // CallUserAsync(string currentUserId, string targerUserId) + Future callUser(String from, to) async{ + return await connectionHub.invoke('CallUserAsync', args: [from, to]); + } + + // CallDeclinedAsync(string currentUserId, string targerUserId) + Future declineCall(String from, to) async{ + return await connectionHub.invoke('CallDeclinedAsync', args: [from, to]); + } + + // AnswerCallAsync(string currentUserId, string targetUserId) + Future answerCall(String from, to) async{ + return await connectionHub.invoke('AnswerCallAsync', args: [from, to]); + } + + // IceCandidateAsync(string targetUserId, string candidate) + Future addIceCandidate(String candidate) async{ + final target = destinationUser; + return await connectionHub.invoke('IceCandidateAsync', args: [target, candidate]); + } + + // OfferAsync(string targetUserId,string currentUserId, string targetOffer) + Future offer(String from, to, offer) async{ + return await connectionHub.invoke('OfferAsync', args: [from, to, offer]); + } + + // AnswerOfferAsync(string targetUserId, string CallerOffer) + Future answerOffer(RTCSessionDescription answerSdp, caller, receiver) async{ + final payload = { + 'target': receiver, + 'caller': caller, + 'sdp': answerSdp.toMap(), + }; + return await connectionHub.invoke('AnswerOfferAsync', args: [caller, jsonEncode(payload)]); + } + + // HangUpAsync(string currentUserId, string targetUserId) + Future hangupCall(String from, to) async{ + return await connectionHub.invoke('HangUpAsync', args: [from, to]); + } + + // CallAccepted(string currentUserId,string targetUserId) + Future acceptCall(String from, to) async{ + return await connectionHub.invoke('CallAccepted', args: [from, to]); + } + + bool getConnectionState() { - if (connectionBuilder.state == HubConnectionState.connected || connectionBuilder.state == HubConnectionState.connecting) return true; - if (connectionBuilder.state == HubConnectionState.disconnected || connectionBuilder.state == HubConnectionState.disconnecting) return false; + if (connectionHub.state == HubConnectionState.connected) return true; + if (connectionHub.state == HubConnectionState.disconnected) return false; + return false; } } + + +class CallUser{ + String Id; + String UserName; + String Email; + String Phone; + String Title; + dynamic UserStatus; + String Image; + int UnreadMessageCount = 0; + + CallUser.from(Map map){ + Id = map['Id']; + UserName = map['UserName']; + Email = map['Email']; + Phone = map['Phone']; + Title = map['Title']; + UserStatus = map['UserStatus']; + Image = map['Image']; + UnreadMessageCount = map['UnreadMessageCount']; + } +} \ No newline at end of file diff --git a/lib/uitl/date_uitl.dart b/lib/uitl/date_uitl.dart index a11b85e6..177b5127 100644 --- a/lib/uitl/date_uitl.dart +++ b/lib/uitl/date_uitl.dart @@ -131,6 +131,10 @@ class DateUtil { dateObj.year.toString(); } + static String getISODateFormat(DateTime dateTime){ // 2020-04-30T00:00:00.000 + return dateTime.toIso8601String(); + } + /// get month by /// [month] convert month number in to month name static getMonth(int month) { diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index 8b3819f1..b7e00d54 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -15,6 +15,7 @@ import 'package:diplomaticquarterapp/pages/DrawerPages/notifications/notificatio import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/pages/rateAppointment/rate_appointment_doctor.dart'; import 'package:diplomaticquarterapp/pages/webRTC/call_page.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/call_page_bkp.dart'; import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart'; From 12b20831df7230f34d31a63761d36b559ad1fa92 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Mon, 22 Nov 2021 09:54:06 +0300 Subject: [PATCH 02/11] fix app bar --- lib/pages/final_products_page.dart | 2 ++ lib/pages/parent_categorise_page.dart | 2 ++ lib/pages/pharmacies/compare.dart | 3 +++ lib/pages/pharmacies/my_reviews.dart | 3 +++ .../shared/product_details_app_bar.dart | 2 +- lib/pages/pharmacies/widgets/ProductOrderItem.dart | 4 +++- lib/pages/pharmacies/wishlist.dart | 3 +++ lib/pages/pharmacy/order/Order.dart | 3 +++ lib/pages/pharmacy/profile/profile.dart | 6 +++--- lib/pages/sub_categories_modalsheet.dart | 10 ++++++++-- lib/pages/sub_categorise_page.dart | 8 ++++++-- 11 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/pages/final_products_page.dart b/lib/pages/final_products_page.dart index 91e953ad..758ceb78 100644 --- a/lib/pages/final_products_page.dart +++ b/lib/pages/final_products_page.dart @@ -93,6 +93,8 @@ class _FinalProductsPageState extends State { isShowAppBar: true, backgroundColor: Colors.white, isShowDecPage: false, + showPharmacyCart: false, + showHomeAppBarIcon: false, baseViewModel: model, body: Container( height: MediaQuery.of(context).size.height * 5.87, diff --git a/lib/pages/parent_categorise_page.dart b/lib/pages/parent_categorise_page.dart index 5a917897..c1b1b2b7 100644 --- a/lib/pages/parent_categorise_page.dart +++ b/lib/pages/parent_categorise_page.dart @@ -93,6 +93,8 @@ class _ParentCategorisePageState extends State { isShowAppBar: true, backgroundColor: Colors.white, isShowDecPage: false, + showPharmacyCart: false, + showHomeAppBarIcon: false, baseViewModel: model, body: SmartRefresher( enablePullDown: false, diff --git a/lib/pages/pharmacies/compare.dart b/lib/pages/pharmacies/compare.dart index 82a11610..f458304f 100644 --- a/lib/pages/pharmacies/compare.dart +++ b/lib/pages/pharmacies/compare.dart @@ -33,6 +33,9 @@ class _ComparePageState extends State { appBarTitle: TranslationBase.of(context).compare, isShowAppBar: true, isPharmacy: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isBottomBar: true, body: SingleChildScrollView( child: Container( child: compareList(), diff --git a/lib/pages/pharmacies/my_reviews.dart b/lib/pages/pharmacies/my_reviews.dart index 08ba3d14..39304cac 100644 --- a/lib/pages/pharmacies/my_reviews.dart +++ b/lib/pages/pharmacies/my_reviews.dart @@ -26,6 +26,9 @@ class _MyReviewsPageState extends State { appBarTitle: TranslationBase.of(context).reviews, isShowAppBar: true, isPharmacy: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isBottomBar: true, baseViewModel: model, body: model.reviewListList.length == 0 ? Container( diff --git a/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart index f58438cf..e42018fc 100644 --- a/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart +++ b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart @@ -157,7 +157,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { quantity: quantity, itemID: itemID, model: model, - context: context); + ); Navigator.of(context).pop(); } diff --git a/lib/pages/pharmacies/widgets/ProductOrderItem.dart b/lib/pages/pharmacies/widgets/ProductOrderItem.dart index fa0ead15..34566d8a 100644 --- a/lib/pages/pharmacies/widgets/ProductOrderItem.dart +++ b/lib/pages/pharmacies/widgets/ProductOrderItem.dart @@ -248,7 +248,9 @@ class _ProductOrderItemState extends State { } else { newValue = widget.item.quantity - 1; } - } else { + widget.item.quantity = newValue; + } else + { _quantityController.text = "${widget.item.quantity}"; _totalPrice = "${(widget.item.product.price * widget.item.quantity).toStringAsFixed(2)}"; diff --git a/lib/pages/pharmacies/wishlist.dart b/lib/pages/pharmacies/wishlist.dart index 3d1c8114..a70f2cab 100644 --- a/lib/pages/pharmacies/wishlist.dart +++ b/lib/pages/pharmacies/wishlist.dart @@ -17,6 +17,9 @@ class WishlistPage extends StatelessWidget { isShowAppBar: true, isShowDecPage: false, isPharmacy: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isBottomBar: true, baseViewModel: model, body: model.wishListList.length == 0 ? Container( diff --git a/lib/pages/pharmacy/order/Order.dart b/lib/pages/pharmacy/order/Order.dart index 9eda1004..ef5c9346 100644 --- a/lib/pages/pharmacy/order/Order.dart +++ b/lib/pages/pharmacy/order/Order.dart @@ -66,6 +66,9 @@ class _OrderPageState extends State with SingleTickerProviderStateMix baseViewModel: model, isShowAppBar: true, isPharmacy: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isBottomBar: true, body: Container( child: Column( children: [ diff --git a/lib/pages/pharmacy/profile/profile.dart b/lib/pages/pharmacy/profile/profile.dart index 1f2520b6..72fa43dc 100644 --- a/lib/pages/pharmacy/profile/profile.dart +++ b/lib/pages/pharmacy/profile/profile.dart @@ -108,10 +108,10 @@ class _ProfilePageState extends State { builder: (_, model, wi) => AppScaffold( appBarTitle: TranslationBase.of(context).myAccount, isShowAppBar: true, - isShowDecPage: true, + isShowDecPage: false, isPharmacy: true, - - //isBottomBar: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, isMainPharmacyPages: true, body: user != null ? Container( diff --git a/lib/pages/sub_categories_modalsheet.dart b/lib/pages/sub_categories_modalsheet.dart index d6499c8e..ed2403db 100644 --- a/lib/pages/sub_categories_modalsheet.dart +++ b/lib/pages/sub_categories_modalsheet.dart @@ -40,11 +40,13 @@ class _SubCategoriseModalsheetState extends State { builder: (_, model, wi) => AppScaffold( // appBarTitle: titleName, appBarTitle: TranslationBase.of(context).categorise, - isBottomBar: false, + isBottomBar: true, isShowAppBar: true, isPharmacy: true, backgroundColor: Colors.white, isShowDecPage: false, + showPharmacyCart: false, + showHomeAppBarIcon: false, baseViewModel: model, body: Container( color: Colors.white, @@ -77,7 +79,11 @@ class _SubCategoriseModalsheetState extends State { context, FadePage( page: SubCategorisePage( - title: model.categoriseParent[index].name, + title: projectViewModel + .isArabic + ? model.categoriseParent[index].namen + : model.categoriseParent[index].name, + // title: model.categoriseParent[index].name, id: model.categoriseParent[index].id, parentId: id, )), diff --git a/lib/pages/sub_categorise_page.dart b/lib/pages/sub_categorise_page.dart index 4bc069dc..a0b54f9f 100644 --- a/lib/pages/sub_categorise_page.dart +++ b/lib/pages/sub_categorise_page.dart @@ -14,6 +14,7 @@ import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_pharmacy_widget.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/others/entity_checkbox_list.dart'; import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; @@ -76,12 +77,15 @@ class _SubCategorisePageState extends State { allowAny: true, builder: (BuildContext context, PharmacyCategoriseViewModel model, Widget child) => - PharmacyAppScaffold( + AppScaffold( + isPharmacy: true, appBarTitle: title, - isBottomBar: false, + isBottomBar: true, isShowAppBar: true, backgroundColor: Colors.white, isShowDecPage: false, + showPharmacyCart: false, + showHomeAppBarIcon: false, baseViewModel: model, body: SmartRefresher( controller: controller, From 7bbabd798ab0101b7440bffcd141bed00568c059 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Mon, 22 Nov 2021 10:32:22 +0300 Subject: [PATCH 03/11] fix issue --- lib/pages/pharmacy/order/OrderDetails.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pages/pharmacy/order/OrderDetails.dart b/lib/pages/pharmacy/order/OrderDetails.dart index fc4ae184..6b7c957e 100644 --- a/lib/pages/pharmacy/order/OrderDetails.dart +++ b/lib/pages/pharmacy/order/OrderDetails.dart @@ -84,6 +84,9 @@ class _OrderDetailsPageState extends State { appBarTitle: TranslationBase.of(context).orderDetail, isShowAppBar: true, isPharmacy: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isBottomBar: true, baseViewModel: model, body: model.orderListModel.length > 0 ? Container( From 21c315c1a30b5ed16ea5895002d593de11262f51 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Mon, 22 Nov 2021 11:27:21 +0300 Subject: [PATCH 04/11] fix wishlist issue --- lib/pages/final_products_page.dart | 2 +- lib/pages/parent_categorise_page.dart | 3 +-- lib/pages/pharmacies/ProductCheckTypeWidget.dart | 1 + .../product-details/shared/product_details_app_bar.dart | 2 +- lib/pages/pharmacies/wishlist.dart | 4 ++-- lib/pages/sub_categorise_page.dart | 3 +-- lib/widgets/pharmacy/product_tile.dart | 9 ++++++++- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/pages/final_products_page.dart b/lib/pages/final_products_page.dart index 758ceb78..253d7c08 100644 --- a/lib/pages/final_products_page.dart +++ b/lib/pages/final_products_page.dart @@ -487,7 +487,7 @@ class _FinalProductsPageState extends State { color: CustomColors.green, ), onPressed: () async { - if (model.finalProducts[index].rxMessage == null) { + if (model.finalProducts[index].isRx == false) { GifLoaderDialogUtils.showMyDialog(context); await addToCartFunction(1, model.finalProducts[index].id); GifLoaderDialogUtils.hideDialog(context); diff --git a/lib/pages/parent_categorise_page.dart b/lib/pages/parent_categorise_page.dart index c1b1b2b7..c025eb3c 100644 --- a/lib/pages/parent_categorise_page.dart +++ b/lib/pages/parent_categorise_page.dart @@ -1273,8 +1273,7 @@ class _ParentCategorisePageState extends State { ), onPressed: () async { - if (model.parentProducts[index].rxMessage == - null) { + if (model.parentProducts[index].isRx == false) { GifLoaderDialogUtils.showMyDialog(context); await addToCartFunction(1, model.parentProducts[index].id); diff --git a/lib/pages/pharmacies/ProductCheckTypeWidget.dart b/lib/pages/pharmacies/ProductCheckTypeWidget.dart index d0a112c6..8ac83fd2 100644 --- a/lib/pages/pharmacies/ProductCheckTypeWidget.dart +++ b/lib/pages/pharmacies/ProductCheckTypeWidget.dart @@ -37,6 +37,7 @@ class _ProductCheckTypeWidgetState extends State { productImage: widget.model.wishListList[index].product.images[0].src, productID: widget.model.wishListList[index].product.id, onDelete: deleteWishListItem, + isRx:widget.model.wishListList[index].product.isRx, ), ), diff --git a/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart index ad638be1..18749662 100644 --- a/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart +++ b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart @@ -149,7 +149,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { return Container( child: new Wrap( children: [ - if (product.stockAvailability != 'Out of stock') + if (product.stockAvailability != 'Out of stock' && product.isRx != true) new ListTile( leading: Icon(Icons.shopping_cart), title: Text( diff --git a/lib/pages/pharmacies/wishlist.dart b/lib/pages/pharmacies/wishlist.dart index a70f2cab..00088b59 100644 --- a/lib/pages/pharmacies/wishlist.dart +++ b/lib/pages/pharmacies/wishlist.dart @@ -38,8 +38,8 @@ class WishlistPage extends StatelessWidget { ), Padding( padding: const EdgeInsets.all(8.0), - child: Text( - 'There is no data', + child: Text(TranslationBase.of(context).noData, + // 'There is no data', style: TextStyle(fontSize: 30), ), ) diff --git a/lib/pages/sub_categorise_page.dart b/lib/pages/sub_categorise_page.dart index a0b54f9f..60b85361 100644 --- a/lib/pages/sub_categorise_page.dart +++ b/lib/pages/sub_categorise_page.dart @@ -1219,8 +1219,7 @@ class _SubCategorisePageState extends State { if (model .subProducts[ index] - .rxMessage == - null) { + .isRx == false) { GifLoaderDialogUtils .showMyDialog( context); diff --git a/lib/widgets/pharmacy/product_tile.dart b/lib/widgets/pharmacy/product_tile.dart index b7293ce1..73565ee7 100644 --- a/lib/widgets/pharmacy/product_tile.dart +++ b/lib/widgets/pharmacy/product_tile.dart @@ -2,6 +2,7 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart' import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_detail_view_model.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/cart-page/cart-order-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacy/order/ProductReview.dart'; +import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; @@ -27,6 +28,7 @@ class productTile extends StatelessWidget { final dynamic productID; final Function onDelete; final dynamic approvedTotalReviews; + final dynamic isRx; // final VoidCallback deleteWishlistItems; @@ -47,6 +49,7 @@ class productTile extends StatelessWidget { this.productID, this.onDelete, this.approvedTotalReviews, + this.isRx }); @override @@ -163,10 +166,14 @@ class productTile extends StatelessWidget { color: Colors.green, ), onPressed: () async { + if(isRx == false){ GifLoaderDialogUtils.showMyDialog(context); await addToCartFunction(1, productID, context); GifLoaderDialogUtils.hideDialog(context); - Utils.navigateToCartPage(); + Utils.navigateToCartPage();} + else { + AppToast.showErrorToast(message: TranslationBase.of(context).needPrescription); + } }, ), ], From 127096ec04e5decf1ef58fd904fb9e16451405bd Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Mon, 22 Nov 2021 12:00:27 +0300 Subject: [PATCH 05/11] fixed wishlist design --- lib/widgets/pharmacy/product_tile.dart | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/widgets/pharmacy/product_tile.dart b/lib/widgets/pharmacy/product_tile.dart index 73565ee7..23a6dd9b 100644 --- a/lib/widgets/pharmacy/product_tile.dart +++ b/lib/widgets/pharmacy/product_tile.dart @@ -1,5 +1,6 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_detail_view_model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/cart-page/cart-order-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacy/order/ProductReview.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; @@ -9,6 +10,7 @@ import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:provider/provider.dart'; import 'package:rating_bar/rating_bar.dart'; class productTile extends StatelessWidget { @@ -54,6 +56,7 @@ class productTile extends StatelessWidget { @override Widget build(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); return Container( height: 180, width: double.infinity, @@ -90,7 +93,16 @@ class productTile extends StatelessWidget { children: [ Container( margin: EdgeInsets.all(5), - child: Align( + child: projectViewModel + .isArabic ? Align( + alignment: Alignment.topRight, + child: RichText( + text: TextSpan( + text: productName, + style: TextStyle(color: Colors.black54, fontSize: 15, fontWeight: FontWeight.bold), + ), + ), + ): Align( alignment: Alignment.topLeft, child: RichText( text: TextSpan( @@ -102,7 +114,17 @@ class productTile extends StatelessWidget { ), Container( margin: EdgeInsets.all(5), - child: Align( + child: projectViewModel + .isArabic ? Align( + alignment: Alignment.topRight, + child: RichText( + text: TextSpan( + text: 'SAR $productPrice', + style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 13), + ), + ), + ) + :Align( alignment: Alignment.topLeft, child: RichText( text: TextSpan( From 4518a26ff12e2466ae991b01b58a798a7a3d8f0f Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 22 Nov 2021 15:50:30 +0300 Subject: [PATCH 06/11] video call improvement. --- ...CustomFlutterFirebaseMessagingService.java | 19 +++ android/app/src/main/AndroidManifest.xml | 5 +- .../diplomaticquarterapp/MainActivity.kt | 5 + .../utils/PlatformBridge.kt | 118 +++++++++++++----- lib/pages/BookAppointment/BookConfirm.dart | 40 ++++++ lib/pages/conference/conference_page.dart | 2 + lib/pages/landing/landing_page.dart | 14 ++- lib/pages/livecare/incoming_call.dart | 2 + lib/uitl/PlatformBridge.dart | 19 ++- 9 files changed, 188 insertions(+), 36 deletions(-) diff --git a/android/CustomFlutterFirebaseMessagingService.java b/android/CustomFlutterFirebaseMessagingService.java index 0a4d83be..113f256f 100644 --- a/android/CustomFlutterFirebaseMessagingService.java +++ b/android/CustomFlutterFirebaseMessagingService.java @@ -2,14 +2,33 @@ package io.flutter.plugins.firebasemessaging; import android.content.Intent; +import java.util.concurrent.TimeUnit; + import com.google.firebase.messaging.RemoteMessage; +//public class CustomFlutterFirebaseMessagingService extends FlutterFirebaseMessagingService { +// @Override +// public void onMessageReceived(RemoteMessage remoteMessage) { +// if (remoteMessage.getData().containsKey("is_call")) { +// Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); +// startActivity(intent); +// super.onMessageReceived(remoteMessage); +// } else +// super.onMessageReceived(remoteMessage); +// } +//} + public class CustomFlutterFirebaseMessagingService extends FlutterFirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { if (remoteMessage.getData().containsKey("is_call")) { Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent); + try { + TimeUnit.SECONDS.sleep(5); + } catch (Exception e) { + } super.onMessageReceived(remoteMessage); } else super.onMessageReceived(remoteMessage); diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 61472941..4d2c9f8a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ + @@ -29,7 +30,7 @@ - + @@ -41,6 +42,8 @@ android:name=".Application" android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true" + android:showOnLockScreen="true" + android:screenOrientation="sensorPortrait" android:label="Dr. Alhabib"> if (methodCall.method == HMG_INTERNET_WIFI_CONNECT_METHOD) { - connectHMGInternetWifi(methodCall,result) - - }else if (methodCall.method == HMG_GUEST_WIFI_CONNECT_METHOD) { - connectHMGGuestWifi(methodCall,result) - - }else if (methodCall.method == ENABLE_WIFI_IF_NOT) { - enableWifiIfNot(methodCall,result) - }else if (methodCall.method == REGISTER_HMG_GEOFENCES) { - registerHmgGeofences(methodCall,result) - }else if (methodCall.method == UN_REGISTER_HMG_GEOFENCES) { - unRegisterHmgGeofences(methodCall,result) - }else{ - + connectHMGInternetWifi(methodCall, result) + + } else if (methodCall.method == HMG_GUEST_WIFI_CONNECT_METHOD) { + connectHMGGuestWifi(methodCall, result) + + } else if (methodCall.method == ENABLE_WIFI_IF_NOT) { + enableWifiIfNot(methodCall, result) + } else if (methodCall.method == REGISTER_HMG_GEOFENCES) { + registerHmgGeofences(methodCall, result) + } else if (methodCall.method == UN_REGISTER_HMG_GEOFENCES) { + unRegisterHmgGeofences(methodCall, result) + } else if (methodCall.method == IS_DRAW_OVER_APPS_PERMISSION_ALLOWED) { + isDrawOverAppsPermissionAllowed(methodCall, result) + } else if (methodCall.method == ASK_DRAW_OVER_APPS_PERMISSION) { + askDrawOverAppsPermission(methodCall, result) + } else if (methodCall.method == GET_INTENT) { + getIntentData(methodCall, result) + } else { result.notImplemented() } } - val res = channel.invokeMethod("localizedValue","errorConnectingHmgNetwork") + val res = channel.invokeMethod("localizedValue", "errorConnectingHmgNetwork") } - private fun connectHMGInternetWifi(methodCall: MethodCall, result: MethodChannel.Result){ + private fun connectHMGInternetWifi(methodCall: MethodCall, result: MethodChannel.Result) { (methodCall.arguments as ArrayList<*>).let { - require(it.size > 0 && (it[0] is String),lazyMessage = { + require(it.size > 0 && (it[0] is String), lazyMessage = { "Missing or invalid arguments (Must have one argument 'String at 0'" }) val patientId = it[0].toString() HMG_Internet(mainActivity) - .connectToHMGGuestNetwork(patientId){ status, message -> + .connectToHMGGuestNetwork(patientId) { status, message -> mainActivity.runOnUiThread { - result.success(if(status) 1 else 0) + result.success(if (status) 1 else 0) HMGUtils.popFlutterText(mainActivity, message) Log.v(this.javaClass.simpleName, "$status | $message") @@ -76,10 +92,10 @@ class PlatformBridge(private var flutterEngine: FlutterEngine, private var mainA } - private fun connectHMGGuestWifi(methodCall: MethodCall, result: MethodChannel.Result){ + private fun connectHMGGuestWifi(methodCall: MethodCall, result: MethodChannel.Result) { HMG_Guest(mainActivity).connectToHMGGuestNetwork { status, message -> mainActivity.runOnUiThread { - result.success(if(status) 1 else 0) + result.success(if (status) 1 else 0) HMGUtils.popFlutterText(mainActivity, message) Log.v(this.javaClass.simpleName, "$status | $message") @@ -89,38 +105,76 @@ class PlatformBridge(private var flutterEngine: FlutterEngine, private var mainA private fun enableWifiIfNot(methodCall: MethodCall, result: MethodChannel.Result) { val wm = mainActivity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager? - if (wm != null){ + if (wm != null) { if (!wm.isWifiEnabled) wm.isWifiEnabled = true result.success(true) - }else - result.error("101","Error while opening wifi, Please try to open wifi yourself and try again","'WifiManager' service failed"); + } else + result.error("101", "Error while opening wifi, Please try to open wifi yourself and try again", "'WifiManager' service failed"); } private fun registerHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) { - channel.invokeMethod("getGeoZones",null, object : MethodChannel.Result{ + channel.invokeMethod("getGeoZones", null, object : MethodChannel.Result { override fun success(result: Any?) { - if(result is String) { + if (result is String) { val geoZones = GeoZoneModel().listFrom(result) - HMG_Geofence.shared(mainActivity).register(){ s, e -> } + HMG_Geofence.shared(mainActivity).register() { s, e -> } } } - override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) { } - override fun notImplemented() { } + override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {} + override fun notImplemented() {} }) } - + private fun unRegisterHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) { HMG_Geofence.shared(mainActivity).unRegisterAll { status, exception -> - if(status) + if (status) result.success(true) else result.error("101", exception?.localizedMessage, exception); } } - + + private fun isDrawOverAppsPermissionAllowed(methodCall: MethodCall, result: MethodChannel.Result) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if ( + Settings.canDrawOverlays(mainActivity) + ) { + result.success(true) + } else { + result.success(false) + } + } else { + result.success(false) + } + } + + private fun askDrawOverAppsPermission(methodCall: MethodCall, result: MethodChannel.Result) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) + val uri = Uri.parse("package:" + mainActivity.getPackageName()) + intent.setData(uri) + startActivityForResult(mainActivity, intent, 102, null) + result.success(true) + } else { + result.success(false) + } + } + + private fun getIntentData(methodCall: MethodCall, result: MethodChannel.Result) { + + val bundle: Bundle? = getIntent("").extras + if (bundle != null) { + val message = bundle.getString("notification") // 1 + System.out.println("BundleExtra:" + message) + Toast.makeText(this.mainActivity, message + "", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(this.mainActivity, "Bundle Null", Toast.LENGTH_SHORT).show(); + } + result.success(true); + } } diff --git a/lib/pages/BookAppointment/BookConfirm.dart b/lib/pages/BookAppointment/BookConfirm.dart index bdf387d6..7377bcc2 100644 --- a/lib/pages/BookAppointment/BookConfirm.dart +++ b/lib/pages/BookAppointment/BookConfirm.dart @@ -9,6 +9,7 @@ import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/PlatformBridge.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; @@ -21,6 +22,7 @@ import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'book_reminder_page.dart'; @@ -240,6 +242,44 @@ class _BookConfirmState extends State { ); } + Future askVideoCallPermission() async { + if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) { + return false; + } + if (!(await PlatformBridge.shared().isDrawOverAppsPermissionAllowed())) { + await drawOverAppsMessageDialog(context); + return false; + } + return true; + } + + Future drawOverAppsMessageDialog(BuildContext context) async { + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: Text("Please select 'Diplomatic Quarter' from the list and allow draw over app permission to use live care."), + contentPadding: EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0.0), + actions: [ + FlatButton( + child: Text("Cancel"), + onPressed: () { + Navigator.pop(context); + }, + ), + FlatButton( + child: Text("Go to Settings"), + onPressed: () async { + await PlatformBridge.shared().askDrawOverAppsPermission(); + Navigator.pop(context); + }, + ) + ], + ); + }, + ); + } + cancelAppointment(DoctorList docObject, AppoitmentAllHistoryResultList appo, BuildContext context) { ConfirmDialog.closeAlertDialog(context); GifLoaderDialogUtils.showMyDialog(context); diff --git a/lib/pages/conference/conference_page.dart b/lib/pages/conference/conference_page.dart index dc00bf6e..c30e7cdf 100644 --- a/lib/pages/conference/conference_page.dart +++ b/lib/pages/conference/conference_page.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:diplomaticquarterapp/models/LiveCare/room_model.dart'; import 'package:diplomaticquarterapp/pages/conference/conference_button_bar.dart'; import 'package:diplomaticquarterapp/pages/conference/conference_room.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/pages/conference/draggable_publisher.dart'; import 'package:diplomaticquarterapp/pages/conference/participant_widget.dart'; import 'package:diplomaticquarterapp/pages/conference/widgets/noise_box.dart'; @@ -152,6 +153,7 @@ class _ConferencePageState extends State { Future _onHangup() async { print('onHangup'); await _conferenceRoom.disconnect(); + LandingPage.isOpenCallPage = false; Navigator.of(context).pop(); } diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 2bca7a9e..db41840d 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -204,10 +204,15 @@ class _LandingPageState extends State with WidgetsBindingObserver { AppGlobal.context = context; if (state == AppLifecycleState.resumed) { if (LandingPage.isOpenCallPage) { + if (Platform.isAndroid) { + return; + } if (!isPageNavigated) { isPageNavigated = true; Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { - isPageNavigated = false; + Future.delayed(Duration(seconds: 5), () { + isPageNavigated = false; + }); }); } } @@ -329,12 +334,17 @@ class _LandingPageState extends State with WidgetsBindingObserver { Map myMap = new Map.from(message['data']); print(myMap); + if (LandingPage.isOpenCallPage) { + return; + } LandingPage.isOpenCallPage = true; LandingPage.incomingCallData = IncomingCallData.fromJson(myMap); if (!isPageNavigated) { isPageNavigated = true; Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { - isPageNavigated = false; + Future.delayed(Duration(seconds: 5), () { + isPageNavigated = false; + }); }); } } else { diff --git a/lib/pages/livecare/incoming_call.dart b/lib/pages/livecare/incoming_call.dart index a463fc00..7e586942 100644 --- a/lib/pages/livecare/incoming_call.dart +++ b/lib/pages/livecare/incoming_call.dart @@ -3,6 +3,7 @@ import 'package:diplomaticquarterapp/models/LiveCare/room_model.dart'; import 'package:diplomaticquarterapp/pages/conference/conference_page.dart'; import 'package:diplomaticquarterapp/pages/conference/web_rtc/call_home_page.dart'; import 'package:diplomaticquarterapp/pages/conference/widgets/platform_exception_alert_dialog.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; import 'package:just_audio/just_audio.dart'; @@ -135,6 +136,7 @@ class _IncomingCallState extends State with SingleTickerProviderSt Container( child: RawMaterialButton( onPressed: () { + LandingPage.isOpenCallPage = false; backToHome(); }, elevation: 2.0, diff --git a/lib/uitl/PlatformBridge.dart b/lib/uitl/PlatformBridge.dart index 56020781..45970e5e 100644 --- a/lib/uitl/PlatformBridge.dart +++ b/lib/uitl/PlatformBridge.dart @@ -1,4 +1,3 @@ - import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/localized_values.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; @@ -89,6 +88,9 @@ class PlatformBridge { static const show_loading_method = "loading"; static const register_Hmg_Geofences = "registerHmgGeofences"; static const un_register_Hmg_Geofences = "unRegisterHmgGeofences"; + static const IS_DRAW_OVER_APPS_PERMISSION_ALLOWED = "isDrawOverAppsPermissionAllowed"; + static const ASK_DRAW_OVER_APPS_PERMISSION = "askDrawOverAppsPermission"; + static const GET_INTENT = "getIntent"; Future connectHMGInternetWifi(String patientId) { try { @@ -142,4 +144,19 @@ class PlatformBridge { void unRegisterHmgGeofences() async { var result = await platform.invokeMethod(un_register_Hmg_Geofences); } + + Future isDrawOverAppsPermissionAllowed() async { + var result = await platform.invokeMethod(IS_DRAW_OVER_APPS_PERMISSION_ALLOWED); + return result as bool; + } + + Future askDrawOverAppsPermission() async { + var result = await platform.invokeMethod(ASK_DRAW_OVER_APPS_PERMISSION); + return result as bool; + } + + Future getIntentData() async { + var result = await platform.invokeMethod(GET_INTENT); + return result as bool; + } } From 8b1733e91734346fa2f4ac969b914f1f9db953fb Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 23 Nov 2021 09:48:56 +0300 Subject: [PATCH 07/11] no message --- android/app/src/main/AndroidManifest.xml | 1 + lib/pages/parent_categorise_page.dart | 1918 +++++++---------- .../shared/product_details_app_bar.dart | 46 +- lib/pages/webRTC/call_page.dart | 12 +- lib/pages/webRTC/signaling.dart | 364 ++-- pubspec.yaml | 6 +- 6 files changed, 965 insertions(+), 1382 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 61472941..eb397698 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + diff --git a/lib/pages/parent_categorise_page.dart b/lib/pages/parent_categorise_page.dart index 5a917897..4e58225e 100644 --- a/lib/pages/parent_categorise_page.dart +++ b/lib/pages/parent_categorise_page.dart @@ -5,7 +5,6 @@ import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_deta import 'package:diplomaticquarterapp/core/viewModels/pharmacy_categorise_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/locator.dart'; -import 'package:diplomaticquarterapp/pages/pharmacies/screens/cart-page/cart-order-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/product-details/product-detail.dart'; import 'package:diplomaticquarterapp/pages/sub_categories_modalsheet.dart'; import 'package:diplomaticquarterapp/pages/sub_categorise_page.dart'; @@ -14,10 +13,8 @@ import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; -import 'package:diplomaticquarterapp/widgets/Loader/gif_loader_container.dart'; import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; -import 'package:diplomaticquarterapp/widgets/others/StarRating.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/others/entity_checkbox_list.dart'; import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart'; @@ -34,14 +31,12 @@ class ParentCategorisePage extends StatefulWidget { String id; String titleName; - AuthenticatedUserObject authenticatedUserObject = - locator(); + AuthenticatedUserObject authenticatedUserObject = locator(); ParentCategorisePage({this.id, this.titleName}); @override - _ParentCategorisePageState createState() => - _ParentCategorisePageState(id: id, titleName: titleName); + _ParentCategorisePageState createState() => _ParentCategorisePageState(id: id, titleName: titleName); } class _ParentCategorisePageState extends State { @@ -80,768 +75,558 @@ class _ParentCategorisePageState extends State { ProjectViewModel projectViewModel = Provider.of(context); ProjectViewModel projectProvider = Provider.of(context); return BaseView( - onModelReady: (model) => model.getCategoriseParent( - i: id, pageIndex: pageIndex, isLoading: false, context: context), + onModelReady: (model) => model.getCategoriseParent(i: id, pageIndex: pageIndex, isLoading: false, context: context), allowAny: true, - builder: - (BuildContext context, PharmacyCategoriseViewModel model, - Widget child) => - AppScaffold( - isPharmacy: true, - appBarTitle: titleName, - isBottomBar: true, - isShowAppBar: true, - backgroundColor: Colors.white, - isShowDecPage: false, - baseViewModel: model, - body: SmartRefresher( - enablePullDown: false, - controller: controller, - enablePullUp: true, - onLoading: () async { - setState(() { - ++pageIndex; - }); - await model.getParentProducts( - pageIndex: pageIndex, - i: id, - isLoading: true, - context: context); - if (model.state != ViewState.BusyLocal && - pageIndex < 5) { - controller.loadComplete(); - } else { - controller.loadFailed(); - } - }, - child: SingleChildScrollView( - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Image.network( - id == '1' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089188_personal-care_2.png' - : id == '2' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089189_skin-care_2.png' - : id == '3' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089190_health-care_2.png' - : id == '4' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089191_sexual-health_2.png' - : id == '5' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089192_beauty_2.png' - : id == '6' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089193_baby-child_2.png' - : id == '7' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089194_vitamins-supplements_2.png' - : id == '8' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089195_diet-nutrition_2.png' - : id == '9' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089196_household_2.png' - : id == '10' - ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089197_home-care-appliances_2.png' - : '', - fit: BoxFit.fill, - height: 160.0, - width: double.infinity), - ), - if (model.categoriseParent.length > 8) - Column( - crossAxisAlignment: CrossAxisAlignment.start, + builder: (BuildContext context, PharmacyCategoriseViewModel model, Widget child) => AppScaffold( + isPharmacy: true, + appBarTitle: titleName, + isBottomBar: true, + isShowAppBar: true, + backgroundColor: Colors.white, + isShowDecPage: false, + baseViewModel: model, + body: SmartRefresher( + enablePullDown: false, + controller: controller, + enablePullUp: true, + onLoading: () async { + setState(() { + ++pageIndex; + }); + await model.getParentProducts(pageIndex: pageIndex, i: id, isLoading: true, context: context); + if (model.state != ViewState.BusyLocal && pageIndex < 5) { + controller.loadComplete(); + } else { + controller.loadFailed(); + } + }, + child: SingleChildScrollView( + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Image.network( + id == '1' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089188_personal-care_2.png' + : id == '2' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089189_skin-care_2.png' + : id == '3' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089190_health-care_2.png' + : id == '4' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089191_sexual-health_2.png' + : id == '5' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089192_beauty_2.png' + : id == '6' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089193_baby-child_2.png' + : id == '7' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089194_vitamins-supplements_2.png' + : id == '8' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089195_diet-nutrition_2.png' + : id == '9' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089196_household_2.png' + : id == '10' + ? 'https://uat.hmgwebservices.com/epharmacy/content/images/thumbs/0089197_home-care-appliances_2.png' + : '', + fit: BoxFit.fill, + height: 160.0, + width: double.infinity), + ), + if (model.categoriseParent.length > 8) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InkWell( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - InkWell( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: EdgeInsets.all(10.0), - child: Container( - child: Texts( - TranslationBase.of(context) - .viewCategorise, + Padding( + padding: EdgeInsets.all(10.0), + child: Container( + child: Texts( + TranslationBase.of(context).viewCategorise, // 'View All Categories', - fontWeight: FontWeight.w300, - ), - ), - ), - Icon(Icons.arrow_forward) - ], + fontWeight: FontWeight.w300, ), - onTap: () { - Navigator.push( - context, - FadePage( - page: SubCategoriseModalsheet( -// id: model.categorise[0].id, -// titleName: model.categorise[0].name, - )), - ); - }), - Divider( - thickness: 1.0, - color: Colors.grey.shade400, + ), ), + Icon(Icons.arrow_forward) ], ), + onTap: () { + Navigator.push( + context, + FadePage( + page: SubCategoriseModalsheet( +// id: model.categorise[0].id, +// titleName: model.categorise[0].name, + )), + ); + }), + Divider( + thickness: 1.0, + color: Colors.grey.shade400, + ), + ], + ), //Expanded widget heree if nassery - Padding( - padding: EdgeInsets.only(top: 35.0), - child: Container( - height: - MediaQuery.of(context).size.height * 0.2, - child: Center( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: - model.categoriseParent.length > 8 - ? 8 - : model.categoriseParent.length, - itemBuilder: - (BuildContext context, int index) { - return Padding( - padding: EdgeInsets.symmetric( - horizontal: 8.0), - child: InkWell( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Padding( - padding: - EdgeInsets.symmetric( - horizontal: 13.0), - child: Container( - height: 60.0, - width: 65.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors - .orange.shade200 - .withOpacity(0.45), - ), - child: Center( - child: Icon( - Icons.apps_sharp, - size: 32.0, - ), - ), - ), - ), - Container( - width: - MediaQuery.of(context) - .size - .width * - 0.197, - // height: MediaQuery.of(context) - // .size - // .height * - // 0.08, - child: Center( - child: Texts( - projectViewModel - .isArabic - ? model - .categoriseParent[ - index] - .namen - : model - .categoriseParent[ - index] - .name, - fontSize: 13.4, - fontWeight: - FontWeight.w600, - maxLines: 3, - ), - ), - ), - ], + Padding( + padding: EdgeInsets.only(top: 35.0), + child: Container( + height: MediaQuery.of(context).size.height * 0.2, + child: Center( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: model.categoriseParent.length > 8 ? 8 : model.categoriseParent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: InkWell( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 13.0), + child: Container( + height: 60.0, + width: 65.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.orange.shade200.withOpacity(0.45), + ), + child: Center( + child: Icon( + Icons.apps_sharp, + size: 32.0, + ), ), - onTap: () { - Navigator.push( - context, - FadePage( - page: SubCategorisePage( - title: projectViewModel - .isArabic - ? model - .categoriseParent[ - index] - .namen - : model - .categoriseParent[ - index] - .name, - id: model - .categoriseParent[index] - .id, - parentId: id, - )), - ); - print(id); - }, ), - ); - }), - ), - ), - ), - - Divider( - thickness: 1.0, - color: Colors.grey.shade400, - ), - Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - InkWell( - child: Row( - children: [ - Icon( - Icons.wrap_text, ), - SizedBox( - width: 10.0, - ), - Texts( - TranslationBase.of(context).refine, - fontWeight: FontWeight.w600, + Container( + width: MediaQuery.of(context).size.width * 0.197, + // height: MediaQuery.of(context) + // .size + // .height * + // 0.08, + child: Center( + child: Texts( + projectViewModel.isArabic ? model.categoriseParent[index].namen : model.categoriseParent[index].name, + fontSize: 13.4, + fontWeight: FontWeight.w600, + maxLines: 3, + ), + ), ), ], ), onTap: () { - showModalBottomSheet( - isScrollControlled: true, - context: context, - builder: (BuildContext context) { - return DraggableScrollableSheet( - initialChildSize: 0.95, - maxChildSize: 0.95, - minChildSize: 0.9, - builder: (BuildContext context, - ScrollController - scrollController) { - return SingleChildScrollView( - controller: - scrollController, - child: Container( - color: Colors.white, - height: - MediaQuery.of(context) - .size - .height * - 1.95, - child: Column( - children: [ - Padding( - padding: - EdgeInsets.all( - 8.0), - child: Row( - children: [ - Icon( - Icons - .wrap_text, - ), - SizedBox( - width: 10.0, - ), - Texts( - TranslationBase.of( - context) - .refine, + Navigator.push( + context, + FadePage( + page: SubCategorisePage( + title: projectViewModel.isArabic ? model.categoriseParent[index].namen : model.categoriseParent[index].name, + id: model.categoriseParent[index].id, + parentId: id, + )), + ); + print(id); + }, + ), + ); + }), + ), + ), + ), + + Divider( + thickness: 1.0, + color: Colors.grey.shade400, + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + child: Row( + children: [ + Icon( + Icons.wrap_text, + ), + SizedBox( + width: 10.0, + ), + Texts( + TranslationBase.of(context).refine, + fontWeight: FontWeight.w600, + ), + ], + ), + onTap: () { + showModalBottomSheet( + isScrollControlled: true, + context: context, + builder: (BuildContext context) { + return DraggableScrollableSheet( + initialChildSize: 0.95, + maxChildSize: 0.95, + minChildSize: 0.9, + builder: (BuildContext context, ScrollController scrollController) { + return SingleChildScrollView( + controller: scrollController, + child: Container( + color: Colors.white, + height: MediaQuery.of(context).size.height * 1.95, + child: Column( + children: [ + Padding( + padding: EdgeInsets.all(8.0), + child: Row( + children: [ + Icon( + Icons.wrap_text, + ), + SizedBox( + width: 10.0, + ), + Texts( + TranslationBase.of(context).refine, // 'Refine', - fontWeight: - FontWeight - .w600, - ), - SizedBox( - width: 250.0, - ), - InkWell( - child: Texts( + fontWeight: FontWeight.w600, + ), + SizedBox( + width: 250.0, + ), + InkWell( + child: Texts( // 'Close', - TranslationBase.of( - context) - .closeIt, - color: Colors - .red, - fontWeight: - FontWeight - .w600, - fontSize: - 15.0, - ), - onTap: () { - Navigator.pop( - context); - }, - ), - ], - ), + TranslationBase.of(context).closeIt, + color: Colors.red, + fontWeight: FontWeight.w600, + fontSize: 15.0, ), - Divider( - thickness: 1.0, - color: - Colors.black12, - ), - Column( - children: [ - ExpansionTile( - title: Texts( - TranslationBase.of( - context) - .categorise), - children: [ - ProcedureListWidget( - model: - model, - masterList: - model - .categoriseParent, - removeHistory: - (item) { - setState( - () { - entityList - .remove(item); - }); - }, - addHistory: - (history) { - setState( - () { - entityList - .add(history); - }); - }, - addSelectedHistories: - () { - //TODO build your fun herr - // widget.addSelectedHistories(); - }, - isEntityListSelected: - (master) => - isEntityListSelected(master), - ) - ], - ), - Divider( - thickness: 1.0, - color: Colors - .black12, - ), - ExpansionTile( - title: Texts( - TranslationBase.of( - context) - .brands), - children: [ - ProcedureListWidget( - model: - model, - masterList: - model - .brandsList, - removeHistory: - (item) { - setState( - () { - entityListBrands - .remove(item); - }); - }, - addHistory: - (history) { - setState( - () { - entityListBrands - .add(history); - }); - }, - addSelectedHistories: - () { - //TODO build your fun herr - // widget.addSelectedHistories(); - }, - isEntityListSelected: - (master) => - isEntityListSelectedBrands(master), - ) - ], - ), - Divider( - thickness: 1.0, - color: Colors - .black12, - ), - ExpansionTile( - title: Texts( - TranslationBase.of( - context) - .price), - children: [ - Container( - color: Color( - 0xffEEEEEE), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceAround, - children: [ - Column( - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Texts(TranslationBase.of(context).min), - Container( - color: Colors.white, - width: 200, - height: 40, - child: TextFormField( - decoration: InputDecoration( - border: OutlineInputBorder(), - ), - controller: minField, - ), - ), - ], - ), - Column( - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Texts(TranslationBase.of(context).max), - Container( - color: Colors.white, - width: 200, - height: 40, - child: TextFormField( - decoration: InputDecoration( - border: OutlineInputBorder(), - ), - controller: maxField, - ), - ), - ], - ), - ], - ), - ) - ], - ), - Divider( - thickness: 1.0, - color: Colors - .black12, - ), - SizedBox( - height: MediaQuery.of( - context) - .size - .height * - 0.4, - ), - Padding( - padding: - EdgeInsets - .all( - 8.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceEvenly, + onTap: () { + Navigator.pop(context); + }, + ), + ], + ), + ), + Divider( + thickness: 1.0, + color: Colors.black12, + ), + Column( + children: [ + ExpansionTile( + title: Texts(TranslationBase.of(context).categorise), + children: [ + ProcedureListWidget( + model: model, + masterList: model.categoriseParent, + removeHistory: (item) { + setState(() { + entityList.remove(item); + }); + }, + addHistory: (history) { + setState(() { + entityList.add(history); + }); + }, + addSelectedHistories: () { + //TODO build your fun herr + // widget.addSelectedHistories(); + }, + isEntityListSelected: (master) => isEntityListSelected(master), + ) + ], + ), + Divider( + thickness: 1.0, + color: Colors.black12, + ), + ExpansionTile( + title: Texts(TranslationBase.of(context).brands), + children: [ + ProcedureListWidget( + model: model, + masterList: model.brandsList, + removeHistory: (item) { + setState(() { + entityListBrands.remove(item); + }); + }, + addHistory: (history) { + setState(() { + entityListBrands.add(history); + }); + }, + addSelectedHistories: () { + //TODO build your fun herr + // widget.addSelectedHistories(); + }, + isEntityListSelected: (master) => isEntityListSelectedBrands(master), + ) + ], + ), + Divider( + thickness: 1.0, + color: Colors.black12, + ), + ExpansionTile( + title: Texts(TranslationBase.of(context).price), + children: [ + Container( + color: Color(0xffEEEEEE), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.start, children: [ + Texts(TranslationBase.of(context).min), Container( - width: - 100, - child: - Button( - label: TranslationBase.of(context) - .reset, - backgroundColor: - Colors.red, + color: Colors.white, + width: 200, + height: 40, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + ), + controller: minField, ), ), - SizedBox( - width: 30, - ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Texts(TranslationBase.of(context).max), Container( - width: - 200, - child: - Button( - onTap: - () async { - String - categoriesId = - ""; - for (CategoriseParentModel category - in entityList) { - if (categoriesId == - "") { - categoriesId = category.id; - } else { - categoriesId = "$categoriesId,${category.id}"; - } - } - String - brandIds = - ""; - for (CategoriseParentModel brand - in entityListBrands) { - if (brandIds == - "") { - brandIds = brand.id; - } else { - brandIds = "$brandIds,${brand.id}"; - } - } - - GifLoaderDialogUtils.showMyDialog( - context); - - await model.getFilteredProducts( - min: minField.text.toString(), - max: maxField.text.toString(), - categoryId: categoriesId, - brandId: brandIds); - GifLoaderDialogUtils.hideDialog( - context); - - Navigator.pop( - context); - }, - label: TranslationBase.of(context) - .apply, - backgroundColor: - Colors.green, + color: Colors.white, + width: 200, + height: 40, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + ), + controller: maxField, ), ), ], ), - ), - ], - ), + ], + ), + ) ], ), - ), - ); - }); - }, - ); - }, - ), - Row( - children: [ - Container( - height: 44.0, - child: VerticalDivider( - color: Colors.black45, - thickness: 1.0, + Divider( + thickness: 1.0, + color: Colors.black12, + ), + SizedBox( + height: MediaQuery.of(context).size.height * 0.4, + ), + Padding( + padding: EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + width: 150, + child: Button( + label: TranslationBase.of(context).reset, + backgroundColor: Colors.red, + ), + ), + SizedBox( + width: 10, + ), + Container( + width: 150, + child: Button( + onTap: () async { + String categoriesId = ""; + for (CategoriseParentModel category in entityList) { + if (categoriesId == "") { + categoriesId = category.id; + } else { + categoriesId = "$categoriesId,${category.id}"; + } + } + String brandIds = ""; + for (CategoriseParentModel brand in entityListBrands) { + if (brandIds == "") { + brandIds = brand.id; + } else { + brandIds = "$brandIds,${brand.id}"; + } + } + + GifLoaderDialogUtils.showMyDialog(context); + + await model.getFilteredProducts( + min: minField.text.toString(), max: maxField.text.toString(), categoryId: categoriesId, brandId: brandIds); + GifLoaderDialogUtils.hideDialog(context); + + Navigator.pop(context); + }, + label: TranslationBase.of(context).apply, + backgroundColor: Colors.green, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ); + }); + }, + ); + }, + ), + Row( + children: [ + Container( + height: 44.0, + child: VerticalDivider( + color: Colors.black45, + thickness: 1.0, //width: 0.3, // indent: 0.0, - ), - ), - Padding( - padding: EdgeInsets.all(8.0), - child: InkWell( - child: styleIcon, - onTap: () { - setState(() { - if (styleOne == true) { - styleOne = false; - styleTwo = true; - styleIcon = Icon( - Icons.auto_awesome_mosaic, - color: CustomColors.green, - size: 29.0, - ); - } else { - styleOne = true; - styleTwo = false; - styleIcon = Icon( - Icons.widgets_sharp, - color: CustomColors.green, - size: 29.0, - ); - } - }); - }, - ), - ), - ], - ), - ], + ), ), - ), - Divider( - thickness: 1.0, - color: Colors.grey.shade400, - ), - model.parentProducts.isNotEmpty - ? styleOne == true - ? Container( - height: model.parentProducts.length * - MediaQuery.of(context) - .size - .height * - 0.15, - child: GridView.builder( - physics: - NeverScrollableScrollPhysics(), - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 0.5, - mainAxisSpacing: 2.0, - childAspectRatio: 0.9, - ), - itemCount: - model.parentProducts.length, - itemBuilder: (BuildContext context, - int index) { - return NetworkBaseView( - baseViewModel: model, - child: InkWell( - child: Card( - color: model - .parentProducts[ - index] - .discountName != - null - ? Color(0xffFFFF00) - : Colors.white, - elevation: 0, - shape: Border( - right: BorderSide( - color: Colors - .grey.shade300, - width: 1, - ), - left: BorderSide( - color: Colors - .grey.shade300, - width: 1, - ), - bottom: BorderSide( - color: Colors - .grey.shade300, - width: 1, - ), - top: BorderSide( - color: Colors - .grey.shade300, - width: 1, - ), - ), - margin: - EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - child: Container( - decoration: - BoxDecoration( - borderRadius: - BorderRadius.only( - topLeft: - Radius.circular( - 110.0), + Padding( + padding: EdgeInsets.all(8.0), + child: InkWell( + child: styleIcon, + onTap: () { + setState(() { + if (styleOne == true) { + styleOne = false; + styleTwo = true; + styleIcon = Icon( + Icons.auto_awesome_mosaic, + color: CustomColors.green, + size: 29.0, + ); + } else { + styleOne = true; + styleTwo = false; + styleIcon = Icon( + Icons.widgets_sharp, + color: CustomColors.green, + size: 29.0, + ); + } + }); + }, + ), + ), + ], + ), + ], + ), + ), + Divider( + thickness: 1.0, + color: Colors.grey.shade400, + ), + model.parentProducts.isNotEmpty + ? styleOne == true + ? Container( + height: model.parentProducts.length * MediaQuery.of(context).size.height * 0.15, + child: GridView.builder( + physics: NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 0.5, + mainAxisSpacing: 2.0, + childAspectRatio: 0.9, + ), + itemCount: model.parentProducts.length, + itemBuilder: (BuildContext context, int index) { + return NetworkBaseView( + baseViewModel: model, + child: InkWell( + child: Card( + color: model.parentProducts[index].discountName != null ? Color(0xffFFFF00) : Colors.white, + elevation: 0, + shape: Border( + right: BorderSide( + color: Colors.grey.shade300, + width: 1, + ), + left: BorderSide( + color: Colors.grey.shade300, + width: 1, + ), + bottom: BorderSide( + color: Colors.grey.shade300, + width: 1, + ), + top: BorderSide( + color: Colors.grey.shade300, + width: 1, + ), + ), + margin: EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(110.0), + ), + color: Colors.white, + ), + padding: EdgeInsets.symmetric(horizontal: 0), + width: MediaQuery.of(context).size.width / 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + children: [ + if (model.parentProducts[index].discountName != null) + RotatedBox( + quarterTurns: 4, + child: Container( + decoration: BoxDecoration(), + child: Padding( + padding: EdgeInsets.only( + right: 5.0, + top: 20.0, + bottom: 5.0, + ), + child: Texts( + TranslationBase.of(context).offers.toUpperCase(), + color: Colors.red, + fontSize: 13.0, + fontWeight: FontWeight.w900, + ), + ), + transform: new Matrix4.rotationZ(5.837200), + ), + ), + Container( + margin: EdgeInsets.fromLTRB(0, 16, 0, 0), + alignment: Alignment.center, + child: Image.network( + model.parentProducts[index].images.isNotEmpty + ? model.parentProducts[index].images[0].thumb + : 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/No_image_3x4.svg/1200px-No_image_3x4.svg.png', + fit: BoxFit.cover, + height: 80, ), - color: Colors.white, ), - padding: EdgeInsets - .symmetric( - horizontal: 0), - width: MediaQuery.of( - context) - .size - .width / - 3, - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - Stack( - children: [ - if (model - .parentProducts[ - index] - .discountName != - null) - RotatedBox( - quarterTurns: - 4, - child: - Container( - decoration: - BoxDecoration(), - child: - Padding( - padding: - EdgeInsets.only( - right: - 5.0, - top: - 20.0, - bottom: - 5.0, - ), - child: - Texts( - TranslationBase.of(context) - .offers - .toUpperCase(), - color: - Colors.red, - fontSize: - 13.0, - fontWeight: - FontWeight.w900, - ), - ), - transform: - new Matrix4.rotationZ( - 5.837200), - ), - ), - Container( - margin: EdgeInsets - .fromLTRB( - 0, - 16, - 0, - 0), - alignment: - Alignment - .center, - child: Image - .network( - model - .parentProducts[ - index] - .images - .isNotEmpty - ? model - .parentProducts[index] - .images[0] - .thumb - : 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/No_image_3x4.svg/1200px-No_image_3x4.svg.png', - fit: BoxFit - .cover, - height: 80, - ), - ), // Container( // width: model.parentProducts[index].rxMessage != // null @@ -891,251 +676,144 @@ class _ParentCategorisePageState extends State { // .w400, // // ), // ), - ], - ), + ], + ), + Container( + margin: EdgeInsets.symmetric( + horizontal: 6, + vertical: 0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (model.parentProducts[index].discountName != null) Container( - margin: EdgeInsets - .symmetric( - horizontal: 6, - vertical: 0, + width: double.infinity, + height: 13.0, + decoration: BoxDecoration( + color: Color(0xff5AB145), ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - if (model - .parentProducts[ - index] - .discountName != - null) - Container( - width: double - .infinity, - height: - 13.0, - decoration: - BoxDecoration( - color: Color( - 0xff5AB145), - ), - child: - Center( - child: - Texts( - model - .parentProducts[index] - .discountName, - regular: - true, - color: - Colors.white, - fontSize: - 10.4, - ), - ), - ), - Texts( - projectViewModel - .isArabic - ? model - .parentProducts[ - index] - .namen - : model - .parentProducts[index] - .name, - regular: - true, - fontSize: - 12, - fontWeight: - FontWeight - .w700, - ), - Padding( - padding: const EdgeInsets - .only( - top: 4, - bottom: - 4), - child: - Texts( - "SAR ${model.parentProducts[index].price}", - bold: - true, - fontSize: - 14, - ), - ), - Row( - children: [ + child: Center( + child: Texts( + model.parentProducts[index].discountName, + regular: true, + color: Colors.white, + fontSize: 10.4, + ), + ), + ), + Texts( + projectViewModel.isArabic ? model.parentProducts[index].namen : model.parentProducts[index].name, + regular: true, + fontSize: 12, + fontWeight: FontWeight.w700, + ), + Padding( + padding: const EdgeInsets.only(top: 4, bottom: 4), + child: Texts( + "SAR ${model.parentProducts[index].price}", + bold: true, + fontSize: 14, + ), + ), + Row( + children: [ // StarRating( // totalAverage: model.parentProducts[index].approvedRatingSum > 0 // ? (model.parentProducts[index].approvedRatingSum.toDouble() / model.parentProducts[index].approvedRatingSum.toDouble()).toDouble() // : 0, // forceStars: true), - RatingBar - .readOnly( - initialRating: model - .parentProducts[index] - .approvedRatingSum - .toDouble(), - size: - 15.0, - filledColor: - Colors.yellow[700], - emptyColor: - Colors.grey[500], - isHalfAllowed: - true, - halfFilledIcon: - Icons.star_half, - filledIcon: - Icons.star, - emptyIcon: - Icons.star, - ), - Texts( - "(${model.parentProducts[index].approvedTotalReviews})", - regular: - true, - fontSize: - 10, - fontWeight: - FontWeight.w400, - ) - ], - ), - ], + RatingBar.readOnly( + initialRating: model.parentProducts[index].approvedRatingSum.toDouble(), + size: 15.0, + filledColor: Colors.yellow[700], + emptyColor: Colors.grey[500], + isHalfAllowed: true, + halfFilledIcon: Icons.star_half, + filledIcon: Icons.star, + emptyIcon: Icons.star, ), - ), - ], - ), + Texts( + "(${model.parentProducts[index].approvedTotalReviews})", + regular: true, + fontSize: 10, + fontWeight: FontWeight.w400, + ) + ], + ), + ], ), ), - onTap: () => { - Navigator.push( - context, - FadePage( - page: ProductDetailPage( - model.parentProducts[ - index]), - )), - }, - )); + ], + ), + ), + ), + onTap: () => { + Navigator.push( + context, + FadePage( + page: ProductDetailPage(model.parentProducts[index]), + )), }, - ), - ) - : Container( - height: model.parentProducts.length * - MediaQuery.of(context) - .size - .height * - 0.122, - child: ListView.builder( - physics: - NeverScrollableScrollPhysics(), - itemCount: - model.parentProducts.length, - itemBuilder: - (BuildContext context, - int index) { - return InkWell( - child: Card( - child: Row( + )); + }, + ), + ) + : Container( + height: model.parentProducts.length * MediaQuery.of(context).size.height * 0.122, + child: ListView.builder( + physics: NeverScrollableScrollPhysics(), + itemCount: model.parentProducts.length, + itemBuilder: (BuildContext context, int index) { + return InkWell( + child: Card( + child: Row( + children: [ + Stack( + children: [ + Column( children: [ - Stack( - children: [ - Column( - children: [ - Container( - decoration: - BoxDecoration(), - child: - Padding( - padding: - EdgeInsets - .only( - left: 9.0, - top: 8.0, - right: - 10.0, - ), - ), - ), - Container( - margin: EdgeInsets - .fromLTRB( - 0, - 0, - 0, - 0), - alignment: - Alignment - .center, - child: model - .parentProducts[ - index] - .images - .isNotEmpty - ? Image - .network( - model - .parentProducts[index] - .images[0] - .thumb, - fit: BoxFit - .contain, - height: - 70, - ) - : Text(TranslationBase.of( - context) - .noImage), - ), - ], + Container( + decoration: BoxDecoration(), + child: Padding( + padding: EdgeInsets.only( + left: 9.0, + top: 8.0, + right: 10.0, ), - Column( - children: [ - Container( - width: model.parentProducts[index].rxMessage != - null - ? MediaQuery.of(context) - .size - .width / - 5.3 - : 0, - padding: - EdgeInsets - .all( - 4), - decoration: - BoxDecoration( - color: Color( - 0xffb23838), - borderRadius: - BorderRadius.only( - topLeft: - Radius.circular(6)), - ), - child: model.parentProducts[index] - .rxMessage != - null - ? Texts( - projectProvider.isArabic - ? model.parentProducts[index].rxMessagen - : model.parentProducts[index].rxMessage, - color: - Colors.white, - regular: - true, - fontSize: - 10, - fontWeight: - FontWeight.w400, - ) - : Texts(""), + ), + ), + Container( + margin: EdgeInsets.fromLTRB(0, 0, 0, 0), + alignment: Alignment.center, + child: model.parentProducts[index].images.isNotEmpty + ? Image.network( + model.parentProducts[index].images[0].thumb, + fit: BoxFit.contain, + height: 70, + ) + : Text(TranslationBase.of(context).noImage), + ), + ], + ), + Column( + children: [ + Container( + width: model.parentProducts[index].rxMessage != null ? MediaQuery.of(context).size.width / 5.3 : 0, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Color(0xffb23838), + borderRadius: BorderRadius.only(topLeft: Radius.circular(6)), + ), + child: model.parentProducts[index].rxMessage != null + ? Texts( + projectProvider.isArabic ? model.parentProducts[index].rxMessagen : model.parentProducts[index].rxMessage, + color: Colors.white, + regular: true, + fontSize: 10, + fontWeight: FontWeight.w400, + ) + : Texts(""), // Texts( // model.parentProducts[index].rxMessage != null ? model.parentProducts[index].rxMessage : "", // color: Colors.white, @@ -1143,201 +821,139 @@ class _ParentCategorisePageState extends State { // fontSize: 10, // fontWeight: FontWeight.w400, // ), - ), - ], - ), - ], ), - Container( - margin: EdgeInsets - .symmetric( - horizontal: 0, - vertical: 0, - ), - child: Column( - mainAxisAlignment: - MainAxisAlignment - .spaceAround, - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - SizedBox( - height: 4.0, - ), - Container( - width: MediaQuery.of( - context) - .size - .width * - 0.635, - child: Texts( - projectViewModel - .isArabic - ? model - .parentProducts[ - index] - .namen - : model - .parentProducts[ - index] - .name, - regular: true, - fontSize: - 13.2, - fontWeight: - FontWeight - .w500, - maxLines: 5, - ), - ), - SizedBox( - height: 8.0, - ), - Padding( - padding: - const EdgeInsets - .only( - top: 4, - bottom: - 4), - child: Texts( - "SAR ${model.parentProducts[index].price}", - bold: true, - fontSize: 14, - ), - ), - Row( - children: [ + ], + ), + ], + ), + Container( + margin: EdgeInsets.symmetric( + horizontal: 0, + vertical: 0, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 4.0, + ), + Container( + width: MediaQuery.of(context).size.width * 0.635, + child: Texts( + projectViewModel.isArabic ? model.parentProducts[index].namen : model.parentProducts[index].name, + regular: true, + fontSize: 13.2, + fontWeight: FontWeight.w500, + maxLines: 5, + ), + ), + SizedBox( + height: 8.0, + ), + Padding( + padding: const EdgeInsets.only(top: 4, bottom: 4), + child: Texts( + "SAR ${model.parentProducts[index].price}", + bold: true, + fontSize: 14, + ), + ), + Row( + children: [ // StarRating( // totalAverage: model.parentProducts[index].approvedRatingSum > 0 // ? (model.parentProducts[index].approvedRatingSum.toDouble() / model.parentProducts[index].approvedRatingSum.toDouble()).toDouble() // : 0, // forceStars: true), - RatingBar - .readOnly( - initialRating: model - .parentProducts[ - index] - .approvedRatingSum - .toDouble(), - size: 15.0, - filledColor: - Colors.yellow[ - 700], - emptyColor: - Colors.grey[ - 500], - isHalfAllowed: - true, - halfFilledIcon: - Icons - .star_half, - filledIcon: - Icons - .star, - emptyIcon: - Icons - .star, - ), - Texts( - "(${model.parentProducts[index].approvedTotalReviews})", - regular: - true, - fontSize: - 10, - fontWeight: - FontWeight - .w400, - ) - ], - ), - ], + RatingBar.readOnly( + initialRating: model.parentProducts[index].approvedRatingSum.toDouble(), + size: 15.0, + filledColor: Colors.yellow[700], + emptyColor: Colors.grey[500], + isHalfAllowed: true, + halfFilledIcon: Icons.star_half, + filledIcon: Icons.star, + emptyIcon: Icons.star, ), - ), - widget.authenticatedUserObject - .isLogin - ? Container( - child: - IconButton( - icon: - Icon( - Icons - .shopping_cart, - size: - 18, - color: - CustomColors.green, - ), - onPressed: - () async { - if (model.parentProducts[index].rxMessage == - null) { - GifLoaderDialogUtils.showMyDialog(context); - await addToCartFunction(1, - model.parentProducts[index].id); - GifLoaderDialogUtils.hideDialog(context); - Utils.navigateToCartPage(); - } else { - AppToast.showErrorToast(message: TranslationBase.of(context).needPrescription); - } - }), - ) - : Container(), - ], - ), + Texts( + "(${model.parentProducts[index].approvedTotalReviews})", + regular: true, + fontSize: 10, + fontWeight: FontWeight.w400, + ) + ], + ), + ], ), - onTap: () => { - Navigator.push( - context, - FadePage( - page: ProductDetailPage( - model.parentProducts[ - index]), - )), - }, - ); - }), - ) - : Padding( - padding: const EdgeInsets.all(12.0), - child: Container( - child: Center( - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Padding( - padding: - const EdgeInsets.all(8.0), - child: Image.asset( - 'assets/images/new-design/empty_box.png', - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - Padding( - padding: - const EdgeInsets.all(8.0), - child: Text( - TranslationBase.of(context) - .noData, - // 'There is no data', - style: - TextStyle(fontSize: 30), ), - ) - ], + widget.authenticatedUserObject.isLogin + ? Container( + child: IconButton( + icon: Icon( + Icons.shopping_cart, + size: 18, + color: CustomColors.green, + ), + onPressed: () async { + if (model.parentProducts[index].rxMessage == null) { + GifLoaderDialogUtils.showMyDialog(context); + await addToCartFunction(1, model.parentProducts[index].id); + GifLoaderDialogUtils.hideDialog(context); + Utils.navigateToCartPage(); + } else { + AppToast.showErrorToast(message: TranslationBase.of(context).needPrescription); + } + }), + ) + : Container(), + ], + ), ), + onTap: () => { + Navigator.push( + context, + FadePage( + page: ProductDetailPage(model.parentProducts[index]), + )), + }, + ); + }), + ) + : Padding( + padding: const EdgeInsets.all(12.0), + child: Container( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Image.asset( + 'assets/images/new-design/empty_box.png', + width: 100, + height: 100, + fit: BoxFit.cover, ), ), - ) - ], - ), - ), - ), - ))); + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + TranslationBase.of(context).noData, + // 'There is no data', + style: TextStyle(fontSize: 30), + ), + ) + ], + ), + ), + ), + ) + ], + ), + ), + ), + ))); } addToCartFunction(quantity, itemID) async { @@ -1346,8 +962,7 @@ class _ParentCategorisePageState extends State { } bool isEntityListSelected(CategoriseParentModel masterKey) { - Iterable history = - entityList.where((element) => masterKey.id == element.id); + Iterable history = entityList.where((element) => masterKey.id == element.id); if (history.length > 0) { return true; } @@ -1355,8 +970,7 @@ class _ParentCategorisePageState extends State { } bool isEntityListSelectedBrands(CategoriseParentModel masterKey) { - Iterable history = - entityListBrands.where((element) => masterKey.id == element.id); + Iterable history = entityListBrands.where((element) => masterKey.id == element.id); if (history.length > 0) { return true; } diff --git a/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart index fb608953..9ed3c037 100644 --- a/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart +++ b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart @@ -3,7 +3,6 @@ import 'package:diplomaticquarterapp/core/service/AuthenticatedUserObject.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_detail_view_model.dart'; import 'package:diplomaticquarterapp/pages/landing/landing_page_pharmcy.dart'; -import 'package:diplomaticquarterapp/pages/pharmacies/screens/cart-page/cart-order-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/product-details/product-detail.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/navigation_service.dart'; @@ -27,19 +26,9 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { final bool isInWishList; final Function addToCartFunction; - ProductAppBar( - {Key key, - this.product, - this.model, - this.addToWishlistFunction, - this.quantity, - this.deleteFromWishlistFunction, - this.isInWishList, - this.addToCartFunction}) - : super(key: key); + ProductAppBar({Key key, this.product, this.model, this.addToWishlistFunction, this.quantity, this.deleteFromWishlistFunction, this.isInWishList, this.addToCartFunction}) : super(key: key); - AuthenticatedUserObject authenticatedUserObject = - locator(); + AuthenticatedUserObject authenticatedUserObject = locator(); @override Widget build(BuildContext context) { @@ -76,7 +65,6 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { icon: Icons.shopping_cart, color: Colors.grey[800], onPress: () { - Navigator.pushAndRemoveUntil( locator().navigatorKey.currentContext, MaterialPageRoute(builder: (context) => LandingPagePharmacy(currentTab: 3)), (Route r) => false); // Navigator.push( @@ -84,11 +72,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { // MaterialPageRoute(builder: (context) => CartOrderPage()), // ); }), - if (Provider.of(context, - listen: false) - .cartResponse - .quantityCount != - 0) + if (Provider.of(context, listen: false).cartResponse.quantityCount != 0) Positioned( top: 0, right: -1.0, @@ -101,11 +85,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { height: 18, child: Center( child: Texts( - Provider.of(context, - listen: false) - .cartResponse - .quantityCount - .toString(), + Provider.of(context, listen: false).cartResponse.quantityCount.toString(), style: "caption", medium: true, color: Colors.white, @@ -144,7 +124,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { return Container( child: new Wrap( children: [ - if (product.stockAvailability != 'Out of stock') + if (product.stockAvailability != 'Out of stock' && !product.isRx) new ListTile( leading: Icon(Icons.shopping_cart), title: Text( @@ -153,17 +133,12 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { onTap: () async { if (quantity > 0) { { - await addToCartFunction( - quantity: quantity, - itemID: itemID, - model: model); + await addToCartFunction(quantity: quantity, itemID: itemID, model: model); Navigator.of(context).pop(); } } else { - AppToast.showErrorToast(message: TranslationBase.of(context).addQuantity - // "you should add quantity" - ); + AppToast.showErrorToast(message: TranslationBase.of(context).addQuantity); } }), ListTile( @@ -172,9 +147,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { color: !isInWishList ? Colors.white : Colors.red[800], ), title: Text( - isInWishList - ? TranslationBase.of(context).removeFromWishlist - : TranslationBase.of(context).addToWishlist, + isInWishList ? TranslationBase.of(context).removeFromWishlist : TranslationBase.of(context).addToWishlist, ), onTap: () async { if (isInWishList) @@ -189,8 +162,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget { TranslationBase.of(context).compare, ), onTap: () { - Provider.of(context, listen: false) - .addItem(specificationData,context); + Provider.of(context, listen: false).addItem(specificationData, context); Navigator.of(context).pop(); }, ), diff --git a/lib/pages/webRTC/call_page.dart b/lib/pages/webRTC/call_page.dart index 4c8ac4f5..c5b41aa3 100644 --- a/lib/pages/webRTC/call_page.dart +++ b/lib/pages/webRTC/call_page.dart @@ -77,7 +77,7 @@ class _CallPageState extends State { ), ElevatedButton( onPressed: () async { - roomId = await signaling.createRoom(_remoteRenderer); + // roomId = await signaling.createRoom(_remoteRenderer); textEditingController.text = roomId; setState(() {}); }, @@ -89,10 +89,10 @@ class _CallPageState extends State { ElevatedButton( onPressed: () { // Add roomId - signaling.joinRoom( - textEditingController.text, - _remoteRenderer, - ); + // signaling.joinRoom( + // textEditingController.text, + // _remoteRenderer, + // ); }, child: Text("Join room"), ), @@ -101,7 +101,7 @@ class _CallPageState extends State { ), ElevatedButton( onPressed: () { - signaling.hangUp(_localRenderer); + // signaling.hangUp(_localRenderer); }, child: Text("Hangup"), ) diff --git a/lib/pages/webRTC/signaling.dart b/lib/pages/webRTC/signaling.dart index f987e285..3f840854 100644 --- a/lib/pages/webRTC/signaling.dart +++ b/lib/pages/webRTC/signaling.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:cloud_firestore/cloud_firestore.dart'; +// import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; typedef void StreamStateCallback(MediaStream stream); @@ -21,161 +21,161 @@ class Signaling { String currentRoomText; StreamStateCallback onAddRemoteStream; - Future createRoom(RTCVideoRenderer remoteRenderer) async { - FirebaseFirestore db = FirebaseFirestore.instance; - DocumentReference roomRef = db.collection('rooms').doc(); - - print('Create PeerConnection with configuration: $configuration'); - - peerConnection = await createPeerConnection(configuration); - - registerPeerConnectionListeners(); - - localStream.getTracks().forEach((track) { - peerConnection?.addTrack(track, localStream); - }); - - // Code for collecting ICE candidates below - var callerCandidatesCollection = roomRef.collection('callerCandidates'); - - peerConnection?.onIceCandidate = (RTCIceCandidate candidate) { - print('Got candidate: ${candidate.toMap()}'); - callerCandidatesCollection.add(candidate.toMap()); - }; - // Finish Code for collecting ICE candidate - - // Add code for creating a room - RTCSessionDescription offer = await peerConnection.createOffer(); - await peerConnection.setLocalDescription(offer); - print('Created offer: $offer'); - - Map roomWithOffer = {'offer': offer.toMap()}; - - await roomRef.set(roomWithOffer); - var roomId = roomRef.id; - print('New room created with SDK offer. Room ID: $roomId'); - currentRoomText = 'Current room is $roomId - You are the caller!'; - // Created a Room - - peerConnection?.onTrack = (RTCTrackEvent event) { - print('Got remote track: ${event.streams[0]}'); - - event.streams[0].getTracks().forEach((track) { - print('Add a track to the remoteStream $track'); - remoteStream?.addTrack(track); - }); - }; - - // Listening for remote session description below - roomRef.snapshots().listen((snapshot) async { - print('Got updated room: ${snapshot.data()}'); - - Map data = snapshot.data() as Map; - if (peerConnection?.getRemoteDescription() != null && data['answer'] != null) { - var answer = RTCSessionDescription( - data['answer']['sdp'], - data['answer']['type'], - ); - - print("Someone tried to connect"); - await peerConnection?.setRemoteDescription(answer); - } - }); - // Listening for remote session description above - - // Listen for remote Ice candidates below - roomRef.collection('calleeCandidates').snapshots().listen((snapshot) { - snapshot.docChanges.forEach((change) { - if (change.type == DocumentChangeType.added) { - Map data = change.doc.data() as Map; - print('Got new remote ICE candidate: ${jsonEncode(data)}'); - peerConnection.addCandidate( - RTCIceCandidate( - data['candidate'], - data['sdpMid'], - data['sdpMLineIndex'], - ), - ); - } - }); - }); - // Listen for remote ICE candidates above - - return roomId; - } - - Future joinRoom(String roomId, RTCVideoRenderer remoteVideo) async { - FirebaseFirestore db = FirebaseFirestore.instance; - DocumentReference roomRef = db.collection('rooms').doc('$roomId'); - var roomSnapshot = await roomRef.get(); - print('Got room ${roomSnapshot.exists}'); - - if (roomSnapshot.exists) { - print('Create PeerConnection with configuration: $configuration'); - peerConnection = await createPeerConnection(configuration); - - registerPeerConnectionListeners(); - - localStream.getTracks().forEach((track) { - peerConnection?.addTrack(track, localStream); - }); - - // Code for collecting ICE candidates below - var calleeCandidatesCollection = roomRef.collection('calleeCandidates'); - peerConnection.onIceCandidate = (RTCIceCandidate candidate) { - if (candidate == null) { - print('onIceCandidate: complete!'); - return; - } - print('onIceCandidate: ${candidate.toMap()}'); - calleeCandidatesCollection.add(candidate.toMap()); - }; - // Code for collecting ICE candidate above - - peerConnection?.onTrack = (RTCTrackEvent event) { - print('Got remote track: ${event.streams[0]}'); - event.streams[0].getTracks().forEach((track) { - print('Add a track to the remoteStream: $track'); - remoteStream?.addTrack(track); - }); - }; - - // Code for creating SDP answer below - var data = roomSnapshot.data() as Map; - print('Got offer $data'); - var offer = data['offer']; - await peerConnection?.setRemoteDescription( - RTCSessionDescription(offer['sdp'], offer['type']), - ); - var answer = await peerConnection.createAnswer(); - print('Created Answer $answer'); - - await peerConnection.setLocalDescription(answer); - - Map roomWithAnswer = { - 'answer': {'type': answer.type, 'sdp': answer.sdp} - }; - - await roomRef.update(roomWithAnswer); - // Finished creating SDP answer - - // Listening for remote ICE candidates below - // roomRef.collection('callerCandidates').snapshots().listen((snapshot) { - // snapshot.docChanges.forEach((document) { - // var data = document.doc.data() as Map; - // print(data); - // print('Got new remote ICE candidate: $data'); - // peerConnection.addCandidate( - // RTCIceCandidate( - // data['candidate'], - // data['sdpMid'], - // data['sdpMLineIndex'], - // ), - // ); - // }); - // }); - } - } + // Future createRoom(RTCVideoRenderer remoteRenderer) async { + // // FirebaseFirestore db = FirebaseFirestore.instance; + // // DocumentReference roomRef = db.collection('rooms').doc(); + // + // print('Create PeerConnection with configuration: $configuration'); + // + // peerConnection = await createPeerConnection(configuration); + // + // registerPeerConnectionListeners(); + // + // localStream.getTracks().forEach((track) { + // peerConnection?.addTrack(track, localStream); + // }); + // + // // Code for collecting ICE candidates below + // var callerCandidatesCollection = roomRef.collection('callerCandidates'); + // + // peerConnection?.onIceCandidate = (RTCIceCandidate candidate) { + // print('Got candidate: ${candidate.toMap()}'); + // callerCandidatesCollection.add(candidate.toMap()); + // }; + // // Finish Code for collecting ICE candidate + // + // // Add code for creating a room + // RTCSessionDescription offer = await peerConnection.createOffer(); + // await peerConnection.setLocalDescription(offer); + // print('Created offer: $offer'); + // + // Map roomWithOffer = {'offer': offer.toMap()}; + // + // await roomRef.set(roomWithOffer); + // var roomId = roomRef.id; + // print('New room created with SDK offer. Room ID: $roomId'); + // currentRoomText = 'Current room is $roomId - You are the caller!'; + // // Created a Room + // + // peerConnection?.onTrack = (RTCTrackEvent event) { + // print('Got remote track: ${event.streams[0]}'); + // + // event.streams[0].getTracks().forEach((track) { + // print('Add a track to the remoteStream $track'); + // remoteStream?.addTrack(track); + // }); + // }; + // + // // Listening for remote session description below + // roomRef.snapshots().listen((snapshot) async { + // print('Got updated room: ${snapshot.data()}'); + // + // Map data = snapshot.data() as Map; + // if (peerConnection?.getRemoteDescription() != null && data['answer'] != null) { + // var answer = RTCSessionDescription( + // data['answer']['sdp'], + // data['answer']['type'], + // ); + // + // print("Someone tried to connect"); + // await peerConnection?.setRemoteDescription(answer); + // } + // }); + // // Listening for remote session description above + // + // // Listen for remote Ice candidates below + // roomRef.collection('calleeCandidates').snapshots().listen((snapshot) { + // snapshot.docChanges.forEach((change) { + // if (change.type == DocumentChangeType.added) { + // Map data = change.doc.data() as Map; + // print('Got new remote ICE candidate: ${jsonEncode(data)}'); + // peerConnection.addCandidate( + // RTCIceCandidate( + // data['candidate'], + // data['sdpMid'], + // data['sdpMLineIndex'], + // ), + // ); + // } + // }); + // }); + // // Listen for remote ICE candidates above + // + // return roomId; + // } + + // Future joinRoom(String roomId, RTCVideoRenderer remoteVideo) async { + // FirebaseFirestore db = FirebaseFirestore.instance; + // DocumentReference roomRef = db.collection('rooms').doc('$roomId'); + // var roomSnapshot = await roomRef.get(); + // print('Got room ${roomSnapshot.exists}'); + // + // if (roomSnapshot.exists) { + // print('Create PeerConnection with configuration: $configuration'); + // peerConnection = await createPeerConnection(configuration); + // + // registerPeerConnectionListeners(); + // + // localStream.getTracks().forEach((track) { + // peerConnection?.addTrack(track, localStream); + // }); + // + // // Code for collecting ICE candidates below + // var calleeCandidatesCollection = roomRef.collection('calleeCandidates'); + // peerConnection.onIceCandidate = (RTCIceCandidate candidate) { + // if (candidate == null) { + // print('onIceCandidate: complete!'); + // return; + // } + // print('onIceCandidate: ${candidate.toMap()}'); + // calleeCandidatesCollection.add(candidate.toMap()); + // }; + // // Code for collecting ICE candidate above + // + // peerConnection?.onTrack = (RTCTrackEvent event) { + // print('Got remote track: ${event.streams[0]}'); + // event.streams[0].getTracks().forEach((track) { + // print('Add a track to the remoteStream: $track'); + // remoteStream?.addTrack(track); + // }); + // }; + // + // // Code for creating SDP answer below + // var data = roomSnapshot.data() as Map; + // print('Got offer $data'); + // var offer = data['offer']; + // await peerConnection?.setRemoteDescription( + // RTCSessionDescription(offer['sdp'], offer['type']), + // ); + // var answer = await peerConnection.createAnswer(); + // print('Created Answer $answer'); + // + // await peerConnection.setLocalDescription(answer); + // + // Map roomWithAnswer = { + // 'answer': {'type': answer.type, 'sdp': answer.sdp} + // }; + // + // await roomRef.update(roomWithAnswer); + // // Finished creating SDP answer + // + // // Listening for remote ICE candidates below + // // roomRef.collection('callerCandidates').snapshots().listen((snapshot) { + // // snapshot.docChanges.forEach((document) { + // // var data = document.doc.data() as Map; + // // print(data); + // // print('Got new remote ICE candidate: $data'); + // // peerConnection.addCandidate( + // // RTCIceCandidate( + // // data['candidate'], + // // data['sdpMid'], + // // data['sdpMLineIndex'], + // // ), + // // ); + // // }); + // // }); + // } + // } Future openUserMedia( RTCVideoRenderer localVideo, @@ -189,32 +189,32 @@ class Signaling { remoteVideo.srcObject = await createLocalMediaStream('key'); } - Future hangUp(RTCVideoRenderer localVideo) async { - List tracks = localVideo.srcObject.getTracks(); - tracks.forEach((track) { - track.stop(); - }); - - if (remoteStream != null) { - remoteStream.getTracks().forEach((track) => track.stop()); - } - if (peerConnection != null) peerConnection.close(); - - if (roomId != null) { - var db = FirebaseFirestore.instance; - var roomRef = db.collection('rooms').doc(roomId); - var calleeCandidates = await roomRef.collection('calleeCandidates').get(); - calleeCandidates.docs.forEach((document) => document.reference.delete()); - - var callerCandidates = await roomRef.collection('callerCandidates').get(); - callerCandidates.docs.forEach((document) => document.reference.delete()); - - await roomRef.delete(); - } - - localStream.dispose(); - remoteStream?.dispose(); - } + // Future hangUp(RTCVideoRenderer localVideo) async { + // List tracks = localVideo.srcObject.getTracks(); + // tracks.forEach((track) { + // track.stop(); + // }); + // + // if (remoteStream != null) { + // remoteStream.getTracks().forEach((track) => track.stop()); + // } + // if (peerConnection != null) peerConnection.close(); + // + // if (roomId != null) { + // var db = FirebaseFirestore.instance; + // var roomRef = db.collection('rooms').doc(roomId); + // var calleeCandidates = await roomRef.collection('calleeCandidates').get(); + // calleeCandidates.docs.forEach((document) => document.reference.delete()); + // + // var callerCandidates = await roomRef.collection('callerCandidates').get(); + // callerCandidates.docs.forEach((document) => document.reference.delete()); + // + // await roomRef.delete(); + // } + // + // localStream.dispose(); + // remoteStream?.dispose(); + // } void registerPeerConnectionListeners() { peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { diff --git a/pubspec.yaml b/pubspec.yaml index c7cda641..744929f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,8 +36,7 @@ dependencies: fl_chart: ^0.12.3 # Permissions - permission_handler: ^5.0.0+hotfix.3 - device_info: ^0.4.2+4 + permission_handler: ^5.1.0+2 # Flutter Html View flutter_html: ^1.2.0 @@ -46,7 +45,6 @@ dependencies: pull_to_refresh: 1.6.2 # Native - flutter_device_type: ^0.2.0 local_auth: ^0.6.2+3 localstorage: ^3.0.3+6 maps_launcher: ^1.2.1 @@ -55,7 +53,6 @@ dependencies: flutter_flexible_toast: ^0.1.4 firebase_messaging: ^7.0.3 firebase_analytics: ^6.3.0 - cloud_firestore: ^0.14.3 # Progress bar progress_hud_v2: ^2.0.0 percent_indicator: ^2.1.5 @@ -156,7 +153,6 @@ dependencies: cached_network_image: ^2.4.1 flutter_tts: path: flutter_tts-voice_enhancement - # flutter_tts: ^1.2.6 sms_otp_auto_verify: ^1.2.2 wifi: ^0.1.5 From 39190681c6bf98171dee68764c71f60f231e70aa Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 23 Nov 2021 10:54:35 +0300 Subject: [PATCH 08/11] Updates --- lib/main.dart | 4 +- lib/pages/webRTC/signaling.dart | 2 +- lib/pages/webRTC/signaling_bkp.dart | 232 ++++++++++++++-------------- 3 files changed, 119 insertions(+), 119 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 93af691e..50a7e1a0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -168,8 +168,8 @@ class _MyApp extends State { // ), // ), // ), - // initialRoute: SPLASH, - initialRoute: CALL_PAGE, + initialRoute: SPLASH, + // initialRoute: CALL_PAGE, // initialRoute: OPENTOK_CALL_PAGE, // initialRoute: PACKAGES_OFFERS, // initialRoute: PACKAGES_ORDER_COMPLETED, diff --git a/lib/pages/webRTC/signaling.dart b/lib/pages/webRTC/signaling.dart index 90127e31..ded40187 100644 --- a/lib/pages/webRTC/signaling.dart +++ b/lib/pages/webRTC/signaling.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:cloud_firestore/cloud_firestore.dart'; +// import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:diplomaticquarterapp/pages/webRTC/fcm/FCMSendNotification.dart'; import 'package:diplomaticquarterapp/uitl/SignalRUtil.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/pages/webRTC/signaling_bkp.dart b/lib/pages/webRTC/signaling_bkp.dart index f987e285..14319df3 100644 --- a/lib/pages/webRTC/signaling_bkp.dart +++ b/lib/pages/webRTC/signaling_bkp.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:cloud_firestore/cloud_firestore.dart'; +// import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; typedef void StreamStateCallback(MediaStream stream); @@ -22,8 +22,8 @@ class Signaling { StreamStateCallback onAddRemoteStream; Future createRoom(RTCVideoRenderer remoteRenderer) async { - FirebaseFirestore db = FirebaseFirestore.instance; - DocumentReference roomRef = db.collection('rooms').doc(); + // FirebaseFirestore db = FirebaseFirestore.instance; + // DocumentReference roomRef = db.collection('rooms').doc(); print('Create PeerConnection with configuration: $configuration'); @@ -36,11 +36,11 @@ class Signaling { }); // Code for collecting ICE candidates below - var callerCandidatesCollection = roomRef.collection('callerCandidates'); + // var callerCandidatesCollection = roomRef.collection('callerCandidates'); peerConnection?.onIceCandidate = (RTCIceCandidate candidate) { print('Got candidate: ${candidate.toMap()}'); - callerCandidatesCollection.add(candidate.toMap()); + // callerCandidatesCollection.add(candidate.toMap()); }; // Finish Code for collecting ICE candidate @@ -51,8 +51,8 @@ class Signaling { Map roomWithOffer = {'offer': offer.toMap()}; - await roomRef.set(roomWithOffer); - var roomId = roomRef.id; + // await roomRef.set(roomWithOffer); + // var roomId = roomRef.id; print('New room created with SDK offer. Room ID: $roomId'); currentRoomText = 'Current room is $roomId - You are the caller!'; // Created a Room @@ -67,114 +67,114 @@ class Signaling { }; // Listening for remote session description below - roomRef.snapshots().listen((snapshot) async { - print('Got updated room: ${snapshot.data()}'); - - Map data = snapshot.data() as Map; - if (peerConnection?.getRemoteDescription() != null && data['answer'] != null) { - var answer = RTCSessionDescription( - data['answer']['sdp'], - data['answer']['type'], - ); - - print("Someone tried to connect"); - await peerConnection?.setRemoteDescription(answer); - } - }); - // Listening for remote session description above - - // Listen for remote Ice candidates below - roomRef.collection('calleeCandidates').snapshots().listen((snapshot) { - snapshot.docChanges.forEach((change) { - if (change.type == DocumentChangeType.added) { - Map data = change.doc.data() as Map; - print('Got new remote ICE candidate: ${jsonEncode(data)}'); - peerConnection.addCandidate( - RTCIceCandidate( - data['candidate'], - data['sdpMid'], - data['sdpMLineIndex'], - ), - ); - } - }); - }); + // roomRef.snapshots().listen((snapshot) async { + // print('Got updated room: ${snapshot.data()}'); + // + // Map data = snapshot.data() as Map; + // if (peerConnection?.getRemoteDescription() != null && data['answer'] != null) { + // var answer = RTCSessionDescription( + // data['answer']['sdp'], + // data['answer']['type'], + // ); + // + // print("Someone tried to connect"); + // await peerConnection?.setRemoteDescription(answer); + // } + // }); + // // Listening for remote session description above + // + // // Listen for remote Ice candidates below + // roomRef.collection('calleeCandidates').snapshots().listen((snapshot) { + // snapshot.docChanges.forEach((change) { + // if (change.type == DocumentChangeType.added) { + // Map data = change.doc.data() as Map; + // print('Got new remote ICE candidate: ${jsonEncode(data)}'); + // peerConnection.addCandidate( + // RTCIceCandidate( + // data['candidate'], + // data['sdpMid'], + // data['sdpMLineIndex'], + // ), + // ); + // } + // }); + // }); // Listen for remote ICE candidates above return roomId; } Future joinRoom(String roomId, RTCVideoRenderer remoteVideo) async { - FirebaseFirestore db = FirebaseFirestore.instance; - DocumentReference roomRef = db.collection('rooms').doc('$roomId'); - var roomSnapshot = await roomRef.get(); - print('Got room ${roomSnapshot.exists}'); - - if (roomSnapshot.exists) { - print('Create PeerConnection with configuration: $configuration'); - peerConnection = await createPeerConnection(configuration); - - registerPeerConnectionListeners(); - - localStream.getTracks().forEach((track) { - peerConnection?.addTrack(track, localStream); - }); - - // Code for collecting ICE candidates below - var calleeCandidatesCollection = roomRef.collection('calleeCandidates'); - peerConnection.onIceCandidate = (RTCIceCandidate candidate) { - if (candidate == null) { - print('onIceCandidate: complete!'); - return; - } - print('onIceCandidate: ${candidate.toMap()}'); - calleeCandidatesCollection.add(candidate.toMap()); - }; - // Code for collecting ICE candidate above - - peerConnection?.onTrack = (RTCTrackEvent event) { - print('Got remote track: ${event.streams[0]}'); - event.streams[0].getTracks().forEach((track) { - print('Add a track to the remoteStream: $track'); - remoteStream?.addTrack(track); - }); - }; - - // Code for creating SDP answer below - var data = roomSnapshot.data() as Map; - print('Got offer $data'); - var offer = data['offer']; - await peerConnection?.setRemoteDescription( - RTCSessionDescription(offer['sdp'], offer['type']), - ); - var answer = await peerConnection.createAnswer(); - print('Created Answer $answer'); - - await peerConnection.setLocalDescription(answer); - - Map roomWithAnswer = { - 'answer': {'type': answer.type, 'sdp': answer.sdp} - }; - - await roomRef.update(roomWithAnswer); - // Finished creating SDP answer - - // Listening for remote ICE candidates below - // roomRef.collection('callerCandidates').snapshots().listen((snapshot) { - // snapshot.docChanges.forEach((document) { - // var data = document.doc.data() as Map; - // print(data); - // print('Got new remote ICE candidate: $data'); - // peerConnection.addCandidate( - // RTCIceCandidate( - // data['candidate'], - // data['sdpMid'], - // data['sdpMLineIndex'], - // ), - // ); - // }); - // }); - } + // FirebaseFirestore db = FirebaseFirestore.instance; + // DocumentReference roomRef = db.collection('rooms').doc('$roomId'); + // var roomSnapshot = await roomRef.get(); + // print('Got room ${roomSnapshot.exists}'); + + // if (roomSnapshot.exists) { + // print('Create PeerConnection with configuration: $configuration'); + // peerConnection = await createPeerConnection(configuration); + // + // registerPeerConnectionListeners(); + // + // localStream.getTracks().forEach((track) { + // peerConnection?.addTrack(track, localStream); + // }); + // + // // Code for collecting ICE candidates below + // // var calleeCandidatesCollection = roomRef.collection('calleeCandidates'); + // peerConnection.onIceCandidate = (RTCIceCandidate candidate) { + // if (candidate == null) { + // print('onIceCandidate: complete!'); + // return; + // } + // print('onIceCandidate: ${candidate.toMap()}'); + // // calleeCandidatesCollection.add(candidate.toMap()); + // }; + // // Code for collecting ICE candidate above + // + // peerConnection?.onTrack = (RTCTrackEvent event) { + // print('Got remote track: ${event.streams[0]}'); + // event.streams[0].getTracks().forEach((track) { + // print('Add a track to the remoteStream: $track'); + // remoteStream?.addTrack(track); + // }); + // }; + // + // // Code for creating SDP answer below + // var data = roomSnapshot.data() as Map; + // print('Got offer $data'); + // var offer = data['offer']; + // await peerConnection?.setRemoteDescription( + // RTCSessionDescription(offer['sdp'], offer['type']), + // ); + // var answer = await peerConnection.createAnswer(); + // print('Created Answer $answer'); + // + // await peerConnection.setLocalDescription(answer); + // + // Map roomWithAnswer = { + // 'answer': {'type': answer.type, 'sdp': answer.sdp} + // }; + // + // await roomRef.update(roomWithAnswer); + // // Finished creating SDP answer + // + // // Listening for remote ICE candidates below + // // roomRef.collection('callerCandidates').snapshots().listen((snapshot) { + // // snapshot.docChanges.forEach((document) { + // // var data = document.doc.data() as Map; + // // print(data); + // // print('Got new remote ICE candidate: $data'); + // // peerConnection.addCandidate( + // // RTCIceCandidate( + // // data['candidate'], + // // data['sdpMid'], + // // data['sdpMLineIndex'], + // // ), + // // ); + // // }); + // // }); + // } } Future openUserMedia( @@ -201,15 +201,15 @@ class Signaling { if (peerConnection != null) peerConnection.close(); if (roomId != null) { - var db = FirebaseFirestore.instance; - var roomRef = db.collection('rooms').doc(roomId); - var calleeCandidates = await roomRef.collection('calleeCandidates').get(); - calleeCandidates.docs.forEach((document) => document.reference.delete()); + // var db = FirebaseFirestore.instance; + // var roomRef = db.collection('rooms').doc(roomId); + // var calleeCandidates = await roomRef.collection('calleeCandidates').get(); + // calleeCandidates.docs.forEach((document) => document.reference.delete()); - var callerCandidates = await roomRef.collection('callerCandidates').get(); - callerCandidates.docs.forEach((document) => document.reference.delete()); + // var callerCandidates = await roomRef.collection('callerCandidates').get(); + // callerCandidates.docs.forEach((document) => document.reference.delete()); - await roomRef.delete(); + // await roomRef.delete(); } localStream.dispose(); From fe7baeab3cc53ca6f4829ab7763781e28a2031db Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 23 Nov 2021 11:55:09 +0300 Subject: [PATCH 09/11] LiveCare permissions --- lib/pages/BookAppointment/BookConfirm.dart | 38 ------ .../widgets/LiveCarePendingRequest.dart | 2 +- lib/pages/livecare/widgets/clinic_list.dart | 116 +++++++++--------- 3 files changed, 60 insertions(+), 96 deletions(-) diff --git a/lib/pages/BookAppointment/BookConfirm.dart b/lib/pages/BookAppointment/BookConfirm.dart index 7377bcc2..f648025d 100644 --- a/lib/pages/BookAppointment/BookConfirm.dart +++ b/lib/pages/BookAppointment/BookConfirm.dart @@ -242,44 +242,6 @@ class _BookConfirmState extends State { ); } - Future askVideoCallPermission() async { - if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) { - return false; - } - if (!(await PlatformBridge.shared().isDrawOverAppsPermissionAllowed())) { - await drawOverAppsMessageDialog(context); - return false; - } - return true; - } - - Future drawOverAppsMessageDialog(BuildContext context) async { - await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - content: Text("Please select 'Diplomatic Quarter' from the list and allow draw over app permission to use live care."), - contentPadding: EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0.0), - actions: [ - FlatButton( - child: Text("Cancel"), - onPressed: () { - Navigator.pop(context); - }, - ), - FlatButton( - child: Text("Go to Settings"), - onPressed: () async { - await PlatformBridge.shared().askDrawOverAppsPermission(); - Navigator.pop(context); - }, - ) - ], - ); - }, - ); - } - cancelAppointment(DoctorList docObject, AppoitmentAllHistoryResultList appo, BuildContext context) { ConfirmDialog.closeAlertDialog(context); GifLoaderDialogUtils.showMyDialog(context); diff --git a/lib/pages/livecare/widgets/LiveCarePendingRequest.dart b/lib/pages/livecare/widgets/LiveCarePendingRequest.dart index 26d2e829..2c47b3c7 100644 --- a/lib/pages/livecare/widgets/LiveCarePendingRequest.dart +++ b/lib/pages/livecare/widgets/LiveCarePendingRequest.dart @@ -120,7 +120,7 @@ class _LiveCarePendingRequestState extends State { style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)), ), Container( - transform: Matrix4.translationValues(0.0, 130.0, 0.0), + transform: Matrix4.translationValues(0.0, 110.0, 0.0), alignment: Alignment.bottomCenter, width: MediaQuery.of(context).size.width, child: ButtonTheme( diff --git a/lib/pages/livecare/widgets/clinic_list.dart b/lib/pages/livecare/widgets/clinic_list.dart index bf4d33c7..232f62de 100644 --- a/lib/pages/livecare/widgets/clinic_list.dart +++ b/lib/pages/livecare/widgets/clinic_list.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart'; import 'package:diplomaticquarterapp/models/Appointments/DoctorListResponse.dart'; @@ -11,12 +13,12 @@ import 'package:diplomaticquarterapp/pages/livecare/livecare_home.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_scheduling/schedule_clinic_card.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_type_select.dart'; import 'package:diplomaticquarterapp/pages/livecare/widgets/LiveCareInfoDialog.dart'; -import 'package:diplomaticquarterapp/pages/livecare/widgets/LiveCarePaymentDialog.dart'; import 'package:diplomaticquarterapp/pages/livecare/widgets/clinic_card.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/services/livecare_services/livecare_provider.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; +import 'package:diplomaticquarterapp/uitl/PlatformBridge.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; @@ -29,6 +31,7 @@ import 'package:diplomaticquarterapp/widgets/in_app_browser/InAppBrowser.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart'; import '../live_care_payment_page.dart'; @@ -180,40 +183,43 @@ class _clinic_listState extends State { navigateTo(context, LiveCarePatmentPage(getERAppointmentFeesList: getERAppointmentFeesList, waitingTime: waitingTime, clinicName: selectedClinicName)).then( (value) { if (value) { - if (getERAppointmentFeesList.total == "0" || getERAppointmentFeesList.total == "0.0") { - showLiveCareInfoDialog(getERAppointmentFeesList); - } else { - navigateToPaymentMethod(getERAppointmentFeesList, context); - } + askVideoCallPermission().then((value) { + if (value) { + if (getERAppointmentFeesList.total == "0" || getERAppointmentFeesList.total == "0.0") { + showLiveCareInfoDialog(getERAppointmentFeesList); + } else { + navigateToPaymentMethod(getERAppointmentFeesList, context); + } + } + }); } }, ); - // showGeneralDialog( - // barrierColor: Colors.black.withOpacity(0.5), - // transitionBuilder: (context, a1, a2, widget) { - // final curvedValue = Curves.easeInOutBack.transform(a1.value) - 1.0; - // return Transform( - // transform: Matrix4.translationValues(0.0, curvedValue * 200, 0.0), - // child: Opacity( - // opacity: a1.value, - // child: LiveCarePaymentDialog(getERAppointmentFeesList: getERAppointmentFeesList, waitingTime: waitingTime, clinicName: selectedClinicName), - // ), - // ); - // }, - // transitionDuration: Duration(milliseconds: 500), - // barrierDismissible: true, - // barrierLabel: '', - // context: context, - // pageBuilder: (context, animation1, animation2) {}) - // .then((value) { - // if (value) { - // if (getERAppointmentFeesList.total == "0" || getERAppointmentFeesList.total == "0.0") { - // showLiveCareInfoDialog(getERAppointmentFeesList); - // } else { - // navigateToPaymentMethod(getERAppointmentFeesList, context); - // } - // } - // }); + } + + Future askVideoCallPermission() async { + if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) { + return false; + } + if (Platform.isAndroid && !(await PlatformBridge.shared().isDrawOverAppsPermissionAllowed())) { + await drawOverAppsMessageDialog(context); + return false; + } + return true; + } + + Future drawOverAppsMessageDialog(BuildContext context) async { + ConfirmDialog dialog = new ConfirmDialog( + context: context, + confirmMessage: "Please select 'Dr. Alhabib' from the list and allow draw over app permission to use live care.", + okText: TranslationBase.of(context).confirm, + cancelText: TranslationBase.of(context).cancel_nocaps, + okFunction: () async { + await PlatformBridge.shared().askDrawOverAppsPermission(); + Navigator.pop(context); + }, + cancelFunction: () => {}); + dialog.showAlertDialog(context); } showLiveCareInfoDialog(GetERAppointmentFeesList getERAppointmentFeesList) async { @@ -452,7 +458,7 @@ class _clinic_listState extends State { children: [ isDataLoaded ? Expanded( - child: Container( + child: Container( child: liveCareScheduleClinicsListResponse.clinicsHaveScheduleList.length > 0 ? Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -484,30 +490,30 @@ class _clinic_listState extends State { ) : getNoDataWidget(context), ), - ) + ) : Container(), isDataLoaded ? Container( - width: double.infinity, - color: Colors.white, - padding: EdgeInsets.all(12), - child: ButtonTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - minWidth: MediaQuery.of(context).size.width * 0.7, - height: 45.0, - child: RaisedButton( - color: CustomColors.accentColor, - textColor: Colors.white, - elevation: 0, - disabledTextColor: Colors.white, - disabledColor: new Color(0xFFbcc2c4), - onPressed: startScheduleLiveCare, - child: Text(TranslationBase.of(context).start, style: TextStyle(fontSize: 18.0)), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.all(12), + child: ButtonTheme( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + minWidth: MediaQuery.of(context).size.width * 0.7, + height: 45.0, + child: RaisedButton( + color: CustomColors.accentColor, + textColor: Colors.white, + elevation: 0, + disabledTextColor: Colors.white, + disabledColor: new Color(0xFFbcc2c4), + onPressed: startScheduleLiveCare, + child: Text(TranslationBase.of(context).start, style: TextStyle(fontSize: 18.0)), + ), ), - ), - ) + ) : Container(), ], ); @@ -542,10 +548,6 @@ class _clinic_listState extends State { ); }, ), - // Container( - // margin: EdgeInsets.all(15.0), - // child: Text(TranslationBase.of(context).offlineClinics, style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)), - // ), ListView.builder( scrollDirection: Axis.vertical, shrinkWrap: true, From db3ea448f6dde4c284367d3587eb1fd20d6ba39f Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Tue, 23 Nov 2021 14:22:53 +0300 Subject: [PATCH 10/11] fix design --- .../product-details/product-detail.dart | 52 ++--- .../product-name-and-price.dart | 195 +++++++++++++----- 2 files changed, 168 insertions(+), 79 deletions(-) diff --git a/lib/pages/pharmacies/screens/product-details/product-detail.dart b/lib/pages/pharmacies/screens/product-details/product-detail.dart index 1f9dcc52..bde315a7 100644 --- a/lib/pages/pharmacies/screens/product-details/product-detail.dart +++ b/lib/pages/pharmacies/screens/product-details/product-detail.dart @@ -158,30 +158,30 @@ class __ProductDetailPageState extends State { ), ), SizedBox( - height: 6, - ), - Container( - color: Colors.white, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.symmetric(vertical: 15, horizontal: 10), - child: Texts( - TranslationBase.of(context).specification, - fontSize: 15, - fontWeight: FontWeight.bold, - ), - width: double.infinity, - ), - // Divider(color: Colors.grey), - ], - ), - ), - SizedBox( - height: 6, + height: 10, ), +// Container( +// color: Colors.white, +// child: Column( +// mainAxisAlignment: MainAxisAlignment.start, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// padding: EdgeInsets.symmetric(vertical: 15, horizontal: 10), +// child: Texts( +// TranslationBase.of(context).specification, +// fontSize: 15, +// fontWeight: FontWeight.bold, +// ), +// width: double.infinity, +// ), +// // Divider(color: Colors.grey), +// ], +// ), +// ), +// SizedBox( +// height: 6, +// ), Container( // width: 500, margin: EdgeInsets.only(bottom: 10), @@ -205,7 +205,7 @@ class __ProductDetailPageState extends State { }, child: Text( TranslationBase.of(context).details, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), color: Colors.white, ), @@ -236,7 +236,7 @@ class __ProductDetailPageState extends State { }, child: Text( TranslationBase.of(context).reviews, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), color: Colors.white, ), @@ -266,7 +266,7 @@ class __ProductDetailPageState extends State { : null, child: Text( TranslationBase.of(context).availability, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), color: Colors.white, ), diff --git a/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart b/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart index f71c92a4..799259d7 100644 --- a/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart +++ b/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart @@ -43,31 +43,100 @@ class _ProductNameAndPriceState extends State { SizedBox( height: 10, ), + widget.item.rxMessage != null + ? Container( + // width: widget.item.rxMessage != null ? MediaQuery.of(context).size.width / 2.8 : 0, + width: double.infinity, + height: 40, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Color(0xffD02127), + // color: Colors.red[700] + // borderRadius: BorderRadius.only(topLeft: Radius.circular(6)), + ), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 8, right: 8), + child: Icon( + Icons.warning, + color: Colors.white, + ), + ), + Text( + projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(), + style: TextStyle(color: Colors.white, + // regular: true, + fontSize: 17, + fontWeight: FontWeight.w600, + // textAlign: TextAlign.center, + ) + ), + ], + ) + ) + : Container(), FractionallySizedBox( widthFactor: 0.95, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Texts(widget.item.price.toString() + " " + TranslationBase.of(context).sar, fontWeight: FontWeight.bold, fontSize: 20), - Texts( - widget.stockAvailability, - fontWeight: FontWeight.bold, - fontSize: 15, - color: widget.isStockAvailable ? Colors.green : Colors.red, +// Texts(widget.item.price.toString() + " " + TranslationBase.of(context).sar, fontWeight: FontWeight.bold, fontSize: 20), + Container( + margin: EdgeInsets.only(top: 10.0, right: 10.0), + padding: EdgeInsets.only(left: 11.0, right: 11.0, top: 0, bottom: 0), + decoration: BoxDecoration( + border: Border.all( + color: getStatusBackgroundColor(), + style: BorderStyle.solid, + width: 5.0, + ), + color: getStatusBackgroundColor(), + borderRadius: BorderRadius.circular(30.0)), + child: Text( + widget.stockAvailability, + style: TextStyle(fontWeight: FontWeight.w600, fontSize: 11, color: Color(0xffFFFFFF),), + //color: widget.isStockAvailable ? Colors.white : Colors.red, + ), ), // SizedBox(width: 20), if (widget.authenticatedUserObject.isLogin) !widget.isStockAvailable && widget.customerId != null - ?BorderedButton( - TranslationBase.of(context).notifyMe, - hasBorder: true, - borderColor: Colors.green, - textColor: Colors.green, - fontWeight: FontWeight.bold, - vPadding: 6, - hPadding: 14, - handler: () => widget.notifyMeWhenAvailable(context, widget.item.id), - ) + ?IconButton( + iconSize: 25, + icon:Icon(Icons.notifications_active), + color: new Color(0xff2E303A), + onPressed: () + { widget.notifyMeWhenAvailable(context, widget.item.id);}, + + ): IconButton( + icon: Icon(!widget.isInWishList ? Icons.favorite_border : Icons.favorite), + color: !widget.isInWishList ? Color(0xff2E303A) : Color(0xffD02127), + onPressed: () async { + { + if (widget.customerId != null) { + if (!widget.isInWishList) { + await widget.addToWishlistFunction(widget.item.id); + } else { + await widget.deleteFromWishlistFunction(widget.item.id); + } + } else { + return; + } + setState(() {}); + } + }, + ) +// BorderedButton( +// TranslationBase.of(context).notifyMe, +// hasBorder: true, +// borderColor: Colors.green, +// textColor: Colors.green, +// fontWeight: FontWeight.bold, +// vPadding: 6, +// hPadding: 14, +// handler: () => widget.notifyMeWhenAvailable(context, widget.item.id), +// ) // InkWell( // onTap: () => widget.notifyMeWhenAvailable(context, widget.item.id), // child: Row(children: [ @@ -84,39 +153,53 @@ class _ProductNameAndPriceState extends State { // ) // ]), // ) - : IconWithBg( - icon: !widget.isInWishList ? Icons.favorite_border : Icons.favorite, - color: !widget.isInWishList ? Colors.white : Colors.red[800], - onPress: () async { - { - if (widget.customerId != null) { - if (!widget.isInWishList) { - await widget.addToWishlistFunction(widget.item.id); - } else { - await widget.deleteFromWishlistFunction(widget.item.id); - } - } else { - return; - } - setState(() {}); - } - }, - ) +// : IconWithBg( +// icon: !widget.isInWishList ? Icons.favorite_border : Icons.favorite, +// color: !widget.isInWishList ? Colors.white : Colors.red[800], +// onPress: () async { +// { +// if (widget.customerId != null) { +// if (!widget.isInWishList) { +// await widget.addToWishlistFunction(widget.item.id); +// } else { +// await widget.deleteFromWishlistFunction(widget.item.id); +// } +// } else { +// return; +// } +// setState(() {}); +// } +// }, +// ) ], ), ), Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(left: 8,right: 8, top: 1, bottom: 15), child: Container( - margin: EdgeInsets.only(left: 5), + margin: EdgeInsets.only(left: 5, right: 5), child: Align( alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, child: Text( projectViewModel.isArabic ? widget.item.namen : widget.item.name, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), + style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16), ), ), ), + + ), + Padding( + padding: const EdgeInsets.only(left: 8,right: 8), + child: Container( + margin: EdgeInsets.only(left: 5, right: 5), + child: Align( + alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, + child: Text( TranslationBase.of(context).sar+ " " + + widget.item.price.toString(), + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 19),), + ), + ), + ), FractionallySizedBox( widthFactor: 0.95, @@ -129,13 +212,13 @@ class _ProductNameAndPriceState extends State { children: [ RatingBar.readOnly( initialRating: double.parse(widget.item.approvedRatingSum.toString()), - size: 15.0, - filledColor: Colors.yellow[700], - emptyColor: Colors.grey[400], + size: 18.0, + filledColor: Color(0XFFD02127), + emptyColor: Color(0XFFD02127), isHalfAllowed: true, halfFilledIcon: Icons.star_half, filledIcon: Icons.star, - emptyIcon: Icons.star, + emptyIcon: Icons.star_border, ), SizedBox( width: 10, @@ -148,22 +231,22 @@ class _ProductNameAndPriceState extends State { SizedBox( width: 30, ), - Texts( + Text( "(${widget.item.approvedTotalReviews}${TranslationBase.of(context).review})", - fontSize: 12, + style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12), ), SizedBox( width: 70, ), - if (widget.item.rxMessage != null) - Row( - children: [ - Text( - projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(), - style: TextStyle(color: Colors.red, fontSize: 10), - ), - ], - ) +// if (widget.item.rxMessage != null) +// Row( +// children: [ +// Text( +// projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(), +// style: TextStyle(color: Colors.red, fontSize: 10), +// ), +// ], +// ) ], ), ), @@ -172,9 +255,15 @@ class _ProductNameAndPriceState extends State { ), ), SizedBox( - height: 10, + height: 30, ), ], ); } + + Color getStatusBackgroundColor() { + if (widget.isStockAvailable) + return Color(0xFF5AB145); + else return Color(0xFFD02127); + } } From dbe74b3eb44c9aaa43e3f7a142f270ba5950d952 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Tue, 23 Nov 2021 14:31:44 +0300 Subject: [PATCH 11/11] fix desing --- .../product-name-and-price.dart | 291 +++++++++--------- 1 file changed, 147 insertions(+), 144 deletions(-) diff --git a/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart b/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart index 799259d7..d585b642 100644 --- a/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart +++ b/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart @@ -37,96 +37,98 @@ class _ProductNameAndPriceState extends State { Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); - return Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SizedBox( - height: 10, - ), - widget.item.rxMessage != null - ? Container( - // width: widget.item.rxMessage != null ? MediaQuery.of(context).size.width / 2.8 : 0, - width: double.infinity, - height: 40, - padding: EdgeInsets.all(4), - decoration: BoxDecoration( - color: Color(0xffD02127), - // color: Colors.red[700] - // borderRadius: BorderRadius.only(topLeft: Radius.circular(6)), + return Container( + color: Color(0xffF7F7F7), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + height: 10, ), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(left: 8, right: 8), - child: Icon( - Icons.warning, - color: Colors.white, + widget.item.rxMessage != null + ? Container( + // width: widget.item.rxMessage != null ? MediaQuery.of(context).size.width / 2.8 : 0, + width: double.infinity, + height: 40, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Color(0xffD02127), + // color: Colors.red[700] + // borderRadius: BorderRadius.only(topLeft: Radius.circular(6)), + ), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 8, right: 8), + child: Icon( + Icons.warning, + color: Colors.white, + ), ), - ), - Text( - projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(), - style: TextStyle(color: Colors.white, - // regular: true, - fontSize: 17, - fontWeight: FontWeight.w600, - // textAlign: TextAlign.center, - ) - ), - ], + Text( + projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(), + style: TextStyle(color: Colors.white, + // regular: true, + fontSize: 17, + fontWeight: FontWeight.w600, + // textAlign: TextAlign.center, + ) + ), + ], + ) ) - ) - : Container(), - FractionallySizedBox( - widthFactor: 0.95, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + : Container(), + FractionallySizedBox( + widthFactor: 0.95, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ // Texts(widget.item.price.toString() + " " + TranslationBase.of(context).sar, fontWeight: FontWeight.bold, fontSize: 20), - Container( - margin: EdgeInsets.only(top: 10.0, right: 10.0), - padding: EdgeInsets.only(left: 11.0, right: 11.0, top: 0, bottom: 0), - decoration: BoxDecoration( - border: Border.all( + Container( + margin: EdgeInsets.only(top: 10.0, right: 10.0), + padding: EdgeInsets.only(left: 11.0, right: 11.0, top: 0, bottom: 0), + decoration: BoxDecoration( + border: Border.all( + color: getStatusBackgroundColor(), + style: BorderStyle.solid, + width: 5.0, + ), color: getStatusBackgroundColor(), - style: BorderStyle.solid, - width: 5.0, - ), - color: getStatusBackgroundColor(), - borderRadius: BorderRadius.circular(30.0)), - child: Text( - widget.stockAvailability, - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 11, color: Color(0xffFFFFFF),), - //color: widget.isStockAvailable ? Colors.white : Colors.red, + borderRadius: BorderRadius.circular(30.0)), + child: Text( + widget.stockAvailability, + style: TextStyle(fontWeight: FontWeight.w600, fontSize: 11, color: Color(0xffFFFFFF),), + //color: widget.isStockAvailable ? Colors.white : Colors.red, + ), ), - ), - // SizedBox(width: 20), - if (widget.authenticatedUserObject.isLogin) - !widget.isStockAvailable && widget.customerId != null - ?IconButton( - iconSize: 25, - icon:Icon(Icons.notifications_active), - color: new Color(0xff2E303A), - onPressed: () - { widget.notifyMeWhenAvailable(context, widget.item.id);}, + // SizedBox(width: 20), + if (widget.authenticatedUserObject.isLogin) + !widget.isStockAvailable && widget.customerId != null + ?IconButton( + iconSize: 25, + icon:Icon(Icons.notifications_active), + color: new Color(0xff2E303A), + onPressed: () + { widget.notifyMeWhenAvailable(context, widget.item.id);}, - ): IconButton( - icon: Icon(!widget.isInWishList ? Icons.favorite_border : Icons.favorite), - color: !widget.isInWishList ? Color(0xff2E303A) : Color(0xffD02127), - onPressed: () async { - { - if (widget.customerId != null) { - if (!widget.isInWishList) { - await widget.addToWishlistFunction(widget.item.id); + ): IconButton( + icon: Icon(!widget.isInWishList ? Icons.favorite_border : Icons.favorite), + color: !widget.isInWishList ? Color(0xff2E303A) : Color(0xffD02127), + onPressed: () async { + { + if (widget.customerId != null) { + if (!widget.isInWishList) { + await widget.addToWishlistFunction(widget.item.id); + } else { + await widget.deleteFromWishlistFunction(widget.item.id); + } } else { - await widget.deleteFromWishlistFunction(widget.item.id); + return; } - } else { - return; + setState(() {}); } - setState(() {}); - } - }, - ) + }, + ) // BorderedButton( // TranslationBase.of(context).notifyMe, // hasBorder: true, @@ -171,73 +173,73 @@ class _ProductNameAndPriceState extends State { // } // }, // ) - ], + ], + ), ), - ), - Padding( - padding: const EdgeInsets.only(left: 8,right: 8, top: 1, bottom: 15), - child: Container( - margin: EdgeInsets.only(left: 5, right: 5), - child: Align( - alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, - child: Text( - projectViewModel.isArabic ? widget.item.namen : widget.item.name, - style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16), + Padding( + padding: const EdgeInsets.only(left: 8,right: 8, top: 1, bottom: 15), + child: Container( + margin: EdgeInsets.only(left: 5, right: 5), + child: Align( + alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, + child: Text( + projectViewModel.isArabic ? widget.item.namen : widget.item.name, + style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16), + ), ), ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8,right: 8), - child: Container( - margin: EdgeInsets.only(left: 5, right: 5), - child: Align( - alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, - child: Text( TranslationBase.of(context).sar+ " " + - widget.item.price.toString(), - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 19),), - ), ), + Padding( + padding: const EdgeInsets.only(left: 8,right: 8), + child: Container( + margin: EdgeInsets.only(left: 5, right: 5), + child: Align( + alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, + child: Text( TranslationBase.of(context).sar+ " " + + widget.item.price.toString(), + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 19),), + ), + ), - ), - FractionallySizedBox( - widthFactor: 0.95, - child: Row( - children: [ - Container( - child: Align( - alignment: Alignment.bottomLeft, - child: Row( - children: [ - RatingBar.readOnly( - initialRating: double.parse(widget.item.approvedRatingSum.toString()), - size: 18.0, - filledColor: Color(0XFFD02127), - emptyColor: Color(0XFFD02127), - isHalfAllowed: true, - halfFilledIcon: Icons.star_half, - filledIcon: Icons.star, - emptyIcon: Icons.star_border, - ), - SizedBox( - width: 10, - ), + ), + FractionallySizedBox( + widthFactor: 0.95, + child: Row( + children: [ + Container( + child: Align( + alignment: Alignment.bottomLeft, + child: Row( + children: [ + RatingBar.readOnly( + initialRating: double.parse(widget.item.approvedRatingSum.toString()), + size: 18.0, + filledColor: Color(0XFFD02127), + emptyColor: Color(0XFFD02127), + isHalfAllowed: true, + halfFilledIcon: Icons.star_half, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + ), + SizedBox( + width: 10, + ), // Texts( // "${widget.item.approvedRatingSum}", // fontWeight: FontWeight.bold, // fontSize: 12, // ), - SizedBox( - width: 30, - ), - Text( - "(${widget.item.approvedTotalReviews}${TranslationBase.of(context).review})", - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12), - ), - SizedBox( - width: 70, - ), + SizedBox( + width: 30, + ), + Text( + "(${widget.item.approvedTotalReviews}${TranslationBase.of(context).review})", + style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12), + ), + SizedBox( + width: 70, + ), // if (widget.item.rxMessage != null) // Row( // children: [ @@ -247,17 +249,18 @@ class _ProductNameAndPriceState extends State { // ), // ], // ) - ], + ], + ), ), ), - ), - ], + ], + ), + ), + SizedBox( + height: 30, ), - ), - SizedBox( - height: 30, - ), - ], + ], + ), ); }