Merge branch 'development' of https://gitlab.com/Cloud_Solution/doctor_app_flutter into in_patient_soap
Conflicts: lib/config/config.dart lib/screens/patients/profile/soap_update/objective/update_objective_page.dart lib/screens/patients/profile/soap_update/subjective/update_subjective_page.dartmerge-requests/781/head
@ -1,15 +0,0 @@
|
||||
package com.example.doctor_app_flutter.Service;
|
||||
|
||||
import com.example.doctor_app_flutter.Model.GetSessionStatusModel;
|
||||
import com.example.doctor_app_flutter.Model.SessionStatusModel;
|
||||
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface SessionStatusAPI {
|
||||
|
||||
@POST("LiveCareApi/DoctorApp/GetSessionStatus")
|
||||
Call<SessionStatusModel> getSessionStatusModelData(@Body GetSessionStatusModel getSessionStatusModel);
|
||||
}
|
@ -1,430 +0,0 @@
|
||||
package com.example.doctor_app_flutter.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.example.doctor_app_flutter.Model.GetSessionStatusModel;
|
||||
import com.example.doctor_app_flutter.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, Manifest.permission.RECORD_AUDIO};
|
||||
if (EasyPermissions.hasPermissions(this, perms)) {
|
||||
mSession = new Session.Builder(VideoCallActivity.this, apiKey, sessionId).build();
|
||||
mSession.setSessionListener(this);
|
||||
mSession.connect(token);
|
||||
} 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);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
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 onFailure() {
|
||||
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package com.example.doctor_app_flutter.ui;
|
||||
|
||||
import com.example.doctor_app_flutter.Model.GetSessionStatusModel;
|
||||
import com.example.doctor_app_flutter.Model.SessionStatusModel;
|
||||
|
||||
public interface VideoCallContract {
|
||||
|
||||
interface VideoCallView{
|
||||
|
||||
void onCallSuccessful(SessionStatusModel sessionStatusModel);
|
||||
void onFailure();
|
||||
}
|
||||
|
||||
interface VideoCallPresenter {
|
||||
|
||||
void callClintConnected(GetSessionStatusModel statusModel);
|
||||
}
|
||||
}
|
@ -1,101 +1,280 @@
|
||||
package com.hmg.hmgDr
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import androidx.annotation.NonNull
|
||||
import com.example.doctor_app_flutter.Model.GetSessionStatusModel
|
||||
import com.example.doctor_app_flutter.Model.SessionStatusModel
|
||||
import com.example.doctor_app_flutter.ui.VideoCallActivity
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.hmg.hmgDr.Model.GetSessionStatusModel
|
||||
import com.hmg.hmgDr.Model.SessionStatusModel
|
||||
import com.hmg.hmgDr.Service.VideoStreamContainerService
|
||||
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
|
||||
private var serviceIntent: Intent? = null
|
||||
private var videoStreamService: VideoStreamContainerService? = null
|
||||
private var bound = false
|
||||
|
||||
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")
|
||||
// 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")
|
||||
val isRecording = call.argument<Boolean>("isRecording")
|
||||
|
||||
val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId)
|
||||
val sessionStatusModel =
|
||||
GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId, patientName, isRecording!!)
|
||||
|
||||
|
||||
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
|
||||
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
|
||||
|
||||
}
|
||||
"closeVideoCall" -> {
|
||||
dialogFragment?.onCallClicked()
|
||||
// videoStreamService?.closeVideoCall()
|
||||
}
|
||||
"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")
|
||||
}
|
||||
}
|
||||
|
||||
// private fun openVideoCall(
|
||||
// apiKey: String?,
|
||||
// sessionId: String?,
|
||||
// token: String?,
|
||||
// appLang: String?,
|
||||
// baseUrl: String?,
|
||||
// sessionStatusModel: GetSessionStatusModel
|
||||
// ) {
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
//// showSoftKeyBoard(null)
|
||||
// // start service
|
||||
// serviceIntent = Intent(this@MainActivity, VideoStreamContainerService::class.java)
|
||||
// serviceIntent?.run {
|
||||
// putExtras(arguments)
|
||||
// startService(this)
|
||||
// }
|
||||
//// bindService()
|
||||
// }
|
||||
|
||||
/* 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()
|
||||
|
||||
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 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 onCallFinished(resultCode: Int, intent: Intent?) {
|
||||
dialogFragment = null
|
||||
|
||||
val sessionStatus : HashMap<String, String> = HashMap()
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
val result: SessionStatusModel? = intent?.getParcelableExtra("sessionStatusNotRespond")
|
||||
val callResponse: HashMap<String, String> = HashMap()
|
||||
|
||||
callResponse["callResponse"] = "CallNotRespond"
|
||||
val jsonRes = gson.toJson(result)
|
||||
callResponse["sessionStatus"] = jsonRes
|
||||
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}.")
|
||||
}
|
||||
}
|
||||
|
||||
// stopService(serviceIntent)
|
||||
// unbindService()
|
||||
// videoStreamService!!.serviceRunning = false
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
// override fun onStart() {
|
||||
// super.onStart()
|
||||
// bindService()
|
||||
// }
|
||||
//
|
||||
// override fun onStop() {
|
||||
// super.onStop()
|
||||
// unbindService()
|
||||
// }
|
||||
|
||||
// private fun bindService() {
|
||||
// serviceIntent?.run {
|
||||
// if (videoStreamService != null && !videoStreamService!!.serviceRunning){
|
||||
// startService(this)
|
||||
// }
|
||||
// bindService(this, serviceConnection, Context.BIND_AUTO_CREATE)
|
||||
// videoStreamService?.serviceRunning = true
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun unbindService() {
|
||||
// if (bound) {
|
||||
// videoStreamService!!.videoCallResponseListener = null // unregister
|
||||
// videoStreamService!!.mActivity = null
|
||||
// unbindService(serviceConnection)
|
||||
// bound = false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private val serviceConnection: ServiceConnection = object : ServiceConnection {
|
||||
// override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
// val binder: VideoStreamContainerService.VideoStreamBinder =
|
||||
// service as VideoStreamContainerService.VideoStreamBinder
|
||||
// videoStreamService = binder.service
|
||||
// bound = true
|
||||
// videoStreamService!!.videoCallResponseListener = this@MainActivity // register
|
||||
// videoStreamService!!.mActivity = this@MainActivity // register
|
||||
// }
|
||||
//
|
||||
// override fun onServiceDisconnected(name: ComponentName?) {
|
||||
// bound = false
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
// code to hide soft keyboard
|
||||
fun hideSoftKeyBoard(editBox: EditText?) {
|
||||
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(editBox?.windowToken, 0)
|
||||
}
|
||||
|
||||
|
||||
// code to show soft keyboard
|
||||
private fun showSoftKeyBoard(editBox: EditText?) {
|
||||
val inputMethodManager = this.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editBox?.requestFocus()
|
||||
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,137 @@
|
||||
package com.hmg.hmgDr.Model;
|
||||
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class ChangeCallStatusRequestModel implements Parcelable {
|
||||
|
||||
@SerializedName("CallStatus")
|
||||
@Expose
|
||||
private Integer callStatus;
|
||||
@SerializedName("DoctorId")
|
||||
@Expose
|
||||
private Integer doctorId;
|
||||
@SerializedName("generalid")
|
||||
@Expose
|
||||
private String generalid;
|
||||
@SerializedName("TokenID")
|
||||
@Expose
|
||||
private String tokenID;
|
||||
@SerializedName("VC_ID")
|
||||
@Expose
|
||||
private Integer vcId;
|
||||
|
||||
public ChangeCallStatusRequestModel(Integer callStatus, Integer doctorId, String generalid, String tokenID, Integer vcId) {
|
||||
this.callStatus = callStatus;
|
||||
this.doctorId = doctorId;
|
||||
this.generalid = generalid;
|
||||
this.tokenID = tokenID;
|
||||
this.vcId = vcId;
|
||||
}
|
||||
|
||||
protected ChangeCallStatusRequestModel(Parcel in) {
|
||||
if (in.readByte() == 0) {
|
||||
callStatus = null;
|
||||
} else {
|
||||
callStatus = in.readInt();
|
||||
}
|
||||
if (in.readByte() == 0) {
|
||||
doctorId = null;
|
||||
} else {
|
||||
doctorId = in.readInt();
|
||||
}
|
||||
generalid = in.readString();
|
||||
tokenID = in.readString();
|
||||
if (in.readByte() == 0) {
|
||||
vcId = null;
|
||||
} else {
|
||||
vcId = in.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator<ChangeCallStatusRequestModel> CREATOR = new Creator<ChangeCallStatusRequestModel>() {
|
||||
@Override
|
||||
public ChangeCallStatusRequestModel createFromParcel(Parcel in) {
|
||||
return new ChangeCallStatusRequestModel(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChangeCallStatusRequestModel[] newArray(int size) {
|
||||
return new ChangeCallStatusRequestModel[size];
|
||||
}
|
||||
};
|
||||
|
||||
public Integer getCallStatus() {
|
||||
return callStatus;
|
||||
}
|
||||
|
||||
public void setCallStatus(Integer callStatus) {
|
||||
this.callStatus = callStatus;
|
||||
}
|
||||
|
||||
public Integer getDoctorId() {
|
||||
return doctorId;
|
||||
}
|
||||
|
||||
public void setDoctorId(Integer doctorId) {
|
||||
this.doctorId = doctorId;
|
||||
}
|
||||
|
||||
public String getGeneralid() {
|
||||
return generalid;
|
||||
}
|
||||
|
||||
public void setGeneralid(String generalid) {
|
||||
this.generalid = generalid;
|
||||
}
|
||||
|
||||
public String getTokenID() {
|
||||
return tokenID;
|
||||
}
|
||||
|
||||
public void setTokenID(String tokenID) {
|
||||
this.tokenID = tokenID;
|
||||
}
|
||||
|
||||
public Integer getVcId() {
|
||||
return vcId;
|
||||
}
|
||||
|
||||
public void setVcId(Integer vcId) {
|
||||
this.vcId = vcId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
if (callStatus == null) {
|
||||
dest.writeByte((byte) 0);
|
||||
} else {
|
||||
dest.writeByte((byte) 1);
|
||||
dest.writeInt(callStatus);
|
||||
}
|
||||
if (doctorId == null) {
|
||||
dest.writeByte((byte) 0);
|
||||
} else {
|
||||
dest.writeByte((byte) 1);
|
||||
dest.writeInt(doctorId);
|
||||
}
|
||||
dest.writeString(generalid);
|
||||
dest.writeString(tokenID);
|
||||
if (vcId == null) {
|
||||
dest.writeByte((byte) 0);
|
||||
} else {
|
||||
dest.writeByte((byte) 1);
|
||||
dest.writeInt(vcId);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.example.doctor_app_flutter.Model;
|
||||
package com.hmg.hmgDr.Model;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
@ -1,4 +1,4 @@
|
||||
package com.example.doctor_app_flutter.Service;
|
||||
package com.hmg.hmgDr.Service;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
@ -0,0 +1,19 @@
|
||||
package com.hmg.hmgDr.Service;
|
||||
|
||||
import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel;
|
||||
import com.hmg.hmgDr.Model.GetSessionStatusModel;
|
||||
import com.hmg.hmgDr.Model.SessionStatusModel;
|
||||
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface SessionStatusAPI {
|
||||
|
||||
@POST("LiveCareApi/DoctorApp/GetSessionStatus")
|
||||
Call<SessionStatusModel> getSessionStatusModelData(@Body GetSessionStatusModel getSessionStatusModel);
|
||||
|
||||
@POST("LiveCareApi/DoctorApp/ChangeCallStatus")
|
||||
Call<SessionStatusModel> changeCallStatus(@Body ChangeCallStatusRequestModel changeCallStatusRequestModel);
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.hmg.hmgDr.Service
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.Binder
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import com.hmg.hmgDr.MainActivity
|
||||
import com.hmg.hmgDr.ui.VideoCallResponseListener
|
||||
import com.hmg.hmgDr.ui.fragment.VideoCallFragment
|
||||
|
||||
class VideoStreamContainerService : Service(), VideoCallResponseListener {
|
||||
|
||||
var videoCallResponseListener: VideoCallResponseListener? = null
|
||||
var mActivity: MainActivity? = null
|
||||
set(value) {
|
||||
field = value
|
||||
if (field != null) {
|
||||
setDialogFragment()
|
||||
}
|
||||
}
|
||||
var arguments: Bundle? = null
|
||||
var serviceRunning: Boolean = false
|
||||
|
||||
|
||||
private val serviceBinder: IBinder = VideoStreamBinder()
|
||||
private var dialogFragment: VideoCallFragment? = null
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder {
|
||||
return serviceBinder
|
||||
}
|
||||
|
||||
private fun setDialogFragment() {
|
||||
mActivity?.run {
|
||||
if (dialogFragment == null) {
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
dialogFragment = VideoCallFragment.newInstance(arguments!!)
|
||||
dialogFragment?.let {
|
||||
it.setCallListener(this@VideoStreamContainerService)
|
||||
it.isCancelable = true
|
||||
if (it.isAdded) {
|
||||
it.dismiss()
|
||||
} else {
|
||||
it.show(transaction, "dialog")
|
||||
}
|
||||
}
|
||||
} else if (!dialogFragment!!.isVisible) {
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
dialogFragment!!.show(transaction, "dialog")
|
||||
} else {
|
||||
// don't do anything
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun closeVideoCall(){
|
||||
dialogFragment?.onCallClicked()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (intent != null && intent.extras != null) {
|
||||
arguments = intent.extras
|
||||
}
|
||||
// Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show()
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
// Toast.makeText(this, "Service destroyed by user.", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
inner class VideoStreamBinder : Binder() {
|
||||
val service: VideoStreamContainerService
|
||||
get() = this@VideoStreamContainerService
|
||||
}
|
||||
|
||||
override fun onCallFinished(resultCode: Int, intent: Intent?) {
|
||||
dialogFragment = null
|
||||
videoCallResponseListener?.onCallFinished(resultCode, intent)
|
||||
}
|
||||
|
||||
override fun errorHandle(message: String) {
|
||||
dialogFragment = null
|
||||
// Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun minimizeVideoEvent(isMinimize: Boolean) {
|
||||
videoCallResponseListener?.minimizeVideoEvent(isMinimize)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.hmg.hmgDr.ui;
|
||||
|
||||
import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel;
|
||||
import com.hmg.hmgDr.Model.GetSessionStatusModel;
|
||||
import com.hmg.hmgDr.Model.SessionStatusModel;
|
||||
|
||||
public interface VideoCallContract {
|
||||
|
||||
interface VideoCallView {
|
||||
|
||||
void onCallSuccessful(SessionStatusModel sessionStatusModel);
|
||||
|
||||
void onCallChangeCallStatusSuccessful(SessionStatusModel sessionStatusModel);
|
||||
|
||||
void onFailure();
|
||||
|
||||
}
|
||||
|
||||
interface VideoCallPresenter {
|
||||
|
||||
void callClintConnected(GetSessionStatusModel statusModel);
|
||||
|
||||
void callChangeCallStatus(ChangeCallStatusRequestModel statusModel);
|
||||
}
|
||||
}
|
@ -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,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
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.hmg.hmgDr.util
|
||||
|
||||
import android.content.Context
|
||||
import android.util.DisplayMetrics
|
||||
|
||||
object ViewsUtil {
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @return the Screen height in DP
|
||||
*/
|
||||
fun getHeightDp(context: Context, isInDp: Boolean = false): Float {
|
||||
val displayMetrics: DisplayMetrics = context.resources.displayMetrics
|
||||
return if (isInDp) {
|
||||
displayMetrics.heightPixels / displayMetrics.density
|
||||
} else {
|
||||
displayMetrics.heightPixels.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @return the screnn width in dp
|
||||
*/
|
||||
fun getWidthDp(context: Context, isInDp: Boolean = false): Float {
|
||||
val displayMetrics: DisplayMetrics = context.resources.displayMetrics
|
||||
return if (isInDp) {
|
||||
displayMetrics.widthPixels / displayMetrics.density
|
||||
} else {
|
||||
displayMetrics.widthPixels.toFloat()
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 6.3 KiB |
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>
|
After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 6.0 KiB |
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>
|
After Width: | Height: | Size: 16 KiB |
@ -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>
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.8 KiB |
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>
|
After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.6 KiB |
@ -1,325 +0,0 @@
|
||||
PODS:
|
||||
- Alamofire (4.9.1)
|
||||
- barcode_scan (0.0.1):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- SwiftProtobuf
|
||||
- connectivity (0.0.1):
|
||||
- Flutter
|
||||
- Reachability
|
||||
- connectivity_for_web (0.1.0):
|
||||
- Flutter
|
||||
- connectivity_macos (0.0.1):
|
||||
- Flutter
|
||||
- device_info (0.0.1):
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (6.33.0):
|
||||
- FirebaseCore (= 6.10.3)
|
||||
- Firebase/Messaging (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 4.7.0)
|
||||
- firebase_core (0.5.3):
|
||||
- Firebase/CoreOnly (~> 6.33.0)
|
||||
- Flutter
|
||||
- firebase_core_web (0.1.0):
|
||||
- Flutter
|
||||
- firebase_messaging (7.0.3):
|
||||
- Firebase/CoreOnly (~> 6.33.0)
|
||||
- Firebase/Messaging (~> 6.33.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseCore (6.10.3):
|
||||
- FirebaseCoreDiagnostics (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- FirebaseCoreDiagnostics (1.7.0):
|
||||
- GoogleDataTransport (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseInstallations (1.7.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseInstanceID (4.8.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- FirebaseMessaging (4.7.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstanceID (~> 4.7)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Reachability (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- Protobuf (>= 3.9.2, ~> 3.9)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_flexible_toast (0.0.1):
|
||||
- Flutter
|
||||
- flutter_plugin_android_lifecycle (0.0.1):
|
||||
- Flutter
|
||||
- GoogleDataTransport (7.5.1):
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (6.7.2):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Network (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (6.7.2)"
|
||||
- GoogleUtilities/Reachability (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- hexcolor (0.0.1):
|
||||
- Flutter
|
||||
- imei_plugin (0.0.1):
|
||||
- Flutter
|
||||
- local_auth (0.0.1):
|
||||
- Flutter
|
||||
- maps_launcher (0.0.1):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner (5.0.11)
|
||||
- nanopb (1.30906.0):
|
||||
- nanopb/decode (= 1.30906.0)
|
||||
- nanopb/encode (= 1.30906.0)
|
||||
- nanopb/decode (1.30906.0)
|
||||
- nanopb/encode (1.30906.0)
|
||||
- OpenTok (2.15.3)
|
||||
- path_provider_linux (0.0.1):
|
||||
- Flutter
|
||||
- path_provider_windows (0.0.1):
|
||||
- Flutter
|
||||
- "permission_handler (5.1.0+2)":
|
||||
- Flutter
|
||||
- PromisesObjC (1.2.11)
|
||||
- Protobuf (3.13.0)
|
||||
- Reachability (3.2)
|
||||
- screen (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_linux (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_macos (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_web (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_windows (0.0.1):
|
||||
- Flutter
|
||||
- speech_to_text (0.0.1):
|
||||
- Flutter
|
||||
- Try
|
||||
- SwiftProtobuf (1.9.0)
|
||||
- Try (2.1.1)
|
||||
- url_launcher (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher_linux (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher_macos (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher_web (0.0.1):
|
||||
- Flutter
|
||||
- url_launcher_windows (0.0.1):
|
||||
- Flutter
|
||||
- video_player (0.0.1):
|
||||
- Flutter
|
||||
- video_player_web (0.0.1):
|
||||
- Flutter
|
||||
- wakelock (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- Alamofire
|
||||
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
|
||||
- connectivity (from `.symlinks/plugins/connectivity/ios`)
|
||||
- connectivity_for_web (from `.symlinks/plugins/connectivity_for_web/ios`)
|
||||
- connectivity_macos (from `.symlinks/plugins/connectivity_macos/ios`)
|
||||
- device_info (from `.symlinks/plugins/device_info/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_core_web (from `.symlinks/plugins/firebase_core_web/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_flexible_toast (from `.symlinks/plugins/flutter_flexible_toast/ios`)
|
||||
- flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`)
|
||||
- hexcolor (from `.symlinks/plugins/hexcolor/ios`)
|
||||
- imei_plugin (from `.symlinks/plugins/imei_plugin/ios`)
|
||||
- local_auth (from `.symlinks/plugins/local_auth/ios`)
|
||||
- maps_launcher (from `.symlinks/plugins/maps_launcher/ios`)
|
||||
- OpenTok
|
||||
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
|
||||
- path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`)
|
||||
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
|
||||
- screen (from `.symlinks/plugins/screen/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`)
|
||||
- shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
|
||||
- shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`)
|
||||
- shared_preferences_windows (from `.symlinks/plugins/shared_preferences_windows/ios`)
|
||||
- speech_to_text (from `.symlinks/plugins/speech_to_text/ios`)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`)
|
||||
- url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`)
|
||||
- url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`)
|
||||
- url_launcher_windows (from `.symlinks/plugins/url_launcher_windows/ios`)
|
||||
- video_player (from `.symlinks/plugins/video_player/ios`)
|
||||
- video_player_web (from `.symlinks/plugins/video_player_web/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Alamofire
|
||||
- Firebase
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseInstallations
|
||||
- FirebaseInstanceID
|
||||
- FirebaseMessaging
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- MTBBarcodeScanner
|
||||
- nanopb
|
||||
- OpenTok
|
||||
- PromisesObjC
|
||||
- Protobuf
|
||||
- Reachability
|
||||
- SwiftProtobuf
|
||||
- Try
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
barcode_scan:
|
||||
:path: ".symlinks/plugins/barcode_scan/ios"
|
||||
connectivity:
|
||||
:path: ".symlinks/plugins/connectivity/ios"
|
||||
connectivity_for_web:
|
||||
:path: ".symlinks/plugins/connectivity_for_web/ios"
|
||||
connectivity_macos:
|
||||
:path: ".symlinks/plugins/connectivity_macos/ios"
|
||||
device_info:
|
||||
:path: ".symlinks/plugins/device_info/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
firebase_core_web:
|
||||
:path: ".symlinks/plugins/firebase_core_web/ios"
|
||||
firebase_messaging:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_flexible_toast:
|
||||
:path: ".symlinks/plugins/flutter_flexible_toast/ios"
|
||||
flutter_plugin_android_lifecycle:
|
||||
:path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios"
|
||||
hexcolor:
|
||||
:path: ".symlinks/plugins/hexcolor/ios"
|
||||
imei_plugin:
|
||||
:path: ".symlinks/plugins/imei_plugin/ios"
|
||||
local_auth:
|
||||
:path: ".symlinks/plugins/local_auth/ios"
|
||||
maps_launcher:
|
||||
:path: ".symlinks/plugins/maps_launcher/ios"
|
||||
path_provider_linux:
|
||||
:path: ".symlinks/plugins/path_provider_linux/ios"
|
||||
path_provider_windows:
|
||||
:path: ".symlinks/plugins/path_provider_windows/ios"
|
||||
permission_handler:
|
||||
:path: ".symlinks/plugins/permission_handler/ios"
|
||||
screen:
|
||||
:path: ".symlinks/plugins/screen/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
shared_preferences_linux:
|
||||
:path: ".symlinks/plugins/shared_preferences_linux/ios"
|
||||
shared_preferences_macos:
|
||||
:path: ".symlinks/plugins/shared_preferences_macos/ios"
|
||||
shared_preferences_web:
|
||||
:path: ".symlinks/plugins/shared_preferences_web/ios"
|
||||
shared_preferences_windows:
|
||||
:path: ".symlinks/plugins/shared_preferences_windows/ios"
|
||||
speech_to_text:
|
||||
:path: ".symlinks/plugins/speech_to_text/ios"
|
||||
url_launcher:
|
||||
:path: ".symlinks/plugins/url_launcher/ios"
|
||||
url_launcher_linux:
|
||||
:path: ".symlinks/plugins/url_launcher_linux/ios"
|
||||
url_launcher_macos:
|
||||
:path: ".symlinks/plugins/url_launcher_macos/ios"
|
||||
url_launcher_web:
|
||||
:path: ".symlinks/plugins/url_launcher_web/ios"
|
||||
url_launcher_windows:
|
||||
:path: ".symlinks/plugins/url_launcher_windows/ios"
|
||||
video_player:
|
||||
:path: ".symlinks/plugins/video_player/ios"
|
||||
video_player_web:
|
||||
:path: ".symlinks/plugins/video_player_web/ios"
|
||||
wakelock:
|
||||
:path: ".symlinks/plugins/wakelock/ios"
|
||||
webview_flutter:
|
||||
:path: ".symlinks/plugins/webview_flutter/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 85e8a02c69d6020a0d734f6054870d7ecb75cf18
|
||||
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
|
||||
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
|
||||
connectivity_for_web: 2b8584556930d4bd490d82b836bcf45067ce345b
|
||||
connectivity_macos: e2e9731b6b22dda39eb1b128f6969d574460e191
|
||||
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
|
||||
firebase_core_web: d501d8b946b60c8af265428ce483b0fff5ad52d1
|
||||
firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
|
||||
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
|
||||
FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1
|
||||
FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a
|
||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||
flutter_flexible_toast: 0547e740cae0c33bb7c51bcd931233f4584e1143
|
||||
flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35
|
||||
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
|
||||
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
|
||||
hexcolor: fdfb9c4258ad96e949c2dbcdf790a62194b8aa89
|
||||
imei_plugin: cb1af7c223ac2d82dcd1457a7137d93d65d2a3cd
|
||||
local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd
|
||||
maps_launcher: eae38ee13a9c3f210fa04e04bb4c073fa4c6ed92
|
||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
OpenTok: fde03ecc5ea31fe0a453242847c4ee1f47e1d735
|
||||
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
|
||||
path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b
|
||||
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
|
||||
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
|
||||
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
screen: abd91ca7bf3426e1cc3646d27e9b2358d6bf07b0
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78
|
||||
shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
|
||||
shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9
|
||||
shared_preferences_windows: 36b76d6f54e76ead957e60b49e2f124b4cd3e6ae
|
||||
speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe
|
||||
SwiftProtobuf: ecbec1be9036d15655f6b3443a1c4ea693c97932
|
||||
Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0
|
||||
url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
|
||||
url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
|
||||
url_launcher_windows: 683d7c283894db8d1914d3ab2223b20cc1ad95d5
|
||||
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
|
||||
video_player_web: da8cadb8274ed4f8dbee8d7171b420dedd437ce7
|
||||
wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4
|
||||
webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96
|
||||
|
||||
PODFILE CHECKSUM: 649616dc336b3659ac6b2b25159d8e488e042b69
|
||||
|
||||
COCOAPODS: 1.10.1
|
@ -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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
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
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
enum PatientType{
|
||||
IN_PATIENT,
|
||||
OUT_PATIENT,
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
enum AuthMethodTypes { SMS, WhatsApp, Fingerprint,FaceID,MoreOptions }
|
||||
extension SelectedAuthMethodTypesService on AuthMethodTypes {
|
||||
// ignore: missing_return
|
||||
int getTypeIdService() {
|
||||
switch (this) {
|
||||
case AuthMethodTypes.SMS:
|
||||
return 1;
|
||||
break;
|
||||
case AuthMethodTypes.WhatsApp:
|
||||
return 2;
|
||||
break;
|
||||
case AuthMethodTypes.Fingerprint:
|
||||
return 3;
|
||||
break;
|
||||
case AuthMethodTypes.FaceID:
|
||||
return 4;
|
||||
break;
|
||||
case AuthMethodTypes.MoreOptions:
|
||||
return 5;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: missing_return
|
||||
static getMethodsTypeService( int typeId) {
|
||||
switch (typeId) {
|
||||
case 1:
|
||||
return AuthMethodTypes.SMS;
|
||||
break;
|
||||
case 2:
|
||||
return AuthMethodTypes.WhatsApp;
|
||||
break;
|
||||
case 3:
|
||||
return AuthMethodTypes.Fingerprint;
|
||||
break;
|
||||
case 4:
|
||||
return AuthMethodTypes.FaceID;
|
||||
break;
|
||||
case 5:
|
||||
return AuthMethodTypes.MoreOptions;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart';
|
||||
|
||||
class CheckActivationCodeForDoctorAppResponseModel {
|
||||
String authenticationTokenID;
|
||||
List<ListDoctorsClinic> listDoctorsClinic;
|
||||
List<DoctorProfileModel> listDoctorProfile;
|
||||
MemberInformation memberInformation;
|
||||
String vidaAuthTokenID;
|
||||
String vidaRefreshTokenID;
|
||||
|
||||
CheckActivationCodeForDoctorAppResponseModel(
|
||||
{this.authenticationTokenID,
|
||||
this.listDoctorsClinic,
|
||||
this.memberInformation,
|
||||
this.listDoctorProfile,
|
||||
this.vidaAuthTokenID,
|
||||
this.vidaRefreshTokenID});
|
||||
|
||||
CheckActivationCodeForDoctorAppResponseModel.fromJson(
|
||||
Map<String, dynamic> json) {
|
||||
authenticationTokenID = json['AuthenticationTokenID'];
|
||||
if (json['List_DoctorsClinic'] != null) {
|
||||
listDoctorsClinic = new List<ListDoctorsClinic>();
|
||||
json['List_DoctorsClinic'].forEach((v) {
|
||||
listDoctorsClinic.add(new ListDoctorsClinic.fromJson(v));
|
||||
});
|
||||
}
|
||||
|
||||
if (json['List_DoctorProfile'] != null) {
|
||||
listDoctorProfile = new List<DoctorProfileModel>();
|
||||
json['List_DoctorProfile'].forEach((v) {
|
||||
listDoctorProfile.add(new DoctorProfileModel.fromJson(v));
|
||||
});
|
||||
}
|
||||
vidaAuthTokenID = json['VidaAuthTokenID'];
|
||||
vidaRefreshTokenID = json['VidaRefreshTokenID'];
|
||||
|
||||
memberInformation = json['memberInformation'] != null
|
||||
? new MemberInformation.fromJson(json['memberInformation'])
|
||||
: null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['AuthenticationTokenID'] = this.authenticationTokenID;
|
||||
if (this.listDoctorsClinic != null) {
|
||||
data['List_DoctorsClinic'] =
|
||||
this.listDoctorsClinic.map((v) => v.toJson()).toList();
|
||||
}
|
||||
|
||||
if (this.listDoctorProfile != null) {
|
||||
data['List_DoctorProfile'] =
|
||||
this.listDoctorProfile.map((v) => v.toJson()).toList();
|
||||
}
|
||||
if (this.memberInformation != null) {
|
||||
data['memberInformation'] = this.memberInformation.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class ListDoctorsClinic {
|
||||
Null setupID;
|
||||
int projectID;
|
||||
int doctorID;
|
||||
int clinicID;
|
||||
bool isActive;
|
||||
String clinicName;
|
||||
|
||||
ListDoctorsClinic(
|
||||
{this.setupID,
|
||||
this.projectID,
|
||||
this.doctorID,
|
||||
this.clinicID,
|
||||
this.isActive,
|
||||
this.clinicName});
|
||||
|
||||
ListDoctorsClinic.fromJson(Map<String, dynamic> json) {
|
||||
setupID = json['SetupID'];
|
||||
projectID = json['ProjectID'];
|
||||
doctorID = json['DoctorID'];
|
||||
clinicID = json['ClinicID'];
|
||||
isActive = json['IsActive'];
|
||||
clinicName = json['ClinicName'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['SetupID'] = this.setupID;
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['ClinicID'] = this.clinicID;
|
||||
data['IsActive'] = this.isActive;
|
||||
data['ClinicName'] = this.clinicName;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class MemberInformation {
|
||||
List<Clinics> clinics;
|
||||
int doctorId;
|
||||
String email;
|
||||
int employeeId;
|
||||
int memberId;
|
||||
Null memberName;
|
||||
Null memberNameArabic;
|
||||
String preferredLanguage;
|
||||
List<Roles> roles;
|
||||
|
||||
MemberInformation(
|
||||
{this.clinics,
|
||||
this.doctorId,
|
||||
this.email,
|
||||
this.employeeId,
|
||||
this.memberId,
|
||||
this.memberName,
|
||||
this.memberNameArabic,
|
||||
this.preferredLanguage,
|
||||
this.roles});
|
||||
|
||||
MemberInformation.fromJson(Map<String, dynamic> json) {
|
||||
if (json['clinics'] != null) {
|
||||
clinics = new List<Clinics>();
|
||||
json['clinics'].forEach((v) {
|
||||
clinics.add(new Clinics.fromJson(v));
|
||||
});
|
||||
}
|
||||
doctorId = json['doctorId'];
|
||||
email = json['email'];
|
||||
employeeId = json['employeeId'];
|
||||
memberId = json['memberId'];
|
||||
memberName = json['memberName'];
|
||||
memberNameArabic = json['memberNameArabic'];
|
||||
preferredLanguage = json['preferredLanguage'];
|
||||
if (json['roles'] != null) {
|
||||
roles = new List<Roles>();
|
||||
json['roles'].forEach((v) {
|
||||
roles.add(new Roles.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
if (this.clinics != null) {
|
||||
data['clinics'] = this.clinics.map((v) => v.toJson()).toList();
|
||||
}
|
||||
data['doctorId'] = this.doctorId;
|
||||
data['email'] = this.email;
|
||||
data['employeeId'] = this.employeeId;
|
||||
data['memberId'] = this.memberId;
|
||||
data['memberName'] = this.memberName;
|
||||
data['memberNameArabic'] = this.memberNameArabic;
|
||||
data['preferredLanguage'] = this.preferredLanguage;
|
||||
if (this.roles != null) {
|
||||
data['roles'] = this.roles.map((v) => v.toJson()).toList();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Clinics {
|
||||
bool defaultClinic;
|
||||
int id;
|
||||
String name;
|
||||
|
||||
Clinics({this.defaultClinic, this.id, this.name});
|
||||
|
||||
Clinics.fromJson(Map<String, dynamic> json) {
|
||||
defaultClinic = json['defaultClinic'];
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['defaultClinic'] = this.defaultClinic;
|
||||
data['id'] = this.id;
|
||||
data['name'] = this.name;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Roles {
|
||||
String name;
|
||||
int roleId;
|
||||
|
||||
Roles({this.name, this.roleId});
|
||||
|
||||
Roles.fromJson(Map<String, dynamic> json) {
|
||||
name = json['name'];
|
||||
roleId = json['roleId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['name'] = this.name;
|
||||
data['roleId'] = this.roleId;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
class NewLoginInformationModel {
|
||||
int doctorID;
|
||||
List<ListMemberInformation> listMemberInformation;
|
||||
String logInTokenID;
|
||||
String mobileNumber;
|
||||
Null sELECTDeviceIMEIbyIMEIList;
|
||||
int userID;
|
||||
String zipCode;
|
||||
bool isActiveCode;
|
||||
bool isSMSSent;
|
||||
|
||||
NewLoginInformationModel(
|
||||
{this.doctorID,
|
||||
this.listMemberInformation,
|
||||
this.logInTokenID,
|
||||
this.mobileNumber,
|
||||
this.sELECTDeviceIMEIbyIMEIList,
|
||||
this.userID,
|
||||
this.zipCode,
|
||||
this.isActiveCode,
|
||||
this.isSMSSent});
|
||||
|
||||
NewLoginInformationModel.fromJson(Map<String, dynamic> json) {
|
||||
doctorID = json['DoctorID'];
|
||||
if (json['List_MemberInformation'] != null) {
|
||||
listMemberInformation = new List<ListMemberInformation>();
|
||||
json['List_MemberInformation'].forEach((v) {
|
||||
listMemberInformation.add(new ListMemberInformation.fromJson(v));
|
||||
});
|
||||
}
|
||||
logInTokenID = json['LogInTokenID'];
|
||||
mobileNumber = json['MobileNumber'];
|
||||
sELECTDeviceIMEIbyIMEIList = json['SELECTDeviceIMEIbyIMEI_List'];
|
||||
userID = json['UserID'];
|
||||
zipCode = json['ZipCode'];
|
||||
isActiveCode = json['isActiveCode'];
|
||||
isSMSSent = json['isSMSSent'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['DoctorID'] = this.doctorID;
|
||||
if (this.listMemberInformation != null) {
|
||||
data['List_MemberInformation'] =
|
||||
this.listMemberInformation.map((v) => v.toJson()).toList();
|
||||
}
|
||||
data['LogInTokenID'] = this.logInTokenID;
|
||||
data['MobileNumber'] = this.mobileNumber;
|
||||
data['SELECTDeviceIMEIbyIMEI_List'] = this.sELECTDeviceIMEIbyIMEIList;
|
||||
data['UserID'] = this.userID;
|
||||
data['ZipCode'] = this.zipCode;
|
||||
data['isActiveCode'] = this.isActiveCode;
|
||||
data['isSMSSent'] = this.isSMSSent;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class ListMemberInformation {
|
||||
Null setupID;
|
||||
int memberID;
|
||||
String memberName;
|
||||
Null memberNameN;
|
||||
String preferredLang;
|
||||
String pIN;
|
||||
String saltHash;
|
||||
int referenceID;
|
||||
int employeeID;
|
||||
int roleID;
|
||||
int projectid;
|
||||
|
||||
ListMemberInformation(
|
||||
{this.setupID,
|
||||
this.memberID,
|
||||
this.memberName,
|
||||
this.memberNameN,
|
||||
this.preferredLang,
|
||||
this.pIN,
|
||||
this.saltHash,
|
||||
this.referenceID,
|
||||
this.employeeID,
|
||||
this.roleID,
|
||||
this.projectid});
|
||||
|
||||
ListMemberInformation.fromJson(Map<String, dynamic> json) {
|
||||
setupID = json['SetupID'];
|
||||
memberID = json['MemberID'];
|
||||
memberName = json['MemberName'];
|
||||
memberNameN = json['MemberNameN'];
|
||||
preferredLang = json['PreferredLang'];
|
||||
pIN = json['PIN'];
|
||||
saltHash = json['SaltHash'];
|
||||
referenceID = json['ReferenceID'];
|
||||
employeeID = json['EmployeeID'];
|
||||
roleID = json['RoleID'];
|
||||
projectid = json['projectid'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['SetupID'] = this.setupID;
|
||||
data['MemberID'] = this.memberID;
|
||||
data['MemberName'] = this.memberName;
|
||||
data['MemberNameN'] = this.memberNameN;
|
||||
data['PreferredLang'] = this.preferredLang;
|
||||
data['PIN'] = this.pIN;
|
||||
data['SaltHash'] = this.saltHash;
|
||||
data['ReferenceID'] = this.referenceID;
|
||||
data['EmployeeID'] = this.employeeID;
|
||||
data['RoleID'] = this.roleID;
|
||||
data['projectid'] = this.projectid;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
class SendActivationCodeForDoctorAppResponseModel {
|
||||
String logInTokenID;
|
||||
String verificationCode;
|
||||
String vidaAuthTokenID;
|
||||
String vidaRefreshTokenID;
|
||||
|
||||
SendActivationCodeForDoctorAppResponseModel(
|
||||
{this.logInTokenID,
|
||||
this.verificationCode,
|
||||
this.vidaAuthTokenID,
|
||||
this.vidaRefreshTokenID});
|
||||
|
||||
SendActivationCodeForDoctorAppResponseModel.fromJson(
|
||||
Map<String, dynamic> json) {
|
||||
logInTokenID = json['LogInTokenID'];
|
||||
verificationCode = json['VerificationCode'];
|
||||
vidaAuthTokenID = json['VidaAuthTokenID'];
|
||||
vidaRefreshTokenID = json['VidaRefreshTokenID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['LogInTokenID'] = this.logInTokenID;
|
||||
data['VerificationCode'] = this.verificationCode;
|
||||
data['VidaAuthTokenID'] = this.vidaAuthTokenID;
|
||||
data['VidaRefreshTokenID'] = this.vidaRefreshTokenID;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
class GetHospitalsRequestModel {
|
||||
int languageID;
|
||||
String stamp;
|
||||
String iPAdress;
|
||||
double versionID;
|
||||
int channel;
|
||||
String tokenID;
|
||||
String sessionID;
|
||||
bool isLoginForDoctorApp;
|
||||
String memberID;
|
||||
|
||||
GetHospitalsRequestModel(
|
||||
{this.languageID,
|
||||
this.stamp,
|
||||
this.iPAdress,
|
||||
this.versionID,
|
||||
this.channel,
|
||||
this.tokenID,
|
||||
this.sessionID,
|
||||
this.isLoginForDoctorApp,
|
||||
this.memberID});
|
||||
|
||||
GetHospitalsRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
languageID = json['LanguageID'];
|
||||
stamp = json['stamp'];
|
||||
iPAdress = json['IPAdress'];
|
||||
versionID = json['VersionID'];
|
||||
channel = json['Channel'];
|
||||
tokenID = json['TokenID'];
|
||||
sessionID = json['SessionID'];
|
||||
isLoginForDoctorApp = json['IsLoginForDoctorApp'];
|
||||
memberID = json['MemberID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['LanguageID'] = this.languageID;
|
||||
data['stamp'] = this.stamp;
|
||||
data['IPAdress'] = this.iPAdress;
|
||||
data['VersionID'] = this.versionID;
|
||||
data['Channel'] = this.channel;
|
||||
data['TokenID'] = this.tokenID;
|
||||
data['SessionID'] = this.sessionID;
|
||||
data['IsLoginForDoctorApp'] = this.isLoginForDoctorApp;
|
||||
data['MemberID'] = this.memberID;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
class GetHospitalsResponseModel {
|
||||
String facilityGroupId;
|
||||
int facilityId;
|
||||
String facilityName;
|
||||
|
||||
GetHospitalsResponseModel(
|
||||
{this.facilityGroupId, this.facilityId, this.facilityName});
|
||||
|
||||
GetHospitalsResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
facilityGroupId = json['facilityGroupId'];
|
||||
facilityId = json['facilityId'];
|
||||
facilityName = json['facilityName'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['facilityGroupId'] = this.facilityGroupId;
|
||||
data['facilityId'] = this.facilityId;
|
||||
data['facilityName'] = this.facilityName;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -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,22 @@
|
||||
class PendingPatientERForDoctorAppRequestModel {
|
||||
bool outSA;
|
||||
int doctorID;
|
||||
String sErServiceID;
|
||||
|
||||
PendingPatientERForDoctorAppRequestModel(
|
||||
{this.outSA, this.doctorID, this.sErServiceID});
|
||||
|
||||
PendingPatientERForDoctorAppRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
outSA = json['OutSA'];
|
||||
doctorID = json['DoctorID'];
|
||||
sErServiceID = json['SErServiceID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['OutSA'] = this.outSA;
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['SErServiceID'] = this.sErServiceID;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
class AddPatientToDoctorListRequestModel {
|
||||
int vCID;
|
||||
String tokenID;
|
||||
String generalid;
|
||||
int doctorId;
|
||||
bool isOutKsa;
|
||||
|
||||
AddPatientToDoctorListRequestModel({this.vCID, this.tokenID, this.generalid, this.doctorId, this.isOutKsa});
|
||||
|
||||
AddPatientToDoctorListRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
vCID = json['VC_ID'];
|
||||
tokenID = json['TokenID'];
|
||||
generalid = json['generalid'];
|
||||
doctorId = json['DoctorId'];
|
||||
isOutKsa = json['IsOutKsa'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['VC_ID'] = this.vCID;
|
||||
data['TokenID'] = this.tokenID;
|
||||
data['generalid'] = this.generalid;
|
||||
data['DoctorId'] = this.doctorId;
|
||||
data['IsOutKsa'] = this.isOutKsa;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
class ProcedureTempleteRequestModel {
|
||||
int doctorID;
|
||||
String firstName;
|
||||
String middleName;
|
||||
String lastName;
|
||||
String patientMobileNumber;
|
||||
String patientIdentificationID;
|
||||
int patientID;
|
||||
String from;
|
||||
String to;
|
||||
int searchType;
|
||||
String mobileNo;
|
||||
String identificationNo;
|
||||
int editedBy;
|
||||
int projectID;
|
||||
int clinicID;
|
||||
String tokenID;
|
||||
int languageID;
|
||||
String stamp;
|
||||
String iPAdress;
|
||||
double versionID;
|
||||
int channel;
|
||||
String sessionID;
|
||||
bool isLoginForDoctorApp;
|
||||
bool patientOutSA;
|
||||
String vidaAuthTokenID;
|
||||
String vidaRefreshTokenID;
|
||||
int deviceTypeID;
|
||||
|
||||
ProcedureTempleteRequestModel(
|
||||
{this.doctorID,
|
||||
this.firstName,
|
||||
this.middleName,
|
||||
this.lastName,
|
||||
this.patientMobileNumber,
|
||||
this.patientIdentificationID,
|
||||
this.patientID,
|
||||
this.from,
|
||||
this.to,
|
||||
this.searchType,
|
||||
this.mobileNo,
|
||||
this.identificationNo,
|
||||
this.editedBy,
|
||||
this.projectID,
|
||||
this.clinicID,
|
||||
this.tokenID,
|
||||
this.languageID,
|
||||
this.stamp,
|
||||
this.iPAdress,
|
||||
this.versionID,
|
||||
this.channel,
|
||||
this.sessionID,
|
||||
this.isLoginForDoctorApp,
|
||||
this.patientOutSA,
|
||||
this.vidaAuthTokenID,
|
||||
this.vidaRefreshTokenID,
|
||||
this.deviceTypeID});
|
||||
|
||||
ProcedureTempleteRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
doctorID = json['DoctorID'];
|
||||
firstName = json['FirstName'];
|
||||
middleName = json['MiddleName'];
|
||||
lastName = json['LastName'];
|
||||
patientMobileNumber = json['PatientMobileNumber'];
|
||||
patientIdentificationID = json['PatientIdentificationID'];
|
||||
patientID = json['PatientID'];
|
||||
from = json['From'];
|
||||
to = json['To'];
|
||||
searchType = json['SearchType'];
|
||||
mobileNo = json['MobileNo'];
|
||||
identificationNo = json['IdentificationNo'];
|
||||
editedBy = json['EditedBy'];
|
||||
projectID = json['ProjectID'];
|
||||
clinicID = json['ClinicID'];
|
||||
tokenID = json['TokenID'];
|
||||
languageID = json['LanguageID'];
|
||||
stamp = json['stamp'];
|
||||
iPAdress = json['IPAdress'];
|
||||
versionID = json['VersionID'];
|
||||
channel = json['Channel'];
|
||||
sessionID = json['SessionID'];
|
||||
isLoginForDoctorApp = json['IsLoginForDoctorApp'];
|
||||
patientOutSA = json['PatientOutSA'];
|
||||
vidaAuthTokenID = json['VidaAuthTokenID'];
|
||||
vidaRefreshTokenID = json['VidaRefreshTokenID'];
|
||||
deviceTypeID = json['DeviceTypeID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['FirstName'] = this.firstName;
|
||||
data['MiddleName'] = this.middleName;
|
||||
data['LastName'] = this.lastName;
|
||||
data['PatientMobileNumber'] = this.patientMobileNumber;
|
||||
data['PatientIdentificationID'] = this.patientIdentificationID;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['From'] = this.from;
|
||||
data['To'] = this.to;
|
||||
data['SearchType'] = this.searchType;
|
||||
data['MobileNo'] = this.mobileNo;
|
||||
data['IdentificationNo'] = this.identificationNo;
|
||||
data['EditedBy'] = this.editedBy;
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['ClinicID'] = this.clinicID;
|
||||
data['TokenID'] = this.tokenID;
|
||||
data['LanguageID'] = this.languageID;
|
||||
data['stamp'] = this.stamp;
|
||||
data['IPAdress'] = this.iPAdress;
|
||||
data['VersionID'] = this.versionID;
|
||||
data['Channel'] = this.channel;
|
||||
data['SessionID'] = this.sessionID;
|
||||
data['IsLoginForDoctorApp'] = this.isLoginForDoctorApp;
|
||||
data['PatientOutSA'] = this.patientOutSA;
|
||||
data['VidaAuthTokenID'] = this.vidaAuthTokenID;
|
||||
data['VidaRefreshTokenID'] = this.vidaRefreshTokenID;
|
||||
data['DeviceTypeID'] = this.deviceTypeID;
|
||||
return data;
|
||||
}
|
||||
}
|