Merge branch 'development_new_design_2.0' of https://gitlab.com/Cloud_Solution/diplomatic-quarter into hussam_pharmacy_fix

 Conflicts:
	lib/pages/pharmacies/screens/product-details/product-name-and-price.dart
merge-requests/549/head
hussam al-habibeh 3 years ago
commit 141e650276

@ -2,14 +2,33 @@ package io.flutter.plugins.firebasemessaging;
import android.content.Intent; import android.content.Intent;
import java.util.concurrent.TimeUnit;
import com.google.firebase.messaging.RemoteMessage; 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 { public class CustomFlutterFirebaseMessagingService extends FlutterFirebaseMessagingService {
@Override @Override
public void onMessageReceived(RemoteMessage remoteMessage) { public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getData().containsKey("is_call")) { if (remoteMessage.getData().containsKey("is_call")) {
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent); startActivity(intent);
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
}
super.onMessageReceived(remoteMessage); super.onMessageReceived(remoteMessage);
} else } else
super.onMessageReceived(remoteMessage); super.onMessageReceived(remoteMessage);

@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
@ -20,6 +21,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-feature android:name="android.hardware.location.network" android:required="false" /> <uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" /> <uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/> <uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
@ -29,7 +31,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- Detect Reboot Permission --> <!-- Detect Reboot Permission -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<queries> <queries>
@ -41,6 +43,8 @@
android:name=".Application" android:name=".Application"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:showOnLockScreen="true"
android:screenOrientation="sensorPortrait"
android:label="Dr. Alhabib"> android:label="Dr. Alhabib">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

@ -1,6 +1,8 @@
package com.ejada.hmg package com.ejada.hmg
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.os.Build
import android.view.WindowManager
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.ejada.hmg.utils.* import com.ejada.hmg.utils.*
import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.android.FlutterFragmentActivity
@ -12,6 +14,9 @@ class MainActivity: FlutterFragmentActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine); GeneratedPluginRegistrant.registerWith(flutterEngine);
// Create Flutter Platform Bridge // Create Flutter Platform Bridge
this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON)
PlatformBridge(flutterEngine, this).create() PlatformBridge(flutterEngine, this).create()
OpenTokPlatformBridge(flutterEngine, this).create() OpenTokPlatformBridge(flutterEngine, this).create()

@ -1,6 +1,14 @@
package com.ejada.hmg.utils package com.ejada.hmg.utils
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.Intent.getIntent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.widget.Toast
import androidx.core.app.ActivityCompat.startActivityForResult
import android.net.wifi.WifiManager import android.net.wifi.WifiManager
import android.util.Log import android.util.Log
import com.ejada.hmg.MainActivity import com.ejada.hmg.MainActivity
@ -24,48 +32,56 @@ class PlatformBridge(private var flutterEngine: FlutterEngine, private var mainA
private const val ENABLE_WIFI_IF_NOT = "enableWifiIfNot" private const val ENABLE_WIFI_IF_NOT = "enableWifiIfNot"
private const val REGISTER_HMG_GEOFENCES = "registerHmgGeofences" private const val REGISTER_HMG_GEOFENCES = "registerHmgGeofences"
private const val UN_REGISTER_HMG_GEOFENCES = "unRegisterHmgGeofences" private const val UN_REGISTER_HMG_GEOFENCES = "unRegisterHmgGeofences"
private const val IS_DRAW_OVER_APPS_PERMISSION_ALLOWED = "isDrawOverAppsPermissionAllowed"
private const val ASK_DRAW_OVER_APPS_PERMISSION = "askDrawOverAppsPermission"
private const val GET_INTENT = "getIntent"
} }
fun create(){ fun create() {
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
HMGUtils.setPlatformChannel(channel) HMGUtils.setPlatformChannel(channel)
channel.setMethodCallHandler { methodCall: MethodCall, result: MethodChannel.Result -> channel.setMethodCallHandler { methodCall: MethodCall, result: MethodChannel.Result ->
if (methodCall.method == HMG_INTERNET_WIFI_CONNECT_METHOD) { if (methodCall.method == HMG_INTERNET_WIFI_CONNECT_METHOD) {
connectHMGInternetWifi(methodCall,result) connectHMGInternetWifi(methodCall, result)
}else if (methodCall.method == HMG_GUEST_WIFI_CONNECT_METHOD) { } else if (methodCall.method == HMG_GUEST_WIFI_CONNECT_METHOD) {
connectHMGGuestWifi(methodCall,result) connectHMGGuestWifi(methodCall, result)
}else if (methodCall.method == ENABLE_WIFI_IF_NOT) { } else if (methodCall.method == ENABLE_WIFI_IF_NOT) {
enableWifiIfNot(methodCall,result) enableWifiIfNot(methodCall, result)
}else if (methodCall.method == REGISTER_HMG_GEOFENCES) { } else if (methodCall.method == REGISTER_HMG_GEOFENCES) {
registerHmgGeofences(methodCall,result) registerHmgGeofences(methodCall, result)
}else if (methodCall.method == UN_REGISTER_HMG_GEOFENCES) { } else if (methodCall.method == UN_REGISTER_HMG_GEOFENCES) {
unRegisterHmgGeofences(methodCall,result) unRegisterHmgGeofences(methodCall, result)
}else{ } 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() 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 { (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'" "Missing or invalid arguments (Must have one argument 'String at 0'"
}) })
val patientId = it[0].toString() val patientId = it[0].toString()
HMG_Internet(mainActivity) HMG_Internet(mainActivity)
.connectToHMGGuestNetwork(patientId){ status, message -> .connectToHMGGuestNetwork(patientId) { status, message ->
mainActivity.runOnUiThread { mainActivity.runOnUiThread {
result.success(if(status) 1 else 0) result.success(if (status) 1 else 0)
HMGUtils.popFlutterText(mainActivity, message) HMGUtils.popFlutterText(mainActivity, message)
Log.v(this.javaClass.simpleName, "$status | $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 -> HMG_Guest(mainActivity).connectToHMGGuestNetwork { status, message ->
mainActivity.runOnUiThread { mainActivity.runOnUiThread {
result.success(if(status) 1 else 0) result.success(if (status) 1 else 0)
HMGUtils.popFlutterText(mainActivity, message) HMGUtils.popFlutterText(mainActivity, message)
Log.v(this.javaClass.simpleName, "$status | $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) { private fun enableWifiIfNot(methodCall: MethodCall, result: MethodChannel.Result) {
val wm = mainActivity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager? val wm = mainActivity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
if (wm != null){ if (wm != null) {
if (!wm.isWifiEnabled) if (!wm.isWifiEnabled)
wm.isWifiEnabled = true wm.isWifiEnabled = true
result.success(true) result.success(true)
}else } else
result.error("101","Error while opening wifi, Please try to open wifi yourself and try again","'WifiManager' service failed"); 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) { 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?) { override fun success(result: Any?) {
if(result is String) { if (result is String) {
val geoZones = GeoZoneModel().listFrom(result) 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 error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {}
override fun notImplemented() { } override fun notImplemented() {}
}) })
} }
private fun unRegisterHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) { private fun unRegisterHmgGeofences(methodCall: MethodCall, result: MethodChannel.Result) {
HMG_Geofence.shared(mainActivity).unRegisterAll { status, exception -> HMG_Geofence.shared(mainActivity).unRegisterAll { status, exception ->
if(status) if (status)
result.success(true) result.success(true)
else else
result.error("101", exception?.localizedMessage, exception); 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);
}
} }

@ -1 +1 @@
3f8c659591fcdd0e47e3895f74af395c 8d8845c5c035b7f87f2849054cdedb69

@ -520,7 +520,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.hmg.smartphone; PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@ -659,7 +659,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.hmg.smartphone; PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -692,7 +692,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.hmg.smartphone; PRODUCT_BUNDLE_IDENTIFIER = "com.HMG.HMG-Smartphone";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

@ -1,4 +1,5 @@
import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
class PackagesCustomerRequestModel { class PackagesCustomerRequestModel {
@ -19,7 +20,9 @@ class PackagesCustomerRequestModel {
this.email = user.emailAddress; this.email = user.emailAddress;
this.phone = user.mobileNumber; this.phone = user.mobileNumber;
this.national_id = user.patientIdentificationNo; this.national_id = user.patientIdentificationNo;
this.date_of_birth = user.dateofBirth;
String isoDateTime = DateUtil.getISODateFormat(user.dateofBirthDataTime);
this.date_of_birth = isoDateTime;
} }
Map<String, dynamic> json() { Map<String, dynamic> json() {

@ -3,6 +3,7 @@ class TamaraPaymentOption {
double minLimit; double minLimit;
double maxLimit; double maxLimit;
int id; int id;
bool enable = true;
String fullName() => '$name Months'; String fullName() => '$name Months';

@ -75,6 +75,7 @@ class OffersAndPackagesServices extends BaseService {
Future<List<TamaraPaymentOption>> getTamaraOptions({@required BuildContext context, @required bool showLoading = true}) async { Future<List<TamaraPaymentOption>> getTamaraOptions({@required BuildContext context, @required bool showLoading = true}) async {
if (tamaraPaymentOptions != null && tamaraPaymentOptions.isNotEmpty) return tamaraPaymentOptions; if (tamaraPaymentOptions != null && tamaraPaymentOptions.isNotEmpty) return tamaraPaymentOptions;
tamaraPaymentOptions.clear();
var url = EXA_CART_API_BASE_URL + PACKAGES_TAMARA_OPT; var url = EXA_CART_API_BASE_URL + PACKAGES_TAMARA_OPT;
await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) {
if (statusCode == 200) { if (statusCode == 200) {

@ -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/PackagesCartItemsResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.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/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/service/packages_offers/PackagesOffersServices.dart';
import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart';
import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/locator.dart';
@ -25,6 +26,22 @@ class PackagesViewModel extends BaseViewModel {
List<PackagesCartItemsResponseModel> get cartItemList => service.cartItemList; List<PackagesCartItemsResponseModel> get cartItemList => service.cartItemList;
List<HospitalsModel> get hospitals => service.hospitals; List<HospitalsModel> get hospitals => service.hospitals;
List<TamaraPaymentOption> 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 = ""; String _cartItemCount = "";

@ -169,6 +169,7 @@ class _MyApp extends State<MyApp> {
// ), // ),
// ), // ),
initialRoute: SPLASH, initialRoute: SPLASH,
// initialRoute: CALL_PAGE,
// initialRoute: OPENTOK_CALL_PAGE, // initialRoute: OPENTOK_CALL_PAGE,
// initialRoute: PACKAGES_OFFERS, // initialRoute: PACKAGES_OFFERS,
// initialRoute: PACKAGES_ORDER_COMPLETED, // initialRoute: PACKAGES_ORDER_COMPLETED,

@ -9,6 +9,7 @@ import 'package:diplomaticquarterapp/routes.dart';
import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart';
import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart'; import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart';
import 'package:diplomaticquarterapp/theme/colors.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_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.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:diplomaticquarterapp/widgets/transitions/fade_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'book_reminder_page.dart'; import 'book_reminder_page.dart';

@ -3,6 +3,7 @@ import 'dart:async';
import 'package:diplomaticquarterapp/models/LiveCare/room_model.dart'; import 'package:diplomaticquarterapp/models/LiveCare/room_model.dart';
import 'package:diplomaticquarterapp/pages/conference/conference_button_bar.dart'; import 'package:diplomaticquarterapp/pages/conference/conference_button_bar.dart';
import 'package:diplomaticquarterapp/pages/conference/conference_room.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/draggable_publisher.dart';
import 'package:diplomaticquarterapp/pages/conference/participant_widget.dart'; import 'package:diplomaticquarterapp/pages/conference/participant_widget.dart';
import 'package:diplomaticquarterapp/pages/conference/widgets/noise_box.dart'; import 'package:diplomaticquarterapp/pages/conference/widgets/noise_box.dart';
@ -152,6 +153,7 @@ class _ConferencePageState extends State<ConferencePage> {
Future<void> _onHangup() async { Future<void> _onHangup() async {
print('onHangup'); print('onHangup');
await _conferenceRoom.disconnect(); await _conferenceRoom.disconnect();
LandingPage.isOpenCallPage = false;
Navigator.of(context).pop(); Navigator.of(context).pop();
} }

@ -2,6 +2,9 @@ import 'dart:async';
import 'package:diplomaticquarterapp/pages/conference/web_rtc/widgets/cam_view_widget.dart'; 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/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/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart';
@ -9,6 +12,11 @@ import 'package:flutter_webrtc/flutter_webrtc.dart';
import '../conference_button_bar.dart'; import '../conference_button_bar.dart';
class CallHomePage extends StatefulWidget { class CallHomePage extends StatefulWidget {
final String receiverId;
final String callerId;
const CallHomePage({Key key, this.receiverId, this.callerId}) : super(key: key);
@override @override
_CallHomePageState createState() => _CallHomePageState(); _CallHomePageState createState() => _CallHomePageState();
} }
@ -24,33 +32,68 @@ class _CallHomePageState extends State<CallHomePage> {
final StreamController<double> _onButtonBarHeightStreamController = StreamController<double>.broadcast(); final StreamController<double> _onButtonBarHeightStreamController = StreamController<double>.broadcast();
//Stream to enable video //Stream to enable video
MediaStream stream; MediaStream localMediaStream;
MediaStream remoteMediaStream;
Signaling signaling = Signaling()..init();
@override @override
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
super.initState(); super.initState();
_localRenderer.initialize(); startCall();
_remoteRenderer.initialize(); }
enableVideo(); startCall() async{
await _localRenderer.initialize();
await _remoteRenderer.initialize();
final connected = await receivedCall();
} }
enableVideo() async {
//Stream to enable video Future<bool> receivedCall() async {
stream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true}); //Stream local media
// _audioButton.add(false); 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 @override
void dispose() { void dispose() {
// TODO: implement dispose // TODO: implement dispose
super.dispose(); super.dispose();
_localRenderer.dispose(); _localRenderer?.dispose();
_remoteRenderer.dispose(); _remoteRenderer?.dispose();
_audioButton.close(); _audioButton?.close();
_videoButton.close(); _videoButton?.close();
stream.dispose(); localMediaStream?.dispose();
remoteMediaStream?.dispose();
_disposeStreamsAndSubscriptions(); _disposeStreamsAndSubscriptions();
} }
@ -83,7 +126,6 @@ class _CallHomePageState extends State<CallHomePage> {
CamViewWidget( CamViewWidget(
localRenderer: _localRenderer, localRenderer: _localRenderer,
remoteRenderer: _remoteRenderer, remoteRenderer: _remoteRenderer,
stream: stream,
constraints: constraints, constraints: constraints,
onButtonBarVisibleStreamController: _onButtonBarVisibleStreamController, onButtonBarVisibleStreamController: _onButtonBarVisibleStreamController,
onButtonBarHeightStreamController: _onButtonBarHeightStreamController, onButtonBarHeightStreamController: _onButtonBarHeightStreamController,
@ -130,26 +172,25 @@ class _CallHomePageState extends State<CallHomePage> {
} }
Function _onAudioEnable() { Function _onAudioEnable() {
bool enabled = stream.getAudioTracks()[0].enabled; final audioTrack = localMediaStream.getAudioTracks()[0];
stream.getAudioTracks()[0].enabled = !enabled; final mute = audioTrack.muted;
_audioButton.add(!enabled); Helper.setMicrophoneMute(!mute, audioTrack);
_audioButton.add(mute);
} }
Function _onVideoEnabled() { Function _onVideoEnabled() {
bool enabled = stream.getVideoTracks()[0].enabled; final videoTrack = localMediaStream.getVideoTracks()[0];
stream.getVideoTracks()[0].enabled = !enabled; bool videoEnabled = videoTrack.enabled;
_videoButton.add(!enabled); localMediaStream.getVideoTracks()[0].enabled = !videoEnabled;
_videoButton.add(!videoEnabled);
} }
Function _onSwitchCamera() { Function _onSwitchCamera() {
// stream.getAudioTracks()[0].enabled = false; Helper.switchCamera(localMediaStream.getVideoTracks()[0]);
// stream.getVideoTracks()[0].enabled = false;
Helper.switchCamera(stream.getVideoTracks()[0]);
} }
void _onShowBar() { void _onShowBar() {
setState(() { setState(() {
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom, SystemUiOverlay.top]);
}); });
_onButtonBarVisibleStreamController.add(true); _onButtonBarVisibleStreamController.add(true);
} }
@ -166,7 +207,10 @@ class _CallHomePageState extends State<CallHomePage> {
} }
Future<void> _onHangup() async { Future<void> _onHangup() async {
signaling.hangupCall(widget.callerId, widget.receiverId);
print('onHangup'); print('onHangup');
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
} }

@ -9,12 +9,12 @@ import 'draggable_cam.dart';
class CamViewWidget extends StatefulWidget { class CamViewWidget extends StatefulWidget {
RTCVideoRenderer localRenderer; RTCVideoRenderer localRenderer;
RTCVideoRenderer remoteRenderer; RTCVideoRenderer remoteRenderer;
MediaStream stream; MediaStream localStream;
BoxConstraints constraints; BoxConstraints constraints;
StreamController<bool> onButtonBarVisibleStreamController; StreamController<bool> onButtonBarVisibleStreamController;
StreamController<double> onButtonBarHeightStreamController; StreamController<double> 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 @override
_CamViewWidgetState createState() => _CamViewWidgetState(); _CamViewWidgetState createState() => _CamViewWidgetState();
@ -24,16 +24,6 @@ class _CamViewWidgetState extends State<CamViewWidget> {
@override @override
void initState() { void initState() {
super.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 @override
@ -43,15 +33,18 @@ class _CamViewWidgetState extends State<CamViewWidget> {
height: double.infinity, height: double.infinity,
child: Stack( child: Stack(
children: [ children: [
Container( FractionallySizedBox(
child: RTCVideoView(widget.localRenderer, mirror: true), heightFactor: 1, widthFactor: 1,
child: Container(
child: RTCVideoView(widget.remoteRenderer, mirror: true),
),
), ),
DraggableCam( DraggableCam(
key: Key('publisher'), key: Key('publisher'),
onButtonBarHeight: widget.onButtonBarHeightStreamController.stream, onButtonBarHeight: widget.onButtonBarHeightStreamController.stream,
onButtonBarVisible: widget.onButtonBarVisibleStreamController.stream, onButtonBarVisible: widget.onButtonBarVisibleStreamController.stream,
availableScreenSize: widget.constraints.biggest, availableScreenSize: widget.constraints.biggest,
child: RTCVideoView(widget.remoteRenderer), child: RTCVideoView(widget.localRenderer),
), ),
// Expanded(child: RTCVideoView(widget.remoteRenderer)), // Expanded(child: RTCVideoView(widget.remoteRenderer)),
], ],

@ -93,6 +93,8 @@ class _FinalProductsPageState extends State<FinalProductsPage> {
isShowAppBar: true, isShowAppBar: true,
backgroundColor: Colors.white, backgroundColor: Colors.white,
isShowDecPage: false, isShowDecPage: false,
showPharmacyCart: false,
showHomeAppBarIcon: false,
baseViewModel: model, baseViewModel: model,
body: Container( body: Container(
height: MediaQuery.of(context).size.height * 5.87, height: MediaQuery.of(context).size.height * 5.87,
@ -485,7 +487,7 @@ class _FinalProductsPageState extends State<FinalProductsPage> {
color: CustomColors.green, color: CustomColors.green,
), ),
onPressed: () async { onPressed: () async {
if (model.finalProducts[index].rxMessage == null) { if (model.finalProducts[index].isRx == false) {
GifLoaderDialogUtils.showMyDialog(context); GifLoaderDialogUtils.showMyDialog(context);
await addToCartFunction(1, model.finalProducts[index].id); await addToCartFunction(1, model.finalProducts[index].id);
GifLoaderDialogUtils.hideDialog(context); GifLoaderDialogUtils.hideDialog(context);

@ -204,10 +204,15 @@ class _LandingPageState extends State<LandingPage> with WidgetsBindingObserver {
AppGlobal.context = context; AppGlobal.context = context;
if (state == AppLifecycleState.resumed) { if (state == AppLifecycleState.resumed) {
if (LandingPage.isOpenCallPage) { if (LandingPage.isOpenCallPage) {
if (Platform.isAndroid) {
return;
}
if (!isPageNavigated) { if (!isPageNavigated) {
isPageNavigated = true; isPageNavigated = true;
Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { 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<LandingPage> with WidgetsBindingObserver {
Map<String, dynamic> myMap = new Map<String, dynamic>.from(message['data']); Map<String, dynamic> myMap = new Map<String, dynamic>.from(message['data']);
print(myMap); print(myMap);
if (LandingPage.isOpenCallPage) {
return;
}
LandingPage.isOpenCallPage = true; LandingPage.isOpenCallPage = true;
LandingPage.incomingCallData = IncomingCallData.fromJson(myMap); LandingPage.incomingCallData = IncomingCallData.fromJson(myMap);
if (!isPageNavigated) { if (!isPageNavigated) {
isPageNavigated = true; isPageNavigated = true;
Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) {
isPageNavigated = false; Future.delayed(Duration(seconds: 5), () {
isPageNavigated = false;
});
}); });
} }
} else { } else {

@ -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/conference_page.dart';
import 'package:diplomaticquarterapp/pages/conference/web_rtc/call_home_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/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:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
@ -135,6 +136,7 @@ class _IncomingCallState extends State<IncomingCall> with SingleTickerProviderSt
Container( Container(
child: RawMaterialButton( child: RawMaterialButton(
onPressed: () { onPressed: () {
LandingPage.isOpenCallPage = false;
backToHome(); backToHome();
}, },
elevation: 2.0, elevation: 2.0,

@ -120,7 +120,7 @@ class _LiveCarePendingRequestState extends State<LiveCarePendingRequest> {
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)), style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)),
), ),
Container( Container(
transform: Matrix4.translationValues(0.0, 130.0, 0.0), transform: Matrix4.translationValues(0.0, 110.0, 0.0),
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
child: ButtonTheme( child: ButtonTheme(

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart'; import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart';
import 'package:diplomaticquarterapp/models/Appointments/DoctorListResponse.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_scheduling/schedule_clinic_card.dart';
import 'package:diplomaticquarterapp/pages/livecare/livecare_type_select.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_type_select.dart';
import 'package:diplomaticquarterapp/pages/livecare/widgets/LiveCareInfoDialog.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/pages/livecare/widgets/clinic_card.dart';
import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart'; import 'package:diplomaticquarterapp/services/appointment_services/GetDoctorsList.dart';
import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart';
import 'package:diplomaticquarterapp/services/livecare_services/livecare_provider.dart'; import 'package:diplomaticquarterapp/services/livecare_services/livecare_provider.dart';
import 'package:diplomaticquarterapp/theme/colors.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_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.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:diplomaticquarterapp/widgets/transitions/fade_page.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import '../live_care_payment_page.dart'; import '../live_care_payment_page.dart';
@ -180,40 +183,43 @@ class _clinic_listState extends State<ClinicList> {
navigateTo(context, LiveCarePatmentPage(getERAppointmentFeesList: getERAppointmentFeesList, waitingTime: waitingTime, clinicName: selectedClinicName)).then( navigateTo(context, LiveCarePatmentPage(getERAppointmentFeesList: getERAppointmentFeesList, waitingTime: waitingTime, clinicName: selectedClinicName)).then(
(value) { (value) {
if (value) { if (value) {
if (getERAppointmentFeesList.total == "0" || getERAppointmentFeesList.total == "0.0") { askVideoCallPermission().then((value) {
showLiveCareInfoDialog(getERAppointmentFeesList); if (value) {
} else { if (getERAppointmentFeesList.total == "0" || getERAppointmentFeesList.total == "0.0") {
navigateToPaymentMethod(getERAppointmentFeesList, context); showLiveCareInfoDialog(getERAppointmentFeesList);
} } else {
navigateToPaymentMethod(getERAppointmentFeesList, context);
}
}
});
} }
}, },
); );
// showGeneralDialog( }
// barrierColor: Colors.black.withOpacity(0.5),
// transitionBuilder: (context, a1, a2, widget) { Future<bool> askVideoCallPermission() async {
// final curvedValue = Curves.easeInOutBack.transform(a1.value) - 1.0; if (!(await Permission.camera.request().isGranted) || !(await Permission.microphone.request().isGranted)) {
// return Transform( return false;
// transform: Matrix4.translationValues(0.0, curvedValue * 200, 0.0), }
// child: Opacity( if (Platform.isAndroid && !(await PlatformBridge.shared().isDrawOverAppsPermissionAllowed())) {
// opacity: a1.value, await drawOverAppsMessageDialog(context);
// child: LiveCarePaymentDialog(getERAppointmentFeesList: getERAppointmentFeesList, waitingTime: waitingTime, clinicName: selectedClinicName), return false;
// ), }
// ); return true;
// }, }
// transitionDuration: Duration(milliseconds: 500),
// barrierDismissible: true, Future drawOverAppsMessageDialog(BuildContext context) async {
// barrierLabel: '', ConfirmDialog dialog = new ConfirmDialog(
// context: context, context: context,
// pageBuilder: (context, animation1, animation2) {}) confirmMessage: "Please select 'Dr. Alhabib' from the list and allow draw over app permission to use live care.",
// .then((value) { okText: TranslationBase.of(context).confirm,
// if (value) { cancelText: TranslationBase.of(context).cancel_nocaps,
// if (getERAppointmentFeesList.total == "0" || getERAppointmentFeesList.total == "0.0") { okFunction: () async {
// showLiveCareInfoDialog(getERAppointmentFeesList); await PlatformBridge.shared().askDrawOverAppsPermission();
// } else { Navigator.pop(context);
// navigateToPaymentMethod(getERAppointmentFeesList, context); },
// } cancelFunction: () => {});
// } dialog.showAlertDialog(context);
// });
} }
showLiveCareInfoDialog(GetERAppointmentFeesList getERAppointmentFeesList) async { showLiveCareInfoDialog(GetERAppointmentFeesList getERAppointmentFeesList) async {
@ -452,7 +458,7 @@ class _clinic_listState extends State<ClinicList> {
children: <Widget>[ children: <Widget>[
isDataLoaded isDataLoaded
? Expanded( ? Expanded(
child: Container( child: Container(
child: liveCareScheduleClinicsListResponse.clinicsHaveScheduleList.length > 0 child: liveCareScheduleClinicsListResponse.clinicsHaveScheduleList.length > 0
? Column( ? Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -484,30 +490,30 @@ class _clinic_listState extends State<ClinicList> {
) )
: getNoDataWidget(context), : getNoDataWidget(context),
), ),
) )
: Container(), : Container(),
isDataLoaded isDataLoaded
? Container( ? Container(
width: double.infinity, width: double.infinity,
color: Colors.white, color: Colors.white,
padding: EdgeInsets.all(12), padding: EdgeInsets.all(12),
child: ButtonTheme( child: ButtonTheme(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), ),
minWidth: MediaQuery.of(context).size.width * 0.7, minWidth: MediaQuery.of(context).size.width * 0.7,
height: 45.0, height: 45.0,
child: RaisedButton( child: RaisedButton(
color: CustomColors.accentColor, color: CustomColors.accentColor,
textColor: Colors.white, textColor: Colors.white,
elevation: 0, elevation: 0,
disabledTextColor: Colors.white, disabledTextColor: Colors.white,
disabledColor: new Color(0xFFbcc2c4), disabledColor: new Color(0xFFbcc2c4),
onPressed: startScheduleLiveCare, onPressed: startScheduleLiveCare,
child: Text(TranslationBase.of(context).start, style: TextStyle(fontSize: 18.0)), child: Text(TranslationBase.of(context).start, style: TextStyle(fontSize: 18.0)),
),
), ),
), )
)
: Container(), : Container(),
], ],
); );
@ -542,10 +548,6 @@ class _clinic_listState extends State<ClinicList> {
); );
}, },
), ),
// Container(
// margin: EdgeInsets.all(15.0),
// child: Text(TranslationBase.of(context).offlineClinics, style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)),
// ),
ListView.builder( ListView.builder(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
shrinkWrap: true, shrinkWrap: true,

@ -263,13 +263,18 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
} }
fetchData() async { fetchData() async {
await viewModel.service.cartItems(context: context).then((value) { final cartResponse = await viewModel.service.cartItems(context: context).catchError((error) {});
subtotal = value['subtotal'] ?? 0.0; if(cartResponse != null){
tax = value['tax'] ?? 0.0; subtotal = cartResponse['subtotal'] ?? 0.0;
total = value['total'] ?? 0.0; tax = cartResponse['tax'] ?? 0.0;
}).catchError((error) {}); total = cartResponse['total'] ?? 0.0;
viewModel.service.getTamaraOptions(context: context, showLoading: true).then((tamara_options){
setState(() {}); if(tamara_options != null || tamara_options.isNotEmpty) {
viewModel.setTamaraIllegablity(total);
setState(() {});
}
});
}
} }
paymentClosed({@required int orderId, @required bool withStatus, dynamic data}) async { paymentClosed({@required int orderId, @required bool withStatus, dynamic data}) async {
@ -282,6 +287,7 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
debugPrint(error); debugPrint(error);
}); });
} }
} }
// Widget _payNow(BuildContext context, {double subtotal, double tax, double total, @required VoidCallback onPayNowClick}) { // Widget _payNow(BuildContext context, {double subtotal, double tax, double total, @required VoidCallback onPayNowClick}) {

File diff suppressed because it is too large Load Diff

@ -37,6 +37,7 @@ class _ProductCheckTypeWidgetState extends State<ProductCheckTypeWidget> {
productImage: widget.model.wishListList[index].product.images[0].src, productImage: widget.model.wishListList[index].product.images[0].src,
productID: widget.model.wishListList[index].product.id, productID: widget.model.wishListList[index].product.id,
onDelete: deleteWishListItem, onDelete: deleteWishListItem,
isRx:widget.model.wishListList[index].product.isRx,
), ),
), ),

@ -33,6 +33,9 @@ class _ComparePageState extends State<ComparePage> {
appBarTitle: TranslationBase.of(context).compare, appBarTitle: TranslationBase.of(context).compare,
isShowAppBar: true, isShowAppBar: true,
isPharmacy: true, isPharmacy: true,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isBottomBar: true,
body: SingleChildScrollView( body: SingleChildScrollView(
child: Container( child: Container(
child: compareList(), child: compareList(),

@ -26,6 +26,9 @@ class _MyReviewsPageState extends State<MyReviewsPage> {
appBarTitle: TranslationBase.of(context).reviews, appBarTitle: TranslationBase.of(context).reviews,
isShowAppBar: true, isShowAppBar: true,
isPharmacy: true, isPharmacy: true,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isBottomBar: true,
baseViewModel: model, baseViewModel: model,
body: model.reviewListList.length == 0 body: model.reviewListList.length == 0
? Container( ? Container(

@ -186,30 +186,30 @@ class __ProductDetailPageState extends State<ProductDetailPage> {
), ),
), ),
SizedBox( 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(
// 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( Container(
// width: 500, // width: 500,
margin: EdgeInsets.only(bottom: 10), margin: EdgeInsets.only(bottom: 10),
@ -233,7 +233,7 @@ class __ProductDetailPageState extends State<ProductDetailPage> {
}, },
child: Text( child: Text(
TranslationBase.of(context).details, TranslationBase.of(context).details,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14),
), ),
color: Colors.white, color: Colors.white,
), ),
@ -264,7 +264,7 @@ class __ProductDetailPageState extends State<ProductDetailPage> {
}, },
child: Text( child: Text(
TranslationBase.of(context).reviews, TranslationBase.of(context).reviews,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14),
), ),
color: Colors.white, color: Colors.white,
), ),
@ -294,7 +294,7 @@ class __ProductDetailPageState extends State<ProductDetailPage> {
: null, : null,
child: Text( child: Text(
TranslationBase.of(context).availability, TranslationBase.of(context).availability,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14),
), ),
color: Colors.white, color: Colors.white,
), ),

@ -37,38 +37,108 @@ class _ProductNameAndPriceState extends State<ProductNameAndPrice> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
ProjectViewModel projectViewModel = Provider.of(context); ProjectViewModel projectViewModel = Provider.of(context);
return Column( return Container(
mainAxisAlignment: MainAxisAlignment.start, color: Color(0xffF7F7F7),
children: [ child: Column(
SizedBox( mainAxisAlignment: MainAxisAlignment.start,
height: 10, children: [
), SizedBox(
FractionallySizedBox( height: 10,
widthFactor: 0.95, ),
child: Row( widget.item.rxMessage != null
mainAxisAlignment: MainAxisAlignment.spaceBetween, ? Container(
children: [ // width: widget.item.rxMessage != null ? MediaQuery.of(context).size.width / 2.8 : 0,
Texts(widget.item.price.toString() + " " + TranslationBase.of(context).sar, fontWeight: FontWeight.bold, fontSize: 20), width: double.infinity,
if(widget.isStockAvailable != null) height: 40,
Texts( padding: EdgeInsets.all(4),
widget.stockAvailability, decoration: BoxDecoration(
fontWeight: FontWeight.bold, color: Color(0xffD02127),
fontSize: 15, // color: Colors.red[700]
color: widget.isStockAvailable ? Colors.green : Colors.red, // borderRadius: BorderRadius.only(topLeft: Radius.circular(6)),
), ),
// SizedBox(width: 20), child: Row(
if (widget.authenticatedUserObject.isLogin) children: [
!widget.isStockAvailable && widget.customerId != null Padding(
?BorderedButton( padding: const EdgeInsets.only(left: 8, right: 8),
TranslationBase.of(context).notifyMe, child: Icon(
hasBorder: true, Icons.warning,
borderColor: Colors.green, color: Colors.white,
textColor: Colors.green, ),
fontWeight: FontWeight.bold, ),
vPadding: 6, Text(
hPadding: 14, projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(),
handler: () => widget.notifyMeWhenAvailable(context, widget.item.id), 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),
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
?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( // InkWell(
// onTap: () => widget.notifyMeWhenAvailable(context, widget.item.id), // onTap: () => widget.notifyMeWhenAvailable(context, widget.item.id),
// child: Row(children: [ // child: Row(children: [
@ -85,97 +155,118 @@ class _ProductNameAndPriceState extends State<ProductNameAndPrice> {
// ) // )
// ]), // ]),
// ) // )
: IconWithBg( // : IconWithBg(
icon: !widget.isInWishList ? Icons.favorite_border : Icons.favorite, // icon: !widget.isInWishList ? Icons.favorite_border : Icons.favorite,
color: !widget.isInWishList ? Colors.white : Colors.red[800], // color: !widget.isInWishList ? Colors.white : Colors.red[800],
onPress: () async { // onPress: () async {
{ // {
if (widget.customerId != null) { // if (widget.customerId != null) {
if (!widget.isInWishList) { // if (!widget.isInWishList) {
await widget.addToWishlistFunction(widget.item.id); // await widget.addToWishlistFunction(widget.item.id);
} else { // } else {
await widget.deleteFromWishlistFunction(widget.item.id); // await widget.deleteFromWishlistFunction(widget.item.id);
} // }
} else { // } else {
return; // return;
} // }
setState(() {}); // setState(() {});
} // }
}, // },
) // )
], ],
),
), ),
), Padding(
Padding( padding: const EdgeInsets.only(left: 8,right: 8, top: 1, bottom: 15),
padding: const EdgeInsets.all(8.0), child: Container(
child: Container( margin: EdgeInsets.only(left: 5, right: 5),
margin: EdgeInsets.only(left: 5), child: Align(
child: Align( alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft,
alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft, child: Text(
child: Text( projectViewModel.isArabic ? widget.item.namen : widget.item.name,
projectViewModel.isArabic ? widget.item.namen : widget.item.name, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ),
), ),
), ),
), ),
), Padding(
FractionallySizedBox( padding: const EdgeInsets.only(left: 8,right: 8),
widthFactor: 0.95, child: Container(
child: Row( margin: EdgeInsets.only(left: 5, right: 5),
children: [ child: Align(
Container( alignment: projectViewModel.isArabic ? Alignment.topRight : Alignment.topLeft,
child: Align( child: Text( TranslationBase.of(context).sar+ " " +
alignment: Alignment.bottomLeft, widget.item.price.toString(),
child: Row( style: TextStyle(fontWeight: FontWeight.bold, fontSize: 19),),
children: [ ),
RatingBar.readOnly( ),
initialRating: double.parse(widget.item.approvedRatingSum.toString()),
size: 15.0, ),
filledColor: Colors.yellow[700], FractionallySizedBox(
emptyColor: Colors.grey[400], widthFactor: 0.95,
isHalfAllowed: true, child: Row(
halfFilledIcon: Icons.star_half, children: [
filledIcon: Icons.star, Container(
emptyIcon: Icons.star, child: Align(
), alignment: Alignment.bottomLeft,
SizedBox( child: Row(
width: 10, 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( // Texts(
// "${widget.item.approvedRatingSum}", // "${widget.item.approvedRatingSum}",
// fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
// fontSize: 12, // fontSize: 12,
// ), // ),
SizedBox( SizedBox(
width: 30, width: 30,
), ),
Texts( Text(
"(${widget.item.approvedTotalReviews}${TranslationBase.of(context).review})", "(${widget.item.approvedTotalReviews}${TranslationBase.of(context).review})",
fontSize: 12, style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
), ),
SizedBox( SizedBox(
width: 70, width: 70,
), ),
if (widget.item.rxMessage != null) // if (widget.item.rxMessage != null)
Row( // Row(
children: [ // children: [
Text( // Text(
projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(), // projectViewModel.isArabic ? widget.item.rxMessagen.toString() : widget.item.rxMessage.toString(),
style: TextStyle(color: Colors.red, fontSize: 10), // style: TextStyle(color: Colors.red, fontSize: 10),
), // ),
], // ],
) // )
], ],
),
), ),
), ),
), ],
], ),
), ),
), SizedBox(
SizedBox( height: 30,
height: 10, ),
), ],
], ),
); );
} }
Color getStatusBackgroundColor() {
if (widget.isStockAvailable)
return Color(0xFF5AB145);
else return Color(0xFFD02127);
}
} }

@ -77,9 +77,14 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget {
icon: Icons.shopping_cart, icon: Icons.shopping_cart,
color: Color(0xFF2B353E), color: Color(0xFF2B353E),
onPress: () { onPress: () {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
locator<NavigationService>().navigatorKey.currentContext, MaterialPageRoute(builder: (context) => LandingPagePharmacy(currentTab: 3)), (Route<dynamic> r) => false); locator<NavigationService>()
.navigatorKey
.currentContext,
MaterialPageRoute(
builder: (context) =>
LandingPagePharmacy(currentTab: 3)),
(Route<dynamic> r) => false);
// Navigator.push( // Navigator.push(
// context, // context,
// MaterialPageRoute(builder: (context) => CartOrderPage()), // MaterialPageRoute(builder: (context) => CartOrderPage()),
@ -145,7 +150,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget {
return Container( return Container(
child: new Wrap( child: new Wrap(
children: <Widget>[ children: <Widget>[
if (product.stockAvailability != 'Out of stock') if (product.stockAvailability != 'Out of stock' && product.isRx != true)
new ListTile( new ListTile(
leading: Icon(Icons.shopping_cart), leading: Icon(Icons.shopping_cart),
title: Text( title: Text(
@ -162,9 +167,10 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget {
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
} else { } else {
AppToast.showErrorToast(message: TranslationBase.of(context).addQuantity AppToast.showErrorToast(
// "you should add quantity" message: TranslationBase.of(context).addQuantity
); // "you should add quantity"
);
} }
}), }),
ListTile( ListTile(
@ -191,7 +197,7 @@ class ProductAppBar extends StatelessWidget with PreferredSizeWidget {
), ),
onTap: () { onTap: () {
Provider.of<CompareList>(context, listen: false) Provider.of<CompareList>(context, listen: false)
.addItem(specificationData,context); .addItem(specificationData, context);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),

@ -252,7 +252,7 @@ class _ProductOrderItemState extends State<ProductOrderItem> {
} }
_quantityController.text = "${widget.item.quantity}"; _quantityController.text = "${widget.item.quantity}";
_totalPrice = _totalPrice =
"${(widget.item.product.price * widget.item.quantity).toStringAsFixed(2)}"; "${(widget.item.product.price * widget.item.quantity).toStringAsFixed(2)}";
} }
}); });
} }

@ -17,6 +17,9 @@ class WishlistPage extends StatelessWidget {
isShowAppBar: true, isShowAppBar: true,
isShowDecPage: false, isShowDecPage: false,
isPharmacy: true, isPharmacy: true,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isBottomBar: true,
baseViewModel: model, baseViewModel: model,
body: model.wishListList.length == 0 body: model.wishListList.length == 0
? Container( ? Container(
@ -35,8 +38,8 @@ class WishlistPage extends StatelessWidget {
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(TranslationBase.of(context).noData,
'There is no data', // 'There is no data',
style: TextStyle(fontSize: 30), style: TextStyle(fontSize: 30),
), ),
) )

@ -66,6 +66,9 @@ class _OrderPageState extends State<OrderPage> with SingleTickerProviderStateMix
baseViewModel: model, baseViewModel: model,
isShowAppBar: true, isShowAppBar: true,
isPharmacy: true, isPharmacy: true,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isBottomBar: true,
body: Container( body: Container(
child: Column( child: Column(
children: [ children: [

@ -84,6 +84,9 @@ class _OrderDetailsPageState extends State<OrderDetailsPage> {
appBarTitle: TranslationBase.of(context).orderDetail, appBarTitle: TranslationBase.of(context).orderDetail,
isShowAppBar: true, isShowAppBar: true,
isPharmacy: true, isPharmacy: true,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isBottomBar: true,
baseViewModel: model, baseViewModel: model,
body: model.orderListModel.length > 0 body: model.orderListModel.length > 0
? Container( ? Container(

@ -108,10 +108,10 @@ class _ProfilePageState extends State<PharmacyProfilePage> {
builder: (_, model, wi) => AppScaffold( builder: (_, model, wi) => AppScaffold(
appBarTitle: TranslationBase.of(context).myAccount, appBarTitle: TranslationBase.of(context).myAccount,
isShowAppBar: true, isShowAppBar: true,
isShowDecPage: true, isShowDecPage: false,
isPharmacy: true, isPharmacy: true,
showPharmacyCart: false,
//isBottomBar: true, showHomeAppBarIcon: false,
isMainPharmacyPages: true, isMainPharmacyPages: true,
body: user != null body: user != null
? Container( ? Container(

@ -40,11 +40,13 @@ class _SubCategoriseModalsheetState extends State<SubCategoriseModalsheet> {
builder: (_, model, wi) => AppScaffold( builder: (_, model, wi) => AppScaffold(
// appBarTitle: titleName, // appBarTitle: titleName,
appBarTitle: TranslationBase.of(context).categorise, appBarTitle: TranslationBase.of(context).categorise,
isBottomBar: false, isBottomBar: true,
isShowAppBar: true, isShowAppBar: true,
isPharmacy: true, isPharmacy: true,
backgroundColor: Colors.white, backgroundColor: Colors.white,
isShowDecPage: false, isShowDecPage: false,
showPharmacyCart: false,
showHomeAppBarIcon: false,
baseViewModel: model, baseViewModel: model,
body: Container( body: Container(
color: Colors.white, color: Colors.white,
@ -77,7 +79,11 @@ class _SubCategoriseModalsheetState extends State<SubCategoriseModalsheet> {
context, context,
FadePage( FadePage(
page: SubCategorisePage( 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, id: model.categoriseParent[index].id,
parentId: id, parentId: id,
)), )),

@ -14,6 +14,7 @@ import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; import 'package:diplomaticquarterapp/widgets/buttons/button.dart';
import 'package:diplomaticquarterapp/widgets/data_display/text.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_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/entity_checkbox_list.dart';
import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart'; import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart';
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
@ -76,12 +77,15 @@ class _SubCategorisePageState extends State<SubCategorisePage> {
allowAny: true, allowAny: true,
builder: (BuildContext context, PharmacyCategoriseViewModel model, builder: (BuildContext context, PharmacyCategoriseViewModel model,
Widget child) => Widget child) =>
PharmacyAppScaffold( AppScaffold(
isPharmacy: true,
appBarTitle: title, appBarTitle: title,
isBottomBar: false, isBottomBar: true,
isShowAppBar: true, isShowAppBar: true,
backgroundColor: Colors.white, backgroundColor: Colors.white,
isShowDecPage: false, isShowDecPage: false,
showPharmacyCart: false,
showHomeAppBarIcon: false,
baseViewModel: model, baseViewModel: model,
body: SmartRefresher( body: SmartRefresher(
controller: controller, controller: controller,
@ -1219,8 +1223,7 @@ class _SubCategorisePageState extends State<SubCategorisePage> {
if (model if (model
.subProducts[ .subProducts[
index] index]
.rxMessage == .isRx == false) {
null) {
GifLoaderDialogUtils GifLoaderDialogUtils
.showMyDialog( .showMyDialog(
context); context);

@ -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/pages/webRTC/signaling.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.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/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.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 { class CallPage extends StatefulWidget {
@override @override
_CallPageState createState() => _CallPageState(); _CallPageState createState() => _CallPageState();
@ -20,10 +32,12 @@ class _CallPageState extends State<CallPage> {
_localRenderer.initialize(); _localRenderer.initialize();
_remoteRenderer.initialize(); _remoteRenderer.initialize();
signaling.onAddRemoteStream = ((stream) { // signaling.onRemoteStream = ((stream) {
_remoteRenderer.srcObject = stream; // _remoteRenderer.srcObject = stream;
setState(() {}); // setState(() {});
}); // });
fcmConfigure();
super.initState(); super.initState();
} }
@ -35,24 +49,13 @@ class _CallPageState extends State<CallPage> {
super.dispose(); super.dispose();
} }
void _getUserMedia() async {
final Map<String, dynamic> constraints = {
'audio': 'false',
'video': {'facingMode': 'user'},
};
MediaStream stream = await navigator.mediaDevices.getUserMedia(constraints);
setState(() {
_localRenderer.srcObject = stream;
});
}
void initializeRenderers() async {
_localRenderer.initialize();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
FirebaseMessaging().getToken().then((value){
print('FCM_TOKEN: $value');
});
return AppScaffold( return AppScaffold(
isShowAppBar: true, isShowAppBar: true,
showNewAppBar: true, showNewAppBar: true,
@ -64,37 +67,14 @@ class _CallPageState extends State<CallPage> {
SizedBox(height: 8), SizedBox(height: 8),
Wrap( Wrap(
children: [ 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( SizedBox(
width: 8, width: 8,
), ),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
// Add roomId dummyCall();
signaling.joinRoom(
textEditingController.text,
_remoteRenderer,
);
}, },
child: Text("Join room"), child: Text("Call"),
), ),
SizedBox( SizedBox(
width: 8, width: 8,
@ -143,5 +123,57 @@ class _CallPageState extends State<CallPage> {
], ],
), ),
); );
} }
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)));
}
);
}
} }

@ -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<CallPage> {
// 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<String, dynamic> 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)
// ],
// ),
// );
// }
// }

@ -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<bool> 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;
}

@ -1,11 +1,45 @@
import 'dart:convert'; 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';
import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'call_page.dart';
typedef void StreamStateCallback(MediaStream stream); typedef void StreamStateCallback(MediaStream stream);
typedef void RTCIceGatheringStateCallback(RTCIceGatheringState state);
typedef void RTCPeerConnectionStateCallback(RTCPeerConnectionState state);
typedef void RTCSignalingStateCallback(RTCSignalingState state);
class Signaling { 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<String, dynamic> configuration = { Map<String, dynamic> configuration = {
'iceServers': [ 'iceServers': [
{ {
@ -14,209 +48,96 @@ class Signaling {
] ]
}; };
SignalRUtil signalR;
RTCPeerConnection peerConnection; RTCPeerConnection peerConnection;
MediaStream localStream; MediaStream localStream;
MediaStream remoteStream; MediaStream remoteStream;
String roomId; RTCDataChannel dataChannel;
String currentRoomText;
StreamStateCallback onAddRemoteStream;
Future<String> createRoom(RTCVideoRenderer remoteRenderer) async {
FirebaseFirestore db = FirebaseFirestore.instance;
DocumentReference roomRef = db.collection('rooms').doc();
print('Create PeerConnection with configuration: $configuration'); Future<bool> 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(); return isCallPlaced;
}
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<String, dynamic> roomWithOffer = {'offer': offer.toMap()};
await roomRef.set(roomWithOffer); Future<bool> acceptCall(String caller, String receiver, {@required MediaStream localMediaStream, @required Function(MediaStream) onRemoteMediaStream}) async{
var roomId = roomRef.id; await initializeSignalR();
print('New room created with SDK offer. Room ID: $roomId'); signalR.setContributors(caller: caller, receiver: receiver);
currentRoomText = 'Current room is $roomId - You are the caller!'; await signalR.acceptCall(receiver, caller).catchError((e) => throw 'Failed to inform signalR that i accepted a call');
// Created a Room
peerConnection?.onTrack = (RTCTrackEvent event) { peerConnection.addStream(localMediaStream);
print('Got remote track: ${event.streams[0]}');
event.streams[0].getTracks().forEach((track) { peerConnection?.onAddStream = (MediaStream stream) {
print('Add a track to the remoteStream $track'); remoteStream = stream;
remoteStream?.addTrack(track); onRemoteMediaStream?.call(stream);
});
}; };
// Listening for remote session description below return true;
roomRef.snapshots().listen((snapshot) async {
print('Got updated room: ${snapshot.data()}');
Map<String, dynamic> data = snapshot.data() as Map<String, dynamic>;
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<String, dynamic> data = change.doc.data() as Map<String, dynamic>;
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<void> joinRoom(String roomId, RTCVideoRenderer remoteVideo) async { Future hangupCall(String caller, String receiver) async{
FirebaseFirestore db = FirebaseFirestore.instance; await signalR.hangupCall(caller, receiver);
DocumentReference roomRef = db.collection('rooms').doc('$roomId'); dispose();
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<String, dynamic>;
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<String, dynamic> 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<String, dynamic>;
// print(data);
// print('Got new remote ICE candidate: $data');
// peerConnection.addCandidate(
// RTCIceCandidate(
// data['candidate'],
// data['sdpMid'],
// data['sdpMLineIndex'],
// ),
// );
// });
// });
}
} }
Future<void> openUserMedia( answerOffer(String sdp) async{
RTCVideoRenderer localVideo, final offer = jsonDecode(sdp);
RTCVideoRenderer remoteVideo, final caller = offer['caller'];
) async { final receiver = offer['target'];
var stream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': false}); final offerSdp = offer['sdp'];
peerConnection.setRemoteDescription(rtcSessionDescriptionFrom(offerSdp))
localVideo.srcObject = stream; .then((value) {
localStream = stream; 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<void> hangUp(RTCVideoRenderer localVideo) async { Future<void> hangUp(RTCVideoRenderer localVideo) async {
List<MediaStreamTrack> 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) { Future<String> createSdpAnswer(String toOfferSdp) async {
var db = FirebaseFirestore.instance; final offerSdp = rtcSessionDescriptionFrom(jsonDecode(toOfferSdp));
var roomRef = db.collection('rooms').doc(roomId); peerConnection.setRemoteDescription(offerSdp);
var calleeCandidates = await roomRef.collection('calleeCandidates').get();
calleeCandidates.docs.forEach((document) => document.reference.delete());
var callerCandidates = await roomRef.collection('callerCandidates').get(); final answer = await peerConnection.createAnswer();
callerCandidates.docs.forEach((document) => document.reference.delete()); var answerSdp = json.encode(answer); // Send SDP via Push or any channel
return answerSdp;
}
await roomRef.delete(); Future<String> 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(); addCandidate(String candidateJson){
remoteStream?.dispose(); peerConnection.addCandidate(rtcIceCandidateFrom(candidateJson));
} }
void registerPeerConnectionListeners() { void registerPeerConnectionListeners() {
peerConnection.onIceCandidate = (RTCIceCandidate candidate){
print(json.encode(candidate.toMap()));
signalR.addIceCandidate(json.encode(candidate.toMap()));
};
peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { peerConnection?.onIceGatheringState = (RTCIceGatheringState state) {
print('ICE gathering state changed: $state'); print('ICE gathering state changed: $state');
}; };
@ -228,15 +149,17 @@ class Signaling {
peerConnection?.onSignalingState = (RTCSignalingState state) { peerConnection?.onSignalingState = (RTCSignalingState state) {
print('Signaling state change: $state'); print('Signaling state change: $state');
}; };
}
}
peerConnection?.onIceGatheringState = (RTCIceGatheringState state) {
print('ICE connection state change: $state');
};
peerConnection?.onAddStream = (MediaStream stream) { rtcSessionDescriptionFrom(Map sdp){
print("Add remote stream"); return RTCSessionDescription(
onAddRemoteStream?.call(stream); sdp['sdp'],sdp['type'],
remoteStream = stream; );
}; }
}
rtcIceCandidateFrom(String json){
final map = jsonDecode(json)['candidate'];
return RTCIceCandidate(map['candidate'], map['sdpMid'], map['sdpMLineIndex']);
} }

@ -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<String, dynamic> 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<String> 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<String, dynamic> 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<String, dynamic> data = snapshot.data() as Map<String, dynamic>;
// 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<String, dynamic> data = change.doc.data() as Map<String, dynamic>;
// 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<void> 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<String, dynamic>;
// 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<String, dynamic> 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<String, dynamic>;
// // print(data);
// // print('Got new remote ICE candidate: $data');
// // peerConnection.addCandidate(
// // RTCIceCandidate(
// // data['candidate'],
// // data['sdpMid'],
// // data['sdpMLineIndex'],
// // ),
// // );
// // });
// // });
// }
}
Future<void> 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<void> hangUp(RTCVideoRenderer localVideo) async {
List<MediaStreamTrack> 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;
};
}
}

@ -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/select-gender.dart';
import 'package:diplomaticquarterapp/pages/symptom-checker/symtom-checker.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/symtom-checker.dart';
import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.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'; import 'package:diplomaticquarterapp/splashPage.dart';
const String INIT_ROUTE = '/'; const String INIT_ROUTE = '/';
@ -48,6 +50,7 @@ const String PACKAGES_ORDER_COMPLETED = 'packages-offers-cart';
const String TEST_PAGE = 'test-page'; const String TEST_PAGE = 'test-page';
const String OPENTOK_CALL_PAGE = 'OPENTOK_CALL_PAGE'; const String OPENTOK_CALL_PAGE = 'OPENTOK_CALL_PAGE';
const String CART_ORDER_PAGE = 'cart-order-page'; const String CART_ORDER_PAGE = 'cart-order-page';
const String CALL_PAGE = 'CALL_PAGE';
const String HEALTH_WEATHER = 'health-weather'; const String HEALTH_WEATHER = 'health-weather';
const APP_UPDATE = 'app-update'; const APP_UPDATE = 'app-update';
@ -76,6 +79,7 @@ var routes = {
APP_UPDATE: (_) => AppUpdatePage(), APP_UPDATE: (_) => AppUpdatePage(),
SETTINGS: (_) => Settings(), SETTINGS: (_) => Settings(),
CART_ORDER_PAGE: (_) => CartOrderPage(), CART_ORDER_PAGE: (_) => CartOrderPage(),
CALL_PAGE: (_) => CallPage(),
OPENTOK_CALL_PAGE: (_) => OpenTokConnectCallPage( OPENTOK_CALL_PAGE: (_) => OpenTokConnectCallPage(
apiKey: '46209962', apiKey: '46209962',
sessionId: '1_MX40NjIwOTk2Mn5-MTYzNDY0ODM3NDY2Nn5PcnpnNGM0R1Q3ODZ6UXlFQ01lMDF5YWJ-fg', sessionId: '1_MX40NjIwOTk2Mn5-MTYzNDY0ODM3NDY2Nn5PcnpnNGM0R1Q3ODZ6UXlFQ01lMDF5YWJ-fg',

@ -1,4 +1,3 @@
import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/localized_values.dart'; import 'package:diplomaticquarterapp/config/localized_values.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
@ -89,6 +88,9 @@ class PlatformBridge {
static const show_loading_method = "loading"; static const show_loading_method = "loading";
static const register_Hmg_Geofences = "registerHmgGeofences"; static const register_Hmg_Geofences = "registerHmgGeofences";
static const un_register_Hmg_Geofences = "unRegisterHmgGeofences"; 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<Object> connectHMGInternetWifi(String patientId) { Future<Object> connectHMGInternetWifi(String patientId) {
try { try {
@ -142,4 +144,19 @@ class PlatformBridge {
void unRegisterHmgGeofences() async { void unRegisterHmgGeofences() async {
var result = await platform.invokeMethod(un_register_Hmg_Geofences); var result = await platform.invokeMethod(un_register_Hmg_Geofences);
} }
Future<bool> isDrawOverAppsPermissionAllowed() async {
var result = await platform.invokeMethod(IS_DRAW_OVER_APPS_PERMISSION_ALLOWED);
return result as bool;
}
Future<bool> askDrawOverAppsPermission() async {
var result = await platform.invokeMethod(ASK_DRAW_OVER_APPS_PERMISSION);
return result as bool;
}
Future<bool> getIntentData() async {
var result = await platform.invokeMethod(GET_INTENT);
return result as bool;
}
} }

@ -1,36 +1,57 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:http/io_client.dart'; import 'package:http/io_client.dart';
import 'package:signalr_core/signalr_core.dart'; import 'package:signalr_core/signalr_core.dart';
class SignalRUtil { class SignalRUtil {
String hubName; 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 { closeConnection() async{
connectionBuilder = HubConnectionBuilder() 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<bool> openConnection() async {
connectionHub = HubConnectionBuilder()
.withUrl( .withUrl(
hubName, hubName,
HttpConnectionOptions( HttpConnectionOptions(
client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true), logMessageContent: true,
logging: (level, message) => print(message), client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true),
)) logging: (level, message) => print(message),
.build(); )).build();
await connectionBuilder.start(); await connectionHub.start();
await Future.delayed(Duration(seconds: 1));
connectionBuilder.on('ReceiveMessage', (message) { connectionHub.on('ReceiveMessage', (message) {
handleIncomingMessage(message); handleIncomingMessage(message);
}); });
}
void closeSignalRConnection() { return getConnectionState();
connectionBuilder.stop();
} }
void handleIncomingMessage(List<dynamic> message) { void handleIncomingMessage(List<dynamic> message) {
@ -38,11 +59,114 @@ class SignalRUtil {
} }
void sendMessage(List<dynamic> args) async { void sendMessage(List<dynamic> 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<dynamic> callUser(String from, to) async{
return await connectionHub.invoke('CallUserAsync', args: [from, to]);
}
// CallDeclinedAsync(string currentUserId, string targerUserId)
Future<dynamic> declineCall(String from, to) async{
return await connectionHub.invoke('CallDeclinedAsync', args: [from, to]);
}
// AnswerCallAsync(string currentUserId, string targetUserId)
Future<dynamic> answerCall(String from, to) async{
return await connectionHub.invoke('AnswerCallAsync', args: [from, to]);
}
// IceCandidateAsync(string targetUserId, string candidate)
Future<dynamic> addIceCandidate(String candidate) async{
final target = destinationUser;
return await connectionHub.invoke('IceCandidateAsync', args: [target, candidate]);
}
// OfferAsync(string targetUserId,string currentUserId, string targetOffer)
Future<dynamic> offer(String from, to, offer) async{
return await connectionHub.invoke('OfferAsync', args: [from, to, offer]);
}
// AnswerOfferAsync(string targetUserId, string CallerOffer)
Future<dynamic> 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<dynamic> hangupCall(String from, to) async{
return await connectionHub.invoke('HangUpAsync', args: [from, to]);
}
// CallAccepted(string currentUserId,string targetUserId)
Future<dynamic> acceptCall(String from, to) async{
return await connectionHub.invoke('CallAccepted', args: [from, to]);
}
bool getConnectionState() { bool getConnectionState() {
if (connectionBuilder.state == HubConnectionState.connected || connectionBuilder.state == HubConnectionState.connecting) return true; if (connectionHub.state == HubConnectionState.connected) return true;
if (connectionBuilder.state == HubConnectionState.disconnected || connectionBuilder.state == HubConnectionState.disconnecting) return false; 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'];
}
}

@ -131,6 +131,10 @@ class DateUtil {
dateObj.year.toString(); dateObj.year.toString();
} }
static String getISODateFormat(DateTime dateTime){ // 2020-04-30T00:00:00.000
return dateTime.toIso8601String();
}
/// get month by /// get month by
/// [month] convert month number in to month name /// [month] convert month number in to month name
static getMonth(int month) { static getMonth(int month) {

@ -15,6 +15,7 @@ import 'package:diplomaticquarterapp/pages/DrawerPages/notifications/notificatio
import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/pages/landing/landing_page.dart';
import 'package:diplomaticquarterapp/pages/rateAppointment/rate_appointment_doctor.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.dart';
import 'package:diplomaticquarterapp/pages/webRTC/call_page_bkp.dart';
import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/routes.dart';
import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart';
import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart'; import 'package:diplomaticquarterapp/services/clinic_services/get_clinic_service.dart';

@ -1,13 +1,16 @@
import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart';
import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_detail_view_model.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/pharmacies/screens/cart-page/cart-order-page.dart';
import 'package:diplomaticquarterapp/pages/pharmacy/order/ProductReview.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/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart';
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import 'package:rating_bar/rating_bar.dart'; import 'package:rating_bar/rating_bar.dart';
class productTile extends StatelessWidget { class productTile extends StatelessWidget {
@ -27,6 +30,7 @@ class productTile extends StatelessWidget {
final dynamic productID; final dynamic productID;
final Function onDelete; final Function onDelete;
final dynamic approvedTotalReviews; final dynamic approvedTotalReviews;
final dynamic isRx;
// final VoidCallback deleteWishlistItems; // final VoidCallback deleteWishlistItems;
@ -47,10 +51,12 @@ class productTile extends StatelessWidget {
this.productID, this.productID,
this.onDelete, this.onDelete,
this.approvedTotalReviews, this.approvedTotalReviews,
this.isRx
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ProjectViewModel projectViewModel = Provider.of(context);
return Container( return Container(
height: 180, height: 180,
width: double.infinity, width: double.infinity,
@ -87,7 +93,16 @@ class productTile extends StatelessWidget {
children: [ children: [
Container( Container(
margin: EdgeInsets.all(5), 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, alignment: Alignment.topLeft,
child: RichText( child: RichText(
text: TextSpan( text: TextSpan(
@ -99,7 +114,17 @@ class productTile extends StatelessWidget {
), ),
Container( Container(
margin: EdgeInsets.all(5), 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, alignment: Alignment.topLeft,
child: RichText( child: RichText(
text: TextSpan( text: TextSpan(
@ -163,10 +188,14 @@ class productTile extends StatelessWidget {
color: Colors.green, color: Colors.green,
), ),
onPressed: () async { onPressed: () async {
if(isRx == false){
GifLoaderDialogUtils.showMyDialog(context); GifLoaderDialogUtils.showMyDialog(context);
await addToCartFunction(1, productID, context); await addToCartFunction(1, productID, context);
GifLoaderDialogUtils.hideDialog(context); GifLoaderDialogUtils.hideDialog(context);
Utils.navigateToCartPage(); Utils.navigateToCartPage();}
else {
AppToast.showErrorToast(message: TranslationBase.of(context).needPrescription);
}
}, },
), ),
], ],

@ -36,8 +36,7 @@ dependencies:
fl_chart: ^0.12.3 fl_chart: ^0.12.3
# Permissions # Permissions
permission_handler: ^5.0.0+hotfix.3 permission_handler: ^5.1.0+2
device_info: ^0.4.2+4
# Flutter Html View # Flutter Html View
flutter_html: ^1.2.0 flutter_html: ^1.2.0
@ -46,7 +45,6 @@ dependencies:
pull_to_refresh: 1.6.2 pull_to_refresh: 1.6.2
# Native # Native
flutter_device_type: ^0.2.0
local_auth: ^0.6.2+3 local_auth: ^0.6.2+3
localstorage: ^3.0.3+6 localstorage: ^3.0.3+6
maps_launcher: ^1.2.1 maps_launcher: ^1.2.1
@ -55,7 +53,6 @@ dependencies:
flutter_flexible_toast: ^0.1.4 flutter_flexible_toast: ^0.1.4
firebase_messaging: ^7.0.3 firebase_messaging: ^7.0.3
firebase_analytics: ^6.3.0 firebase_analytics: ^6.3.0
cloud_firestore: ^0.14.3
# Progress bar # Progress bar
progress_hud_v2: ^2.0.0 progress_hud_v2: ^2.0.0
percent_indicator: ^2.1.5 percent_indicator: ^2.1.5
@ -156,7 +153,6 @@ dependencies:
cached_network_image: ^2.4.1 cached_network_image: ^2.4.1
flutter_tts: flutter_tts:
path: flutter_tts-voice_enhancement path: flutter_tts-voice_enhancement
# flutter_tts: ^1.2.6
sms_otp_auto_verify: ^1.2.2 sms_otp_auto_verify: ^1.2.2
wifi: ^0.1.5 wifi: ^0.1.5

Loading…
Cancel
Save