Merge branch 'flutter_2_developemt' of https://gitlab.com/Cloud_Solution/doctor_app_flutter into flutter_vervion_2_elham

 Conflicts:
	ios/Podfile
	lib/client/base_app_client.dart
	lib/core/model/patient_muse/PatientSearchRequestModel.dart
	lib/core/model/referral/MyReferralPatientModel.dart
	lib/core/service/patient/LiveCarePatientServices.dart
	lib/core/service/patient/MyReferralPatientService.dart
	lib/core/service/patient/patient_service.dart
	lib/core/viewModel/LiveCarePatientViewModel.dart
	lib/core/viewModel/PatientMedicalReportViewModel.dart
	lib/core/viewModel/PatientSearchViewModel.dart
	lib/core/viewModel/authentication_view_model.dart
	lib/core/viewModel/dashboard_view_model.dart
	lib/core/viewModel/patient-referral-viewmodel.dart
	lib/core/viewModel/procedure_View_model.dart
	lib/core/viewModel/referred_view_model.dart
	lib/models/livecare/start_call_req.dart
	lib/models/patient/patiant_info_model.dart
	lib/screens/auth/login_screen.dart
	lib/screens/auth/verification_methods_screen.dart
	lib/screens/home/dashboard_slider-item-widget.dart
	lib/screens/home/dashboard_swipe_widget.dart
	lib/screens/home/home_page_card.dart
	lib/screens/home/home_patient_card.dart
	lib/screens/home/home_screen.dart
	lib/screens/live_care/end_call_screen.dart
	lib/screens/live_care/live-care_transfer_to_admin.dart
	lib/screens/live_care/live_care_patient_screen.dart
	lib/screens/medical-file/health_summary_page.dart
	lib/screens/medical-file/medical_file_details.dart
	lib/screens/patients/ECGPage.dart
	lib/screens/patients/insurance_approval_screen_patient.dart
	lib/screens/patients/insurance_approvals_details.dart
	lib/screens/patients/profile/UCAF/UCAF-detail-screen.dart
	lib/screens/patients/profile/UCAF/UCAF-input-screen.dart
	lib/screens/patients/profile/admission-request/admission-request-first-screen.dart
	lib/screens/patients/profile/admission-request/admission-request-third-screen.dart
	lib/screens/patients/profile/admission-request/admission-request_second-screen.dart
	lib/screens/patients/profile/medical_report/AddVerifyMedicalReport.dart
	lib/screens/patients/profile/medical_report/MedicalReportPage.dart
	lib/screens/patients/profile/note/progress_note_screen.dart
	lib/screens/patients/profile/profile_screen/PatientProfileCardModel.dart
	lib/screens/patients/profile/profile_screen/patient_profile_screen.dart
	lib/screens/patients/profile/radiology/radiology_details_page.dart
	lib/screens/patients/profile/radiology/radiology_home_page.dart
	lib/screens/patients/profile/referral/AddReplayOnReferralPatient.dart
	lib/screens/patients/profile/referral/my-referral-inpatient-screen.dart
	lib/screens/patients/profile/referral/refer-patient-screen-in-patient.dart
	lib/screens/patients/profile/referral/refer-patient-screen.dart
	lib/screens/patients/profile/referral/referral_patient_detail_in-paint.dart
	lib/screens/patients/profile/referral/referred-patient-screen.dart
	lib/screens/patients/profile/referral/referred_patient_detail_in-paint.dart
	lib/screens/patients/profile/soap_update/update_soap_index.dart
	lib/screens/patients/profile/vital_sign/vital_sign_details_screen.dart
	lib/screens/patients/profile/vital_sign/vital_sign_item_details_screen.dart
	lib/screens/prescription/add_favourite_prescription.dart
	lib/screens/prescription/add_prescription_form.dart
	lib/screens/prescription/prescription_home_screen.dart
	lib/screens/prescription/prescription_item_in_patient_page.dart
	lib/screens/prescription/prescription_items_page.dart
	lib/screens/prescription/prescription_screen.dart
	lib/screens/prescription/prescription_screen_history.dart
	lib/screens/prescription/prescriptions_page.dart
	lib/screens/procedures/ProcedureCard.dart
	lib/screens/procedures/add-favourite-procedure.dart
	lib/screens/procedures/add-procedure-form.dart
	lib/screens/procedures/add_lab_home_screen.dart
	lib/screens/procedures/add_lab_orders.dart
	lib/screens/procedures/add_radiology_order.dart
	lib/screens/procedures/add_radiology_screen.dart
	lib/screens/procedures/base_add_procedure_tab_page.dart
	lib/screens/procedures/entity_list_procedure_widget.dart
	lib/screens/qr_reader/QR_reader_screen.dart
	lib/util/VideoChannel.dart
	lib/util/translations_delegate_base.dart
	lib/widgets/auth/sms-popup.dart
	lib/widgets/auth/verification_methods_list.dart
	lib/widgets/dashboard/out_patient_stack.dart
	lib/widgets/patients/patient-referral-item-widget.dart
	lib/widgets/patients/patient_card/PatientCard.dart
	lib/widgets/patients/profile/PatientHeaderWidgetNoAvatar.dart
	lib/widgets/patients/profile/PatientProfileButton.dart
	lib/widgets/patients/profile/patient-page-header-widget.dart
	lib/widgets/patients/profile/patient-profile-header-new-design-app-bar.dart
	lib/widgets/patients/profile/patient-profile-header-new-design.dart
	lib/widgets/patients/profile/patient_profile_header_with_appointment_card_app_bar.dart
	lib/widgets/patients/profile/profile-welcome-widget.dart
	lib/widgets/shared/app_drawer_widget.dart
	lib/widgets/shared/app_scaffold_widget.dart
	lib/widgets/shared/app_texts_widget.dart
	lib/widgets/shared/bottom_navigation_item.dart
	lib/widgets/shared/buttons/app_buttons_widget.dart
	lib/widgets/shared/drawer_item_widget.dart
	pubspec.lock
merge-requests/748/head
Elham Rababah 5 years ago
commit ca6306950d

@ -54,6 +54,11 @@ android {
signingConfig signingConfigs.debug
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
flutter {
@ -65,6 +70,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
@ -74,9 +80,10 @@ dependencies {
//permissions
implementation 'pub.devrel:easypermissions:0.4.0'
//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
}
apply plugin: 'com.google.gms.google-services'

@ -9,18 +9,24 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here.
-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:name="io.flutter.app.FlutterApplication"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="HMG Doctor">
<activity android:name=".ui.VideoCallActivity"></activity>
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

@ -2,100 +2,177 @@ package com.hmg.hmgDr
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import com.google.gson.GsonBuilder
import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.ui.VideoCallActivity
import com.google.gson.GsonBuilder
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler {
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler, VideoCallResponseListener {
private val CHANNEL = "Dr.cloudSolution/videoCall"
private lateinit var methodChannel: MethodChannel
private var result: MethodChannel.Result? = null
private var call: MethodCall? = null
private val LAUNCH_VIDEO: Int = 1
private var dialogFragment: VideoCallFragment? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler(this)
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
methodChannel.setMethodCallHandler(this)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
this.result = result
this.call = call
if (call.method == "openVideoCall") {
val apiKey = call.argument<String>("kApiKey")
val sessionId = call.argument<String>("kSessionId")
val token = call.argument<String>("kToken")
val appLang = call.argument<String>("appLang")
val baseUrl = call.argument<String>("baseUrl")
when (call.method) {
"openVideoCall" -> {
val apiKey = call.argument<String>("kApiKey")
val sessionId = call.argument<String>("kSessionId")
val token = call.argument<String>("kToken")
val appLang = call.argument<String>("appLang")
val baseUrl = call.argument<String>("baseUrl")
// Session Status model
val VC_ID = call.argument<Int>("VC_ID")
val tokenID = call.argument<String>("TokenID")
val generalId = call.argument<String>("generalId")
val doctorId = call.argument<Int>("DoctorId")
val patientName = call.argument<String>("patientName")
// Session Status model
val VC_ID = call.argument<Int>("VC_ID")
val tokenID = call.argument<String>("TokenID")
val generalId = call.argument<String>("generalId")
val doctorId = call.argument<Int>("DoctorId")
val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName)
val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId)
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
}
"closeVideoCall" -> {
dialogFragment?.onCallClicked()
}
"onCallConnected" -> {
} else {
result.notImplemented()
}
else -> {
result.notImplemented()
}
}
}
private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) {
// val videoCallActivity = VideoCallActivity()
if (dialogFragment == null) {
val arguments = Bundle()
arguments.putString("apiKey", apiKey)
arguments.putString("sessionId", sessionId)
arguments.putString("token", token)
arguments.putString("appLang", appLang)
arguments.putString("baseUrl", baseUrl)
arguments.putParcelable("sessionStatusModel", sessionStatusModel)
val transaction = supportFragmentManager.beginTransaction()
dialogFragment = VideoCallFragment.newInstance(arguments)
dialogFragment?.let {
it.setCallListener(this)
it.isCancelable = true
if (it.isAdded){
it.dismiss()
}else {
it.show(transaction, "dialog")
}
val intent = Intent(this, VideoCallActivity::class.java)
intent.putExtra("apiKey", apiKey)
intent.putExtra("sessionId", sessionId)
intent.putExtra("token", token)
intent.putExtra("appLang", appLang)
intent.putExtra("baseUrl", baseUrl)
intent.putExtra("sessionStatusModel", sessionStatusModel)
startActivityForResult(intent, LAUNCH_VIDEO)
}
} else if (!dialogFragment!!.isVisible) {
val transaction = supportFragmentManager.beginTransaction()
dialogFragment!!.show(transaction, "dialog")
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
var asd = "";
if (requestCode == LAUNCH_VIDEO) {
if (resultCode == Activity.RESULT_OK) {
val result : SessionStatusModel? = data?.getParcelableExtra("sessionStatusNotRespond")
val callResponse : HashMap<String, String> = HashMap()
/* override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
var asd = "";
if (requestCode == LAUNCH_VIDEO) {
if (resultCode == Activity.RESULT_OK) {
val result : SessionStatusModel? = data?.getParcelableExtra("sessionStatusNotRespond")
val callResponse : HashMap<String, String> = HashMap()
val sessionStatus : HashMap<String, String> = HashMap()
val gson = GsonBuilder().serializeNulls().create()
val sessionStatus : HashMap<String, String> = HashMap()
val gson = GsonBuilder().serializeNulls().create()
callResponse["callResponse"] = "CallNotRespond"
val jsonRes = gson.toJson(result)
callResponse["sessionStatus"] = jsonRes
callResponse["callResponse"] = "CallNotRespond"
val jsonRes = gson.toJson(result)
callResponse["sessionStatus"] = jsonRes
this.result?.success(callResponse)
}
if (resultCode == Activity.RESULT_CANCELED) {
val callResponse : HashMap<String, String> = HashMap()
callResponse["callResponse"] = "CallEnd"
result?.success(callResponse)
}
}
}*/
override fun onCallFinished(resultCode: Int, intent: Intent?) {
dialogFragment = null
if (resultCode == Activity.RESULT_OK) {
val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond")
val callResponse: HashMap<String, String> = HashMap()
val sessionStatus: HashMap<String, String> = HashMap()
val gson = GsonBuilder().serializeNulls().create()
callResponse["callResponse"] = "CallNotRespond"
val jsonRes = gson.toJson(result)
callResponse["sessionStatus"] = jsonRes
try {
this.result?.success(callResponse)
} catch (e : Exception){
Log.e("onVideoCallFinished", "${e.message}.")
}
if (resultCode == Activity.RESULT_CANCELED) {
val callResponse : HashMap<String, String> = HashMap()
callResponse["callResponse"] = "CallEnd"
} else if (resultCode == Activity.RESULT_CANCELED) {
val callResponse: HashMap<String, String> = HashMap()
callResponse["callResponse"] = "CallEnd"
try {
result?.success(callResponse)
} catch (e : Exception){
Log.e("onVideoCallFinished", "${e.message}.")
}
}
}
override fun errorHandle(message: String) {
dialogFragment = null
// Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
override fun minimizeVideoEvent(isMinimize: Boolean) {
if (isMinimize)
methodChannel.invokeMethod("onCallConnected", null)
else
methodChannel.invokeMethod("onCallDisconnected", null)
}
override fun onBackPressed() {
super.onBackPressed()
}
}

@ -20,15 +20,19 @@ public class GetSessionStatusModel implements Parcelable {
@SerializedName("DoctorId")
@Expose
private Integer doctorId;
@SerializedName("PatientName")
@Expose
private String patientName;
public GetSessionStatusModel() {
}
public GetSessionStatusModel(Integer vCID, String tokenID, String generalid, Integer doctorId) {
public GetSessionStatusModel(Integer vCID, String tokenID, String generalid, Integer doctorId, String patientName) {
this.vCID = vCID;
this.tokenID = tokenID;
this.generalid = generalid;
this.doctorId = doctorId;
this.patientName = patientName;
}
protected GetSessionStatusModel(Parcel in) {
@ -44,6 +48,7 @@ public class GetSessionStatusModel implements Parcelable {
} else {
doctorId = in.readInt();
}
patientName = in.readString();
}
public static final Creator<GetSessionStatusModel> CREATOR = new Creator<GetSessionStatusModel>() {
@ -90,6 +95,16 @@ public class GetSessionStatusModel implements Parcelable {
this.doctorId = doctorId;
}
public String getPatientName() {
if (patientName == null)
patientName = "-";
return patientName;
}
public void setPatientName(String patientName) {
this.patientName = patientName;
}
@Override
public int describeContents() {
return 0;
@ -111,5 +126,6 @@ public class GetSessionStatusModel implements Parcelable {
dest.writeByte((byte) 1);
dest.writeInt(doctorId);
}
dest.writeString(patientName);
}
}

@ -1,442 +0,0 @@
package com.hmg.hmgDr.ui;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel;
import com.hmg.hmgDr.Model.GetSessionStatusModel;
import com.hmg.hmgDr.Model.SessionStatusModel;
import com.hmg.hmgDr.R;
import com.opentok.android.Session;
import com.opentok.android.Stream;
import com.opentok.android.Publisher;
import com.opentok.android.PublisherKit;
import com.opentok.android.Subscriber;
import com.opentok.android.BaseVideoRenderer;
import com.opentok.android.OpentokError;
import com.opentok.android.SubscriberKit;
import java.util.List;
import java.util.Objects;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.AppSettingsDialog;
import pub.devrel.easypermissions.EasyPermissions;
public class VideoCallActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks,
Session.SessionListener,
Publisher.PublisherListener,
Subscriber.VideoListener, VideoCallContract.VideoCallView {
private static final String TAG = VideoCallActivity.class.getSimpleName();
VideoCallContract.VideoCallPresenter videoCallPresenter;
private static final int RC_SETTINGS_SCREEN_PERM = 123;
private static final int RC_VIDEO_APP_PERM = 124;
private Session mSession;
private Publisher mPublisher;
private Subscriber mSubscriber;
private Handler mVolHandler, mConnectedHandler;
private Runnable mVolRunnable, mConnectedRunnable;
private FrameLayout mPublisherViewContainer;
private RelativeLayout mSubscriberViewContainer;
private RelativeLayout controlPanel;
private String apiKey;
private String sessionId;
private String token;
private String appLang;
private String baseUrl;
private boolean isSwitchCameraClicked;
private boolean isCameraClicked;
private boolean isSpeckerClicked;
private boolean isMicClicked;
private ImageView mCallBtn;
private ImageView mCameraBtn;
private ImageView mSwitchCameraBtn;
private ImageView mspeckerBtn;
private ImageView mMicBtn;
private ProgressBar progressBar;
private CountDownTimer countDownTimer;
private TextView progressBarTextView;
private RelativeLayout progressBarLayout;
private boolean isConnected = false;
private GetSessionStatusModel sessionStatusModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_call);
Objects.requireNonNull(getSupportActionBar()).hide();
initUI();
requestPermissions();
}
@Override
protected void onPause() {
super.onPause();
if (mSession == null) {
return;
}
mSession.onPause();
if (isFinishing()) {
disconnectSession();
}
}
@Override
protected void onResume() {
super.onResume();
if (mSession == null) {
return;
}
mSession.onResume();
}
@Override
protected void onDestroy() {
disconnectSession();
super.onDestroy();
}
@SuppressLint("ClickableViewAccessibility")
private void initUI() {
mPublisherViewContainer = (FrameLayout) findViewById(R.id.local_video_view_container);
mSubscriberViewContainer = (RelativeLayout) findViewById(R.id.remote_video_view_container);
apiKey = getIntent().getStringExtra("apiKey");
sessionId = getIntent().getStringExtra("sessionId");
token = getIntent().getStringExtra("token");
appLang = getIntent().getStringExtra("appLang");
baseUrl = getIntent().getStringExtra("baseUrl");
sessionStatusModel = getIntent().getParcelableExtra("sessionStatusModel");
controlPanel = findViewById(R.id.control_panel);
videoCallPresenter = new VideoCallPresenterImpl(this, baseUrl);
mCallBtn = findViewById(R.id.btn_call);
mCameraBtn = findViewById(R.id.btn_camera);
mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);
mspeckerBtn = findViewById(R.id.btn_specker);
mMicBtn = findViewById(R.id.btn_mic);
// progressBarLayout=findViewById(R.id.progressBar);
// progressBar=findViewById(R.id.progress_bar);
// progressBarTextView=findViewById(R.id.progress_bar_text);
// progressBar.setVisibility(View.GONE);
hiddenButtons();
checkClientConnected();
mSubscriberViewContainer.setOnTouchListener((v, event) -> {
controlPanel.setVisibility(View.VISIBLE);
mVolHandler.removeCallbacks(mVolRunnable);
mVolHandler.postDelayed(mVolRunnable, 5 * 1000);
return true;
});
if (appLang.equals("ar")) {
progressBarLayout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
}
}
private void checkClientConnected() {
mConnectedHandler = new Handler();
mConnectedRunnable = () -> {
if (!isConnected) {
videoCallPresenter.callClintConnected(sessionStatusModel);
}
};
mConnectedHandler.postDelayed(mConnectedRunnable, 30 * 1000);
}
private void hiddenButtons() {
mVolHandler = new Handler();
mVolRunnable = new Runnable() {
public void run() {
controlPanel.setVisibility(View.GONE);
}
};
mVolHandler.postDelayed(mVolRunnable, 5 * 1000);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size());
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size());
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this)
.setTitle(getString(R.string.title_settings_dialog))
.setRationale(getString(R.string.rationale_ask_again))
.setPositiveButton(getString(R.string.setting))
.setNegativeButton(getString(R.string.cancel))
.setRequestCode(RC_SETTINGS_SCREEN_PERM)
.build()
.show();
}
}
@AfterPermissionGranted(RC_VIDEO_APP_PERM)
private void requestPermissions() {
String[] perms = {Manifest.permission.INTERNET, Manifest.permission.CAMERA,};
if (EasyPermissions.hasPermissions(this, perms)) {
try {
mSession = new Session.Builder(this, apiKey, sessionId).build();
mSession.setSessionListener(this);
mSession.connect(token);
} catch (Exception e) {
e.printStackTrace();
}
} else {
EasyPermissions.requestPermissions(this, getString(R.string.remaining_ar), RC_VIDEO_APP_PERM, perms);
}
}
@Override
public void onConnected(Session session) {
Log.i(TAG, "Session Connected");
mPublisher = new Publisher.Builder(this).build();
mPublisher.setPublisherListener(this);
mPublisherViewContainer.addView(mPublisher.getView());
if (mPublisher.getView() instanceof GLSurfaceView) {
((GLSurfaceView) mPublisher.getView()).setZOrderOnTop(true);
}
mSession.publish(mPublisher);
}
@Override
public void onDisconnected(Session session) {
Log.d(TAG, "onDisconnected: disconnected from session " + session.getSessionId());
mSession = null;
}
@Override
public void onError(Session session, OpentokError opentokError) {
Log.d(TAG, "onError: Error (" + opentokError.getMessage() + ") in session " + session.getSessionId());
Toast.makeText(this, "Session error. See the logcat please.", Toast.LENGTH_LONG).show();
finish();
}
@Override
public void onStreamReceived(Session session, Stream stream) {
Log.d(TAG, "onStreamReceived: New stream " + stream.getStreamId() + " in session " + session.getSessionId());
if (mSubscriber != null) {
isConnected = true;
return;
}
isConnected = true;
subscribeToStream(stream);
videoCallPresenter.callChangeCallStatus(new ChangeCallStatusRequestModel(3,sessionStatusModel.getDoctorId(), sessionStatusModel.getGeneralid(),token,sessionStatusModel.getVCID()));
}
@Override
public void onStreamDropped(Session session, Stream stream) {
Log.d(TAG, "onStreamDropped: Stream " + stream.getStreamId() + " dropped from session " + session.getSessionId());
if (mSubscriber == null) {
return;
}
if (mSubscriber.getStream().equals(stream)) {
mSubscriberViewContainer.removeView(mSubscriber.getView());
mSubscriber.destroy();
mSubscriber = null;
}
disconnectSession();
}
@Override
public void onStreamCreated(PublisherKit publisherKit, Stream stream) {
Log.d(TAG, "onStreamCreated: Own stream " + stream.getStreamId() + " created");
}
@Override
public void onStreamDestroyed(PublisherKit publisherKit, Stream stream) {
Log.d(TAG, "onStreamDestroyed: Own stream " + stream.getStreamId() + " destroyed");
}
@Override
public void onError(PublisherKit publisherKit, OpentokError opentokError) {
Log.d(TAG, "onError: Error (" + opentokError.getMessage() + ") in publisher");
Toast.makeText(this, "Session error. See the logcat please.", Toast.LENGTH_LONG).show();
finish();
}
@Override
public void onVideoDataReceived(SubscriberKit subscriberKit) {
mSubscriber.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL);
mSubscriberViewContainer.addView(mSubscriber.getView());
}
@Override
public void onVideoDisabled(SubscriberKit subscriberKit, String s) {
}
@Override
public void onVideoEnabled(SubscriberKit subscriberKit, String s) {
}
@Override
public void onVideoDisableWarning(SubscriberKit subscriberKit) {
}
@Override
public void onVideoDisableWarningLifted(SubscriberKit subscriberKit) {
}
private void subscribeToStream(Stream stream) {
mSubscriber = new Subscriber.Builder(VideoCallActivity.this, stream).build();
mSubscriber.setVideoListener(this);
mSession.subscribe(mSubscriber);
}
private void disconnectSession() {
if (mSession == null) {
setResult(Activity.RESULT_CANCELED);
finish();
return;
}
if (mSubscriber != null) {
mSubscriberViewContainer.removeView(mSubscriber.getView());
mSession.unsubscribe(mSubscriber);
mSubscriber.destroy();
mSubscriber = null;
}
if (mPublisher != null) {
mPublisherViewContainer.removeView(mPublisher.getView());
mSession.unpublish(mPublisher);
mPublisher.destroy();
mPublisher = null;
}
mSession.disconnect();
if (countDownTimer != null) {
countDownTimer.cancel();
}
videoCallPresenter.callChangeCallStatus(new ChangeCallStatusRequestModel(16,sessionStatusModel.getDoctorId(), sessionStatusModel.getGeneralid(),token,sessionStatusModel.getVCID()));
finish();
}
public void onSwitchCameraClicked(View view) {
if (mPublisher != null) {
isSwitchCameraClicked = !isSwitchCameraClicked;
mPublisher.cycleCamera();
int res = isSwitchCameraClicked ? R.drawable.flip_disapled : R.drawable.flip_enabled;
mSwitchCameraBtn.setImageResource(res);
}
}
public void onCameraClicked(View view) {
if (mPublisher != null) {
isCameraClicked = !isCameraClicked;
mPublisher.setPublishVideo(!isCameraClicked);
int res = isCameraClicked ? R.drawable.video_disanabled : R.drawable.video_enabled;
mCameraBtn.setImageResource(res);
}
}
public void onSpeckerClicked(View view) {
if (mSubscriber != null) {
isSpeckerClicked = !isSpeckerClicked;
mSubscriber.setSubscribeToAudio(!isSpeckerClicked);
int res = isSpeckerClicked ? R.drawable.audio_disabled : R.drawable.audio_enabled;
mspeckerBtn.setImageResource(res);
}
}
public void onMicClicked(View view) {
if (mPublisher != null) {
isMicClicked = !isMicClicked;
mPublisher.setPublishAudio(!isMicClicked);
int res = isMicClicked ? R.drawable.mic_disabled : R.drawable.mic_enabled;
mMicBtn.setImageResource(res);
}
}
public void onCallClicked(View view) {
disconnectSession();
}
@Override
public void onCallSuccessful(SessionStatusModel sessionStatusModel) {
if (sessionStatusModel.getSessionStatus() == 2 || sessionStatusModel.getSessionStatus() == 3) {
Intent returnIntent = new Intent();
returnIntent.putExtra("sessionStatusNotRespond", sessionStatusModel);
setResult(Activity.RESULT_OK, returnIntent);
finish();
}
}
@Override
public void onCallChangeCallStatusSuccessful(SessionStatusModel sessionStatusModel) {
}
@Override
public void onFailure() {
}
}

@ -0,0 +1,14 @@
package com.hmg.hmgDr.ui
import android.content.Intent
interface VideoCallResponseListener {
fun onCallFinished(resultCode : Int, intent: Intent? = null)
fun errorHandle(message: String)
fun minimizeVideoEvent(isMinimize : Boolean)
fun onBackHandle(){}
}

@ -0,0 +1,893 @@
package com.hmg.hmgDr.ui.fragment
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Point
import android.graphics.drawable.ColorDrawable
import android.opengl.GLSurfaceView
import android.os.*
import android.util.Log
import android.view.*
import android.widget.*
import androidx.annotation.Nullable
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
import androidx.fragment.app.DialogFragment
import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel
import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.R
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView
import com.hmg.hmgDr.ui.VideoCallPresenterImpl
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.util.DynamicVideoRenderer
import com.hmg.hmgDr.util.ThumbnailCircleVideoRenderer
import com.opentok.android.*
import com.opentok.android.PublisherKit.PublisherListener
import pub.devrel.easypermissions.AfterPermissionGranted
import pub.devrel.easypermissions.AppSettingsDialog
import pub.devrel.easypermissions.EasyPermissions
import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
import kotlin.math.ceil
class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.SessionListener, PublisherListener,
SubscriberKit.VideoListener, VideoCallView {
private var isFullScreen: Boolean = true
private var isCircle: Boolean = false
private var x_init_cord = 0
private var y_init_cord: Int = 0
private var x_init_margin: Int = 0
private var y_init_margin: Int = 0
private val szWindow: Point = Point()
private lateinit var mWindowManager: WindowManager
private var isLeft = true
private lateinit var videoCallPresenter: VideoCallPresenter
private var mSession: Session? = null
private var mPublisher: Publisher? = null
private var mSubscriber: Subscriber? = null
private var mVolHandler: Handler? = null
private var mConnectedHandler: Handler? = null
private var mVolRunnable: Runnable? = null
private var mConnectedRunnable: Runnable? = null
private lateinit var thumbnail_container: FrameLayout
private lateinit var mPublisherViewContainer: FrameLayout
private lateinit var mPublisherViewIcon: View
private lateinit var mSubscriberViewContainer: FrameLayout
private lateinit var mSubscriberViewIcon: ImageView
private lateinit var controlPanel: ConstraintLayout
private var apiKey: String? = null
private var sessionId: String? = null
private var token: String? = null
private var appLang: String? = null
private var baseUrl: String? = null
private var isSwitchCameraClicked = false
private var isCameraClicked = false
private var isSpeckerClicked = false
private var isMicClicked = false
private lateinit var parentView: View
private lateinit var videoCallContainer: ConstraintLayout
private lateinit var layoutName: RelativeLayout
private lateinit var layoutMini: RelativeLayout
private lateinit var icMini: ImageButton
private lateinit var mCallBtn: ImageView
private lateinit var btnMinimize: ImageView
private lateinit var mCameraBtn: ImageView
private lateinit var mSwitchCameraBtn: ImageView
private lateinit var mspeckerBtn: ImageView
private lateinit var mMicBtn: ImageView
private lateinit var patientName: TextView
private lateinit var cmTimer: Chronometer
private var elapsedTime: Long = 0
private var resume = false
private val progressBar: ProgressBar? = null
private val countDownTimer: CountDownTimer? = null
private val progressBarTextView: TextView? = null
private val progressBarLayout: RelativeLayout? = null
private var isConnected = false
private var sessionStatusModel: GetSessionStatusModel? = null
private var videoCallResponseListener: VideoCallResponseListener? = null
private lateinit var mDetector: GestureDetectorCompat
override fun onCreate(savedInstanceState: Bundle?) {
requireActivity().setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
}
override fun onStart() {
super.onStart()
dialog?.window?.setLayout(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
}
override fun getTheme(): Int {
return R.style.dialogTheme
}
override fun onCreateDialog(@Nullable savedInstanceState: Bundle?): Dialog {
val dialog: Dialog = super.onCreateDialog(savedInstanceState)
// Add back button listener
// Add back button listener
dialog.setOnKeyListener { _, keyCode, keyEvent ->
// getAction to make sure this doesn't double fire
if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
videoCallResponseListener?.onBackHandle()
false // Capture onKey
} else true
// Don't capture
}
return dialog
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// This is done in a post() since the dialog must be drawn before locating.
requireView().post {
val dialogWindow = dialog!!.window
if (dialog != null && dialogWindow != null) {
dialogWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
}
// Make the dialog possible to be outside touch
dialogWindow!!.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
)
dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
requireView().invalidate()
}
}
fun setCallListener(videoCallResponseListener: VideoCallResponseListener) {
this.videoCallResponseListener = videoCallResponseListener
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
parentView = inflater.inflate(R.layout.activity_video_call, container, false)
// Objects.requireNonNull(requireActivity().actionBar)!!.hide()
arguments?.run {
apiKey = getString("apiKey")
sessionId = getString("sessionId")
token = getString("token")
appLang = getString("appLang")
baseUrl = getString("baseUrl")
sessionStatusModel = getParcelable("sessionStatusModel")
}
initUI(parentView)
requestPermissions()
handleDragDialog()
mDetector = GestureDetectorCompat(context, MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() }))
return parentView
}
override fun onPause() {
super.onPause()
if (mSession == null) {
return
}
mSession!!.onPause()
if (requireActivity().isFinishing) {
disconnectSession()
}
}
override fun onResume() {
super.onResume()
if (mSession == null) {
return
}
mSession!!.onResume()
}
override fun onDestroy() {
disconnectSession()
cmTimer.stop()
super.onDestroy()
}
@SuppressLint("ClickableViewAccessibility")
private fun initUI(view: View) {
videoCallContainer = view.findViewById(R.id.video_call_ll)
layoutName = view.findViewById(R.id.layout_name)
layoutMini = view.findViewById(R.id.layout_mini)
icMini = view.findViewById(R.id.ic_mini)
thumbnail_container = view.findViewById(R.id.thumbnail_container)
mPublisherViewContainer = view.findViewById(R.id.local_video_view_container)
mPublisherViewIcon = view.findViewById(R.id.local_video_view_icon)
mSubscriberViewIcon = view.findViewById(R.id.remote_video_view_icon)
mSubscriberViewContainer = view.findViewById(R.id.remote_video_view_container)
patientName = view.findViewById<TextView>(R.id.patient_name)
patientName.text = sessionStatusModel!!.patientName
cmTimer = view.findViewById<Chronometer>(R.id.cmTimer)
cmTimer.format = "mm:ss"
cmTimer.onChronometerTickListener = Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
val minutes: Long
val seconds: Long
if (!resume) {
minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60
seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60
elapsedTime = SystemClock.elapsedRealtime()
} else {
minutes = (elapsedTime - cmTimer.base) / 1000 / 60
seconds = (elapsedTime - cmTimer.base) / 1000 % 60
elapsedTime += 1000
}
arg0?.text = "$minutes:$seconds"
Log.d(VideoCallFragment.TAG, "onChronometerTick: $minutes : $seconds")
}
icMini.setOnClickListener {
onMiniCircleClicked()
}
controlPanel = view.findViewById(R.id.control_panel)
videoCallPresenter = VideoCallPresenterImpl(this, baseUrl)
mCallBtn = view.findViewById<ImageView>(R.id.btn_call)
mCallBtn.setOnClickListener {
onCallClicked()
}
btnMinimize = view.findViewById<ImageView>(R.id.btn_minimize)
btnMinimize.setOnClickListener {
onMinimizedClicked(it)
}
mCameraBtn = view.findViewById<ImageView>(R.id.btn_camera)
mCameraBtn.setOnClickListener {
onCameraClicked(it)
}
mSwitchCameraBtn = view.findViewById<ImageView>(R.id.btn_switch_camera)
mSwitchCameraBtn.setOnClickListener {
onSwitchCameraClicked(it)
}
mspeckerBtn = view.findViewById<ImageView>(R.id.btn_specker)
mspeckerBtn.setOnClickListener {
onSpeckerClicked(it)
}
mMicBtn = view.findViewById<ImageView>(R.id.btn_mic)
mMicBtn.setOnClickListener {
onMicClicked(it)
}
// progressBarLayout=findViewById(R.id.progressBar);
// progressBar=findViewById(R.id.progress_bar);
// progressBarTextView=findViewById(R.id.progress_bar_text);
// progressBar.setVisibility(View.GONE);
hiddenButtons()
checkClientConnected()
if (appLang == "ar") {
progressBarLayout!!.layoutDirection = View.LAYOUT_DIRECTION_RTL
}
}
private fun checkClientConnected() {
mConnectedHandler = Handler((Looper.getMainLooper()))
mConnectedRunnable = Runnable {
if (!isConnected) {
videoCallPresenter.callClintConnected(sessionStatusModel)
}
}
mConnectedHandler!!.postDelayed(mConnectedRunnable!!, (55 * 1000).toLong())
}
private fun hiddenButtons() {
mVolHandler = Handler()
mVolRunnable = Runnable { controlPanel.visibility = View.GONE }
mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
override fun onPermissionsGranted(requestCode: Int, perms: List<String?>) {
Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size)
}
override fun onPermissionsDenied(requestCode: Int, perms: List<String?>) {
Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size)
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
AppSettingsDialog.Builder(this)
.setTitle(getString(R.string.title_settings_dialog))
.setRationale(getString(R.string.rationale_ask_again))
.setPositiveButton(getString(R.string.setting))
.setNegativeButton(getString(R.string.cancel))
.setRequestCode(RC_SETTINGS_SCREEN_PERM)
.build()
.show()
}
}
@AfterPermissionGranted(RC_VIDEO_APP_PERM)
private fun requestPermissions() {
val perms = arrayOf(Manifest.permission.INTERNET, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.CALL_PHONE)
if (EasyPermissions.hasPermissions(requireContext(), *perms)) {
try {
mSession = Session.Builder(context, apiKey, sessionId).build()
mSession!!.setSessionListener(this)
mSession!!.connect(token)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
EasyPermissions.requestPermissions(this, getString(R.string.remaining_ar), RC_VIDEO_APP_PERM, *perms)
}
}
override fun onConnected(session: Session?) {
Log.i(TAG, "Session Connected")
mPublisher = Publisher.Builder(requireContext())
// .name("publisher")
// .renderer(ThumbnailCircleVideoRenderer(requireContext()))
.build()
mPublisher!!.setPublisherListener(this)
if (mPublisher!!.view is GLSurfaceView) {
(mPublisher!!.view as GLSurfaceView).setZOrderOnTop(true)
}
mPublisherViewContainer.addView(mPublisher!!.view)
mSession!!.publish(mPublisher)
if (!resume) {
cmTimer.base = SystemClock.elapsedRealtime()
}
cmTimer.start()
videoCallResponseListener?.minimizeVideoEvent(true)
}
override fun onDisconnected(session: Session) {
Log.d(TAG, "onDisconnected: disconnected from session " + session.sessionId)
mSession = null
cmTimer.stop()
disconnectSession()
videoCallResponseListener?.minimizeVideoEvent(false)
}
override fun onError(session: Session, opentokError: OpentokError) {
Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId)
// videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in session ")
// dialog?.dismiss()
}
override fun onStreamReceived(session: Session, stream: Stream) {
Log.d(TAG, "onStreamReceived: New stream " + stream.streamId + " in session " + session.sessionId)
if (mSubscriber != null) {
isConnected = true
return
}
isConnected = true
subscribeToStream(stream)
if (mConnectedHandler != null && mConnectedRunnable != null)
mConnectedHandler!!.removeCallbacks(mConnectedRunnable!!)
videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(3, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid))
}
override fun onStreamDropped(session: Session, stream: Stream) {
Log.d(TAG, "onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId)
if (mSubscriber == null) {
return
}
if (mSubscriber!!.stream == stream) {
mSubscriberViewContainer.removeView(mSubscriber!!.view)
mSubscriber!!.destroy()
mSubscriber = null
}
disconnectSession()
}
override fun onStreamCreated(publisherKit: PublisherKit?, stream: Stream) {
Log.d(TAG, "onStreamCreated: Own stream " + stream.streamId + " created")
}
override fun onStreamDestroyed(publisherKit: PublisherKit?, stream: Stream) {
Log.d(TAG, "onStreamDestroyed: Own stream " + stream.streamId + " destroyed")
}
override fun onError(publisherKit: PublisherKit?, opentokError: OpentokError) {
Log.d(VideoCallFragment.TAG, "onError: Error (" + opentokError.message + ") in publisher")
// videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in publisher")
// dialog?.dismiss()
}
override fun onVideoDataReceived(subscriberKit: SubscriberKit?) {
mSubscriber!!.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL)
(mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
mSubscriberViewContainer.addView(mSubscriber!!.view)
// switchToThumbnailCircle()
}
fun switchToThumbnailCircle() {
thumbnail_container.postDelayed({
val view = mSubscriber!!.view
if (view.parent != null) {
(view.parent as ViewGroup).removeView(view)
}
if (view is GLSurfaceView) {
view.setZOrderOnTop(true)
if (mSubscriber!!.renderer is DynamicVideoRenderer) {
(mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(true)
thumbnail_container.addView(view)
}
}
switchToFullScreenView()
}, 4000)
}
fun switchToFullScreenView() {
mSubscriberViewContainer.postDelayed({
val view = mSubscriber!!.view
if (view.parent != null) {
(view.parent as ViewGroup).removeView(view)
}
if (view is GLSurfaceView) {
view.setZOrderOnTop(false)
if (mSubscriber!!.renderer is DynamicVideoRenderer) {
(mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
mSubscriberViewContainer.addView(view)
}
}
switchToThumbnailCircle()
}, 4000)
}
override fun onVideoDisabled(subscriberKit: SubscriberKit?, s: String?) {}
override fun onVideoEnabled(subscriberKit: SubscriberKit?, s: String?) {}
override fun onVideoDisableWarning(subscriberKit: SubscriberKit?) {}
override fun onVideoDisableWarningLifted(subscriberKit: SubscriberKit?) {}
private fun subscribeToStream(stream: Stream) {
mSubscriber = Subscriber.Builder(requireContext(), stream)
.renderer(DynamicVideoRenderer(requireContext()))
.build()
mSubscriber!!.setVideoListener(this)
mSession!!.subscribe(mSubscriber)
}
private fun disconnectSession() {
if (mSession == null) {
videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED)
// requireActivity().setResult(Activity.RESULT_CANCELED)
dialog?.dismiss()
return
}
if (mSubscriber != null) {
mSubscriberViewContainer.removeView(mSubscriber!!.view)
mSession!!.unsubscribe(mSubscriber)
mSubscriber!!.destroy()
mSubscriber = null
}
if (mPublisher != null) {
mPublisherViewContainer.removeView(mPublisher!!.view)
mSession!!.unpublish(mPublisher)
mPublisher!!.destroy()
mPublisher = null
}
mSession!!.disconnect()
countDownTimer?.cancel()
videoCallPresenter.callChangeCallStatus(ChangeCallStatusRequestModel(16, sessionStatusModel!!.doctorId, sessionStatusModel!!.generalid, token, sessionStatusModel!!.vcid))
dialog?.dismiss()
}
override fun onCallSuccessful(sessionStatusModel: SessionStatusModel) {
if (sessionStatusModel.sessionStatus == 2 || sessionStatusModel.sessionStatus == 3) {
val returnIntent = Intent()
returnIntent.putExtra("sessionStatusNotRespond", sessionStatusModel)
videoCallResponseListener?.onCallFinished(Activity.RESULT_OK, returnIntent)
// requireActivity().setResult(Activity.RESULT_OK, returnIntent)
dialog?.dismiss()
}
}
override fun onCallChangeCallStatusSuccessful(sessionStatusModel: SessionStatusModel?) {}
override fun onFailure() {}
private fun onSwitchCameraClicked(view: View?) {
if (mPublisher != null) {
isSwitchCameraClicked = !isSwitchCameraClicked
mPublisher!!.cycleCamera()
val res = if (isSwitchCameraClicked) R.drawable.camera_front else R.drawable.camera_back
mSwitchCameraBtn.setImageResource(res)
}
}
fun onCallClicked() {
disconnectSession()
}
private fun miniCircleDoubleTap() {
if (isCircle) {
onMiniCircleClicked()
}
}
private fun onMiniCircleClicked() {
if (isCircle) {
dialog?.window?.setLayout(
400,
600
)
} else {
dialog?.window?.setLayout(
300,
300
)
}
isCircle = !isCircle
if (mSubscriber != null) {
(mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle)
} else {
if (isCircle) {
videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
} else {
videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
}
}
if (isCircle) {
controlPanel.visibility = View.GONE
layoutMini.visibility = View.GONE
} else {
controlPanel.visibility = View.VISIBLE
layoutMini.visibility = View.VISIBLE
}
}
private fun onMinimizedClicked(view: View?) {
if (isFullScreen) {
dialog?.window?.setLayout(
400,
600
)
} else {
dialog?.window?.setLayout(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
}
isFullScreen = !isFullScreen
val res = if (isFullScreen) R.drawable.reducing else R.drawable.expand
btnMinimize.setImageResource(res)
setViewsVisibility()
// videoCallResponseListener?.minimizeVideoEvent(!isFullScreen)
}
private fun setViewsVisibility() {
val iconSize: Int = context!!.resources.getDimension(R.dimen.video_icon_size).toInt()
val iconSizeSmall: Int = context!!.resources.getDimension(R.dimen.video_icon_size_small).toInt()
val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams = btnMinimize.layoutParams as ConstraintLayout.LayoutParams
val mCallBtnLayoutParam: ConstraintLayout.LayoutParams = mCallBtn.layoutParams as ConstraintLayout.LayoutParams
val localPreviewMargin: Int = context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt()
val localPreviewWidth: Int = context!!.resources.getDimension(R.dimen.local_preview_width).toInt()
val localPreviewHeight: Int = context!!.resources.getDimension(R.dimen.local_preview_height).toInt()
// val localPreviewIconSize: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size).toInt()
// val localPreviewMarginSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_margin_small).toInt()
// val localPreviewWidthSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_width_small).toInt()
// val localPreviewHeightSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_height_small).toInt()
// val localPreviewIconSmall: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size_small).toInt()
// val localPreviewLayoutIconParam : FrameLayout.LayoutParams
val localPreviewLayoutParam: RelativeLayout.LayoutParams = mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams
val remotePreviewIconSize: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size).toInt()
val remotePreviewIconSizeSmall: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size_small).toInt()
val remotePreviewLayoutParam: FrameLayout.LayoutParams = mSubscriberViewIcon.layoutParams as FrameLayout.LayoutParams
if (isFullScreen) {
layoutName.visibility = View.VISIBLE
layoutMini.visibility = View.GONE
mCameraBtn.visibility = View.VISIBLE
mSwitchCameraBtn.visibility = View.VISIBLE
// mspeckerBtn.visibility = View.VISIBLE
mMicBtn.visibility = View.VISIBLE
btnMinimizeLayoutParam.width = iconSize
btnMinimizeLayoutParam.height = iconSize
mCallBtnLayoutParam.width = iconSize
mCallBtnLayoutParam.height = iconSize
// localPreviewLayoutIconParam = FrameLayout.LayoutParams(localPreviewIconSize, localPreviewIconSize)
//// localPreviewLayoutParam = RelativeLayout.LayoutParams(localPreviewWidth, localPreviewHeight)
localPreviewLayoutParam.width = localPreviewWidth
localPreviewLayoutParam.height = localPreviewHeight
localPreviewLayoutParam.setMargins(0, localPreviewMargin, localPreviewMargin, 0)
// remotePreviewLayoutParam = FrameLayout.LayoutParams(remotePreviewIconSize, remotePreviewIconSize)
remotePreviewLayoutParam.width = remotePreviewIconSize
remotePreviewLayoutParam.height = remotePreviewIconSize
} else {
layoutName.visibility = View.GONE
layoutMini.visibility = View.VISIBLE
mCameraBtn.visibility = View.GONE
mSwitchCameraBtn.visibility = View.GONE
// mspeckerBtn.visibility = View.GONE
mMicBtn.visibility = View.GONE
// mPublisherViewContainer.visibility = View.GONE
// mPublisherViewIcon.visibility = View.GONE
// layoutParam = ConstraintLayout.LayoutParams(iconSizeSmall, iconSizeSmall)
btnMinimizeLayoutParam.width = iconSizeSmall
btnMinimizeLayoutParam.height = iconSizeSmall
mCallBtnLayoutParam.width = iconSizeSmall
mCallBtnLayoutParam.height = iconSizeSmall
localPreviewLayoutParam.width = 0
localPreviewLayoutParam.height = 0
localPreviewLayoutParam.setMargins(0, localPreviewMargin / 2, localPreviewMargin / 2, 0)
// localPreviewLayoutIconParam = FrameLayout.LayoutParams(localPreviewIconSmall, localPreviewIconSmall)
//// localPreviewLayoutParam = RelativeLayout.LayoutParams(localPreviewWidthSmall, localPreviewHeightSmall)
// localPreviewLayoutParam.width = localPreviewWidthSmall
// localPreviewLayoutParam.height = localPreviewWidthSmall
// localPreviewLayoutParam.setMargins(0,localPreviewMarginSmall, localPreviewMarginSmall, 0)
// remotePreviewLayoutParam = FrameLayout.LayoutParams(remotePreviewIconSizeSmall, remotePreviewIconSizeSmall)
remotePreviewLayoutParam.width = remotePreviewIconSizeSmall
remotePreviewLayoutParam.height = remotePreviewIconSizeSmall
if (isCircle) {
controlPanel.visibility = View.GONE
layoutMini.visibility = View.GONE
} else {
controlPanel.visibility = View.VISIBLE
layoutMini.visibility = View.VISIBLE
}
}
mPublisherViewContainer.layoutParams = localPreviewLayoutParam
// mPublisherViewIcon.layoutParams = localPreviewLayoutIconParam
mSubscriberViewIcon.layoutParams = remotePreviewLayoutParam
btnMinimize.layoutParams = btnMinimizeLayoutParam
mCallBtn.layoutParams = mCallBtnLayoutParam
}
private fun onCameraClicked(view: View?) {
if (mPublisher != null) {
isCameraClicked = !isCameraClicked
mPublisher!!.publishVideo = !isCameraClicked
val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled
mCameraBtn!!.setImageResource(res)
}
}
private fun onMicClicked(view: View?) {
if (mPublisher != null) {
isMicClicked = !isMicClicked
mPublisher!!.publishAudio = !isMicClicked
val res = if (isMicClicked) R.drawable.mic_disabled else R.drawable.mic_enabled
mMicBtn!!.setImageResource(res)
}
}
private fun onSpeckerClicked(view: View?) {
if (mSubscriber != null) {
isSpeckerClicked = !isSpeckerClicked
mSubscriber!!.subscribeToAudio = !isSpeckerClicked
val res = if (isSpeckerClicked) R.drawable.audio_disabled else R.drawable.audio_enabled
mspeckerBtn.setImageResource(res)
}
}
@SuppressLint("ClickableViewAccessibility")
private fun handleDragDialog() {
mWindowManager = requireActivity().getSystemService(Context.WINDOW_SERVICE) as WindowManager
getWindowManagerDefaultDisplay()
videoCallContainer.setOnTouchListener(dragListener)
mSubscriberViewContainer.setOnTouchListener(dragListener)
}
@SuppressLint("ClickableViewAccessibility")
private val dragListener: View.OnTouchListener = View.OnTouchListener { _, event ->
mDetector.onTouchEvent(event)
//Get Floating widget view params
val layoutParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
//get the touch location coordinates
val x_cord = event.rawX.toInt()
val y_cord = event.rawY.toInt()
val x_cord_Destination: Int
var y_cord_Destination: Int
when (event.action) {
MotionEvent.ACTION_DOWN -> {
x_init_cord = x_cord
y_init_cord = y_cord
//remember the initial position.
x_init_margin = layoutParams.x
y_init_margin = layoutParams.y
}
MotionEvent.ACTION_UP -> {
//Get the difference between initial coordinate and current coordinate
val x_diff: Int = x_cord - x_init_cord
val y_diff: Int = y_cord - y_init_cord
y_cord_Destination = y_init_margin + y_diff
val barHeight: Int = getStatusBarHeight()
if (y_cord_Destination < 0) {
// y_cord_Destination = 0
// y_cord_Destination =
// -(szWindow.y - (videoCallContainer.height /*+ barHeight*/))
y_cord_Destination = -(szWindow.y / 2)
} else if (y_cord_Destination + (videoCallContainer.height + barHeight) > szWindow.y) {
// y_cord_Destination = szWindow.y - (videoCallContainer.height + barHeight)
y_cord_Destination = (szWindow.y / 2)
}
layoutParams.y = y_cord_Destination
//reset position if user drags the floating view
resetPosition(x_cord)
}
MotionEvent.ACTION_MOVE -> {
val x_diff_move: Int = x_cord - x_init_cord
val y_diff_move: Int = y_cord - y_init_cord
x_cord_Destination = x_init_margin + x_diff_move
y_cord_Destination = y_init_margin + y_diff_move
layoutParams.x = x_cord_Destination
layoutParams.y = y_cord_Destination
dialog!!.window!!.attributes = layoutParams
}
}
true
}
private fun showControlPanelTemporarily() {
if (!isCircle) {
controlPanel.visibility = View.VISIBLE
mVolHandler!!.removeCallbacks(mVolRunnable!!)
mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
}
}
/* Reset position of Floating Widget view on dragging */
private fun resetPosition(x_cord_now: Int) {
if (x_cord_now <= szWindow.x / 2) {
isLeft = true
moveToLeft(x_cord_now)
} else {
isLeft = false
moveToRight(x_cord_now)
}
}
/* Method to move the Floating widget view to Left */
private fun moveToLeft(current_x_cord: Int) {
var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
mParams.x =
(szWindow.x - current_x_cord * current_x_cord - videoCallContainer.width).toInt()
dialog!!.window!!.attributes = mParams
val x = szWindow.x - current_x_cord
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
override fun onTick(t: Long) {
val step = (500 - t) / 5
// mParams.x = 0 - (current_x_cord * current_x_cord * step).toInt()
mParams.x =
(szWindow.x - current_x_cord * current_x_cord * step - videoCallContainer.width).toInt()
dialog!!.window!!.attributes = mParams
}
override fun onFinish() {
mParams.x = -(szWindow.x - videoCallContainer.width)
dialog!!.window!!.attributes = mParams
}
}.start()
}
/* Method to move the Floating widget view to Right */
private fun moveToRight(current_x_cord: Int) {
// var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes
// mParams.x =
// (szWindow.x + current_x_cord * current_x_cord - videoCallContainer.width).toInt()
//
// dialog!!.window!!.attributes = mParams
object : CountDownTimer(500, 5) {
//get params of Floating Widget view
var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
override fun onTick(t: Long) {
val step = (500 - t) / 5
mParams.x =
(szWindow.x + current_x_cord * current_x_cord * step - videoCallContainer.width).toInt()
dialog!!.window!!.attributes = mParams
}
override fun onFinish() {
mParams.x = szWindow.x - videoCallContainer.width
dialog!!.window!!.attributes = mParams
}
}.start()
}
private fun getWindowManagerDefaultDisplay() {
mWindowManager.getDefaultDisplay()
.getSize(szWindow)
}
/* return status bar height on basis of device display metrics */
private fun getStatusBarHeight(): Int {
return ceil(
(25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble()
).toInt()
}
private class MyGestureListener(val onTabCall: () -> Unit, val miniCircleDoubleTap: () -> Unit) : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
onTabCall()
return true
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
miniCircleDoubleTap()
return super.onDoubleTap(e)
}
}
companion object {
@JvmStatic
fun newInstance(args: Bundle) =
VideoCallFragment().apply {
arguments = args
}
private val TAG = VideoCallFragment::class.java.simpleName
private const val RC_SETTINGS_SCREEN_PERM = 123
private const val RC_VIDEO_APP_PERM = 124
}
}

@ -0,0 +1,379 @@
package com.hmg.hmgDr.util
import android.content.Context
import android.content.res.Resources
import android.graphics.PixelFormat
import android.opengl.GLES20
import android.opengl.GLSurfaceView
import android.opengl.Matrix
import android.view.View
import com.opentok.android.BaseVideoRenderer
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.ShortBuffer
import java.util.concurrent.locks.ReentrantLock
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
/*
* https://nhancv.medium.com/android-how-to-make-a-circular-view-as-a-thumbnail-of-opentok-27992aee15c9
* to solve make circle video stream
* */
class DynamicVideoRenderer(private val mContext: Context) : BaseVideoRenderer() {
private val mView: GLSurfaceView = GLSurfaceView(mContext)
private val mRenderer: MyRenderer
interface DynamicVideoRendererMetadataListener {
fun onMetadataReady(metadata: ByteArray?)
}
fun setDynamicVideoRendererMetadataListener(metadataListener: DynamicVideoRendererMetadataListener?) {
mRenderer.metadataListener = metadataListener
}
fun enableThumbnailCircle(enable: Boolean) {
mRenderer.requestEnableThumbnailCircle = enable
}
internal class MyRenderer : GLSurfaceView.Renderer {
var mTextureIds = IntArray(3)
var mScaleMatrix = FloatArray(16)
private val mVertexBuffer: FloatBuffer
private val mTextureBuffer: FloatBuffer
private val mDrawListBuffer: ShortBuffer
var requestEnableThumbnailCircle = false
var mVideoFitEnabled = true
var mVideoDisabled = false
private val mVertexIndex = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw
// vertices
private val vertexShaderCode = """uniform mat4 uMVPMatrix;attribute vec4 aPosition;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = aTextureCoord;
}
"""
private val fragmentShaderCode = """precision mediump float;
uniform sampler2D Ytex;
uniform sampler2D Utex,Vtex;
uniform int enableCircle;
uniform vec2 radiusDp;
varying vec2 vTextureCoord;
void main(void) {
float nx,ny,r,g,b,y,u,v;
mediump vec4 txl,ux,vx; nx=vTextureCoord[0];
ny=vTextureCoord[1];
y=texture2D(Ytex,vec2(nx,ny)).r;
u=texture2D(Utex,vec2(nx,ny)).r;
v=texture2D(Vtex,vec2(nx,ny)).r;
y=1.1643*(y-0.0625);
u=u-0.5;
v=v-0.5;
r=y+1.5958*v;
g=y-0.39173*u-0.81290*v;
b=y+2.017*u;
if (enableCircle > 0) {
float radius = 0.5;
vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
vec4 color1 = vec4(r, g, b, 1.0);
vec2 st = (gl_FragCoord.xy/radiusDp.xy); float dist = radius - distance(st,vec2(0.5));
float t = 1.0;
if (dist < 0.0) t = 0.0;
gl_FragColor = mix(color0, color1, t);
}
else {
gl_FragColor = vec4(r, g, b, 1.0);
}
}
"""
var mFrameLock = ReentrantLock()
var mCurrentFrame: Frame? = null
private var mProgram = 0
private var mTextureWidth = 0
private var mTextureHeight = 0
private var mViewportWidth = 0
private var mViewportHeight = 0
override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
gl.glClearColor(0f, 0f, 0f, 1f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode)
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode)
mProgram = GLES20.glCreateProgram() // create empty OpenGL ES
// Program
GLES20.glAttachShader(mProgram, vertexShader) // add the vertex
// shader to program
GLES20.glAttachShader(mProgram, fragmentShader) // add the fragment
// shader to
// program
GLES20.glLinkProgram(mProgram)
val positionHandle = GLES20.glGetAttribLocation(mProgram,
"aPosition")
val textureHandle = GLES20.glGetAttribLocation(mProgram,
"aTextureCoord")
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false, COORDS_PER_VERTEX * 4,
mVertexBuffer)
GLES20.glEnableVertexAttribArray(positionHandle)
GLES20.glVertexAttribPointer(textureHandle,
TEXTURECOORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
TEXTURECOORDS_PER_VERTEX * 4, mTextureBuffer)
GLES20.glEnableVertexAttribArray(textureHandle)
GLES20.glUseProgram(mProgram)
var i = GLES20.glGetUniformLocation(mProgram, "Ytex")
GLES20.glUniform1i(i, 0) /* Bind Ytex to texture unit 0 */
i = GLES20.glGetUniformLocation(mProgram, "Utex")
GLES20.glUniform1i(i, 1) /* Bind Utex to texture unit 1 */
i = GLES20.glGetUniformLocation(mProgram, "Vtex")
GLES20.glUniform1i(i, 2) /* Bind Vtex to texture unit 2 */
val radiusDpLocation = GLES20.glGetUniformLocation(mProgram, "radiusDp")
val radiusDp = (Resources.getSystem().displayMetrics.density * THUMBNAIL_SIZE).toInt()
GLES20.glUniform2f(radiusDpLocation, radiusDp.toFloat(), radiusDp.toFloat())
mTextureWidth = 0
mTextureHeight = 0
}
fun enableThumbnailCircle(enable: Boolean) {
GLES20.glUseProgram(mProgram)
val enableCircleLocation = GLES20.glGetUniformLocation(mProgram, "enableCircle")
GLES20.glUniform1i(enableCircleLocation, if (enable) 1 else 0)
}
fun setupTextures(frame: Frame) {
if (mTextureIds[0] != 0) {
GLES20.glDeleteTextures(3, mTextureIds, 0)
}
GLES20.glGenTextures(3, mTextureIds, 0)
val w = frame.width
val h = frame.height
val hw = w + 1 shr 1
val hh = h + 1 shr 1
initializeTexture(GLES20.GL_TEXTURE0, mTextureIds[0], w, h)
initializeTexture(GLES20.GL_TEXTURE1, mTextureIds[1], hw, hh)
initializeTexture(GLES20.GL_TEXTURE2, mTextureIds[2], hw, hh)
mTextureWidth = frame.width
mTextureHeight = frame.height
}
fun updateTextures(frame: Frame) {
val width = frame.width
val height = frame.height
val half_width = width + 1 shr 1
val half_height = height + 1 shr 1
val y_size = width * height
val uv_size = half_width * half_height
val bb = frame.buffer
// If we are reusing this frame, make sure we reset position and
// limit
bb.clear()
if (bb.remaining() == y_size + uv_size * 2) {
bb.position(0)
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1)
GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1)
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[0])
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
bb)
bb.position(y_size)
GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[1])
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
half_width, half_height, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, bb)
bb.position(y_size + uv_size)
GLES20.glActiveTexture(GLES20.GL_TEXTURE2)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[2])
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
half_width, half_height, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, bb)
} else {
mTextureWidth = 0
mTextureHeight = 0
}
}
override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
mViewportWidth = width
mViewportHeight = height
}
var metadataListener: DynamicVideoRendererMetadataListener? = null
override fun onDrawFrame(gl: GL10) {
gl.glClearColor(0f, 0f, 0f, 0f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
mFrameLock.lock()
if (mCurrentFrame != null && !mVideoDisabled) {
GLES20.glUseProgram(mProgram)
if (mTextureWidth != mCurrentFrame!!.width
|| mTextureHeight != mCurrentFrame!!.height) {
setupTextures(mCurrentFrame!!)
}
updateTextures(mCurrentFrame!!)
Matrix.setIdentityM(mScaleMatrix, 0)
var scaleX = 1.0f
var scaleY = 1.0f
val ratio = (mCurrentFrame!!.width.toFloat()
/ mCurrentFrame!!.height)
val vratio = mViewportWidth.toFloat() / mViewportHeight
if (mVideoFitEnabled) {
if (ratio > vratio) {
scaleY = vratio / ratio
} else {
scaleX = ratio / vratio
}
} else {
if (ratio < vratio) {
scaleY = vratio / ratio
} else {
scaleX = ratio / vratio
}
}
Matrix.scaleM(mScaleMatrix, 0,
scaleX * if (mCurrentFrame!!.isMirroredX) -1.0f else 1.0f,
scaleY, 1f)
metadataListener?.onMetadataReady(mCurrentFrame!!.metadata)
val mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
"uMVPMatrix")
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false,
mScaleMatrix, 0)
enableThumbnailCircle(requestEnableThumbnailCircle)
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mVertexIndex.size,
GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer)
} else {
//black frame when video is disabled
gl.glClearColor(0f, 0f, 0f, 1f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
}
mFrameLock.unlock()
}
fun displayFrame(frame: Frame?) {
mFrameLock.lock()
if (mCurrentFrame != null) {
mCurrentFrame!!.recycle()
}
mCurrentFrame = frame
mFrameLock.unlock()
}
fun disableVideo(b: Boolean) {
mFrameLock.lock()
mVideoDisabled = b
if (mVideoDisabled) {
if (mCurrentFrame != null) {
mCurrentFrame!!.recycle()
}
mCurrentFrame = null
}
mFrameLock.unlock()
}
fun enableVideoFit(enableVideoFit: Boolean) {
mVideoFitEnabled = enableVideoFit
}
companion object {
// number of coordinates per vertex in this array
const val COORDS_PER_VERTEX = 3
const val TEXTURECOORDS_PER_VERTEX = 2
var mXYZCoords = floatArrayOf(
-1.0f, 1.0f, 0.0f, // top left
-1.0f, -1.0f, 0.0f, // bottom left
1.0f, -1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f // top right
)
var mUVCoords = floatArrayOf(0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f)
fun initializeTexture(name: Int, id: Int, width: Int, height: Int) {
GLES20.glActiveTexture(name)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id)
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE.toFloat())
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, null)
}
fun loadShader(type: Int, shaderCode: String?): Int {
val shader = GLES20.glCreateShader(type)
GLES20.glShaderSource(shader, shaderCode)
GLES20.glCompileShader(shader)
return shader
}
}
init {
val bb = ByteBuffer.allocateDirect(mXYZCoords.size * 4)
bb.order(ByteOrder.nativeOrder())
mVertexBuffer = bb.asFloatBuffer()
mVertexBuffer.put(mXYZCoords)
mVertexBuffer.position(0)
val tb = ByteBuffer.allocateDirect(mUVCoords.size * 4)
tb.order(ByteOrder.nativeOrder())
mTextureBuffer = tb.asFloatBuffer()
mTextureBuffer.put(mUVCoords)
mTextureBuffer.position(0)
val dlb = ByteBuffer.allocateDirect(mVertexIndex.size * 2)
dlb.order(ByteOrder.nativeOrder())
mDrawListBuffer = dlb.asShortBuffer()
mDrawListBuffer.put(mVertexIndex)
mDrawListBuffer.position(0)
}
}
override fun onFrame(frame: Frame) {
mRenderer.displayFrame(frame)
mView.requestRender()
}
override fun setStyle(key: String, value: String) {
if (STYLE_VIDEO_SCALE == key) {
if (STYLE_VIDEO_FIT == value) {
mRenderer.enableVideoFit(true)
} else if (STYLE_VIDEO_FILL == value) {
mRenderer.enableVideoFit(false)
}
}
}
override fun onVideoPropertiesChanged(videoEnabled: Boolean) {
mRenderer.disableVideo(!videoEnabled)
}
override fun getView(): View {
return mView
}
override fun onPause() {
mView.onPause()
}
override fun onResume() {
mView.onResume()
}
companion object {
private const val THUMBNAIL_SIZE = 90 //in dp
}
init {
mView.setEGLContextClientVersion(2)
mView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)
mView.holder.setFormat(PixelFormat.TRANSLUCENT)
mRenderer = MyRenderer()
mView.setRenderer(mRenderer)
mView.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
}
}

@ -0,0 +1,357 @@
package com.hmg.hmgDr.util
import android.content.Context
import android.content.res.Resources
import android.graphics.PixelFormat
import android.opengl.GLES20
import android.opengl.GLSurfaceView
import android.opengl.Matrix
import android.view.View
import com.opentok.android.BaseVideoRenderer
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.ShortBuffer
import java.util.concurrent.locks.ReentrantLock
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
class ThumbnailCircleVideoRenderer(private val mContext: Context) : BaseVideoRenderer() {
private val mView: GLSurfaceView = GLSurfaceView(mContext)
private val mRenderer: MyRenderer
interface ThumbnailCircleVideoRendererMetadataListener {
fun onMetadataReady(metadata: ByteArray?)
}
fun setThumbnailCircleVideoRendererMetadataListener(metadataListener: ThumbnailCircleVideoRendererMetadataListener?) {
mRenderer.metadataListener = metadataListener
}
internal class MyRenderer : GLSurfaceView.Renderer {
var mTextureIds = IntArray(3)
var mScaleMatrix = FloatArray(16)
private val mVertexBuffer: FloatBuffer
private val mTextureBuffer: FloatBuffer
private val mDrawListBuffer: ShortBuffer
var mVideoFitEnabled = true
var mVideoDisabled = false
private val mVertexIndex = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw
// vertices
private val vertexShaderCode = """uniform mat4 uMVPMatrix;attribute vec4 aPosition;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = aTextureCoord;
}
"""
private val fragmentShaderCode = """precision mediump float;
uniform sampler2D Ytex;
uniform sampler2D Utex,Vtex;
uniform vec2 radiusDp;
varying vec2 vTextureCoord;
void main(void) {
float nx,ny,r,g,b,y,u,v;
mediump vec4 txl,ux,vx; nx=vTextureCoord[0];
ny=vTextureCoord[1];
y=texture2D(Ytex,vec2(nx,ny)).r;
u=texture2D(Utex,vec2(nx,ny)).r;
v=texture2D(Vtex,vec2(nx,ny)).r;
y=1.1643*(y-0.0625);
u=u-0.5;
v=v-0.5;
r=y+1.5958*v;
g=y-0.39173*u-0.81290*v;
b=y+2.017*u;
float radius = 0.5;
vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
vec4 color1 = vec4(r, g, b, 1.0);
vec2 st = (gl_FragCoord.xy/radiusDp.xy); float dist = radius - distance(st,vec2(0.5));
float t = 1.0;
if (dist < 0.0) t = 0.0;
gl_FragColor = mix(color0, color1, t);
}
"""
var mFrameLock = ReentrantLock()
var mCurrentFrame: Frame? = null
private var mProgram = 0
private var mTextureWidth = 0
private var mTextureHeight = 0
private var mViewportWidth = 0
private var mViewportHeight = 0
override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
gl.glClearColor(0f, 0f, 0f, 1f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode)
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode)
mProgram = GLES20.glCreateProgram() // create empty OpenGL ES
// Program
GLES20.glAttachShader(mProgram, vertexShader) // add the vertex
// shader to program
GLES20.glAttachShader(mProgram, fragmentShader) // add the fragment
// shader to
// program
GLES20.glLinkProgram(mProgram)
val positionHandle = GLES20.glGetAttribLocation(mProgram,
"aPosition")
val textureHandle = GLES20.glGetAttribLocation(mProgram,
"aTextureCoord")
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false, COORDS_PER_VERTEX * 4,
mVertexBuffer)
GLES20.glEnableVertexAttribArray(positionHandle)
GLES20.glVertexAttribPointer(textureHandle,
TEXTURECOORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
TEXTURECOORDS_PER_VERTEX * 4, mTextureBuffer)
GLES20.glEnableVertexAttribArray(textureHandle)
GLES20.glUseProgram(mProgram)
var i = GLES20.glGetUniformLocation(mProgram, "Ytex")
GLES20.glUniform1i(i, 0) /* Bind Ytex to texture unit 0 */
i = GLES20.glGetUniformLocation(mProgram, "Utex")
GLES20.glUniform1i(i, 1) /* Bind Utex to texture unit 1 */
i = GLES20.glGetUniformLocation(mProgram, "Vtex")
GLES20.glUniform1i(i, 2) /* Bind Vtex to texture unit 2 */
val radiusDpLocation = GLES20.glGetUniformLocation(mProgram, "radiusDp")
val radiusDp = (Resources.getSystem().displayMetrics.density * THUMBNAIL_SIZE).toInt()
GLES20.glUniform2f(radiusDpLocation, radiusDp.toFloat(), radiusDp.toFloat())
mTextureWidth = 0
mTextureHeight = 0
}
fun setupTextures(frame: Frame) {
if (mTextureIds[0] != 0) {
GLES20.glDeleteTextures(3, mTextureIds, 0)
}
GLES20.glGenTextures(3, mTextureIds, 0)
val w = frame.width
val h = frame.height
val hw = w + 1 shr 1
val hh = h + 1 shr 1
initializeTexture(GLES20.GL_TEXTURE0, mTextureIds[0], w, h)
initializeTexture(GLES20.GL_TEXTURE1, mTextureIds[1], hw, hh)
initializeTexture(GLES20.GL_TEXTURE2, mTextureIds[2], hw, hh)
mTextureWidth = frame.width
mTextureHeight = frame.height
}
fun updateTextures(frame: Frame) {
val width = frame.width
val height = frame.height
val half_width = width + 1 shr 1
val half_height = height + 1 shr 1
val y_size = width * height
val uv_size = half_width * half_height
val bb = frame.buffer
// If we are reusing this frame, make sure we reset position and
// limit
bb.clear()
if (bb.remaining() == y_size + uv_size * 2) {
bb.position(0)
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1)
GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1)
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[0])
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
bb)
bb.position(y_size)
GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[1])
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
half_width, half_height, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, bb)
bb.position(y_size + uv_size)
GLES20.glActiveTexture(GLES20.GL_TEXTURE2)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[2])
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
half_width, half_height, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, bb)
} else {
mTextureWidth = 0
mTextureHeight = 0
}
}
override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
mViewportWidth = width
mViewportHeight = height
}
var metadataListener: ThumbnailCircleVideoRendererMetadataListener? = null
override fun onDrawFrame(gl: GL10) {
gl.glClearColor(0f, 0f, 0f, 0f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
mFrameLock.lock()
if (mCurrentFrame != null && !mVideoDisabled) {
GLES20.glUseProgram(mProgram)
if (mTextureWidth != mCurrentFrame!!.width
|| mTextureHeight != mCurrentFrame!!.height) {
setupTextures(mCurrentFrame!!)
}
updateTextures(mCurrentFrame!!)
Matrix.setIdentityM(mScaleMatrix, 0)
var scaleX = 1.0f
var scaleY = 1.0f
val ratio = (mCurrentFrame!!.width.toFloat()
/ mCurrentFrame!!.height)
val vratio = mViewportWidth.toFloat() / mViewportHeight
if (mVideoFitEnabled) {
if (ratio > vratio) {
scaleY = vratio / ratio
} else {
scaleX = ratio / vratio
}
} else {
if (ratio < vratio) {
scaleY = vratio / ratio
} else {
scaleX = ratio / vratio
}
}
Matrix.scaleM(mScaleMatrix, 0,
scaleX * if (mCurrentFrame!!.isMirroredX) -1.0f else 1.0f,
scaleY, 1f)
metadataListener?.onMetadataReady(mCurrentFrame!!.metadata)
val mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
"uMVPMatrix")
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false,
mScaleMatrix, 0)
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mVertexIndex.size,
GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer)
} else {
//black frame when video is disabled
gl.glClearColor(0f, 0f, 0f, 1f)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
}
mFrameLock.unlock()
}
fun displayFrame(frame: Frame?) {
mFrameLock.lock()
if (mCurrentFrame != null) {
mCurrentFrame!!.recycle()
}
mCurrentFrame = frame
mFrameLock.unlock()
}
fun disableVideo(b: Boolean) {
mFrameLock.lock()
mVideoDisabled = b
if (mVideoDisabled) {
if (mCurrentFrame != null) {
mCurrentFrame!!.recycle()
}
mCurrentFrame = null
}
mFrameLock.unlock()
}
fun enableVideoFit(enableVideoFit: Boolean) {
mVideoFitEnabled = enableVideoFit
}
companion object {
// number of coordinates per vertex in this array
const val COORDS_PER_VERTEX = 3
const val TEXTURECOORDS_PER_VERTEX = 2
var mXYZCoords = floatArrayOf(
-1.0f, 1.0f, 0.0f, // top left
-1.0f, -1.0f, 0.0f, // bottom left
1.0f, -1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f // top right
)
var mUVCoords = floatArrayOf(0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f)
fun initializeTexture(name: Int, id: Int, width: Int, height: Int) {
GLES20.glActiveTexture(name)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id)
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE.toFloat())
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE, null)
}
fun loadShader(type: Int, shaderCode: String?): Int {
val shader = GLES20.glCreateShader(type)
GLES20.glShaderSource(shader, shaderCode)
GLES20.glCompileShader(shader)
return shader
}
}
init {
val bb = ByteBuffer.allocateDirect(mXYZCoords.size * 4)
bb.order(ByteOrder.nativeOrder())
mVertexBuffer = bb.asFloatBuffer()
mVertexBuffer.put(mXYZCoords)
mVertexBuffer.position(0)
val tb = ByteBuffer.allocateDirect(mUVCoords.size * 4)
tb.order(ByteOrder.nativeOrder())
mTextureBuffer = tb.asFloatBuffer()
mTextureBuffer.put(mUVCoords)
mTextureBuffer.position(0)
val dlb = ByteBuffer.allocateDirect(mVertexIndex.size * 2)
dlb.order(ByteOrder.nativeOrder())
mDrawListBuffer = dlb.asShortBuffer()
mDrawListBuffer.put(mVertexIndex)
mDrawListBuffer.position(0)
}
}
override fun onFrame(frame: Frame) {
mRenderer.displayFrame(frame)
mView.requestRender()
}
override fun setStyle(key: String, value: String) {
if (STYLE_VIDEO_SCALE == key) {
if (STYLE_VIDEO_FIT == value) {
mRenderer.enableVideoFit(true)
} else if (STYLE_VIDEO_FILL == value) {
mRenderer.enableVideoFit(false)
}
}
}
override fun onVideoPropertiesChanged(videoEnabled: Boolean) {
mRenderer.disableVideo(!videoEnabled)
}
override fun getView(): View {
return mView
}
override fun onPause() {
mView.onPause()
}
override fun onResume() {
mView.onResume()
}
companion object {
private const val THUMBNAIL_SIZE = 90 //in dp
}
init {
mView.setEGLContextClientVersion(2)
mView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)
mView.holder.setFormat(PixelFormat.TRANSLUCENT)
mRenderer = MyRenderer()
mView.setRenderer(mRenderer)
mView.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/remoteBackground"/>
<stroke android:width="2dp" android:color="@color/text_color" />
<size
android:width="120dp"
android:height="120dp"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,13H5v-2h14v2z"/>
</vector>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/text_color" />
<stroke
android:width="3dp"
android:color="@color/text_color" />
<corners android:radius="10dp" />
<padding
android:bottom="0dp"
android:left="0dp"
android:right="0dp"
android:top="0dp" />
</shape>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="1000dp"/>
<solid android:color="@color/green_dark"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

@ -1,169 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_clingo_video_call"
android:id="@+id/video_call_ll"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.VideoCallActivity">
android:background="@color/text_color"
android:orientation="vertical">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:keepScreenOn="true"
android:clickable="true">
<LinearLayout
android:id="@+id/subscriberview"
android:id="@+id/layout_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/padding_space_medium"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/patient_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/video_counter_fl"
android:textColor="@color/white"
android:textSize="@dimen/text_size_big"
android:textStyle="bold"
tools:text="Mousa Abuzaid" />
<FrameLayout
android:id="@+id/video_counter_fl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:orientation="horizontal"/>
android:layout_alignParentEnd="true"
android:background="@drawable/shape_capsule"
android:padding="@dimen/padding_space_small">
<Chronometer
android:id="@+id/cmTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
tools:text="25:45" />
</FrameLayout>
<RelativeLayout
android:id="@+id/publisherview"
android:layout_height="200dp"
android:layout_width="150dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/remote_video_view_container"
android:id="@+id/activity_clingo_video_call"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/remoteBackground">
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/control_panel"
app:layout_constraintTop_toBottomOf="@+id/layout_name">
<RelativeLayout
android:id="@+id/layout_mini"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/remoteBackground"
android:alpha="0.5"
android:visibility="gone">
<ImageButton
android:id="@+id/ic_mini"
style="@style/Widget.MaterialComponents.Button.Icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="@dimen/padding_space_medium"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@null"
android:src="@drawable/ic_mini" />
</RelativeLayout>
<FrameLayout
android:id="@+id/remote_video_view_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/icon_padding">
android:layout_below="@+id/layout_mini"
android:background="@color/remoteBackground">
<ImageView
android:id="@+id/remote_video_view_icon"
android:layout_width="@dimen/remote_back_icon_size"
android:layout_height="@dimen/remote_back_icon_size"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="@drawable/video_off_fill" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/icon_padding"
android:layout_width="match_parent"
android:layout_height="@dimen/remote_back_icon_margin_bottom"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
<FrameLayout
android:id="@+id/local_video_view_container"
android:layout_width="@dimen/local_preview_width"
android:layout_height="@dimen/local_preview_height"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/local_preview_margin_right"
android:layout_marginRight="@dimen/local_preview_margin_right"
android:layout_marginTop="@dimen/local_preview_margin_top"
android:background="@color/localBackground">
</FrameLayout>
<ImageView
android:layout_width="@dimen/local_back_icon_size"
android:layout_height="@dimen/local_back_icon_size"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/video_off_fill" />
</FrameLayout>
<FrameLayout
android:id="@+id/local_video_view_container"
android:layout_width="@dimen/local_preview_width"
android:layout_height="@dimen/local_preview_height"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="@dimen/local_preview_margin_top"
android:layout_marginEnd="@dimen/local_preview_margin_top">
<RelativeLayout
<ImageView
android:id="@+id/local_video_view_icon"
android:layout_width="@dimen/local_back_icon_size"
android:layout_height="@dimen/local_back_icon_size"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/video_off_fill" />
</FrameLayout>
<FrameLayout
android:id="@+id/thumbnail_container"
android:layout_width="90dp"
android:layout_height="90dp"
android:visibility="gone"
android:layout_alignParentBottom="true"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
/>
</RelativeLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/control_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp">
android:padding="@dimen/padding_space_big"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/btn_call"
android:layout_width="71dp"
android:layout_height="71dp"
android:layout_centerInParent="true"
android:onClick="onCallClicked"
android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size"
android:scaleType="centerCrop"
android:src="@drawable/call" />
android:src="@drawable/call"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/btn_switch_camera"
android:layout_width="39dp"
android:layout_height="39dp"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/control_bottom_horizontal_margin"
android:layout_toEndOf="@id/btn_camera"
android:layout_toRightOf="@id/btn_camera"
android:onClick="onSwitchCameraClicked"
android:id="@+id/btn_minimize"
android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size"
android:scaleType="centerCrop"
android:src="@drawable/flip_enabled" />
android:src="@drawable/reducing"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/btn_camera"
android:layout_width="39dp"
android:layout_height="39dp"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/control_bottom_horizontal_margin"
android:layout_toEndOf="@id/btn_call"
android:layout_toRightOf="@id/btn_call"
android:onClick="onCameraClicked"
android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerCrop"
android:src="@drawable/video_enabled" />
android:src="@drawable/video_enabled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_minimize"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/btn_mic"
android:layout_width="39dp"
android:layout_height="39dp"
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/control_bottom_horizontal_margin"
android:layout_toStartOf="@id/btn_call"
android:layout_toLeftOf="@id/btn_call"
android:onClick="onMicClicked"
android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerCrop"
android:src="@drawable/mic_enabled" />
android:src="@drawable/mic_enabled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_camera"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/btn_switch_camera"
android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerCrop"
android:src="@drawable/camera_back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_mic"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/btn_specker"
android:layout_width="39dp"
android:layout_height="39dp"
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/control_bottom_horizontal_margin"
android:layout_toStartOf="@id/btn_mic"
android:layout_toLeftOf="@id/btn_mic"
android:onClick="onSpeckerClicked"
android:layout_width="@dimen/video_icon_size"
android:layout_height="@dimen/video_icon_size"
android:layout_marginStart="@dimen/padding_space_medium"
android:scaleType="centerCrop"
android:src="@drawable/audio_enabled" />
</RelativeLayout>
android:src="@drawable/audio_enabled"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_mic"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- <RelativeLayout-->
<!-- android:id="@+id/progressBar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="40dp"-->
<!-- android:layout_alignParentBottom="true">-->
<!-- <ProgressBar-->
<!-- android:id="@+id/progress_bar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="31dp"-->
<!-- android:layout_alignParentEnd="true"-->
<!-- android:layout_alignParentBottom="true"-->
<!-- android:layout_marginEnd="0dp"-->
<!-- android:layout_marginBottom="0dp"-->
<!-- android:progressBackgroundTint="@color/colorProgressBarBackground"-->
<!-- style="@android:style/Widget.ProgressBar.Horizontal" />-->
<!-- <TextView-->
<!-- android:id="@+id/progress_bar_text"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginLeft="9dp"-->
<!-- android:gravity="center_vertical"-->
<!-- android:textColor="@color/colorPrimary"-->
<!-- android:layout_centerInParent="true"/>-->
<!-- </RelativeLayout>-->
</RelativeLayout>

@ -5,7 +5,17 @@
<color name="colorAccent">#fc3850</color>
<color name="colorProgressBarBackground">#e4e9f2</color>
<color name="transparent">#80757575</color>
<color name="transparent_full_opacity">#00ffffff</color>
<!-- Chat Activity -->
<color name="localBackground">#827b92</color>
<color name="remoteBackground">#484258</color>
<color name="text_color">#FF2E303A</color>
<color name="white">#fff</color>
<color name="black">#000</color>
<color name="green_dark">#389842</color>
<color name="red_dark">#d51e26</color>
</resources>

@ -3,20 +3,39 @@
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="local_preview_margin_top">28dp</dimen>
<dimen name="local_preview_margin_small">12dp</dimen>
<dimen name="local_preview_margin_right">24dp</dimen>
<!-- buttons -->
<dimen name="call_button_size">60dp</dimen>
<dimen name="other_button_size">54dp</dimen>
<dimen name="video_icon_size">52dp</dimen>
<dimen name="video_icon_size_small">24dp</dimen>
<!-- buttons -->
<dimen name="control_bottom_margin">24dp</dimen>
<dimen name="control_bottom_horizontal_margin">25dp</dimen>
<dimen name="local_preview_width">88dp</dimen>
<dimen name="local_preview_width_small">40dp</dimen>
<dimen name="local_preview_height">117dp</dimen>
<dimen name="local_preview_height_small">50dp</dimen>
<dimen name="local_back_icon_size">50dp</dimen>
<dimen name="local_back_icon_size_small">25dp</dimen>
<dimen name="remote_back_icon_size">100dp</dimen>
<dimen name="remote_back_icon_size_small">40dp</dimen>
<dimen name="remote_back_icon_margin_bottom">90dp</dimen>
<!-- buttons -->
<dimen name="control_bottom_margin">24dp</dimen>
<dimen name="control_bottom_horizontal_margin">25dp</dimen>
<!-- text-->
<dimen name="text_size_small">14sp</dimen>
<dimen name="text_size_medium">16sp</dimen>
<dimen name="text_size_big">22sp</dimen>
<!-- padding/margin-->
<dimen name="padding_space_small">4dp</dimen>
<dimen name="padding_space_medium">8sp</dimen>
<dimen name="padding_space_big">16dp</dimen>
<dimen name="padding_space_big_2">24dp</dimen>
</resources>

@ -4,5 +4,7 @@
<string name="remaining_ar">الوقت المتبقي بالثانيه: </string>
<string name="setting">Settings</string>
<string name="cancel">Cancel</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources>

@ -16,4 +16,21 @@
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="dialogTheme" parent="Theme.AppCompat.DayNight.Dialog.Alert">
<!-- title encapsulating main part (backgroud) of custom alertdialog -->
<item name="android:windowFrame">@null</item>
<!-- turn off any drawable used to draw a frame on the window -->
<item name="android:windowBackground">@null</item>
<!-- turn off any drawable used to draw a frame on the window -->
<item name="android:windowIsFloating">true</item>
<!-- float the window so it does not fill the screen -->
<item name="android:windowNoTitle">true</item>
<!-- remove the title bar we make our own-->
<item name="android:windowContentOverlay">@null</item>
<!-- remove the shadow from under the title bar -->
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
</style>
</resources>

@ -16,10 +16,12 @@ allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://tokbox.bintray.com/maven' }
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"

@ -0,0 +1,92 @@
# Uncomment this line to define a global platform for your project
platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end
generated_key_values
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
pod 'OpenTok'
pod 'Alamofire', '~> 5.2'
pod 'AADraggableView'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end

@ -9,12 +9,16 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
29211E4225C172B700DD740D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 29211E4125C172B700DD740D /* GoogleService-Info.plist */; };
300790FA266FB14B0052174C /* VCEmbeder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300790F9266FB14B0052174C /* VCEmbeder.swift */; };
300790FC26710CAB0052174C /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300790FB26710CAB0052174C /* Extensions.swift */; };
30F70E6C266F56FD005D8F8E /* MainAppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */; };
30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
9CE61EBD24AB366E008D68DD /* VideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61EBC24AB366E008D68DD /* VideoViewController.swift */; };
9CE61EBD24AB366E008D68DD /* VideoCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */; };
9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */; };
B650DC3076E9D70CB188286A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93A5F83B23AB032D1E096663 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
@ -37,6 +41,10 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
29211CD725C165D600DD740D /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = "<group>"; };
29211E4125C172B700DD740D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
300790F9266FB14B0052174C /* VCEmbeder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VCEmbeder.swift; sourceTree = "<group>"; };
300790FB26710CAB0052174C /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAppViewController.swift; sourceTree = "<group>"; };
30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallRequestParameters.swift; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -50,7 +58,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9CE61EBC24AB366E008D68DD /* VideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = "<group>"; };
9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallViewController.swift; sourceTree = "<group>"; };
9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICallProtocoll.swift; sourceTree = "<group>"; };
9D4B7DB43C6A6C849D2387CE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
E698D7B14B12DF768FE47A1A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
@ -68,6 +76,31 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
300790F8266FB0F10052174C /* helpers */ = {
isa = PBXGroup;
children = (
300790F9266FB14B0052174C /* VCEmbeder.swift */,
300790FB26710CAB0052174C /* Extensions.swift */,
);
name = helpers;
sourceTree = "<group>";
};
30F70E6A266F56C9005D8F8E /* controllers */ = {
isa = PBXGroup;
children = (
30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */,
);
name = controllers;
sourceTree = "<group>";
};
30F70E6D266F64F8005D8F8E /* Models */ = {
isa = PBXGroup;
children = (
30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */,
);
name = Models;
sourceTree = "<group>";
};
7D66D387293CE5376A07EC5F /* Pods */ = {
isa = PBXGroup;
children = (
@ -111,6 +144,9 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
300790F8266FB0F10052174C /* helpers */,
30F70E6D266F64F8005D8F8E /* Models */,
30F70E6A266F56C9005D8F8E /* controllers */,
29211E4125C172B700DD740D /* GoogleService-Info.plist */,
29211CD725C165D600DD740D /* RunnerRelease.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
@ -122,7 +158,7 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
9CE61EBC24AB366E008D68DD /* VideoViewController.swift */,
9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */,
9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */,
);
path = Runner;
@ -359,10 +395,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
300790FA266FB14B0052174C /* VCEmbeder.swift in Sources */,
30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */,
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
9CE61EBD24AB366E008D68DD /* VideoViewController.swift in Sources */,
300790FC26710CAB0052174C /* Extensions.swift in Sources */,
9CE61EBD24AB366E008D68DD /* VideoCallViewController.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */,
30F70E6C266F56FD005D8F8E /* MainAppViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

@ -27,6 +27,8 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@ -36,8 +38,8 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -59,6 +61,8 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"

@ -22,34 +22,8 @@ import OpenTok
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall",
binaryMessenger: controller.binaryMessenger)
videoCallChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
self.result = result
switch call.method {
case "openVideoCall":
do {
let arguments = call.arguments as? NSDictionary
let kApiKey = arguments!["kApiKey"] as? String
let kSessionId = arguments!["kSessionId"] as? String
let kToken = arguments!["kToken"] as? String
let appLang = arguments!["appLang"] as? String
let vC_ID = arguments!["VC_ID"] as? Int
let tokenID = arguments!["TokenID"] as? String
let generalId = arguments!["generalId"] as? String
let doctorId = arguments!["DoctorId"] as? Int
let baseUrl = arguments!["baseUrl"] as? String
self.openVideoChat(result: result,kApiKey: kApiKey!,kSessionId:kSessionId!,kToken: kToken!, appLang: appLang!, vC_ID: vC_ID!,tokenID: tokenID!,generalId: generalId!,doctorId: doctorId!, baseUrl: baseUrl!)
}
default:
result(FlutterMethodNotImplemented)
}
})
GeneratedPluginRegistrant.register(with: self)
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
@ -61,7 +35,7 @@ import OpenTok
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let identifier = "ViewControllerNav"
let navVC = storyboard.instantiateViewController(withIdentifier: identifier) as! UINavigationController
let videoVC = navVC.viewControllers.first as! ViewController
let videoVC = navVC.viewControllers.first as! VideoCallViewController
videoVC.kApiKey=kApiKey
videoVC.kSessionId=kSessionId
videoVC.kToken=kToken
@ -75,6 +49,6 @@ import OpenTok
navVC.modalPresentationStyle = .fullScreen
window.rootViewController?.present(navVC, animated: true, completion: nil)
}
}

@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "camera_back.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "camera_front.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "end_call.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "expand.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Group 8024.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "hide_video_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 B

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "mic_mute.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Group 8020.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "video_mute.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Group 8022.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

@ -1,296 +1,366 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<!--Main App View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="MainAppViewController" customModule="Runner" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-45" y="1436"/>
<point key="canvasLocation" x="-1535" y="2239"/>
</scene>
<!--View Controller-->
<!--Video Call View Controller-->
<scene sceneID="L7v-n1-KvF">
<objects>
<viewController id="t2c-G5-7AE" customClass="ViewController" customModule="Runner" customModuleProvider="target" sceneMemberID="viewController">
<viewController storyboardIdentifier="videoCall" id="t2c-G5-7AE" customClass="VideoCallViewController" customModule="Runner" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="BIa-yr-ZMY"/>
<viewControllerLayoutGuide type="bottom" id="VIH-1T-Ife"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="PoR-7r-yNe">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6C5-o5-R1n" userLabel="controlButtonSpacer">
<rect key="frame" x="14" y="844" width="139" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="0mU-Ko-Up3"/>
<constraint firstAttribute="width" constant="139" id="DNz-Ig-XOS"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yS9-HT-vp8" userLabel="controlButtonSpacer">
<rect key="frame" x="265" y="844" width="140" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="140" id="Alm-7E-yeU"/>
<constraint firstAttribute="height" constant="30" id="amS-in-0UH"/>
</constraints>
</view>
<view contentMode="scaleToFill" restorationIdentifier="VideoCallNavigationViewController" translatesAutoresizingMaskIntoConstraints="NO" id="eOT-Jr-GUl" userLabel="remoteVideo">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
<color key="backgroundColor" white="0.0" alpha="0.98999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="videoMutedIndicator" translatesAutoresizingMaskIntoConstraints="NO" id="CL1-2v-m1L" userLabel="remoteVideoMutedIndicator">
<rect key="frame" x="147" y="398" width="120" height="100"/>
<rect key="frame" x="160.66666666666666" y="418.33333333333331" width="106.99999999999997" height="89.333333333333314"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="eon-3Z-74P"/>
<constraint firstAttribute="height" constant="100" id="iyK-hL-H3m"/>
<constraint firstAttribute="width" secondItem="CL1-2v-m1L" secondAttribute="height" multiplier="6:5" id="xqE-6Q-WAu"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0ZP-s2-kM5" userLabel="localVideo">
<rect key="frame" x="270.5" y="138" width="103.5" height="224"/>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="localVideoMutedBg" translatesAutoresizingMaskIntoConstraints="NO" id="A0G-cT-yji" userLabel="localVideoMutedBg">
<rect key="frame" x="215" y="138" width="159" height="224"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sK0-tB-H9u" userLabel="controlButtons">
<rect key="frame" x="0.0" y="740" width="414" height="80"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O5s-CJ-RFv">
<rect key="frame" x="0.0" y="100" width="428" height="731"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NUO-2p-pzL" userLabel="videoMuteButton">
<rect key="frame" x="29" y="20.5" width="39" height="39"/>
<constraints>
<constraint firstAttribute="width" constant="39" id="CWU-fT-9gx"/>
<constraint firstAttribute="height" constant="39" id="nsM-Xv-O2N"/>
</constraints>
<state key="normal" title="Button" image="speakerOff"/>
<state key="selected" image="speakerOffSelected"/>
<connections>
<action selector="didClickSpeakerButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="XHg-oo-TWD"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="N2h-FX-kF5" userLabel="muteButton">
<rect key="frame" x="98" y="20.5" width="39" height="39"/>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XHG-Db-3Px" customClass="AADraggableView" customModule="AADraggableView">
<rect key="frame" x="288" y="10" width="130" height="182"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0ZP-s2-kM5" userLabel="localVideo">
<rect key="frame" x="0.0" y="0.0" width="130" height="182"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="5"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
<real key="value" value="0.5"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6y1-an-W7F">
<rect key="frame" x="0.0" y="0.0" width="130" height="182"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="videoMutedIndicator" translatesAutoresizingMaskIntoConstraints="NO" id="FEH-bC-Hnh" userLabel="localVideoMutedIndicator">
<rect key="frame" x="47" y="76" width="36" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="1iv-w5-GDT"/>
<constraint firstAttribute="width" constant="36" id="AwX-vQ-Ynn"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="FEH-bC-Hnh" firstAttribute="centerX" secondItem="6y1-an-W7F" secondAttribute="centerX" id="dtO-VP-8qV"/>
<constraint firstItem="FEH-bC-Hnh" firstAttribute="centerY" secondItem="6y1-an-W7F" secondAttribute="centerY" id="lpW-Vr-bH2"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="5"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="39" id="Nv9-dR-SYL"/>
<constraint firstAttribute="height" constant="39" id="lFc-rS-c6B"/>
<constraint firstItem="0ZP-s2-kM5" firstAttribute="top" secondItem="XHG-Db-3Px" secondAttribute="top" id="E5A-Yq-Ods"/>
<constraint firstAttribute="trailing" secondItem="6y1-an-W7F" secondAttribute="trailing" id="I0l-x2-rGO"/>
<constraint firstAttribute="width" secondItem="XHG-Db-3Px" secondAttribute="height" multiplier="1:1.4" id="M3V-vM-m0V"/>
<constraint firstAttribute="bottom" secondItem="6y1-an-W7F" secondAttribute="bottom" id="T0D-IE-19P"/>
<constraint firstItem="6y1-an-W7F" firstAttribute="top" secondItem="XHG-Db-3Px" secondAttribute="top" id="T8b-Nd-jdR"/>
<constraint firstItem="6y1-an-W7F" firstAttribute="leading" secondItem="XHG-Db-3Px" secondAttribute="leading" id="brg-bp-MME"/>
<constraint firstAttribute="bottom" secondItem="0ZP-s2-kM5" secondAttribute="bottom" id="hso-Od-7QF"/>
<constraint firstItem="0ZP-s2-kM5" firstAttribute="leading" secondItem="XHG-Db-3Px" secondAttribute="leading" id="k5R-AM-3J6"/>
<constraint firstAttribute="trailing" secondItem="0ZP-s2-kM5" secondAttribute="trailing" id="z8V-qh-Rzq"/>
</constraints>
<state key="normal" title="Button" image="muteButton"/>
<state key="selected" image="muteButtonSelected"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="padding">
<integer key="value" value="20"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4S7-45-trL">
<rect key="frame" x="0.0" y="0.0" width="428" height="731"/>
<connections>
<action selector="didClickMuteButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="7lr-uj-db1"/>
<action selector="btnSwipeVideoTapped:" destination="t2c-G5-7AE" eventType="touchUpInside" id="7AQ-6d-4iR"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ygd-al-G4F" userLabel="switchCameraButton">
<rect key="frame" x="352" y="20.5" width="39" height="39"/>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="4S7-45-trL" firstAttribute="leading" secondItem="O5s-CJ-RFv" secondAttribute="leading" id="AMe-9q-Xk9"/>
<constraint firstAttribute="trailing" secondItem="4S7-45-trL" secondAttribute="trailing" id="CX4-Rs-rep"/>
<constraint firstAttribute="trailing" secondItem="XHG-Db-3Px" secondAttribute="trailing" constant="10" id="Ncy-sD-qeL"/>
<constraint firstAttribute="bottom" secondItem="4S7-45-trL" secondAttribute="bottom" id="iJ9-pg-VXQ"/>
<constraint firstItem="XHG-Db-3Px" firstAttribute="top" secondItem="O5s-CJ-RFv" secondAttribute="top" constant="10" id="nM8-B7-soj"/>
<constraint firstItem="4S7-45-trL" firstAttribute="top" secondItem="O5s-CJ-RFv" secondAttribute="top" id="sNK-WK-tqV"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WPH-QE-Fvp">
<rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
<connections>
<action selector="btnOnScreenTapped:" destination="t2c-G5-7AE" eventType="touchUpInside" id="jDS-QU-1VX"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sK0-tB-H9u" userLabel="controlButtons">
<rect key="frame" x="0.0" y="831" width="428" height="95"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="r9w-8l-Zxj">
<rect key="frame" x="15" y="15" width="230" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UZ6-EY-a59" userLabel="minMax">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<constraints>
<constraint firstAttribute="width" secondItem="UZ6-EY-a59" secondAttribute="height" multiplier="1:1" id="Ula-Qc-wJE"/>
</constraints>
<state key="normal" title="Button" image="float_video"/>
<state key="selected" image="expand_video"/>
<connections>
<action selector="btnMinimizeTapped:" destination="t2c-G5-7AE" eventType="touchUpInside" id="xul-cC-cbm"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NUO-2p-pzL" userLabel="videoMuteButton">
<rect key="frame" x="60" y="0.0" width="50" height="50"/>
<constraints>
<constraint firstAttribute="width" secondItem="NUO-2p-pzL" secondAttribute="height" multiplier="1:1" id="KGm-Yp-MqK"/>
</constraints>
<state key="normal" image="video_unmute"/>
<state key="selected" image="video_mute"/>
<connections>
<action selector="didClickVideoMuteButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="nk9-nS-UDE"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="N2h-FX-kF5" userLabel="muteButton">
<rect key="frame" x="120" y="0.0" width="50" height="50"/>
<constraints>
<constraint firstAttribute="width" secondItem="N2h-FX-kF5" secondAttribute="height" multiplier="1:1" id="hI1-G0-K3C"/>
</constraints>
<state key="normal" image="mic_unmute"/>
<state key="selected" image="mic_mute"/>
<connections>
<action selector="didClickMuteButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="7lr-uj-db1"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" selected="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lar-xK-rhR" userLabel="switchCamera">
<rect key="frame" x="180" y="0.0" width="50" height="50"/>
<constraints>
<constraint firstAttribute="width" secondItem="lar-xK-rhR" secondAttribute="height" multiplier="1:1" id="Wpc-dx-kpF"/>
</constraints>
<state key="normal" image="camera_back"/>
<state key="selected" image="camera_front"/>
<connections>
<action selector="didClickSwitchCameraButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="S3g-7j-Ca0"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="39" id="EHa-e5-BfD"/>
<constraint firstAttribute="height" constant="39" id="KEK-0n-HJw"/>
<constraint firstAttribute="height" constant="50" id="3L0-3h-Bxg"/>
<constraint firstItem="lar-xK-rhR" firstAttribute="width" secondItem="lar-xK-rhR" secondAttribute="height" multiplier="1:1" id="R46-j0-zPf"/>
<constraint firstItem="UZ6-EY-a59" firstAttribute="height" secondItem="NUO-2p-pzL" secondAttribute="height" id="kK6-uF-bf6"/>
<constraint firstItem="N2h-FX-kF5" firstAttribute="height" secondItem="NUO-2p-pzL" secondAttribute="height" id="o4R-49-iMe"/>
<constraint firstAttribute="height" constant="30" id="y90-hA-p5Z"/>
</constraints>
<state key="normal" title="Button" image="switchCameraButton"/>
<state key="selected" image="switchCameraButtonSelected"/>
<connections>
<action selector="didClickSwitchCameraButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="TBa-Av-IXy"/>
</connections>
</button>
<variation key="default">
<mask key="constraints">
<exclude reference="y90-hA-p5Z"/>
</mask>
</variation>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AoF-Up-Yu5" userLabel="hangUpButton">
<rect key="frame" x="174" y="4.5" width="71" height="71"/>
<rect key="frame" x="363" y="15" width="50" height="50"/>
<constraints>
<constraint firstAttribute="width" constant="71" id="ACP-i0-gK8"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="71" id="DS1-a1-ep3"/>
<constraint firstAttribute="height" constant="71" id="ltx-rR-am0"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="71" id="s7u-Zs-z2Q"/>
<constraint firstAttribute="width" secondItem="AoF-Up-Yu5" secondAttribute="height" multiplier="1:1" id="6LJ-QR-WEY"/>
</constraints>
<state key="normal" image="hangUpButton"/>
<state key="normal" image="end_call"/>
<connections>
<action selector="hangUp:" destination="t2c-G5-7AE" eventType="touchUpInside" id="SUH-Gd-OXj"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7vf-kV-eQ5" userLabel="videoMuteButton">
<rect key="frame" x="283" y="20.5" width="39" height="39"/>
</subviews>
<color key="backgroundColor" red="0.18431372549019609" green="0.1764705882352941" blue="0.16470588235294117" alpha="0.5" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstItem="r9w-8l-Zxj" firstAttribute="top" secondItem="sK0-tB-H9u" secondAttribute="top" constant="15" id="00C-1i-sGc"/>
<constraint firstItem="AoF-Up-Yu5" firstAttribute="bottom" secondItem="r9w-8l-Zxj" secondAttribute="bottom" id="1kB-OK-b0L"/>
<constraint firstItem="r9w-8l-Zxj" firstAttribute="leading" secondItem="sK0-tB-H9u" secondAttribute="leading" priority="900" constant="5" id="6B7-94-Myo"/>
<constraint firstAttribute="trailing" secondItem="AoF-Up-Yu5" secondAttribute="trailing" priority="900" constant="5" id="DgE-WQ-KQm"/>
<constraint firstItem="r9w-8l-Zxj" firstAttribute="top" secondItem="sK0-tB-H9u" secondAttribute="top" priority="900" constant="5" id="Ft5-cy-2d0"/>
<constraint firstAttribute="bottom" secondItem="r9w-8l-Zxj" secondAttribute="bottom" constant="30" id="G9u-kw-mVz"/>
<constraint firstItem="AoF-Up-Yu5" firstAttribute="top" secondItem="r9w-8l-Zxj" secondAttribute="top" id="H4s-Y8-HAI"/>
<constraint firstAttribute="trailing" secondItem="AoF-Up-Yu5" secondAttribute="trailing" constant="15" id="flB-AR-zo3"/>
<constraint firstAttribute="bottom" secondItem="r9w-8l-Zxj" secondAttribute="bottom" priority="900" constant="5" id="n0r-vM-wKh"/>
<constraint firstItem="r9w-8l-Zxj" firstAttribute="leading" secondItem="sK0-tB-H9u" secondAttribute="leading" constant="15" id="x13-gZ-cYp"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2nj-Va-L7c" userLabel="TopBar">
<rect key="frame" x="0.0" y="0.0" width="428" height="100"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="n8H-om-4LV">
<rect key="frame" x="398" y="75" width="25" height="25"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="39" id="7Rd-r8-zJP"/>
<constraint firstAttribute="width" constant="39" id="mwK-hd-jIy"/>
<constraint firstAttribute="height" constant="25" id="dyc-7x-bTk"/>
<constraint firstAttribute="width" constant="25" id="tYx-Ul-0Pf"/>
</constraints>
<state key="normal" title="Button" image="videoMuteButton"/>
<state key="selected" image="videoMuteButtonSelected"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="●">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="didClickVideoMuteButton:" destination="t2c-G5-7AE" eventType="touchUpInside" id="Hza-Ft-NNB"/>
<action selector="circleFloatBtnTapped:" destination="t2c-G5-7AE" eventType="touchUpInside" id="2mC-ry-Lis"/>
</connections>
</button>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9g2-IH-l8e" userLabel="controlButtonSpacer">
<rect key="frame" x="396" y="0.0" width="18" height="80"/>
<constraints>
<constraint firstAttribute="width" priority="750" constant="18" id="7f6-zT-RoW"/>
<constraint firstAttribute="height" constant="80" id="cmy-aX-hM0"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a4N-1U-1Yt" userLabel="controlButtonSpacer">
<rect key="frame" x="328" y="0.0" width="18" height="80"/>
<constraints>
<constraint firstAttribute="width" priority="750" constant="18" id="X8j-wu-KrQ"/>
<constraint firstAttribute="height" constant="80" id="vkd-63-bmN"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GbA-j6-191" userLabel="controlButtonSpacer">
<rect key="frame" x="259" y="0.0" width="18" height="80"/>
<constraints>
<constraint firstAttribute="width" priority="750" constant="18" id="Bz0-tD-Q4d"/>
<constraint firstAttribute="height" constant="80" id="Ovg-ap-S7E"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h0g-z5-Y95" userLabel="controlButtonSpacer">
<rect key="frame" x="143" y="0.0" width="18" height="80"/>
<constraints>
<constraint firstAttribute="height" constant="80" id="Vaj-Va-jZn"/>
<constraint firstAttribute="width" priority="750" constant="18" id="Wv5-ys-Ho4"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gop-Yl-2fm" userLabel="controlButtonSpacer">
<rect key="frame" x="73" y="0.0" width="18" height="80"/>
<constraints>
<constraint firstAttribute="width" priority="750" constant="18" id="iqX-Wz-fb1"/>
<constraint firstAttribute="height" constant="80" id="j0P-xC-zSP"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JCG-W9-5ko" userLabel="controlButtonSpacer">
<rect key="frame" x="6" y="0.0" width="18" height="80"/>
<constraints>
<constraint firstAttribute="width" priority="750" constant="18" id="La6-ZY-Qs8"/>
<constraint firstAttribute="height" constant="80" id="mf9-Qg-gVZ"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="bvC-Fa-s3m">
<rect key="frame" x="15" y="50" width="398" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Al-Anoud Al-Anoud" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zct-62-YE6">
<rect key="frame" x="0.0" y="0.0" width="328" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8Xn-w6-Mox">
<rect key="frame" x="338" y="3" width="60" height="24"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-- : --" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Btq-Ll-BPH">
<rect key="frame" x="13.333333333333314" y="5.0000000000000009" width="33.666666666666664" height="14.333333333333336"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.0018553551427920477" green="0.59902576721627221" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="InL-xK-60G"/>
<constraint firstItem="Btq-Ll-BPH" firstAttribute="centerY" secondItem="8Xn-w6-Mox" secondAttribute="centerY" id="Vbi-zv-vUQ"/>
<constraint firstItem="Btq-Ll-BPH" firstAttribute="centerX" secondItem="8Xn-w6-Mox" secondAttribute="centerX" id="WNT-XA-AW6"/>
<constraint firstAttribute="height" constant="24" id="Zck-PD-EN0"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.18431372549019609" green="0.1764705882352941" blue="0.16470588235294117" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstItem="9g2-IH-l8e" firstAttribute="leading" secondItem="ygd-al-G4F" secondAttribute="trailing" constant="5" id="0Bv-9b-HQh"/>
<constraint firstItem="a4N-1U-1Yt" firstAttribute="leading" secondItem="7vf-kV-eQ5" secondAttribute="trailing" constant="6" id="4vp-mw-gRE"/>
<constraint firstAttribute="height" constant="80" id="5QG-54-ulG"/>
<constraint firstItem="GbA-j6-191" firstAttribute="width" secondItem="h0g-z5-Y95" secondAttribute="width" id="5cw-b2-SPx"/>
<constraint firstItem="h0g-z5-Y95" firstAttribute="width" secondItem="gop-Yl-2fm" secondAttribute="width" id="7oE-3V-2Gc"/>
<constraint firstItem="7vf-kV-eQ5" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="8zH-6k-6Wz"/>
<constraint firstItem="gop-Yl-2fm" firstAttribute="leading" secondItem="NUO-2p-pzL" secondAttribute="trailing" constant="5" id="Bbh-OY-I9f"/>
<constraint firstItem="NUO-2p-pzL" firstAttribute="leading" secondItem="JCG-W9-5ko" secondAttribute="trailing" constant="5" id="Ccz-Qq-RXf"/>
<constraint firstItem="gop-Yl-2fm" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="DE6-nZ-rEI"/>
<constraint firstItem="GbA-j6-191" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="EVH-xy-wpT"/>
<constraint firstItem="ygd-al-G4F" firstAttribute="leading" secondItem="a4N-1U-1Yt" secondAttribute="trailing" constant="6" id="FNy-Br-FIj"/>
<constraint firstItem="NUO-2p-pzL" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="Fme-oB-F7i"/>
<constraint firstItem="GbA-j6-191" firstAttribute="leading" secondItem="AoF-Up-Yu5" secondAttribute="trailing" constant="14" id="GxO-Fe-iqR"/>
<constraint firstItem="JCG-W9-5ko" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="HPP-q4-IDT"/>
<constraint firstItem="h0g-z5-Y95" firstAttribute="leading" secondItem="N2h-FX-kF5" secondAttribute="trailing" constant="6" id="I2J-pE-7yx"/>
<constraint firstItem="7vf-kV-eQ5" firstAttribute="leading" secondItem="GbA-j6-191" secondAttribute="trailing" constant="6" id="MVo-If-UVQ"/>
<constraint firstItem="a4N-1U-1Yt" firstAttribute="width" secondItem="GbA-j6-191" secondAttribute="width" id="Me9-IC-YE2"/>
<constraint firstItem="N2h-FX-kF5" firstAttribute="leading" secondItem="gop-Yl-2fm" secondAttribute="trailing" constant="7" id="RHr-s8-sAg"/>
<constraint firstItem="h0g-z5-Y95" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="RJj-Uh-H2E"/>
<constraint firstItem="a4N-1U-1Yt" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="Tb2-6o-Wqh"/>
<constraint firstItem="AoF-Up-Yu5" firstAttribute="leading" secondItem="h0g-z5-Y95" secondAttribute="trailing" constant="13" id="VZS-xZ-nbe"/>
<constraint firstItem="NUO-2p-pzL" firstAttribute="leading" secondItem="JCG-W9-5ko" secondAttribute="trailing" constant="5" id="Z1j-5z-34E"/>
<constraint firstItem="7vf-kV-eQ5" firstAttribute="leading" secondItem="GbA-j6-191" secondAttribute="trailing" constant="6" id="ZjD-GK-SkY"/>
<constraint firstItem="ygd-al-G4F" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="bJA-GM-b2E"/>
<constraint firstItem="ygd-al-G4F" firstAttribute="leading" secondItem="a4N-1U-1Yt" secondAttribute="trailing" constant="6" id="eFd-3F-A5f"/>
<constraint firstItem="JCG-W9-5ko" firstAttribute="leading" secondItem="sK0-tB-H9u" secondAttribute="leading" constant="6" id="f0s-gb-347"/>
<constraint firstItem="gop-Yl-2fm" firstAttribute="leading" secondItem="NUO-2p-pzL" secondAttribute="trailing" constant="5" id="frf-I5-Rs9"/>
<constraint firstItem="gop-Yl-2fm" firstAttribute="width" secondItem="JCG-W9-5ko" secondAttribute="width" id="i84-jd-Hwr"/>
<constraint firstItem="N2h-FX-kF5" firstAttribute="leading" secondItem="gop-Yl-2fm" secondAttribute="trailing" constant="7" id="jlv-lR-Nlf"/>
<constraint firstItem="N2h-FX-kF5" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="nU8-Hw-s0U"/>
<constraint firstItem="9g2-IH-l8e" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="pxq-U1-zP5"/>
<constraint firstItem="AoF-Up-Yu5" firstAttribute="centerY" secondItem="sK0-tB-H9u" secondAttribute="centerY" id="ql2-fm-OeZ"/>
<constraint firstItem="9g2-IH-l8e" firstAttribute="width" secondItem="a4N-1U-1Yt" secondAttribute="width" id="uXs-zM-gyf"/>
<constraint firstItem="h0g-z5-Y95" firstAttribute="leading" secondItem="N2h-FX-kF5" secondAttribute="trailing" constant="6" id="uia-9X-UrW"/>
<constraint firstItem="a4N-1U-1Yt" firstAttribute="leading" secondItem="7vf-kV-eQ5" secondAttribute="trailing" constant="6" id="vgH-Oj-HJc"/>
<constraint firstAttribute="trailing" secondItem="9g2-IH-l8e" secondAttribute="trailing" id="vng-6I-eYj"/>
<constraint firstAttribute="height" constant="100" id="6eP-Zl-97q"/>
<constraint firstAttribute="trailing" secondItem="n8H-om-4LV" secondAttribute="trailing" constant="5" id="7Uq-4Q-ywD"/>
<constraint firstAttribute="bottom" secondItem="bvC-Fa-s3m" secondAttribute="bottom" priority="900" constant="5" id="HgY-Dw-B9R"/>
<constraint firstAttribute="bottom" secondItem="n8H-om-4LV" secondAttribute="bottom" id="Nr2-zL-avJ"/>
<constraint firstAttribute="bottom" secondItem="bvC-Fa-s3m" secondAttribute="bottom" constant="20" id="PWn-Sb-O8B"/>
<constraint firstItem="bvC-Fa-s3m" firstAttribute="leading" secondItem="2nj-Va-L7c" secondAttribute="leading" constant="15" id="YH4-fV-fkQ"/>
<constraint firstAttribute="trailing" secondItem="bvC-Fa-s3m" secondAttribute="trailing" constant="15" id="oq6-Oi-i7g"/>
<constraint firstAttribute="height" priority="900" constant="25" id="s8H-wK-WPB"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="videoMutedIndicator" translatesAutoresizingMaskIntoConstraints="NO" id="FEH-bC-Hnh" userLabel="localVideoMutedIndicator">
<rect key="frame" x="276" y="235" width="36" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="1iv-w5-GDT"/>
<constraint firstAttribute="width" constant="36" id="AwX-vQ-Ynn"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="VIH-1T-Ife" firstAttribute="top" secondItem="sK0-tB-H9u" secondAttribute="bottom" constant="42" id="1tT-KH-NEk"/>
<constraint firstAttribute="trailing" secondItem="sK0-tB-H9u" secondAttribute="trailing" id="6K9-n9-ceJ"/>
<constraint firstAttribute="bottom" secondItem="6C5-o5-R1n" secondAttribute="bottom" constant="22" id="76x-6M-xOb"/>
<constraint firstItem="yS9-HT-vp8" firstAttribute="top" secondItem="sK0-tB-H9u" secondAttribute="bottom" constant="24" id="9zS-Fw-oaT"/>
<constraint firstItem="eOT-Jr-GUl" firstAttribute="centerX" secondItem="PoR-7r-yNe" secondAttribute="centerX" id="HMH-Hc-ofZ"/>
<constraint firstItem="FEH-bC-Hnh" firstAttribute="centerY" secondItem="0ZP-s2-kM5" secondAttribute="centerY" id="K8x-bd-bS9"/>
<constraint firstItem="eOT-Jr-GUl" firstAttribute="width" secondItem="PoR-7r-yNe" secondAttribute="width" id="PH6-qw-V6p"/>
<constraint firstItem="eOT-Jr-GUl" firstAttribute="centerY" secondItem="PoR-7r-yNe" secondAttribute="centerY" id="Prz-4m-LHB"/>
<constraint firstItem="0ZP-s2-kM5" firstAttribute="width" secondItem="PoR-7r-yNe" secondAttribute="width" multiplier="0.25" id="QCm-L0-oF7"/>
<constraint firstItem="sK0-tB-H9u" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" id="TPj-1d-lx6"/>
<constraint firstItem="eOT-Jr-GUl" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" id="4xz-lj-CXd"/>
<constraint firstAttribute="bottom" secondItem="eOT-Jr-GUl" secondAttribute="bottom" id="5Ae-F1-hSz"/>
<constraint firstItem="WPH-QE-Fvp" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" id="5Yr-p4-csA"/>
<constraint firstItem="2nj-Va-L7c" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" id="8Gx-Tb-bpo"/>
<constraint firstItem="O5s-CJ-RFv" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" id="Hyn-9r-k8s"/>
<constraint firstItem="sK0-tB-H9u" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" id="Itp-Pe-kh9"/>
<constraint firstItem="2nj-Va-L7c" firstAttribute="top" secondItem="PoR-7r-yNe" secondAttribute="top" id="LDC-Rq-79f"/>
<constraint firstItem="XHG-Db-3Px" firstAttribute="height" secondItem="eOT-Jr-GUl" secondAttribute="height" multiplier="0.196544" id="LwG-7m-Ihd"/>
<constraint firstAttribute="trailing" secondItem="eOT-Jr-GUl" secondAttribute="trailing" id="Pcn-K9-H92"/>
<constraint firstAttribute="bottom" secondItem="sK0-tB-H9u" secondAttribute="bottom" id="Tu5-Op-mnF"/>
<constraint firstItem="CL1-2v-m1L" firstAttribute="centerY" secondItem="PoR-7r-yNe" secondAttribute="centerY" id="UGv-46-ri8"/>
<constraint firstAttribute="trailingMargin" secondItem="0ZP-s2-kM5" secondAttribute="trailing" constant="20" id="UZX-Yj-Efk"/>
<constraint firstItem="A0G-cT-yji" firstAttribute="width" secondItem="0ZP-s2-kM5" secondAttribute="width" constant="55.5" id="WMH-vd-rQe"/>
<constraint firstAttribute="trailing" secondItem="O5s-CJ-RFv" secondAttribute="trailing" id="VcP-8e-3Un"/>
<constraint firstItem="CL1-2v-m1L" firstAttribute="centerX" secondItem="PoR-7r-yNe" secondAttribute="centerX" id="Xt8-k3-fDj"/>
<constraint firstItem="FEH-bC-Hnh" firstAttribute="centerX" secondItem="0ZP-s2-kM5" secondAttribute="centerX" constant="-28.25" id="Yvq-7p-bjS"/>
<constraint firstAttribute="bottom" secondItem="yS9-HT-vp8" secondAttribute="bottom" constant="22" id="bVF-wg-lH8"/>
<constraint firstItem="6C5-o5-R1n" firstAttribute="leading" secondItem="PoR-7r-yNe" secondAttribute="leading" constant="14" id="der-54-SZ4"/>
<constraint firstItem="A0G-cT-yji" firstAttribute="centerX" secondItem="0ZP-s2-kM5" secondAttribute="centerX" constant="-27.75" id="ga5-7D-8CU"/>
<constraint firstItem="A0G-cT-yji" firstAttribute="height" secondItem="0ZP-s2-kM5" secondAttribute="height" id="hMV-RD-NwE"/>
<constraint firstItem="A0G-cT-yji" firstAttribute="centerY" secondItem="0ZP-s2-kM5" secondAttribute="centerY" id="nBC-L0-5Pe"/>
<constraint firstItem="0ZP-s2-kM5" firstAttribute="height" secondItem="PoR-7r-yNe" secondAttribute="height" multiplier="0.25" id="pq3-Iv-N4l"/>
<constraint firstItem="0ZP-s2-kM5" firstAttribute="top" secondItem="BIa-yr-ZMY" secondAttribute="bottom" constant="50" id="qrs-H2-Rw4"/>
<constraint firstItem="eOT-Jr-GUl" firstAttribute="height" secondItem="PoR-7r-yNe" secondAttribute="height" id="rbk-Lc-qip"/>
<constraint firstAttribute="trailing" secondItem="yS9-HT-vp8" secondAttribute="trailing" constant="9" id="vEv-GY-lDH"/>
<constraint firstItem="6C5-o5-R1n" firstAttribute="top" secondItem="sK0-tB-H9u" secondAttribute="bottom" constant="24" id="xhd-lu-lFH"/>
<constraint firstItem="CL1-2v-m1L" firstAttribute="width" secondItem="PoR-7r-yNe" secondAttribute="width" multiplier="0.25" id="Yce-bz-JBd"/>
<constraint firstItem="WPH-QE-Fvp" firstAttribute="top" secondItem="PoR-7r-yNe" secondAttribute="top" id="ddA-LD-2O3"/>
<constraint firstItem="sK0-tB-H9u" firstAttribute="top" secondItem="O5s-CJ-RFv" secondAttribute="bottom" id="eOi-4p-iMm"/>
<constraint firstAttribute="trailing" secondItem="WPH-QE-Fvp" secondAttribute="trailing" id="evw-Oc-GgJ"/>
<constraint firstItem="O5s-CJ-RFv" firstAttribute="top" secondItem="2nj-Va-L7c" secondAttribute="bottom" id="fLH-dK-xpa"/>
<constraint firstItem="eOT-Jr-GUl" firstAttribute="top" secondItem="PoR-7r-yNe" secondAttribute="top" id="gFm-X8-RIU"/>
<constraint firstAttribute="trailing" secondItem="sK0-tB-H9u" secondAttribute="trailing" id="gSh-7K-3p5"/>
<constraint firstAttribute="bottom" secondItem="WPH-QE-Fvp" secondAttribute="bottom" id="sYs-wp-cot"/>
<constraint firstAttribute="trailing" secondItem="2nj-Va-L7c" secondAttribute="trailing" id="vQp-Bv-IVU"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="s5b-6P-Hwj"/>
<connections>
<outlet property="btnMinimize" destination="UZ6-EY-a59" id="bDC-LS-qlX"/>
<outlet property="btnScreenTap" destination="WPH-QE-Fvp" id="wiN-5a-WJO"/>
<outlet property="camSwitchBtn" destination="lar-xK-rhR" id="tde-s5-Mji"/>
<outlet property="controlButtons" destination="sK0-tB-H9u" id="mDK-cq-oQz"/>
<outlet property="localVideo" destination="0ZP-s2-kM5" id="C68-k7-h5j"/>
<outlet property="localVideoMutedBg" destination="A0G-cT-yji" id="5Ia-9g-7CT"/>
<outlet property="localVideoMutedIndicator" destination="FEH-bC-Hnh" id="PKd-gQ-Jct"/>
<outlet property="remoteVideo" destination="eOT-Jr-GUl" id="VKE-el-YGR"/>
<outlet property="fullVideoView" destination="eOT-Jr-GUl" id="VKE-el-YGR"/>
<outlet property="hideVideoBtn" destination="n8H-om-4LV" id="tTp-Ep-XKS"/>
<outlet property="lblCallDuration" destination="Btq-Ll-BPH" id="Jdh-yK-PEx"/>
<outlet property="lblRemoteUsername" destination="Zct-62-YE6" id="OQ0-mf-mvc"/>
<outlet property="localVideoContainer" destination="O5s-CJ-RFv" id="bh9-Yr-UGv"/>
<outlet property="localVideoMutedBg" destination="6y1-an-W7F" id="5FF-Ak-Vxb"/>
<outlet property="micMuteBtn" destination="N2h-FX-kF5" id="zgK-g1-Ndr"/>
<outlet property="remoteVideoMutedIndicator" destination="CL1-2v-m1L" id="aJ0-QC-m9Y"/>
<outlet property="smallVideoView" destination="0ZP-s2-kM5" id="C68-k7-h5j"/>
<outlet property="topBar" destination="2nj-Va-L7c" id="Zt4-J2-uw8"/>
<outlet property="videoMuteBtn" destination="NUO-2p-pzL" id="XCc-nu-N8P"/>
<outletCollection property="minimizeConstraint" destination="s8H-wK-WPB" collectionClass="NSMutableArray" id="XTM-jR-Cos"/>
<outletCollection property="minimizeConstraint" destination="HgY-Dw-B9R" collectionClass="NSMutableArray" id="Fi8-YX-9iQ"/>
<outletCollection property="minimizeConstraint" destination="Ft5-cy-2d0" collectionClass="NSMutableArray" id="Ze3-H8-gj4"/>
<outletCollection property="minimizeConstraint" destination="n0r-vM-wKh" collectionClass="NSMutableArray" id="IaQ-TS-ng8"/>
<outletCollection property="maximisedConstraint" destination="G9u-kw-mVz" collectionClass="NSMutableArray" id="TaK-5m-byK"/>
<outletCollection property="maximisedConstraint" destination="00C-1i-sGc" collectionClass="NSMutableArray" id="vmx-rp-JZI"/>
<outletCollection property="maximisedConstraint" destination="PWn-Sb-O8B" collectionClass="NSMutableArray" id="pK4-yA-36p"/>
<outletCollection property="maximisedConstraint" destination="6eP-Zl-97q" collectionClass="NSMutableArray" id="dxk-ol-uAW"/>
<outletCollection property="maximisedConstraint" destination="3L0-3h-Bxg" collectionClass="NSMutableArray" id="w3Q-AR-TQY"/>
<outletCollection property="minimizeConstraint" destination="y90-hA-p5Z" collectionClass="NSMutableArray" id="INL-Bc-eTM"/>
<outletCollection property="minimizeConstraint" destination="DgE-WQ-KQm" collectionClass="NSMutableArray" id="zy0-aI-bnY"/>
<outletCollection property="maximisedConstraint" destination="flB-AR-zo3" collectionClass="NSMutableArray" id="hwu-U4-5s5"/>
<outletCollection property="minimizeConstraint" destination="6B7-94-Myo" collectionClass="NSMutableArray" id="epM-Kg-2yi"/>
<outletCollection property="maximisedConstraint" destination="x13-gZ-cYp" collectionClass="NSMutableArray" id="uLI-UQ-yIo"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="x33-EE-6Ak" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1685.5072463768117" y="1435.7142857142856"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="GvA-TT-FAo">
<objects>
<navigationController restorationIdentifier="ViewControllerNav" storyboardIdentifier="ViewControllerNav" id="0WJ-RG-MEh" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="S7n-df-cyC">
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="t2c-G5-7AE" kind="relationship" relationship="rootViewController" id="L74-If-nYJ"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vSx-dK-kQe" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="880" y="1436"/>
<point key="canvasLocation" x="-797.66355140186909" y="2238.6609071274302"/>
</scene>
</scenes>
<resources>
<image name="hangUpButton" width="71" height="71"/>
<image name="localVideoMutedBg" width="90" height="120"/>
<image name="muteButton" width="39" height="39"/>
<image name="muteButtonSelected" width="39" height="39"/>
<image name="speakerOff" width="39" height="39"/>
<image name="speakerOffSelected" width="39" height="39"/>
<image name="switchCameraButton" width="39" height="39"/>
<image name="switchCameraButtonSelected" width="39" height="39"/>
<image name="videoMuteButton" width="39" height="39"/>
<image name="videoMuteButtonSelected" width="39" height="39"/>
<image name="camera_back" width="198" height="202"/>
<image name="camera_front" width="198" height="202"/>
<image name="end_call" width="488" height="488"/>
<image name="expand_video" width="202" height="199"/>
<image name="float_video" width="202" height="202"/>
<image name="mic_mute" width="198" height="199"/>
<image name="mic_unmute" width="198" height="202"/>
<image name="videoMutedIndicator" width="153.5" height="129"/>
<image name="video_mute" width="202" height="199"/>
<image name="video_unmute" width="202" height="202"/>
</resources>
</document>

@ -0,0 +1,27 @@
//
// Extensions.swift
// Runner
//
// Created by Zohaib Iqbal Kambrani on 09/06/2021.
// Copyright © 2021 The Chromium Authors. All rights reserved.
//
import AADraggableView
extension AADraggableView{
func enable(_ enable:Bool){
isEnabled = enable
if enable == false{
gestureRecognizers?.forEach({ gest in
removeGestureRecognizer(gest)
})
}
}
}
extension UIView{
func hidden(_ hidden:Bool, rootView:UIView){
UIView.transition(with: rootView, duration: 0.5, options: .transitionCrossDissolve, animations: {
self.isHidden = hidden
})
}
}

@ -0,0 +1,190 @@
//
// MainAppViewController.swift
// Runner
//
// Created by Zohaib Iqbal Kambrani on 08/06/2021.
// Copyright © 2021 The Chromium Authors. All rights reserved.
//
import Foundation
import AADraggableView
class MainAppViewController: FlutterViewController{
var videoCallContainer:AADraggableView!
var videoCallViewController:VideoCallViewController!
var videoCallFlutterResult:FlutterResult?
var vdoCallViewFloatRectConstraint:[NSLayoutConstraint]!
var vdoCallViewFullConstraint:[NSLayoutConstraint]!
var vdoCallViewFloatCircleConstraint:[NSLayoutConstraint]!
override func viewDidLoad() {
super.viewDidLoad()
initFlutterBridge()
prepareVideoCallView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
var videoCallChannel:FlutterMethodChannel?
private func initFlutterBridge(){
videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall", binaryMessenger: binaryMessenger)
videoCallChannel?.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch call.method {
case "openVideoCall":
self.startVideoCall(result: result, call: call)
default:
result(FlutterMethodNotImplemented)
}
})
}
}
// Video Call Functions
extension MainAppViewController : ICallProtocol{
func prepareVideoCallView(){
videoCallContainer = AADraggableView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
videoCallContainer.backgroundColor = UIColor.black
videoCallContainer.isHidden = true
videoCallContainer.clipsToBounds = true
videoCallContainer.padding = 20
videoCallContainer.reposition = .edgesOnly
videoCallContainer.isEnabled = false
view.addSubview(videoCallContainer)
setVideoViewConstrints()
NSLayoutConstraint.activate(vdoCallViewFullConstraint)
NSLayoutConstraint.deactivate(vdoCallViewFloatRectConstraint)
ViewEmbedder.embed(
withIdentifier: "videoCall", // Storyboard ID
parent: self,
container: self.videoCallContainer){ vc in
self.videoCallViewController = vc as? VideoCallViewController
}
}
private func showVideo(show:Bool){
self.videoCallContainer.hidden(!show, rootView: view)
}
private func startVideoCall(result: @escaping FlutterResult, call:FlutterMethodCall) {
videoCallFlutterResult = result
if let arguments = call.arguments as? NSDictionary{
showVideoCallView(true)
videoCallViewController.onRectFloat = { isRectFloat in
self.rectFloatVideoCallView(isRectFloat)
}
videoCallViewController.onCircleFloat = { isCircleFloat in
self.circleFloatVideoCallView(isCircleFloat)
}
videoCallViewController.onCallConnect = {
self.videoCallChannel?.invokeMethod("onCallConnected",arguments: nil)
}
videoCallViewController.onCallDisconnect = {
self.showVideoCallView(false)
self.videoCallViewController.minimizeVideoState(state: false)
self.videoCallChannel?.invokeMethod("onCallDisconnected",arguments: nil)
}
videoCallViewController.callBack = self
videoCallViewController.start(params: VideoCallRequestParameters(dictionary: arguments))
}
}
private func rectFloatVideoCallView(_ value:Bool){
videoCallContainer.enable(value)
UIView.animate(withDuration: 0.5) {
if(value){
NSLayoutConstraint.deactivate(self.vdoCallViewFullConstraint)
NSLayoutConstraint.deactivate(self.vdoCallViewFloatCircleConstraint)
NSLayoutConstraint.activate(self.vdoCallViewFloatRectConstraint)
}else{
NSLayoutConstraint.deactivate(self.vdoCallViewFloatRectConstraint)
NSLayoutConstraint.deactivate(self.vdoCallViewFloatCircleConstraint)
NSLayoutConstraint.activate(self.vdoCallViewFullConstraint)
}
self.videoCallContainer.layer.cornerRadius = value ? 10 : 0
self.videoCallContainer.layer.borderColor = value ? UIColor.white.cgColor : nil
self.videoCallContainer.layer.borderWidth = value ? 2 : 0
self.view.layoutIfNeeded()
}
}
private func circleFloatVideoCallView(_ value:Bool){
videoCallContainer.reposition = value ? .sticky : .edgesOnly
UIView.animate(withDuration: 0.5) {
if(value){
NSLayoutConstraint.deactivate(self.vdoCallViewFullConstraint)
NSLayoutConstraint.deactivate(self.vdoCallViewFloatRectConstraint)
NSLayoutConstraint.activate(self.vdoCallViewFloatCircleConstraint)
self.videoCallContainer.layer.cornerRadius = 35
}else{
NSLayoutConstraint.activate(self.vdoCallViewFloatRectConstraint)
NSLayoutConstraint.deactivate(self.vdoCallViewFullConstraint)
NSLayoutConstraint.deactivate(self.vdoCallViewFloatCircleConstraint)
self.videoCallContainer.layer.cornerRadius = 10
}
self.videoCallContainer.layer.borderColor = value ? UIColor.white.cgColor : nil
self.videoCallContainer.layer.borderWidth = value ? 2 : 0
self.view.layoutIfNeeded()
}
}
private func showVideoCallView(_ value:Bool){
self.videoCallContainer.hidden(!value, rootView: view)
}
func sessionDone(res: Any) {
videoCallFlutterResult?(res)
}
func sessionNotResponded(res: Any) {
videoCallFlutterResult?(res)
}
func setVideoViewConstrints(){
videoCallContainer.layer.shadowColor = UIColor.black.cgColor
videoCallContainer.layer.shadowOffset = CGSize(width: 1, height: 1)
videoCallContainer.layer.shadowRadius = 5
let screen = UIScreen.main.bounds
videoCallContainer.translatesAutoresizingMaskIntoConstraints = false
vdoCallViewFullConstraint = [
videoCallContainer.topAnchor.constraint(equalTo: view.topAnchor),
videoCallContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor),
videoCallContainer.widthAnchor.constraint(equalToConstant: screen.width),
videoCallContainer.heightAnchor.constraint(equalToConstant: screen.height)
]
vdoCallViewFloatRectConstraint = [
videoCallContainer.topAnchor.constraint(equalTo: view.topAnchor, constant: 40),
videoCallContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
videoCallContainer.widthAnchor.constraint(equalToConstant: screen.width/3),
videoCallContainer.heightAnchor.constraint(equalToConstant: screen.height/3.5)
]
vdoCallViewFloatCircleConstraint = [
videoCallContainer.topAnchor.constraint(equalTo: view.topAnchor, constant: 40),
videoCallContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
videoCallContainer.widthAnchor.constraint(equalToConstant: 70),
videoCallContainer.heightAnchor.constraint(equalToConstant: 70)
]
}
}

@ -0,0 +1,78 @@
//
// VCEmbeder.swift
// Runner
//
// Created by Zohaib Iqbal Kambrani on 08/06/2021.
// Copyright © 2021 The Chromium Authors. All rights reserved.
//
import Foundation
extension UIView {
func fill(to parent: UIView, animateDuration:Double = 0.5) {
self.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true
UIView.animate(withDuration: animateDuration) {
parent.layoutIfNeeded()
}
}
func fillToParent(animateDuration:Double = 0.5) {
if let parent = self.superview{
self.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true
UIView.animate(withDuration: animateDuration) {
parent.layoutIfNeeded()
}
}
}
func fillInTo(view:UIView) {
view.addSubview(self)
fillToParent()
}
}
class ViewEmbedder {
class func embed(
parent:UIViewController,
container:UIView,
child:UIViewController,
previous:UIViewController?){
if let previous = previous {
removeFromParent(vc: previous)
}
child.willMove(toParent: parent)
parent.addChild(child)
container.addSubview(child.view)
child.didMove(toParent: parent)
let w = container.frame.size.width;
let h = container.frame.size.height;
child.view.frame = CGRect(x: 0, y: 0, width: w, height: h)
child.view.backgroundColor = UIColor.black
child.view.fill(to: container)
}
class func removeFromParent(vc:UIViewController){
vc.willMove(toParent: nil)
vc.view.removeFromSuperview()
vc.removeFromParent()
}
class func embed(withIdentifier id:String, parent:UIViewController, container:UIView, completion:((UIViewController)->Void)? = nil){
let vc = parent.storyboard!.instantiateViewController(withIdentifier: id)
embed(
parent: parent,
container: container,
child: vc,
previous: parent.children.first
)
completion?(vc)
}
}

@ -0,0 +1,29 @@
import Foundation
class VideoCallRequestParameters{
var apiKey:String?
var sessionId:String?
var token:String?
var lang:String?
var vcId:Int?
var tokenId:String?
var generalId:String?
var doctorId:Int?
var baseUrl:String?
var patientName:String?
init(dictionary:NSDictionary){
self.apiKey = dictionary["kApiKey"] as? String
self.sessionId = dictionary["kSessionId"] as? String
self.token = dictionary["kToken"] as? String
self.lang = dictionary["appLang"] as? String
self.vcId = dictionary["VC_ID"] as? Int
self.tokenId = dictionary["TokenID"] as? String
self.generalId = dictionary["generalId"] as? String
self.doctorId = dictionary["DoctorId"] as? Int
self.baseUrl = dictionary["baseUrl"] as? String
self.patientName = dictionary["patientName"] as? String
}
}

@ -9,9 +9,9 @@
import UIKit
import OpenTok
import Alamofire
import AADraggableView
class ViewController: UIViewController {
class VideoCallViewController: UIViewController {
var session: OTSession?
var publisher: OTPublisher?
@ -31,21 +31,191 @@ class ViewController: UIViewController {
var callBack: ICallProtocol?
var timer = Timer()
var seconds = 30
var seconds = 55
var isUserConnect : Bool = false
var onRectFloat:((Bool)->Void)? = nil
var onCircleFloat:((Bool)->Void)? = nil
var onCallConnect:(()->Void)? = nil
var onCallDisconnect:(()->Void)? = nil
@IBOutlet weak var lblRemoteUsername: UILabel!
// Bottom Actions
@IBOutlet weak var videoMuteBtn: UIButton!
@IBOutlet weak var micMuteBtn: UIButton!
@IBOutlet weak var camSwitchBtn: UIButton!
@IBOutlet var minimizeConstraint: [NSLayoutConstraint]!
@IBOutlet var maximisedConstraint: [NSLayoutConstraint]!
@IBOutlet weak var btnMinimize: UIButton!
@IBOutlet weak var hideVideoBtn: UIButton!
var localVideoDraggable:AADraggableView?
@IBOutlet weak var controlButtons: UIView!
@IBOutlet weak var remoteVideoMutedIndicator: UIImageView!
@IBOutlet weak var localVideoMutedBg: UIView!
@IBOutlet weak var btnScreenTap: UIButton!
@IBOutlet weak var localVideoContainer: UIView!
@IBOutlet weak var topBar: UIView!
@IBOutlet weak var lblCallDuration: UILabel!
@IBOutlet weak var fullVideoView: UIView!
@IBOutlet weak var smallVideoView: UIView!{
didSet{
smallVideoView.layer.borderColor = UIColor.white.cgColor
localVideoDraggable = smallVideoView?.superview as? AADraggableView
localVideoDraggable?.reposition = .edgesOnly
}
}
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
localVideoDraggable?.respectedView = localVideoContainer
}
@objc func click(gesture:UIGestureRecognizer){
gesture.view?.removeFromSuperview()
}
@IBAction func btnOnScreenTapped(_ sender: Any) {
if(hideVideoBtn.isSelected){
circleFloatBtnTapped(hideVideoBtn)
}else if(btnMinimize.isSelected){
btnMinimizeTapped(btnMinimize)
}
}
@IBAction func btnSwipeVideoTapped(_ sender: Any) {
// let smallVdoRender = smallVideoView.subviews.first
// let fullVdoRender = fullVideoView.subviews.first
// if let vdo = smallVdoRender{
// fullVideoView.addSubview(vdo)
// }
// if let vdo = fullVdoRender{
// smallVideoView.addSubview(vdo)
// }
//
// layoutVideoRenderViews()
}
@IBAction func didClickMuteButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
publisher!.publishAudio = !sender.isSelected
}
@IBAction func didClickSpeakerButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
subscriber?.subscribeToAudio = !sender.isSelected
}
@IBAction func didClickVideoMuteButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if publisher!.publishVideo {
publisher!.publishVideo = false
} else {
publisher!.publishVideo = true
}
smallVideoView.isHidden = sender.isSelected
localVideoMutedBg.isHidden = !sender.isSelected
}
@IBAction func didClickSwitchCameraButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
publisher!.cameraPosition = AVCaptureDevice.Position.front
} else {
publisher!.cameraPosition = AVCaptureDevice.Position.back
}
}
@IBAction func hangUp(_ sender: UIButton) {
callBack?.sessionDone(res:["callResponse":"CallEnd"])
sessionDisconnect()
}
@IBAction func circleFloatBtnTapped(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
onCircleFloat?(sender.isSelected)
topBar.isHidden = sender.isSelected
controlButtons.isHidden = sender.isSelected
smallVideoView.isHidden = sender.isSelected
self.publisher?.view?.layoutIfNeeded()
}
@IBAction func btnMinimizeTapped(_ sender: UIButton) {
minimizeVideoState(state: !sender.isSelected)
btnScreenTap.isHidden = !sender.isSelected
}
func minimizeVideoState(state:Bool){
btnMinimize.isSelected = state
onRectFloat?(state)
setupButtons()
askForMicrophonePermission()
requestCameraPermissionsIfNeeded()
hideVideoMuted()
setupSession()
}
NSLayoutConstraint.activate(state ? minimizeConstraint : maximisedConstraint)
NSLayoutConstraint.deactivate(state ? maximisedConstraint : minimizeConstraint)
localVideoDraggable?.enable(!state)
lblRemoteUsername.isHidden = state
hideVideoBtn.isHidden = !state
lblCallDuration.superview?.isHidden = !hideVideoBtn.isHidden
UIView.animate(withDuration: 0.5) {
self.videoMuteBtn.isHidden = state
self.micMuteBtn.isHidden = state
self.camSwitchBtn.isHidden = state
self.layoutVideoRenderViews()
}
}
func layoutVideoRenderViews(){
if let publisherVdoSize = publisher?.view?.superview?.bounds.size{
publisher?.view?.frame = CGRect(x: 0, y: 0, width: publisherVdoSize.width, height: publisherVdoSize.height)
}
if let subscriberVdoSize = subscriber?.view?.superview?.bounds.size{
subscriber?.view?.frame = CGRect(x: 0, y: 0, width: subscriberVdoSize.width, height: subscriberVdoSize.height)
}
}
var durationTimer:Timer?;
func startUpdateCallDuration(){
var seconds = 0
durationTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
seconds = seconds+1
let durationSegments = (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
let hours = String(format: "%02d", durationSegments.0)
let mins = String(format: "%02d", durationSegments.1)
let secs = String(format: "%02d", durationSegments.2)
let durationString = "\(mins):\(secs)"
self.lblCallDuration.text = durationString
}
}
func start(params:VideoCallRequestParameters){
lblRemoteUsername.text = params.patientName ?? "- - -"
btnScreenTap.isHidden = true
hideVideoBtn.isHidden = true
self.kApiKey = params.apiKey ?? ""
self.kSessionId = params.sessionId ?? ""
self.kToken = params.token ?? ""
self.VC_ID = params.vcId ?? 0
self.generalid = params.generalId ?? ""
self.TokenID = params.tokenId ?? ""
self.DoctorId = params.doctorId ?? 0
self.baseUrl = params.baseUrl ?? ""
askForMicrophonePermission()
requestCameraPermissionsIfNeeded()
hideVideoMuted()
setupSession()
}
private func changeCallStatus(callStatus:Int){
let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/ChangeCallStatus"
@ -107,13 +277,6 @@ class ViewController: UIViewController {
}
}
func setupButtons() {
perform(#selector(hideControlButtons), with: nil, afterDelay: 3)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(remoteVideoTapped(_:)))
view.addGestureRecognizer(tapGestureRecognizer)
view.isUserInteractionEnabled = true
}
// MARK: -Microphone Camera and Permission Request
func askForMicrophonePermission() {
@ -137,59 +300,16 @@ class ViewController: UIViewController {
// display a useful message asking the user to grant permissions from within Settings > Privacy > Camera
}
@IBAction func didClickMuteButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
publisher!.publishAudio = !sender.isSelected
}
@IBAction func didClickSpeakerButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
subscriber?.subscribeToAudio = !sender.isSelected
// resetHideButtonsTimer()
}
@IBAction func didClickVideoMuteButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if publisher!.publishVideo {
publisher!.publishVideo = false
} else {
publisher!.publishVideo = true
}
localVideo.isHidden = sender.isSelected
localVideoMutedBg.isHidden = !sender.isSelected
localVideoMutedIndicator.isHidden = !sender.isSelected
// resetHideButtonsTimer()
}
@IBAction func didClickSwitchCameraButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
publisher!.cameraPosition = AVCaptureDevice.Position.front
} else {
publisher!.cameraPosition = AVCaptureDevice.Position.back
}
/// resetHideButtonsTimer()
}
@IBAction func hangUp(_ sender: UIButton) {
callBack?.sessionDone(res:["callResponse":"CallEnd"])
sessionDisconnect()
}
func sessionDisconnect() {
changeCallStatus(callStatus: 16)
if (session != nil) {
print("disconnecting....")
session!.disconnect(nil)
dismiss(animated: true)
return
}
dismiss(animated: true)
onCallDisconnect?()
durationTimer?.invalidate()
}
func requestCameraPermissionsIfNeeded() {
@ -226,7 +346,6 @@ class ViewController: UIViewController {
func hideVideoMuted() {
remoteVideoMutedIndicator.isHidden = true
localVideoMutedBg.isHidden = true
localVideoMutedIndicator.isHidden = true
}
func setupSession() {
@ -267,19 +386,6 @@ class ViewController: UIViewController {
@IBOutlet weak var localVideo: UIView!
@IBOutlet weak var remoteVideo: UIView!
@IBOutlet weak var controlButtons: UIView!
@IBOutlet weak var remoteVideoMutedIndicator: UIImageView!
@IBOutlet weak var localVideoMutedBg: UIImageView!
@IBOutlet weak var localVideoMutedIndicator: UIImageView!
@objc func updateTimer(){
seconds -= 1 //This will decrement(count down)the seconds.
print(seconds)
@ -293,17 +399,11 @@ class ViewController: UIViewController {
}
extension ViewController: OTSessionDelegate {
extension VideoCallViewController: OTSessionDelegate {
func sessionDidConnect(_ session: OTSession) {
print("The client connected to the OpenTok session.")
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
print("The client connected to the OpenTok session.")
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(VideoCallViewController.updateTimer)), userInfo: nil, repeats: true)
setupPublisher()
}
@ -318,10 +418,12 @@ extension ViewController: OTSessionDelegate {
if error != nil {
showAlert(error?.localizedDescription)
}
publisher?.view!.frame = CGRect(x: localVideo.bounds.origin.x, y: localVideo.bounds.origin.y, width: localVideo.bounds.size.width, height: localVideo.bounds.size.height)
localVideo.addSubview((publisher?.view)!)
publisher?.view?.tag = 11
publisher?.view?.layer.cornerRadius = 5
publisher?.view?.clipsToBounds = true
smallVideoView.addSubview((publisher?.view)!)
layoutVideoRenderViews()
}
func sessionDidDisconnect(_ session: OTSession) {
@ -346,27 +448,27 @@ extension ViewController: OTSessionDelegate {
func session(_ session: OTSession, streamCreated stream: OTStream) {
subscriber = OTSubscriber(stream: stream, delegate: self)
guard let subscriber = subscriber else {
return
}
subscriber = OTSubscriber(stream: stream, delegate: self)
guard let subscriber = subscriber else {
return
}
var error: OTError?
session.subscribe(subscriber, error: &error)
guard error == nil else {
print(error!)
return
}
var error: OTError?
session.subscribe(subscriber, error: &error)
guard error == nil else {
print(error!)
return
}
guard let subscriberView = subscriber.view else {
return
}
subscriberView.frame = UIScreen.main.bounds
view.insertSubview(subscriberView, at: 0)
guard let subscriberView = subscriber.view else {
return
}
subscriberView.tag = 22
fullVideoView.addSubview(subscriberView)
layoutVideoRenderViews()
// if nil == subscriber {
// setupSubscribe(stream)
// }
startUpdateCallDuration()
onCallConnect?()
}
func setupSubscribe(_ stream: OTStream?) {
@ -408,19 +510,13 @@ extension ViewController: OTSessionDelegate {
}
extension ViewController: OTPublisherDelegate {
extension VideoCallViewController: OTPublisherDelegate {
func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {
print("The publisher failed: \(error)")
}
@objc func remoteVideoTapped(_ recognizer: UITapGestureRecognizer?) {
if controlButtons.isHidden {
controlButtons.isHidden = false
perform(#selector(hideControlButtons), with: nil, afterDelay: 3)
}
}
}
extension ViewController: OTSubscriberDelegate {
extension VideoCallViewController: OTSubscriberDelegate {
public func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {
print("The subscriber did connect to the stream.")
}
@ -428,8 +524,5 @@ extension ViewController: OTSubscriberDelegate {
public func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
print("The subscriber failed to connect to the stream.")
}
@objc func hideControlButtons() {
controlButtons.isHidden = true
}
}

@ -3,6 +3,7 @@ import 'dart:io' show Platform;
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/service/NavigationService.dart';
import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart';
import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
@ -12,6 +13,9 @@ import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import '../locator.dart';
import '../routes.dart';
DrAppSharedPreferances sharedPref = new DrAppSharedPreferances();
Helpers helpers = new Helpers();
@ -101,12 +105,13 @@ class BaseAppClient {
helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], parsed['AndroidLink'], parsed['IOSLink']);
}
if (!parsed['IsAuthenticated']) {
if (parsed['IsAuthenticated'] != null && !parsed['IsAuthenticated']) {
if (body['OTP_SendType'] != null) {
onFailure(getError(parsed), statusCode);
} else if (!isAllowAny) {
await Provider.of<AuthenticationViewModel>(AppGlobal.CONTEX, listen: false).logout();
Helpers.showErrorToast('Your session expired Please login again');
locator<NavigationService>().pushNamedAndRemoveUntil(ROOT);
}
if (isAllowAny) {
onFailure(getError(parsed), statusCode);

@ -56,6 +56,8 @@ const ADD_REFERRED_DOCTOR_REMARKS = 'Services/DoctorApplication.svc/REST/AddRefe
const GET_MY_REFERRED_PATIENT = 'Services/DoctorApplication.svc/REST/GtMyReferredPatient';
const GET_MY_REFERRED_OUT_PATIENT = 'Services/DoctorApplication.svc/REST/GtMyReferredOutPatient';
const GET_PENDING_REFERRAL_PATIENT = 'Services/DoctorApplication.svc/REST/PendingReferrals';
const CREATE_REFERRAL_PATIENT = 'Services/DoctorApplication.svc/REST/CreateReferral';
@ -89,6 +91,8 @@ const CHECK_ACTIVATION_CODE_FOR_DOCTOR_APP = 'Services/DoctorApplication.svc/RES
const GET_DOC_PROFILES = 'Services/Doctors.svc/REST/GetDocProfiles';
const TRANSFERT_TO_ADMIN = 'LiveCareApi/DoctorApp/TransferToAdmin';
const SEND_SMS_INSTRUCTIONS = 'LiveCareApi/DoctorApp/SendSMSInstruction';
const GET_ALTERNATIVE_SERVICE = 'LiveCareApi/DoctorApp/GetAlternativeServices';
const END_CALL = 'LiveCareApi/DoctorApp/EndCall';
const END_CALL_WITH_CHARGE = 'LiveCareApi/DoctorApp/CompleteCallWithCharge';
const GET_DASHBOARD = 'Services/DoctorApplication.svc/REST/GetDoctorDashboardKPI';
@ -177,6 +181,8 @@ const GET_ECG = "Services/Patients.svc/REST/HIS_GetPatientMuseResults";
const GET_MY_REFERRAL_INPATIENT = "Services/DoctorApplication.svc/REST/GtMyReferralPatient";
const GET_MY_REFERRAL_OUT_PATIENT = "Services/DoctorApplication.svc/REST/GtMyReferralForOutPatient";
const GET_MY_DISCHARGE_PATIENT = "Services/DoctorApplication.svc/REST/GtMyDischargeReferralPatient";
const GET_DISCHARGE_PATIENT = "Services/DoctorApplication.svc/REST/GtMyDischargePatient";
@ -217,6 +223,11 @@ const GET_PENDING_PATIENT_ER_FOR_DOCTOR_APP = 'Services/DoctorApplication.svc/RE
const DOCTOR_CHECK_HAS_LIVE_CARE = "Services/DoctorApplication.svc/REST/CheckDoctorHasLiveCare";
const LIVE_CARE_IS_LOGIN = "LiveCareApi/DoctorApp/UseIsLogin";
const ADD_REFERRED_REMARKS_NEW = "Services/DoctorApplication.svc/REST/AddReferredDoctorRemarks_New";
const GET_SPECIAL_CLINICAL_CARE_LIST = "Services/DoctorApplication.svc/REST/GetSpecialClinicalCareList";
const GET_SPECIAL_CLINICAL_CARE_MAPPING_LIST = "Services/DoctorApplication.svc/REST/GetSpecialClinicalCareMappingList";
var selectedPatientType = 1;
//*********change value to decode json from Dropdown ************

@ -568,7 +568,7 @@ const Map<String, Map<String, String>> localizedValues = {
'ar': "ليس هناك شكوى رئيس"
},
"more-verify": {
"en": "More Verification Options",
"en": "More Verification \n Options",
"ar": "المزيد من خيارات التحقق"
},
"welcome-back": {"en": "Welcome back!", "ar": "مرحبا بعودتك!"},
@ -651,6 +651,10 @@ const Map<String, Map<String, String>> localizedValues = {
'en': "add Selected Procedures",
'ar': "اضافة العمليات المختارة "
},
'addProcedures': {
'en': "Add Procedure",
'ar': "اضافة العمليات"
},
'updateProcedure': {'en': "Update Procedure", 'ar': "تحديث العملية"},
'orderProcedure': {'en': "order procedure", 'ar': "طلب العمليات"},
'nameOrICD': {'en': "Name or ICD", 'ar': "الاسم او  ICD"},
@ -708,7 +712,7 @@ const Map<String, Map<String, String>> localizedValues = {
'days': {'en': "Days", 'ar': "أيام"},
'months': {'en': "Months", 'ar': "أشهر"},
'years': {'en': "Years", 'ar': "سنين"},
'hr': {'en': "HR", 'ar': "س"},
'hr': {'en': "Hr", 'ar': "س"},
'min': {'en': "Min", 'ar': "د"},
'appointmentNumber': {'en': "Appointment Number", 'ar': "رقم الموعد"},
'referralStatusHold': {'en': "Hold", 'ar': "معلق"},
@ -998,4 +1002,12 @@ const Map<String, Map<String, String>> localizedValues = {
"onHold": {"en": "On Hold", "ar": "قيد الانتظار"},
"verified": {"en": "Verified", "ar": "تم التحقق"},
"endCall": {"en": "End Call", "ar": "انهاء"},
"favoriteTemplates": {"en": "Favorite Templates", "ar": "القوالب المفضلة"},
"allProcedures": {"en": "All Procedures", "ar": "جميع الإجراءات"},
"allRadiology": {"en": "All Radiology", "ar": "جميع الأشعة"},
"allLab": {"en": "All Lab", "ar": "جميع المختبرات"},
"allPrescription": {"en": "All Prescription", "ar": "جميع الوصفات"},
"addPrescription": {"en": "Add prescription", "ar": "إضافة الوصفات"},
"edit": {"en": "Edit", "ar": "تعديل"},
"summeryReply": {"en": "Summary Reply", "ar": "موجز الرد"},
};

@ -17,6 +17,11 @@ class SizeConfig {
static bool isPortrait = true;
static bool isMobilePortrait = false;
static bool isMobile = false;
static bool isHeightShort = false;
static bool isHeightVeryShort = false;
static bool isHeightMiddle = false;
static bool isHeightLarge = false;
static bool isWidthLarge = false;
void init(BoxConstraints constraints, Orientation orientation) {
realScreenHeight = constraints.maxHeight;
@ -25,20 +30,30 @@ class SizeConfig {
if (constraints.maxWidth <= MAX_SMALL_SCREEN) {
isMobile = true;
}
if (constraints.maxHeight < 600) {
isHeightVeryShort = true;
} else if (constraints.maxHeight < 800) {
isHeightShort = true;
} else if (constraints.maxHeight < 1000) {
isHeightMiddle = true;
} else {
isHeightLarge = true;
}
if(constraints.maxWidth > 600) {
isWidthLarge = true;
}
if (orientation == Orientation.portrait) {
isPortrait = true;
if (realScreenWidth! < 450) {
isMobilePortrait = true;
}
// textMultiplier = _blockHeight;
// imageSizeMultiplier = _blockWidth;
screenHeight = realScreenHeight;
screenWidth = realScreenWidth;
} else {
isPortrait = false;
isMobilePortrait = false;
// textMultiplier = _blockWidth;
// imageSizeMultiplier = _blockHeight;
screenHeight = realScreenWidth;
screenWidth = realScreenHeight;
}
@ -59,4 +74,29 @@ class SizeConfig {
print('isPortrait $isPortrait');
print('isMobilePortrait $isMobilePortrait');
}
static getTextMultiplierBasedOnWidth({double width}){
// TODO handel LandScape case
if(width != null) {
return width / 100;
}
return widthMultiplier;
}
static getWidthMultiplier({double width}){
// TODO handel LandScape case
if(width != null) {
return width / 100;
}
return widthMultiplier;
}
static getHeightMultiplier({double height}){
// TODO handel LandScape case
if(height != null) {
return height / 100;
}
return heightMultiplier;
}
}

@ -0,0 +1,4 @@
enum PatientType{
IN_PATIENT,
OUT_PATIENT,
}

@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
class AlternativeService {
int serviceID;
String serviceName;
bool isSelected;
AlternativeService(
{this.serviceID, this.serviceName, this.isSelected = false});
AlternativeService.fromJson(Map<String, dynamic> json) {
serviceID = json['ServicID'];
serviceName = json['ServiceName'];
isSelected = false;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ServicID'] = this.serviceID;
data['ServiceName'] = this.serviceName;
return data;
}
}
class AlternativeServicesList with ChangeNotifier {
List<AlternativeService> _alternativeServicesList;
getServicesList(){
return _alternativeServicesList;
}
setServicesList(List<AlternativeService> alternativeServicesList) {
this._alternativeServicesList = alternativeServicesList;
notifyListeners();
}
setSelected(AlternativeService service, bool isSelected) {
List<AlternativeService> alternativeService = _alternativeServicesList.where((element) => service.serviceID == element.serviceID).toList();
alternativeService[0].isSelected = isSelected;
notifyListeners();
}
}

@ -0,0 +1,27 @@
class LiveCareUserLoginRequestModel {
String tokenID;
String generalid;
int doctorId;
int isOutKsa;
int isLogin;
LiveCareUserLoginRequestModel({this.tokenID, this.generalid, this.doctorId, this.isOutKsa, this.isLogin});
LiveCareUserLoginRequestModel.fromJson(Map<String, dynamic> json) {
tokenID = json['TokenID'];
generalid = json['generalid'];
doctorId = json['DoctorId'];
isOutKsa = json['IsOutKsa'];
isLogin = json['IsLogin'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['TokenID'] = this.tokenID;
data['generalid'] = this.generalid;
data['DoctorId'] = this.doctorId;
data['IsOutKsa'] = this.isOutKsa;
data['IsLogin'] = this.isLogin;
return data;
}
}

@ -11,20 +11,24 @@ class PatientSearchRequestModel {
int ?searchType;
String? mobileNo;
String? identificationNo;
int nursingStationID;
int clinicID=0;
PatientSearchRequestModel(
{this.doctorID =0,
this.firstName ="0",
this.middleName ="0",
this.lastName ="0",
this.patientMobileNumber ="0",
this.patientIdentificationID ="0",
this.patientID =0,
this.searchType =1,
this.mobileNo="",
this.identificationNo="0",
this.from ="0",
this.to ="0"});
{this.doctorID = 0,
this.firstName = "0",
this.middleName = "0",
this.lastName = "0",
this.patientMobileNumber = "0",
this.patientIdentificationID = "0",
this.patientID = 0,
this.searchType = 1,
this.mobileNo = "",
this.identificationNo = "0",
this.from = "0",
this.to = "0",
this.clinicID,
this.nursingStationID = 0});
PatientSearchRequestModel.fromJson(Map<String, dynamic> json) {
doctorID = json['DoctorID'];
@ -39,6 +43,8 @@ class PatientSearchRequestModel {
searchType = json['SearchType'];
mobileNo = json['MobileNo'];
identificationNo = json['IdentificationNo'];
nursingStationID = json['NursingStationID'];
clinicID = json['ClinicID'];
}
Map<String, dynamic> toJson() {
@ -55,6 +61,9 @@ class PatientSearchRequestModel {
data['SearchType'] = this.searchType;
data['MobileNo'] = this.mobileNo;
data['IdentificationNo'] = this.identificationNo;
data['NursingStationID'] = this.nursingStationID;
data['ClinicID'] = this.clinicID;
data['ProjectID'] = 0;
return data;
}
}

@ -61,71 +61,74 @@ class MyReferralPatientModel {
String? priorityDescription;
String? referringClinicDescription;
String? referringDoctorName;
int referalStatus;
MyReferralPatientModel(
{this.rowID,
this.projectID,
this.lineItemNo,
this.doctorID,
this.patientID,
this.doctorName,
this.doctorNameN,
this.firstName,
this.middleName,
this.lastName,
this.firstNameN,
this.middleNameN,
this.lastNameN,
this.gender,
this.dateofBirth,
this.mobileNumber,
this.emailAddress,
this.patientIdentificationNo,
this.patientType,
this.admissionNo,
this.admissionDate,
this.roomID,
this.bedID,
this.nursingStationID,
this.description,
this.nationalityName,
this.nationalityNameN,
this.clinicDescription,
this.clinicDescriptionN,
this.referralDoctor,
this.referringDoctor,
this.referralClinic,
this.referringClinic,
this.referralStatus,
this.referralDate,
this.referringDoctorRemarks,
this.referredDoctorRemarks,
this.referralResponseOn,
this.priority,
this.frequency,
this.mAXResponseTime,
this.episodeID,
this.appointmentNo,
this.appointmentDate,
this.appointmentType,
this.patientMRN,
this.createdOn,
this.clinicID,
this.nationalityID,
this.age,
this.doctorImageURL,
this.frequencyDescription,
this.genderDescription,
this.isDoctorLate,
this.isDoctorResponse,
this.nationalityFlagURL,
this.nursingStationName,
this.priorityDescription,
this.referringClinicDescription,
this.referringDoctorName});
this.projectID,
this.lineItemNo,
this.doctorID,
this.patientID,
this.doctorName,
this.doctorNameN,
this.firstName,
this.middleName,
this.lastName,
this.firstNameN,
this.middleNameN,
this.lastNameN,
this.gender,
this.dateofBirth,
this.mobileNumber,
this.emailAddress,
this.patientIdentificationNo,
this.patientType,
this.admissionNo,
this.admissionDate,
this.roomID,
this.bedID,
this.nursingStationID,
this.description,
this.nationalityName,
this.nationalityNameN,
this.clinicDescription,
this.clinicDescriptionN,
this.referralDoctor,
this.referringDoctor,
this.referralClinic,
this.referringClinic,
this.referralStatus,
this.referralDate,
this.referringDoctorRemarks,
this.referredDoctorRemarks,
this.referralResponseOn,
this.priority,
this.frequency,
this.mAXResponseTime,
this.episodeID,
this.appointmentNo,
this.appointmentDate,
this.appointmentType,
this.patientMRN,
this.createdOn,
this.clinicID,
this.nationalityID,
this.age,
this.doctorImageURL,
this.frequencyDescription,
this.genderDescription,
this.isDoctorLate,
this.isDoctorResponse,
this.nationalityFlagURL,
this.nursingStationName,
this.priorityDescription,
this.referringClinicDescription,
this.referringDoctorName,
this.referalStatus});
MyReferralPatientModel.fromJson(Map<String?, dynamic> json) {
rowID = json['RowID'];
referalStatus = json['ReferalStatus'];
projectID = json['ProjectID'];
lineItemNo = json['LineItemNo'];
doctorID = json['DoctorID'];
@ -158,8 +161,21 @@ class MyReferralPatientModel {
referringDoctor = json['ReferringDoctor'];
referralClinic = json['ReferralClinic'];
referringClinic = json['ReferringClinic'];
referralStatus = json['ReferralStatus'];
referralDate = AppDateUtils.convertStringToDate(json['ReferralDate']);
referralStatus = json["ReferralStatus"] is String
? json['ReferralStatus'] == "Accepted"
? 46
: json['ReferralStatus'] == "Pending"
? 1
: 0
: json["ReferralStatus"];
try {
referralDate = AppDateUtils.getDateTimeFromString(json['ReferralDate']);
} catch (e) {
referralDate = AppDateUtils.convertStringToDate(json['ReferralDate']);
} finally {
referralDate = DateTime.now();
}
referringDoctorRemarks = json['ReferringDoctorRemarks'];
referredDoctorRemarks = json['ReferredDoctorRemarks'];
referralResponseOn = json['ReferralResponseOn'];
@ -190,6 +206,7 @@ class MyReferralPatientModel {
Map<String?, dynamic> toJson() {
final Map<String?, dynamic> data = new Map<String?, dynamic>();
data['RowID'] = this.rowID;
data['ReferalStatus'] = this.referalStatus;
data['ProjectID'] = this.projectID;
data['LineItemNo'] = this.lineItemNo;
data['DoctorID'] = this.doctorID;
@ -253,6 +270,6 @@ class MyReferralPatientModel {
}
get patientName {
return this.firstName!+" "+this.lastName!;
return this.firstName !+ " " + this.lastName!;
}
}

@ -0,0 +1,104 @@
class MyReferralPatientRequestModel {
int channel;
int clinicID;
int doctorID;
int editedBy;
String firstName;
String from;
String iPAdress;
bool isLoginForDoctorApp;
int languageID;
String lastName;
String middleName;
int patientID;
String patientIdentificationID;
String patientMobileNumber;
bool patientOutSA;
int patientTypeID;
int projectID;
String sessionID;
String stamp;
String to;
String tokenID;
double versionID;
String vidaAuthTokenID;
MyReferralPatientRequestModel(
{this.channel,
this.clinicID,
this.doctorID,
this.editedBy,
this.firstName,
this.from,
this.iPAdress,
this.isLoginForDoctorApp,
this.languageID,
this.lastName,
this.middleName,
this.patientID,
this.patientIdentificationID,
this.patientMobileNumber,
this.patientOutSA,
this.patientTypeID,
this.projectID,
this.sessionID,
this.stamp,
this.to,
this.tokenID,
this.versionID,
this.vidaAuthTokenID});
MyReferralPatientRequestModel.fromJson(Map<String, dynamic> json) {
channel = json['Channel'];
clinicID = json['ClinicID'];
doctorID = json['DoctorID'];
editedBy = json['EditedBy'];
firstName = json['FirstName'];
from = json['From'];
iPAdress = json['IPAdress'];
isLoginForDoctorApp = json['IsLoginForDoctorApp'];
languageID = json['LanguageID'];
lastName = json['LastName'];
middleName = json['MiddleName'];
patientID = json['PatientID'];
patientIdentificationID = json['PatientIdentificationID'];
patientMobileNumber = json['PatientMobileNumber'];
patientOutSA = json['PatientOutSA'];
patientTypeID = json['PatientTypeID'];
projectID = json['ProjectID'];
sessionID = json['SessionID'];
stamp = json['stamp'];
to = json['To'];
tokenID = json['TokenID'];
versionID = json['VersionID'];
vidaAuthTokenID = json['VidaAuthTokenID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Channel'] = this.channel;
data['ClinicID'] = this.clinicID;
data['DoctorID'] = this.doctorID;
data['EditedBy'] = this.editedBy;
data['FirstName'] = this.firstName;
data['From'] = this.from;
data['IPAdress'] = this.iPAdress;
data['IsLoginForDoctorApp'] = this.isLoginForDoctorApp;
data['LanguageID'] = this.languageID;
data['LastName'] = this.lastName;
data['MiddleName'] = this.middleName;
data['PatientID'] = this.patientID;
data['PatientIdentificationID'] = this.patientIdentificationID;
data['PatientMobileNumber'] = this.patientMobileNumber;
data['PatientOutSA'] = this.patientOutSA;
data['PatientTypeID'] = this.patientTypeID;
data['ProjectID'] = this.projectID;
data['SessionID'] = this.sessionID;
data['stamp'] = this.stamp;
data['To'] = this.to;
data['TokenID'] = this.tokenID;
data['VersionID'] = this.versionID;
data['VidaAuthTokenID'] = this.vidaAuthTokenID;
return data;
}
}

@ -0,0 +1,72 @@
class AddReferredRemarksRequestModel {
int projectID;
int admissionNo;
int lineItemNo;
String referredDoctorRemarks;
int editedBy;
int referalStatus;
bool isLoginForDoctorApp;
String iPAdress;
bool patientOutSA;
String tokenID;
int languageID;
double versionID;
int channel;
String sessionID;
int deviceTypeID;
AddReferredRemarksRequestModel(
{this.projectID,
this.admissionNo,
this.lineItemNo,
this.referredDoctorRemarks,
this.editedBy,
this.referalStatus,
this.isLoginForDoctorApp,
this.iPAdress,
this.patientOutSA,
this.tokenID,
this.languageID,
this.versionID,
this.channel,
this.sessionID,
this.deviceTypeID});
AddReferredRemarksRequestModel.fromJson(Map<String, dynamic> json) {
projectID = json['ProjectID'];
admissionNo = json['AdmissionNo'];
lineItemNo = json['LineItemNo'];
referredDoctorRemarks = json['ReferredDoctorRemarks'];
editedBy = json['EditedBy'];
referalStatus = json['ReferalStatus'];
isLoginForDoctorApp = json['IsLoginForDoctorApp'];
iPAdress = json['IPAdress'];
patientOutSA = json['PatientOutSA'];
tokenID = json['TokenID'];
languageID = json['LanguageID'];
versionID = json['VersionID'];
channel = json['Channel'];
sessionID = json['SessionID'];
deviceTypeID = json['DeviceTypeID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ProjectID'] = this.projectID;
data['AdmissionNo'] = this.admissionNo;
data['LineItemNo'] = this.lineItemNo;
data['ReferredDoctorRemarks'] = this.referredDoctorRemarks;
data['EditedBy'] = this.editedBy;
data['ReferalStatus'] = this.referalStatus;
data['IsLoginForDoctorApp'] = this.isLoginForDoctorApp;
data['IPAdress'] = this.iPAdress;
data['PatientOutSA'] = this.patientOutSA;
data['TokenID'] = this.tokenID;
data['LanguageID'] = this.languageID;
data['VersionID'] = this.versionID;
data['Channel'] = this.channel;
data['SessionID'] = this.sessionID;
data['DeviceTypeID'] = this.deviceTypeID;
return data;
}
}

@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey =
new GlobalKey<NavigatorState>();
Future<dynamic> navigateTo(String routeName,{Object arguments}) {
return navigatorKey.currentState.pushNamed(routeName,arguments: arguments);
}
Future<dynamic> pushReplacementNamed(String routeName,{Object arguments}) {
return navigatorKey.currentState.pushReplacementNamed(routeName,arguments: arguments);
}
Future<dynamic> pushNamedAndRemoveUntil(String routeName) {
return navigatorKey.currentState.pushNamedAndRemoveUntil(routeName,(asd)=>false);
}
}

@ -0,0 +1,89 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/core/service/patient/LiveCarePatientServices.dart';
import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart';
import 'package:doctor_app_flutter/models/livecare/end_call_req.dart';
import 'package:doctor_app_flutter/models/livecare/session_status_model.dart';
import 'package:doctor_app_flutter/models/livecare/start_call_res.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/util/VideoChannel.dart';
import 'package:doctor_app_flutter/util/dr_app_toast_msg.dart';
import 'package:doctor_app_flutter/widgets/shared/loader/gif_loader_dialog_utils.dart';
import 'package:flutter/cupertino.dart';
import '../../locator.dart';
import '../../routes.dart';
import 'NavigationService.dart';
class VideoCallService extends BaseService{
StartCallRes startCallRes;
PatiantInformtion patient;
LiveCarePatientServices _liveCarePatientServices = locator<LiveCarePatientServices>();
openVideo(StartCallRes startModel,PatiantInformtion patientModel,VoidCallback onCallConnected, VoidCallback onCallDisconnected)async{
this.startCallRes = startModel;
this.patient = patientModel;
DoctorProfileModel doctorProfile = await getDoctorProfile(isGetProfile: true);
await VideoChannel.openVideoCallScreen(
kToken: startCallRes.openTokenID,//"T1==cGFydG5lcl9pZD00NzI0Nzk1NCZzaWc9NGIyZDljOTY3YjFiNWU1YzUzNzFmMjIyNjJmNmEzY2Y5NzZjOTdlYzpzZXNzaW9uX2lkPTFfTVg0ME56STBOemsxTkg1LU1UWXlNekEyTlRRMU9EVXhObjVrVFRoMFlVdFJXaXRYTWpadFZGZHFhSGxZVGpOdE1UVi1mZyZjcmVhdGVfdGltZT0xNjIzMDY1NDk1Jm5vbmNlPTAuMjM2Mjk0NTIwMTkyOTA4OTcmcm9sZT1wdWJsaXNoZXImZXhwaXJlX3RpbWU9MTYyNTY1NzQ5NCZpbml0aWFsX2xheW91dF9jbGFzc19saXN0PQ==",
kSessionId:startCallRes.openSessionID,//1_MX40NzI0Nzk1NH5-MTYyMzA2NTQ1ODUxNn5kTTh0YUtRWitXMjZtVFdqaHlYTjNtMTV-fg
kApiKey: '46209962',//'47247954'
vcId: patient.vcId,
patientName: patient.fullName ?? (patient.firstName != null ? "${patient.firstName} ${patient.lastName}" : "-"),
tokenID: await sharedPref.getString(TOKEN),
generalId: GENERAL_ID,
doctorId: doctorProfile.doctorID,
onFailure: (String error) {
DrAppToastMsg.showErrorToast(error);
},onCallConnected: onCallConnected,
onCallEnd: () {
WidgetsBinding.instance.addPostFrameCallback((_) async {
GifLoaderDialogUtils.showMyDialog(locator<NavigationService>().navigatorKey.currentContext);
endCall(patient.vcId, false,).then((value) {
GifLoaderDialogUtils.hideDialog(locator<NavigationService>().navigatorKey.currentContext);
if (hasError) {
DrAppToastMsg.showErrorToast(error);
}else
locator<NavigationService>().navigateTo(PATIENTS_END_Call,arguments: {
"patient": patient,
});
});
});
},
onCallNotRespond: (SessionStatusModel sessionStatusModel) {
WidgetsBinding.instance.addPostFrameCallback((_) {
GifLoaderDialogUtils.showMyDialog(locator<NavigationService>().navigatorKey.currentContext);
endCall(patient.vcId, sessionStatusModel.sessionStatus == 3,).then((value) {
GifLoaderDialogUtils.hideDialog(locator<NavigationService>().navigatorKey.currentContext);
if (hasError) {
DrAppToastMsg.showErrorToast(error);
} else {
locator<NavigationService>().navigateTo(PATIENTS_END_Call,arguments: {
"patient": patient,
});
}
});
});
});
}
Future endCall(int vCID, bool isPatient) async {
hasError = false;
await getDoctorProfile(isGetProfile: true);
EndCallReq endCallReq = new EndCallReq();
endCallReq.doctorId = doctorProfile.doctorID;
endCallReq.generalid = 'Cs2020@2016\$2958';
endCallReq.vCID = vCID;
endCallReq.isDestroy = isPatient;
await _liveCarePatientServices.endCall(endCallReq);
if (_liveCarePatientServices.hasError) {
error = _liveCarePatientServices.error;
}
}
}

@ -1,10 +1,12 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/dashboard/dashboard_model.dart';
import 'package:doctor_app_flutter/models/dashboard/get_special_clinical_care_List_Respose_Model.dart';
class DashboardService extends BaseService {
List<DashboardModel> _dashboardItemsList = [];
List<DashboardModel> get dashboardItemsList => _dashboardItemsList;
bool hasVirtualClinic = false;
String ?sServiceID;
@ -24,8 +26,6 @@ class DashboardService extends BaseService {
super.error = error;
},
body: {
// "VidaAuthTokenID":
// "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyODA0IiwianRpIjoiZDYxZmM5MTQtZWFhYy00YjQ4LTgyMmEtMmE3OTNlZDMzZGYwIiwiZW1haWwiOiJNb2hhbWVkLlJlc3dhbkBjbG91ZHNvbHV0aW9uLXNhLmNvbSIsImlkIjoiMjgwNCIsIk5hbWUiOiJNVUhBTU1BRCBBWkFNIiwiRW1wbG95ZWVJZCI6IjE0ODUiLCJGYWNpbGl0eUdyb3VwSWQiOiIwMTAyNjYiLCJGYWNpbGl0eUlkIjoiMTUiLCJQaGFyYW1jeUZhY2lsaXR5SWQiOiI1NSIsIklTX1BIQVJNQUNZX0NPTk5FQ1RFRCI6IlRydWUiLCJEb2N0b3JJZCI6IjE0ODUiLCJTRVNTSU9OSUQiOiIyMTU3NTgwOCIsIkNsaW5pY0lkIjoiMyIsInJvbGUiOlsiU0VDVVJJVFkgQURNSU5JU1RSQVRPUlMiLCJTRVRVUCBBRE1JTklTVFJBVE9SUyIsIkNFTydTIiwiRVhFQ1VUSVZFIERJUkVDVE9SUyIsIk1BTkFHRVJTIiwiU1VQRVJWSVNPUlMiLCJDTElFTlQgU0VSVklDRVMgQ09PUkRJTkFUT1JTIiwiQ0xJRU5UIFNFUlZJQ0VTIFNVUEVSVklTT1JTIiwiQ0xJRU5UIFNFUlZJQ0VTIE1BTkdFUlMiLCJIRUFEIE5VUlNFUyIsIkRPQ1RPUlMiLCJDSElFRiBPRiBNRURJQ0FMIFNUQUZGUyIsIkJJTy1NRURJQ0FMIFRFQ0hOSUNJQU5TIiwiQklPLU1FRElDQUwgRU5HSU5FRVJTIiwiQklPLU1FRElDQUwgREVQQVJUTUVOVCBIRUFEUyIsIklUIEhFTFAgREVTSyIsIkFETUlOSVNUUkFUT1JTIiwiTEFCIEFETUlOSVNUUkFUT1IiLCJMQUIgVEVDSE5JQ0lBTiIsIkJVU0lORVNTIE9GRklDRSBTVEFGRiIsIkZJTkFOQ0UgQUNDT1VOVEFOVFMiLCJQSEFSTUFDWSBTVEFGRiIsIkFDQ09VTlRTIFNUQUZGIiwiTEFCIFJFQ0VQVElPTklTVCIsIkVSIE5VUlNFIiwiSU5QQVRJRU5UIEJJTExJTkcgU1VQRVJWSVNPUiIsIkxEUi1PUiBOVVJTRVMiLCJBRE1JU1NJT04gU1RBRkYiLCJIRUxQIERFU0sgQURNSU4iLCJBUFBST1ZBTCBTVEFGRiIsIklOUEFUSUVOVCBCSUxMSU5HIENPT1JESU5BVE9SIiwiQklMTElORyBTVEFGRiIsIkNPTlNFTlQgIiwiQ29uc2VudCAtIERlbnRhbCIsIldFQkVNUiJdLCJuYmYiOjE2MDgwMjg0NzQsImV4cCI6MTYwODg5MjQ3NCwiaWF0IjoxNjA4MDI4NDc0fQ.8OJcy6vUuPnNTi_qSjip8YCrFdaRLtJKbNKXcMtnQxk"
},
);
}
@ -48,4 +48,5 @@ class DashboardService extends BaseService {
},
);
}
}

@ -0,0 +1,41 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/model/patient_muse/PatientSearchRequestModel.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
class ScanQrService extends BaseService {
List<PatiantInformtion> myInPatientList = List();
List<PatiantInformtion> inPatientList = List();
Future getInPatient(PatientSearchRequestModel requestModel, bool isMyInpatient) async {
hasError = false;
await getDoctorProfile();
if (isMyInpatient) {
requestModel.doctorID = doctorProfile.doctorID;
} else {
requestModel.doctorID = 0;
}
await baseAppClient.post(
GET_PATIENT_IN_PATIENT_LIST,
onSuccess: (dynamic response, int statusCode) {
inPatientList.clear();
myInPatientList.clear();
response['List_MyInPatient'].forEach((v) {
PatiantInformtion patient = PatiantInformtion.fromJson(v);
inPatientList.add(patient);
if (patient.doctorId == doctorProfile.doctorID) {
myInPatientList.add(patient);
}
});
},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: requestModel.toJson(),
);
}
}

@ -1,5 +1,8 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/model/live_care/AlternativeServicesList.dart';
import 'package:doctor_app_flutter/core/model/live_care/PendingPatientERForDoctorAppRequestModel.dart';
import 'package:doctor_app_flutter/core/model/live_care/live_care_login_reguest_model.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/livecare/end_call_req.dart';
import 'package:doctor_app_flutter/models/livecare/start_call_req.dart';
@ -11,8 +14,12 @@ class LiveCarePatientServices extends BaseService {
List<PatiantInformtion> get patientList => _patientList;
List<AlternativeService> alternativeServicesList = [];
bool _isFinished = false;
bool _isLive = true;
bool get isFinished => _isFinished;
setFinished(bool isFinished) {
@ -21,12 +28,14 @@ class LiveCarePatientServices extends BaseService {
var endCallResponse = {};
var transferToAdminResponse = {};
var isLoginResponse = {};
late StartCallRes _startCallRes;
StartCallRes get startCallRes => _startCallRes;
Future getPendingPatientERForDoctorApp(
PendingPatientERForDoctorAppRequestModel pendingPatientERForDoctorAppRequestModel) async {
PendingPatientERForDoctorAppRequestModel
pendingPatientERForDoctorAppRequestModel) async {
hasError = false;
await baseAppClient.post(
GET_PENDING_PATIENT_ER_FOR_DOCTOR_APP,
@ -51,7 +60,7 @@ class LiveCarePatientServices extends BaseService {
}, onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
}, body: endCallReq.toJson(), isLiveCare: true);
}, body: endCallReq.toJson(), isLiveCare: _isLive);
}
Future startCall(StartCallReq startCallReq) async {
@ -61,10 +70,10 @@ class LiveCarePatientServices extends BaseService {
}, onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
}, body: startCallReq.toJson(), isLiveCare: true);
}, body: startCallReq.toJson(), isLiveCare: _isLive);
}
Future endCallWithCharge(int vcID) async {
Future endCallWithCharge(int vcID, List<int> altServiceList) async {
hasError = false;
await baseAppClient.post(END_CALL_WITH_CHARGE, onSuccess: (dynamic response, int statusCode) {
endCallResponse = response;
@ -73,8 +82,8 @@ class LiveCarePatientServices extends BaseService {
super.error = error;
}, body: {
"VC_ID": vcID,
"generalid": "Cs2020@2016\$2958",
}, isLiveCare: true);
"AltServiceList": altServiceList,"generalid": GENERAL_ID
}, isLiveCare: _isLive);
}
Future transferToAdmin(int vcID, String notes) async {
@ -88,6 +97,49 @@ class LiveCarePatientServices extends BaseService {
"VC_ID": vcID,
"IsOutKsa": false,
"Notes": notes,
}, isLiveCare: true);
}, isLiveCare: _isLive);
}
Future sendSMSInstruction(int vcID) async {
hasError = false;
await baseAppClient.post(SEND_SMS_INSTRUCTIONS,
onSuccess: (dynamic response, int statusCode) {
transferToAdminResponse = response;
}, onFailure: (String error, int statusCode) {
hasError =true;
super.error = error;
}, body: {
"VC_ID": vcID, "generalid": GENERAL_ID
}, isLiveCare: _isLive);
}
Future isLogin({LiveCareUserLoginRequestModel isLoginRequestModel, int loginStatus}) async {
hasError = false;
await getDoctorProfile( );
isLoginRequestModel.doctorId = super.doctorProfile.doctorID;
await baseAppClient.post(LIVE_CARE_IS_LOGIN, onSuccess: (response, statusCode) async {
isLoginResponse = response;
}, onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
}, body: isLoginRequestModel.toJson(), isLiveCare: _isLive);
}
Future getAlternativeServices(int vcID) async {
hasError = false;
alternativeServicesList.clear();
await baseAppClient.post(GET_ALTERNATIVE_SERVICE,
onSuccess: (dynamic response, int statusCode) {
response['AlternativeServicesList'].forEach((v) {
alternativeServicesList.add(AlternativeService.fromJson(v));
});
}, onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
}, body: {
"VC_ID": vcID,
"generalid": GENERAL_ID
}, isLiveCare: _isLive);
}
}

@ -1,5 +1,7 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/model/referral/MyReferralPatientModel.dart';
import 'package:doctor_app_flutter/core/model/referral/MyReferralPatientRequestModel.dart';
import 'package:doctor_app_flutter/core/model/referral/add_referred_remarks_request.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/doctor/request_add_referred_doctor_remarks.dart';
@ -8,22 +10,21 @@ class MyReferralInPatientService extends BaseService {
Future getMyReferralPatientService() async {
hasError = false;
Map<String, dynamic> body = Map();
await getDoctorProfile();
body['DoctorID'] = doctorProfile!.doctorID;
body['FirstName'] = "0";
body['MiddleName'] = "0";
body['LastName'] = "0";
body['PatientMobileNumber'] = "0";
body['PatientIdentificationID'] = "0";
body['PatientID'] = 0;
body['From'] = "0";
body['To'] = "0";
body['stamp'] = DateTime.now().toIso8601String();
body['IsLoginForDoctorApp'] = true;
body['IPAdress'] = "11.11.11.11";
body['PatientOutSA'] = false;
body['PatientTypeID'] = 1;
MyReferralPatientRequestModel myReferralPatientRequestModel = MyReferralPatientRequestModel(
doctorID: doctorProfile!.doctorID,
firstName: "0",
middleName: "0",
lastName: "0",
patientMobileNumber: "0",
patientIdentificationID: "0",
patientID: 0,
from: "0",
to: "0",
stamp: DateTime.now().toIso8601String(),
isLoginForDoctorApp: true,
patientTypeID: 1);
myReferralPatients.clear();
await baseAppClient.post(
GET_MY_REFERRAL_INPATIENT,
@ -38,7 +39,42 @@ class MyReferralInPatientService extends BaseService {
hasError = true;
super.error = error;
},
body: body,
body: myReferralPatientRequestModel.toJson(),
);
}
Future getMyReferralOutPatientService() async {
hasError = false;
await getDoctorProfile();
MyReferralPatientRequestModel myReferralPatientRequestModel = MyReferralPatientRequestModel(
doctorID: doctorProfile.doctorID,
firstName: "0",
middleName: "0",
lastName: "0",
patientMobileNumber: "0",
patientIdentificationID: "0",
patientID: 0,
from: "0",
to: "0",
stamp: DateTime.now().toIso8601String(),
isLoginForDoctorApp: true,
patientTypeID: 1);
myReferralPatients.clear();
await baseAppClient.post(
GET_MY_REFERRAL_OUT_PATIENT,
onSuccess: (dynamic response, int statusCode) {
if (response['List_MyOutPatientReferral'] != null) {
response['List_MyOutPatientReferral'].forEach((v) {
myReferralPatients.add(MyReferralPatientModel.fromJson(v));
});
}
},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: myReferralPatientRequestModel.toJson(),
);
}
@ -63,4 +99,32 @@ class MyReferralInPatientService extends BaseService {
},
);
}
Future replayReferred(String referredDoctorRemarks, MyReferralPatientModel referral, int referalStatus) async {
hasError = false;
await getDoctorProfile();
AddReferredRemarksRequestModel _requestAddReferredDoctorRemarks = AddReferredRemarksRequestModel(
editedBy: doctorProfile.doctorID,
projectID: doctorProfile.projectID,
referredDoctorRemarks: referredDoctorRemarks,
referalStatus: referalStatus);
_requestAddReferredDoctorRemarks.projectID = referral.projectID;
_requestAddReferredDoctorRemarks.admissionNo = int.parse(referral.admissionNo);
_requestAddReferredDoctorRemarks.lineItemNo = referral.lineItemNo;
_requestAddReferredDoctorRemarks.referredDoctorRemarks = referredDoctorRemarks;
_requestAddReferredDoctorRemarks.editedBy = doctorProfile.doctorID;
_requestAddReferredDoctorRemarks.referalStatus = referalStatus;
// _requestAddReferredDoctorRemarks.patientID = referral.patientID;
// _requestAddReferredDoctorRemarks.referringDoctor = referral.referringDoctor;
await baseAppClient.post(
ADD_REFERRED_REMARKS_NEW,
body: _requestAddReferredDoctorRemarks.toJson(),
onSuccess: (dynamic body, int statusCode) {},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
);
}
}

@ -151,6 +151,36 @@ class PatientReferralService extends LookupService {
);
}
Future getMyReferredOutPatient() async {
hasError = false;
RequestMyReferralPatientModel _requestMyReferralPatient =
RequestMyReferralPatientModel();
DoctorProfileModel doctorProfile = await getDoctorProfile();
await baseAppClient.post(
GET_MY_REFERRED_OUT_PATIENT,
onSuccess: (dynamic response, int statusCode) {
listMyReferredPatientModel.clear();
response['List_MyReferredOutPatient'].forEach((v) {
MyReferredPatientModel item = MyReferredPatientModel.fromJson(v);
if (doctorProfile != null) {
item.isReferralDoctorSameBranch =
doctorProfile.projectID == item.projectID;
} else {
item.isReferralDoctorSameBranch = false;
}
listMyReferredPatientModel.add(item);
});
},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: _requestMyReferralPatient.toJson(),
);
}
Future getPendingReferralList() async {
hasError = false;
DoctorProfileModel? doctorProfile = await getDoctorProfile();

@ -4,6 +4,7 @@ import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/model/note/CreateNoteModel.dart';
import 'package:doctor_app_flutter/core/model/note/note_model.dart';
import 'package:doctor_app_flutter/core/model/note/update_note_model.dart';
import 'package:doctor_app_flutter/core/model/patient_muse/PatientSearchRequestModel.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart';
import 'package:doctor_app_flutter/models/patient/get_clinic_by_project_id_request.dart';
@ -12,6 +13,7 @@ import 'package:doctor_app_flutter/models/patient/get_list_stp_referral_frequenc
import 'package:doctor_app_flutter/models/patient/lab_orders/lab_orders_res_model.dart';
import 'package:doctor_app_flutter/models/patient/lab_result/lab_result.dart';
import 'package:doctor_app_flutter/models/patient/lab_result/lab_result_req_model.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/models/patient/prescription/prescription_report.dart';
import 'package:doctor_app_flutter/models/patient/prescription/prescription_report_for_in_patient.dart';
import 'package:doctor_app_flutter/models/patient/prescription/prescription_res_model.dart';
@ -22,6 +24,8 @@ import 'package:doctor_app_flutter/models/patient/vital_sign/vital_sign_res_mode
class PatientService extends BaseService {
List<VitalSignResModel> _patientVitalSignList = [];
List<VitalSignResModel> patientVitalSignOrderdSubList = [];
List<PatiantInformtion> inPatientList = List();
List<PatiantInformtion> myInPatientList = List();
List<VitalSignResModel> get patientVitalSignList => _patientVitalSignList;
@ -132,6 +136,38 @@ class PatientService extends BaseService {
return Future.value(localRes);
}
Future getInPatient(PatientSearchRequestModel requestModel, bool isMyInpatient) async {
hasError = false;
await getDoctorProfile();
if (isMyInpatient) {
requestModel.doctorID = doctorProfile.doctorID;
} else {
requestModel.doctorID = 0;
}
await baseAppClient.post(
GET_PATIENT_IN_PATIENT_LIST,
onSuccess: (dynamic response, int statusCode) {
inPatientList.clear();
myInPatientList.clear();
response['List_MyInPatient'].forEach((v) {
PatiantInformtion patient = PatiantInformtion.fromJson(v);
inPatientList.add(patient);
if (patient.doctorId == doctorProfile.doctorID) {
myInPatientList.add(patient);
}
});
},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: requestModel.toJson(),
);
}
Future getLabResultOrders(patient) async {
hasError = false;
await baseAppClient.post(

@ -1,36 +0,0 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/doctor/verify_referral_doctor_remarks.dart';
import 'package:doctor_app_flutter/models/patient/my_referral/my_referred_patient_model.dart';
import 'package:doctor_app_flutter/models/patient/request_my_referral_patient_model.dart';
class ReferredPatientService extends BaseService {
List<MyReferredPatientModel> _listMyReferredPatientModel = [];
List<MyReferredPatientModel> get listMyReferredPatientModel =>
_listMyReferredPatientModel;
RequestMyReferralPatientModel _requestMyReferralPatient =
RequestMyReferralPatientModel();
VerifyReferralDoctorRemarks _verifyreferraldoctorremarks =
VerifyReferralDoctorRemarks();
Future getMyReferredPatient() async {
await baseAppClient.post(
GET_MY_REFERRED_PATIENT,
onSuccess: (dynamic response, int statusCode) {
_listMyReferredPatientModel.clear();
response['List_MyReferredPatient'].forEach((v) {
listMyReferredPatientModel.add(MyReferredPatientModel.fromJson(v));
});
// print(response['List_MyReferredPatient']);
},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: _requestMyReferralPatient.toJson(),
);
}
}

@ -61,7 +61,7 @@ class ProcedureService extends BaseService {
Future getProcedureTemplate({int? doctorId, int? projectId, int? clinicId, String? categoryID}) async {
_procedureTempleteRequestModel = ProcedureTempleteRequestModel(
tokenID: "@dm!n",
// tokenID: "@dm!n",
patientID: 0,
searchType: 1,
);

@ -40,6 +40,9 @@ class RadiologyService extends BaseService {
if (isInPatient) {
label = "List_GetRadOreders";
}
if(response[label] == null || response[label].length == 0){
label = "FinalRadiologyList";
}
response[label].forEach((radiology) {
finalRadiologyList.add(FinalRadiology.fromJson(radiology));
});

@ -0,0 +1,57 @@
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/core/service/base/base_service.dart';
import 'package:doctor_app_flutter/models/dashboard/dashboard_model.dart';
import 'package:doctor_app_flutter/models/dashboard/get_special_clinical_care_List_Respose_Model.dart';
import 'package:doctor_app_flutter/models/dashboard/get_special_clinical_care_mapping_List_Respose_Model.dart';
class SpecialClinicsService extends BaseService {
List<GetSpecialClinicalCareListResponseModel> _specialClinicalCareList = [];
List<GetSpecialClinicalCareListResponseModel> get specialClinicalCareList => _specialClinicalCareList;
List<GetSpecialClinicalCareMappingListResponseModel> _specialClinicalCareMappingList = [];
List<GetSpecialClinicalCareMappingListResponseModel> get specialClinicalCareMappingList => _specialClinicalCareMappingList;
Future getSpecialClinicalCareList() async {
hasError = false;
await baseAppClient.post(
GET_SPECIAL_CLINICAL_CARE_LIST,
onSuccess: (dynamic response, int statusCode) {
_specialClinicalCareList.clear();
response['List_SpecialClinicalCareList'].forEach((v) {
_specialClinicalCareList.add(GetSpecialClinicalCareListResponseModel.fromJson(v));
});},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: {
},
);
}
Future getSpecialClinicalCareMappingList(int clinicId) async {
hasError = false;
await baseAppClient.post(
GET_SPECIAL_CLINICAL_CARE_MAPPING_LIST,
onSuccess: (dynamic response, int statusCode) {
_specialClinicalCareMappingList.clear();
response['List_SpecialClinicalCareMappingList'].forEach((v) {
_specialClinicalCareMappingList.add(GetSpecialClinicalCareMappingListResponseModel.fromJson(v));
});},
onFailure: (String error, int statusCode) {
hasError = true;
super.error = error;
},
body: {
"ClinicID": clinicId,
"DoctorID":0,
"EditedBy":0
},
);
}
}

@ -1,6 +1,8 @@
import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/model/live_care/AlternativeServicesList.dart';
import 'package:doctor_app_flutter/core/model/live_care/PendingPatientERForDoctorAppRequestModel.dart';
import 'package:doctor_app_flutter/core/model/live_care/live_care_login_reguest_model.dart';
import 'package:doctor_app_flutter/core/service/home/dasboard_service.dart';
import 'package:doctor_app_flutter/core/service/patient/LiveCarePatientServices.dart';
import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart';
@ -18,6 +20,9 @@ class LiveCarePatientViewModel extends BaseViewModel {
StartCallRes get startCallRes => _liveCarePatientServices.startCallRes;
List<AlternativeService> get alternativeServicesList =>
_liveCarePatientServices.alternativeServicesList;
DashboardService _dashboardService = locator<DashboardService>();
getPendingPatientERForDoctorApp({bool isFromTimer = false}) async {
@ -87,9 +92,22 @@ class LiveCarePatientViewModel extends BaseViewModel {
}
}
Future endCallWithCharge(int vcID) async {
setSelectedCheckboxValues(AlternativeService service, bool isSelected) {
int index = alternativeServicesList.indexOf(service);
if (index != -1) alternativeServicesList[index].isSelected = isSelected;
notifyListeners();
}
Future endCallWithCharge(int vcID, bool isConfirmed) async {
setState(ViewState.BusyLocal);
await _liveCarePatientServices.endCallWithCharge(vcID);
List<int> selectedServices = [];
if (isConfirmed) {
selectedServices = getSelectedAlternativeServices();
}
await _liveCarePatientServices.endCallWithCharge(
vcID, selectedServices);
if (_liveCarePatientServices.hasError) {
error = _liveCarePatientServices.error!;
setState(ViewState.ErrorLocal);
@ -99,6 +117,27 @@ class LiveCarePatientViewModel extends BaseViewModel {
}
}
List<int> getSelectedAlternativeServices() {
List<int> selectedServices = List();
for (AlternativeService service in alternativeServicesList) {
if (service.isSelected) {
selectedServices.add(service.serviceID);
}
}
return selectedServices;
}
Future getAlternativeServices(int vcID) async {
setState(ViewState.BusyLocal);
await _liveCarePatientServices.getAlternativeServices(vcID);
if (_liveCarePatientServices.hasError) {
error = _liveCarePatientServices.error;
setState(ViewState.ErrorLocal);
} else {
setState(ViewState.Idle);
}
}
Future transferToAdmin(int vcID, String notes) async {
setState(ViewState.BusyLocal);
await _liveCarePatientServices.transferToAdmin(vcID, notes);
@ -111,6 +150,18 @@ class LiveCarePatientViewModel extends BaseViewModel {
}
}
Future sendSMSInstruction(int vcID) async {
setState(ViewState.BusyLocal);
await _liveCarePatientServices.sendSMSInstruction(vcID);
if (_liveCarePatientServices.hasError) {
error = _liveCarePatientServices.error;
setState(ViewState.ErrorLocal);
} else {
await getPendingPatientERForDoctorApp();
setState(ViewState.Idle);
}
}
searchData(String str) {
var strExist = str.length > 0 ? true : false;
if (strExist) {
@ -130,4 +181,61 @@ class LiveCarePatientViewModel extends BaseViewModel {
notifyListeners();
}
}
Future isLogin(int loginStatus) async {
await getDoctorProfile(isGetProfile: true);
LiveCareUserLoginRequestModel userLoginRequestModel = new LiveCareUserLoginRequestModel();
userLoginRequestModel.isOutKsa = (doctorProfile.projectID == 2 || doctorProfile.projectID == 3) ? 1 : 0;
userLoginRequestModel.isLogin = loginStatus;
userLoginRequestModel.generalid = "Cs2020@2016\$2958";
setState(ViewState.BusyLocal);
await _liveCarePatientServices.isLogin(loginStatus: loginStatus, isLoginRequestModel: userLoginRequestModel);
if (_liveCarePatientServices.hasError) {
error = _liveCarePatientServices.error;
setState(ViewState.ErrorLocal);
} else {
setState(ViewState.Idle);
}
}
setDemoData() {
alternativeServicesList.clear();
alternativeServicesList.add(
AlternativeService(serviceID: 1, serviceName: "Medicine Home Delivery"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 2, serviceName: "LABORATORY"),
);
alternativeServicesList.add(
AlternativeService(
serviceID: 3, serviceName: "RADIOLOGY(ULTRASOUND) For pregnant only"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 4, serviceName: "VACCINATIONS"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 5, serviceName: "ER SERVICES"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 6, serviceName: "PHYSIOTHERAPY"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 7, serviceName: "DRESSING"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 8, serviceName: "INJECTION"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 9, serviceName: "FAMILY MEDICIN DR"),
);
alternativeServicesList.add(
AlternativeService(
serviceID: 10, serviceName: "FOLYS CATHETER INSERTION"),
);
alternativeServicesList.add(
AlternativeService(serviceID: 11, serviceName: "GASTRIC TUBE CHANGE"),
);
}
}

@ -25,12 +25,24 @@ class PatientMedicalReportViewModel extends BaseViewModel {
setState(ViewState.Idle);
}
bool hasOnHold(){
bool hasHold = false;
medicalReportList.forEach((element) {
if(element.status == 1){
hasHold = true;
}
});
return hasHold;
}
Future getMedicalReportTemplate() async {
setState(ViewState.Busy);
setState(ViewState.BusyLocal);
await _service.getMedicalReportTemplate();
if (_service.hasError) {
error = _service.error!;
setState(ViewState.Error);
setState(ViewState.ErrorLocal);
} else
setState(ViewState.Idle);
}

@ -4,6 +4,8 @@ import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/model/patient_muse/PatientSearchRequestModel.dart';
import 'package:doctor_app_flutter/core/service/patient/out_patient_service.dart';
import 'package:doctor_app_flutter/core/service/patient/patientInPatientService.dart';
import 'package:doctor_app_flutter/core/service/special_clinics/special_clinic_service.dart';
import 'package:doctor_app_flutter/models/dashboard/get_special_clinical_care_mapping_List_Respose_Model.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/util/date-utils.dart';
@ -12,8 +14,10 @@ import 'base_view_model.dart';
class PatientSearchViewModel extends BaseViewModel {
OutPatientService _outPatientService = locator<OutPatientService>();
SpecialClinicsService _specialClinicsService = locator<SpecialClinicsService>();
List<PatiantInformtion> get patientList => _outPatientService.patientList;
List<GetSpecialClinicalCareMappingListResponseModel> get specialClinicalCareMappingList => _specialClinicsService.specialClinicalCareMappingList;
List<PatiantInformtion> filterData = [];
@ -123,14 +127,21 @@ class PatientSearchViewModel extends BaseViewModel {
List<PatiantInformtion> filteredInPatientItems = [];
Future getInPatientList(PatientSearchRequestModel requestModel, {bool isMyInpatient = false}) async {
Future getInPatientList(PatientSearchRequestModel requestModel, {bool isMyInpatient = false, bool isLocalBusy = false}) async {
await getDoctorProfile();
setState(ViewState.Busy);
if(isLocalBusy) {
setState(ViewState.BusyLocal);
} else{
setState(ViewState.Busy);
}
if (inPatientList.length == 0) await _inPatientService.getInPatientList(requestModel, false);
if (_inPatientService.hasError) {
error = _inPatientService.error!;
if(isLocalBusy) {
setState(ViewState.ErrorLocal);
} else{
setState(ViewState.Error);
}
} else {
// setDefaultInPatientList();
setState(ViewState.Idle);
@ -145,6 +156,9 @@ class PatientSearchViewModel extends BaseViewModel {
setState(ViewState.Idle);
}
void clearPatientList() {
_inPatientService.inPatientList = [];
_inPatientService.myInPatientList = [];
@ -174,4 +188,25 @@ class PatientSearchViewModel extends BaseViewModel {
notifyListeners();
}
}
getSpecialClinicalCareMappingList(clinicId,
{bool isLocalBusy = false}) async {
if (isLocalBusy) {
setState(ViewState.BusyLocal);
} else {
setState(ViewState.Busy);
}
await _specialClinicsService.getSpecialClinicalCareMappingList(clinicId);
if (_specialClinicsService.hasError) {
error = _specialClinicsService.error;
if (isLocalBusy) {
setState(ViewState.ErrorLocal);
} else {
setState(ViewState.Error);
}
} else {
setState(ViewState.Idle);
}
}
}

@ -26,9 +26,7 @@ import 'package:doctor_app_flutter/root_page.dart';
import 'package:doctor_app_flutter/util/dr_app_toast_msg.dart';
import 'package:doctor_app_flutter/util/helpers.dart';
import 'package:doctor_app_flutter/util/translations_delegate_base.dart';
import 'package:doctor_app_flutter/widgets/transitions/fade_page.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
@ -234,7 +232,8 @@ class AuthenticationViewModel extends BaseViewModel {
/// add  token to shared preferences in case of send activation code is success
setDataAfterSendActivationSuccess(
SendActivationCodeForDoctorAppResponseModel sendActivationCodeForDoctorAppResponseModel) {
print("VerificationCode : " + sendActivationCodeForDoctorAppResponseModel.verificationCode!);
print("VerificationCode : " +sendActivationCodeForDoctorAppResponseModel.verificationCode);
// DrAppToastMsg.showSuccesToast("VerificationCode : " + sendActivationCodeForDoctorAppResponseModel.verificationCode!);
sharedPref.setString(VIDA_AUTH_TOKEN_ID, sendActivationCodeForDoctorAppResponseModel.vidaAuthTokenID!);
sharedPref.setString(VIDA_REFRESH_TOKEN_ID, sendActivationCodeForDoctorAppResponseModel.vidaRefreshTokenID!);
sharedPref.setString(LOGIN_TOKEN_ID, sendActivationCodeForDoctorAppResponseModel.logInTokenID!);
@ -275,8 +274,7 @@ class AuthenticationViewModel extends BaseViewModel {
clinicID: clinicInfo.clinicID,
license: true,
projectID: clinicInfo.projectID,
tokenID: '',
languageID: 2); //TODO change the lan
tokenID: '',); //TODO change the lan
await _authService.getDoctorProfileBasedOnClinic(docInfo);
if (_authService.hasError) {
error = _authService.error!;

@ -2,8 +2,10 @@ import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/service/home/dasboard_service.dart';
import 'package:doctor_app_flutter/core/service/special_clinics/special_clinic_service.dart';
import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart';
import 'package:doctor_app_flutter/models/dashboard/dashboard_model.dart';
import 'package:doctor_app_flutter/models/dashboard/get_special_clinical_care_List_Respose_Model.dart';
import 'package:doctor_app_flutter/models/doctor/clinic_model.dart';
import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
@ -14,6 +16,7 @@ import 'base_view_model.dart';
class DashboardViewModel extends BaseViewModel {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
DashboardService _dashboardService = locator<DashboardService>();
SpecialClinicsService _specialClinicsService = locator<SpecialClinicsService>();
List<DashboardModel> get dashboardItemsList => _dashboardService.dashboardItemsList;
@ -21,6 +24,9 @@ class DashboardViewModel extends BaseViewModel {
String? get sServiceID => _dashboardService.sServiceID;
List<GetSpecialClinicalCareListResponseModel> get specialClinicalCareList => _specialClinicsService.specialClinicalCareList;
Future setFirebaseNotification(ProjectViewModel projectsProvider, AuthenticationViewModel authProvider) async {
setState(ViewState.Busy);
await projectsProvider.getDoctorClinicsList();
@ -56,6 +62,16 @@ class DashboardViewModel extends BaseViewModel {
setState(ViewState.Idle);
}
Future getSpecialClinicalCareList() async {
setState(ViewState.Busy);
await _specialClinicsService.getSpecialClinicalCareList();
if (_specialClinicsService.hasError) {
error = _specialClinicsService.error;
setState(ViewState.Error);
} else
setState(ViewState.Idle);
}
Future changeClinic(int clinicId, AuthenticationViewModel authProvider) async {
setState(ViewState.BusyLocal);
await getDoctorProfile();
@ -76,4 +92,17 @@ class DashboardViewModel extends BaseViewModel {
return value.toString();
}
GetSpecialClinicalCareListResponseModel getSpecialClinic(clinicId){
GetSpecialClinicalCareListResponseModel special ;
specialClinicalCareList.forEach((element) {
if(element.clinicID == 1){
special = element;
}
});
return special;
}
}

@ -2,6 +2,7 @@ import 'package:doctor_app_flutter/core/enum/master_lookup_key.dart';
import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/model/referral/DischargeReferralPatient.dart';
import 'package:doctor_app_flutter/core/model/referral/MyReferralPatientModel.dart';
import 'package:doctor_app_flutter/core/model/referral/add_referred_remarks_request.dart';
import 'package:doctor_app_flutter/core/service/patient/DischargedPatientService.dart';
import 'package:doctor_app_flutter/core/service/patient/MyReferralPatientService.dart';
import 'package:doctor_app_flutter/core/service/patient/ReferralService.dart';
@ -119,8 +120,11 @@ class PatientReferralViewModel extends BaseViewModel {
return null;
}
Future getMyReferredPatient() async {
setState(ViewState.Busy);
Future getMyReferredPatient({bool isFirstTime = true}) async {
if (isFirstTime)
setState(ViewState.Busy);
else
setState(ViewState.BusyLocal);
await _referralPatientService.getMyReferredPatient();
if (_referralPatientService.hasError) {
error = _referralPatientService.error!;
@ -129,6 +133,19 @@ class PatientReferralViewModel extends BaseViewModel {
setState(ViewState.Idle);
}
Future getMyReferredOutPatient({bool isFirstTime = true}) async {
if (isFirstTime)
setState(ViewState.Busy);
else
setState(ViewState.BusyLocal);
await _referralPatientService.getMyReferredOutPatient();
if (_referralPatientService.hasError) {
error = _referralPatientService.error;
setState(ViewState.Error);
} else
setState(ViewState.Idle);
}
MyReferredPatientModel getReferredPatientItem(int index) {
return listMyReferredPatientModel[index];
}
@ -143,12 +160,34 @@ class PatientReferralViewModel extends BaseViewModel {
setState(ViewState.Idle);
}
Future getMyReferralPatientService() async {
setState(ViewState.Busy);
Future getMyReferralPatientService({bool localBusy = false}) async {
if (localBusy)
setState(ViewState.BusyLocal);
else
setState(ViewState.Busy);
await _myReferralService.getMyReferralPatientService();
if (_myReferralService.hasError) {
error = _myReferralService.error!;
setState(ViewState.Error);
if (localBusy)
setState(ViewState.ErrorLocal);
else
setState(ViewState.Error);
} else
setState(ViewState.Idle);
}
Future getMyReferralOutPatientService({bool localBusy = false}) async {
if (localBusy)
setState(ViewState.BusyLocal);
else
setState(ViewState.Busy);
await _myReferralService.getMyReferralOutPatientService();
if (_myReferralService.hasError) {
error = _myReferralService.error;
if (localBusy)
setState(ViewState.ErrorLocal);
else
setState(ViewState.Error);
} else
setState(ViewState.Idle);
}
@ -200,7 +239,7 @@ class PatientReferralViewModel extends BaseViewModel {
patientID: patient.patientId,
roomID: patient.roomId,
referralClinic: clinicID,
admissionNo: int.parse(patient.admissionNo!), /// TODO Elham* something in case inpateint since we send send appointmentNo for admissionNo which all time null
admissionNo: int.parse(patient.admissionNo),
referralDoctor: doctorID,
patientTypeID: patient.patientType,
referringDoctorRemarks: remarks,
@ -351,4 +390,14 @@ class PatientReferralViewModel extends BaseViewModel {
patient.clinicDescription = referredPatient.clinicDescription!;
return patient;
}
Future replayReferred(String referredDoctorRemarks, MyReferralPatientModel referral, int referalStatus) async {
setState(ViewState.Busy);
await _myReferralService.replayReferred(referredDoctorRemarks, referral, referalStatus);
if (_myReferralService.hasError) {
error = _myReferralService.error;
setState(ViewState.ErrorLocal);
} else
getMyReferralPatientService();
}
}

@ -2,9 +2,11 @@ import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/model/note/CreateNoteModel.dart';
import 'package:doctor_app_flutter/core/model/note/note_model.dart';
import 'package:doctor_app_flutter/core/model/note/update_note_model.dart';
import 'package:doctor_app_flutter/core/model/patient_muse/PatientSearchRequestModel.dart';
import 'package:doctor_app_flutter/core/service/patient/patient_service.dart';
import 'package:doctor_app_flutter/models/patient/lab_orders/lab_orders_res_model.dart';
import 'package:doctor_app_flutter/models/patient/lab_result/lab_result.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/models/patient/prescription/prescription_report.dart';
import 'package:doctor_app_flutter/models/patient/prescription/prescription_report_for_in_patient.dart';
import 'package:doctor_app_flutter/models/patient/prescription/prescription_res_model.dart';
@ -17,51 +19,43 @@ import 'base_view_model.dart';
class PatientViewModel extends BaseViewModel {
PatientService _patientService = locator<PatientService>();
List<VitalSignResModel> get patientVitalSignList =>
_patientService.patientVitalSignList;
List<PatiantInformtion> get inPatientList => _patientService.inPatientList;
List<VitalSignResModel> get patientVitalSignOrderdSubList =>
_patientService.patientVitalSignOrderdSubList;
List<VitalSignResModel> get patientVitalSignList => _patientService.patientVitalSignList;
List<LabOrdersResModel> get patientLabResultOrdersList =>
_patientService.patientLabResultOrdersList;
List<VitalSignResModel> get patientVitalSignOrderdSubList => _patientService.patientVitalSignOrderdSubList;
List<PrescriptionResModel> get patientPrescriptionsList =>
_patientService.patientPrescriptionsList;
List<LabOrdersResModel> get patientLabResultOrdersList => _patientService.patientLabResultOrdersList;
List<PrescriptionResModel> get patientPrescriptionsList => _patientService.patientPrescriptionsList;
List<PrescriptionReportForInPatient> get prescriptionReportForInPatientList =>
_patientService.prescriptionReportForInPatientList;
List<PrescriptionReport> get prescriptionReport =>
_patientService.prescriptionReport;
List<PrescriptionReport> get prescriptionReport => _patientService.prescriptionReport;
List<RadiologyResModel> get patientRadiologyList =>
_patientService.patientRadiologyList;
List<RadiologyResModel> get patientRadiologyList => _patientService.patientRadiologyList;
List<LabResult> get labResultList => _patientService.labResultList;
get insuranceApporvalsList => _patientService.insuranceApporvalsList;
List<NoteModel> get patientProgressNoteList =>
_patientService.patientProgressNoteList;
List<NoteModel> get patientProgressNoteList => _patientService.patientProgressNoteList;
List<dynamic> get clinicsList => _patientService.clinicsList;
List<dynamic> get doctorsList => _patientService.doctorsList;
List<dynamic> get referralFrequencyList =>
_patientService.referalFrequancyList;
List<dynamic> get referralFrequencyList => _patientService.referalFrequancyList;
Future getPatientList(patient, patientType,
{bool isBusyLocal = false, isView}) async {
Future getPatientList(patient, patientType, {bool isBusyLocal = false, isView}) async {
var localRes;
if (isBusyLocal) {
setState(ViewState.BusyLocal);
} else {
setState(ViewState.Busy);
}
localRes = await _patientService.getPatientList(patient, patientType,
isView: isView);
localRes = await _patientService.getPatientList(patient, patientType, isView: isView);
if (_patientService.hasError) {
error = _patientService.error!;
@ -210,16 +204,12 @@ class PatientViewModel extends BaseViewModel {
}
List getDoctorNameList() {
var doctorNamelist = _patientService.doctorsList
.map((value) => value['DoctorName'].toString())
.toList();
var doctorNamelist = _patientService.doctorsList.map((value) => value['DoctorName'].toString()).toList();
return doctorNamelist;
}
List getClinicNameList() {
var clinicsNameslist = _patientService.clinicsList
.map((value) => value['ClinicDescription'].toString())
.toList();
var clinicsNameslist = _patientService.clinicsList.map((value) => value['ClinicDescription'].toString()).toList();
return clinicsNameslist;
}
@ -234,9 +224,8 @@ class PatientViewModel extends BaseViewModel {
}
List getReferralNamesList() {
var referralNamesList = _patientService.referalFrequancyList
.map((value) => value['Description'].toString())
.toList();
var referralNamesList =
_patientService.referalFrequancyList.map((value) => value['Description'].toString()).toList();
return referralNamesList;
}
@ -281,4 +270,18 @@ class PatientViewModel extends BaseViewModel {
} else
setState(ViewState.Idle);
}
Future getInPatientList(PatientSearchRequestModel requestModel, {bool isMyInpatient = false}) async {
await getDoctorProfile();
setState(ViewState.Busy);
await _patientService.getInPatient(requestModel, false);
if (_patientService.hasError) {
error = _patientService.error;
setState(ViewState.ErrorLocal);
} else {
// setDefaultInPatientList();
setState(ViewState.Idle);
}
}
}

@ -4,10 +4,10 @@ import 'package:doctor_app_flutter/core/model/labs/LabOrderResult.dart';
import 'package:doctor_app_flutter/core/model/labs/lab_result.dart';
import 'package:doctor_app_flutter/core/model/labs/patient_lab_orders.dart';
import 'package:doctor_app_flutter/core/model/labs/patient_lab_special_result.dart';
import 'package:doctor_app_flutter/core/model/procedure/ControlsModel.dart';
import 'package:doctor_app_flutter/core/model/procedure/categories_procedure.dart';
import 'package:doctor_app_flutter/core/model/procedure/get_ordered_procedure_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/post_procedure_req_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_templateModel.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_template_details_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_valadate_model.dart';
import 'package:doctor_app_flutter/core/model/procedure/procedure_valadate_request_model.dart';
@ -19,8 +19,12 @@ import 'package:doctor_app_flutter/core/service/patient_medical_file/radiology/r
import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart';
import 'package:doctor_app_flutter/locator.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/screens/procedures/ProcedureType.dart';
import 'package:doctor_app_flutter/util/dr_app_toast_msg.dart';
import 'package:doctor_app_flutter/util/helpers.dart';
import 'package:flutter/cupertino.dart';
import 'package:doctor_app_flutter/core/model/procedure/categories_procedure.dart'
as cpe;
class ProcedureViewModel extends BaseViewModel {
//TODO Hussam clean it
@ -74,11 +78,15 @@ class ProcedureViewModel extends BaseViewModel {
setState(ViewState.Idle);
}
Future getProcedureCategory({String? categoryName, String? categoryID, patientId}) async {
Future getProcedureCategory(
{String? categoryName, String? categoryID, patientId}) async {
if (categoryName == null) return;
hasError = false;
setState(ViewState.Busy);
await _procedureService.getProcedureCategory(
categoryName: categoryName, categoryID: categoryID, patientId: patientId);
categoryName: categoryName,
categoryID: categoryID,
patientId: patientId);
if (_procedureService.hasError) {
error = _procedureService.error!;
setState(ViewState.ErrorLocal);
@ -305,4 +313,70 @@ class ProcedureViewModel extends BaseViewModel {
} else
DrAppToastMsg.showSuccesToast(mes);
}
Future preparePostProcedure(
{String remarks,
String orderType,
PatiantInformtion patient,
List<cpe.EntityList> entityList,
ProcedureType procedureType}) async {
PostProcedureReqModel postProcedureReqModel = new PostProcedureReqModel();
ProcedureValadteRequestModel procedureValadteRequestModel =
new ProcedureValadteRequestModel();
procedureValadteRequestModel.patientMRN = patient.patientMRN;
procedureValadteRequestModel.episodeID = patient.episodeNo;
procedureValadteRequestModel.appointmentNo = patient.appointmentNo;
List<Procedures> controlsProcedure = List();
postProcedureReqModel.appointmentNo = patient.appointmentNo;
postProcedureReqModel.episodeID = patient.episodeNo;
postProcedureReqModel.patientMRN = patient.patientMRN;
entityList.forEach((element) {
procedureValadteRequestModel.procedure = [element.procedureId];
List<Controls> controls = List();
controls.add(
Controls(
code: "remarks",
controlValue: element.remarks != null ? element.remarks : ""),
);
controls.add(
Controls(
code: "ordertype",
controlValue: procedureType == ProcedureType.PROCEDURE
? element.type ?? "1"
: "0"),
);
controlsProcedure.add(Procedures(
category: element.categoryID,
procedure: element.procedureId,
controls: controls));
});
postProcedureReqModel.procedures = controlsProcedure;
await valadteProcedure(procedureValadteRequestModel);
if (state == ViewState.Idle) {
if (valadteProcedureList[0].entityList.length == 0) {
await postProcedure(postProcedureReqModel, patient.patientMRN);
if (state == ViewState.ErrorLocal) {
Helpers.showErrorToast(error);
getProcedure(mrn: patient.patientMRN);
} else if (state == ViewState.Idle) {
DrAppToastMsg.showSuccesToast('procedure has been added');
}
} else {
if (state == ViewState.ErrorLocal) {
Helpers.showErrorToast(error);
getProcedure(mrn: patient.patientMRN);
} else if (state == ViewState.Idle) {
Helpers.showErrorToast(
valadteProcedureList[0].entityList[0].warringMessages);
}
}
} else {
Helpers.showErrorToast(error);
}
}
}

@ -1,22 +0,0 @@
import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/service/patient/referred_patient_service.dart';
import 'package:doctor_app_flutter/models/patient/my_referral/my_referred_patient_model.dart';
import '../../locator.dart';
import 'base_view_model.dart';
class ReferredPatientViewModel extends BaseViewModel {
ReferredPatientService _referralPatientService = locator<ReferredPatientService>();
List<MyReferredPatientModel> get listMyReferredPatientModel => _referralPatientService.listMyReferredPatientModel;
Future getMyReferredPatient() async {
setState(ViewState.Busy);
await _referralPatientService.getMyReferredPatient();
if (_referralPatientService.hasError) {
error = _referralPatientService.error!;
setState(ViewState.Error);
} else
setState(ViewState.Idle);
}
}

@ -0,0 +1,26 @@
import 'package:doctor_app_flutter/core/enum/viewstate.dart';
import 'package:doctor_app_flutter/core/model/patient_muse/PatientSearchRequestModel.dart';
import 'package:doctor_app_flutter/core/service/home/scan_qr_service.dart';
import 'package:doctor_app_flutter/core/viewModel/base_view_model.dart';
import 'package:doctor_app_flutter/locator.dart';
import 'package:doctor_app_flutter/models/patient/patiant_info_model.dart';
class ScanQrViewModel extends BaseViewModel {
ScanQrService _scanQrService = locator<ScanQrService>();
List<PatiantInformtion> get inPatientList => _scanQrService.inPatientList;
Future getInPatientList(PatientSearchRequestModel requestModel, {bool isMyInpatient = false}) async {
await getDoctorProfile();
setState(ViewState.Busy);
await _scanQrService.getInPatient(requestModel, true);
if (_scanQrService.hasError) {
error = _scanQrService.error;
setState(ViewState.ErrorLocal);
} else {
// setDefaultInPatientList();
setState(ViewState.Idle);
}
}
}

@ -4,6 +4,7 @@ import 'package:doctor_app_flutter/screens/home/home_screen.dart';
import 'package:doctor_app_flutter/screens/qr_reader/QR_reader_screen.dart';
import 'package:doctor_app_flutter/util/translations_delegate_base.dart';
import 'package:doctor_app_flutter/widgets/shared/app_drawer_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/app_scaffold_widget.dart';
import 'package:doctor_app_flutter/widgets/shared/bottom_nav_bar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -32,7 +33,7 @@ class _LandingPageState extends State<LandingPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
return AppScaffold(
appBar: currentTab != 0
? AppBar(
elevation: 0,

@ -1,42 +1,46 @@
import 'package:doctor_app_flutter/core/service/authentication_service.dart';
import 'package:doctor_app_flutter/core/service/home/scan_qr_service.dart';
import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/hospitals_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/medical_file_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/patient_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/prescription_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/procedure_View_model.dart';
import 'package:doctor_app_flutter/core/viewModel/scan_qr_view_model.dart';
import 'package:doctor_app_flutter/core/viewModel/sick_leave_view_model.dart';
import 'package:get_it/get_it.dart';
import 'core/service/NavigationService.dart';
import 'core/service/VideoCallService.dart';
import 'core/service/home/dasboard_service.dart';
import 'core/service/home/doctor_reply_service.dart';
import 'core/service/home/schedule_service.dart';
import 'core/service/hospitals/hospitals_service.dart';
import 'core/service/patient/DischargedPatientService.dart';
import 'core/service/patient/LiveCarePatientServices.dart';
import 'core/service/patient/patient_service.dart';
import 'core/service/patient_medical_file/insurance/InsuranceCardService.dart';
import 'core/service/patient/MyReferralPatientService.dart';
import 'core/service/patient/PatientMuseService.dart';
import 'core/service/patient/ReferralService.dart';
import 'core/service/patient/out_patient_service.dart';
import 'core/service/patient/patient-doctor-referral-service.dart';
import 'core/service/patient/patientInPatientService.dart';
import 'core/service/patient/patient_service.dart';
import 'core/service/patient/referral_patient_service.dart';
import 'core/service/patient_medical_file/admission_request/patient-admission-request-service.dart';
import 'core/service/patient_medical_file/insurance/InsuranceCardService.dart';
import 'core/service/patient_medical_file/lab_order/labs_service.dart';
import 'core/service/patient_medical_file/medical_report/PatientMedicalReportService.dart';
import 'core/service/patient_medical_file/medical_report/medical_file_service.dart';
import 'core/service/patient_medical_file/prescription/medicine_service.dart';
import 'core/service/patient_medical_file/prescription/prescription_service.dart';
import 'core/service/patient_medical_file/prescription/prescriptions_service.dart';
import 'core/service/patient_medical_file/procedure/procedure_service.dart';
import 'core/service/patient_medical_file/radiology/radiology_service.dart';
import 'core/service/patient_medical_file/sick_leave/sickleave_service.dart';
import 'core/service/patient_medical_file/soap/SOAP_service.dart';
import 'core/service/home/doctor_reply_service.dart';
import 'core/service/hospitals/hospitals_service.dart';
import 'core/service/patient_medical_file/lab_order/labs_service.dart';
import 'core/service/patient_medical_file/prescription/medicine_service.dart';
import 'core/service/patient_medical_file/admission_request/patient-admission-request-service.dart';
import 'core/service/patient/patient-doctor-referral-service.dart';
import 'core/service/patient_medical_file/ucaf/patient-ucaf-service.dart';
import 'core/service/patient_medical_file/vital_sign/patient-vital-signs-service.dart';
import 'core/service/patient/out_patient_service.dart';
import 'core/service/patient/patientInPatientService.dart';
import 'core/service/patient_medical_file/prescription/prescriptions_service.dart';
import 'core/service/patient_medical_file/radiology/radiology_service.dart';
import 'core/service/patient/referral_patient_service.dart';
import 'core/service/patient/referred_patient_service.dart';
import 'core/service/home/schedule_service.dart';
import 'core/service/special_clinics/special_clinic_service.dart';
import 'core/viewModel/DischargedPatientViewModel.dart';
import 'core/viewModel/InsuranceViewModel.dart';
import 'core/viewModel/LiveCarePatientViewModel.dart';
@ -54,7 +58,6 @@ import 'core/viewModel/patient-vital-sign-viewmodel.dart';
import 'core/viewModel/prescriptions_view_model.dart';
import 'core/viewModel/radiology_view_model.dart';
import 'core/viewModel/referral_view_model.dart';
import 'core/viewModel/referred_view_model.dart';
import 'core/viewModel/schedule_view_model.dart';
GetIt locator = GetIt.instance;
@ -65,7 +68,6 @@ void setupLocator() {
locator.registerLazySingleton(() => DoctorReplyService());
locator.registerLazySingleton(() => ScheduleService());
locator.registerLazySingleton(() => ReferralPatientService());
locator.registerLazySingleton(() => ReferredPatientService());
locator.registerLazySingleton(() => MedicineService());
locator.registerLazySingleton(() => PatientService());
locator.registerLazySingleton(() => DashboardService());
@ -92,12 +94,15 @@ void setupLocator() {
locator.registerLazySingleton(() => HospitalsService());
locator.registerLazySingleton(() => PatientMedicalReportService());
locator.registerLazySingleton(() => LiveCarePatientServices());
locator.registerLazySingleton(() => NavigationService());
locator.registerLazySingleton(() => ScanQrService());
locator.registerLazySingleton(() => SpecialClinicsService());
locator.registerLazySingleton(() => VideoCallService());
/// View Model
locator.registerFactory(() => DoctorReplayViewModel());
locator.registerFactory(() => ScheduleViewModel());
locator.registerFactory(() => ReferralPatientViewModel());
locator.registerFactory(() => ReferredPatientViewModel());
locator.registerFactory(() => MedicineViewModel());
locator.registerFactory(() => PatientViewModel());
locator.registerFactory(() => DashboardViewModel());
@ -120,4 +125,5 @@ void setupLocator() {
locator.registerFactory(() => HospitalViewModel());
locator.registerFactory(() => LiveCarePatientViewModel());
locator.registerFactory(() => PatientMedicalReportViewModel());
locator.registerFactory(() => ScanQrViewModel());
}

@ -11,6 +11,7 @@ import 'package:provider/provider.dart';
import './config/size_config.dart';
import './routes.dart';
import 'config/config.dart';
import 'core/service/NavigationService.dart';
import 'core/viewModel/authentication_view_model.dart';
import 'locator.dart';
@ -66,6 +67,7 @@ class MyApp extends StatelessWidget {
dividerColor: Colors.grey[350],
backgroundColor: Color.fromRGBO(255, 255, 255, 1),
),
navigatorKey: locator<NavigationService>().navigatorKey,
initialRoute: INIT_ROUTE,
routes: routes,
debugShowCheckedModeBanner: false,

@ -0,0 +1,32 @@
class GetSpecialClinicalCareListResponseModel {
int projectID;
int clinicID;
String clinicDescription;
String clinicDescriptionN;
bool isActive;
GetSpecialClinicalCareListResponseModel(
{this.projectID,
this.clinicID,
this.clinicDescription,
this.clinicDescriptionN,
this.isActive});
GetSpecialClinicalCareListResponseModel.fromJson(Map<String, dynamic> json) {
projectID = json['ProjectID'];
clinicID = json['ClinicID'];
clinicDescription = json['ClinicDescription'];
clinicDescriptionN = json['ClinicDescriptionN'];
isActive = json['IsActive'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ProjectID'] = this.projectID;
data['ClinicID'] = this.clinicID;
data['ClinicDescription'] = this.clinicDescription;
data['ClinicDescriptionN'] = this.clinicDescriptionN;
data['IsActive'] = this.isActive;
return data;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save