merge-requests/155/head
hussam al-habibeh 5 years ago
commit ba72d40deb

@ -72,4 +72,9 @@ dependencies {
implementation 'com.opentok.android:opentok-android-sdk:2.16.5'
//permissions
implementation 'pub.devrel:easypermissions:0.4.0'
//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1'
}

@ -15,7 +15,7 @@
android:name="io.flutter.app.FlutterApplication"
android:icon="@mipmap/ic_launcher"
android:label="doctor_app_flutter">
<activity android:name=".VideoCallActivity"></activity>
<activity android:name=".ui.VideoCallActivity"></activity>
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

@ -0,0 +1,115 @@
package com.example.doctor_app_flutter.Model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class GetSessionStatusModel implements Parcelable {
@SerializedName("VC_ID")
@Expose
private Integer vCID;
@SerializedName("TokenID")
@Expose
private String tokenID;
@SerializedName("generalid")
@Expose
private String generalid;
@SerializedName("DoctorId")
@Expose
private Integer doctorId;
public GetSessionStatusModel() {
}
public GetSessionStatusModel(Integer vCID, String tokenID, String generalid, Integer doctorId) {
this.vCID = vCID;
this.tokenID = tokenID;
this.generalid = generalid;
this.doctorId = doctorId;
}
protected GetSessionStatusModel(Parcel in) {
if (in.readByte() == 0) {
vCID = null;
} else {
vCID = in.readInt();
}
tokenID = in.readString();
generalid = in.readString();
if (in.readByte() == 0) {
doctorId = null;
} else {
doctorId = in.readInt();
}
}
public static final Creator<GetSessionStatusModel> CREATOR = new Creator<GetSessionStatusModel>() {
@Override
public GetSessionStatusModel createFromParcel(Parcel in) {
return new GetSessionStatusModel(in);
}
@Override
public GetSessionStatusModel[] newArray(int size) {
return new GetSessionStatusModel[size];
}
};
public Integer getVCID() {
return vCID;
}
public void setVCID(Integer vCID) {
this.vCID = vCID;
}
public String getTokenID() {
return tokenID;
}
public void setTokenID(String tokenID) {
this.tokenID = tokenID;
}
public String getGeneralid() {
return generalid;
}
public void setGeneralid(String generalid) {
this.generalid = generalid;
}
public Integer getDoctorId() {
return doctorId;
}
public void setDoctorId(Integer doctorId) {
this.doctorId = doctorId;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
if (vCID == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(vCID);
}
dest.writeString(tokenID);
dest.writeString(generalid);
if (doctorId == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(doctorId);
}
}
}

@ -0,0 +1,106 @@
package com.example.doctor_app_flutter.Model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class SessionStatusModel implements Parcelable {
@SerializedName("Result")
@Expose
private String result;
@SerializedName("SessionStatus")
@Expose
private Integer sessionStatus;
@SerializedName("IsAuthenticated")
@Expose
private Boolean isAuthenticated;
@SerializedName("MessageStatus")
@Expose
private Integer messageStatus;
protected SessionStatusModel(Parcel in) {
result = in.readString();
if (in.readByte() == 0) {
sessionStatus = null;
} else {
sessionStatus = in.readInt();
}
byte tmpIsAuthenticated = in.readByte();
isAuthenticated = tmpIsAuthenticated == 0 ? null : tmpIsAuthenticated == 1;
if (in.readByte() == 0) {
messageStatus = null;
} else {
messageStatus = in.readInt();
}
}
public static final Creator<SessionStatusModel> CREATOR = new Creator<SessionStatusModel>() {
@Override
public SessionStatusModel createFromParcel(Parcel in) {
return new SessionStatusModel(in);
}
@Override
public SessionStatusModel[] newArray(int size) {
return new SessionStatusModel[size];
}
};
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public Integer getSessionStatus() {
return sessionStatus;
}
public void setSessionStatus(Integer sessionStatus) {
this.sessionStatus = sessionStatus;
}
public Boolean getIsAuthenticated() {
return isAuthenticated;
}
public void setIsAuthenticated(Boolean isAuthenticated) {
this.isAuthenticated = isAuthenticated;
}
public Integer getMessageStatus() {
return messageStatus;
}
public void setMessageStatus(Integer messageStatus) {
this.messageStatus = messageStatus;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(result);
if (sessionStatus == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(sessionStatus);
}
dest.writeByte((byte) (isAuthenticated == null ? 0 : isAuthenticated ? 1 : 2));
if (messageStatus == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(messageStatus);
}
}
}

@ -0,0 +1,69 @@
package com.example.doctor_app_flutter.Service;
import android.app.Activity;
import android.app.Application;
import androidx.annotation.CallSuper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.concurrent.TimeUnit;
import io.flutter.view.FlutterMain;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class AppRetrofit extends Application {
private static final int MY_SOCKET_TIMEOUT_MS = 20000;
@Override
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity() {
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity) {
this.mCurrentActivity = mCurrentActivity;
}
public static Retrofit getRetrofit( String baseUrl) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Gson gson = new GsonBuilder().serializeNulls().create();
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(chain -> {
okhttp3.Request originalRequest = chain.request();
okhttp3.Request newRequest = originalRequest.newBuilder()
.addHeader("Content-Type","application/json")
.addHeader("Accept","application/json")
.build();
return chain.proceed(newRequest);
})
.addInterceptor(interceptor)
.callTimeout(MY_SOCKET_TIMEOUT_MS, TimeUnit.SECONDS)
.connectTimeout(MY_SOCKET_TIMEOUT_MS, TimeUnit.SECONDS)
.readTimeout(MY_SOCKET_TIMEOUT_MS, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(0, 5 * 60 * 1000, TimeUnit.SECONDS))
.retryOnConnectionFailure(false)
.build();
return new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build();
}
}

@ -0,0 +1,15 @@
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,18 +1,17 @@
package com.example.doctor_app_flutter;
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.content.res.ColorStateList;
import android.graphics.Color;
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.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@ -21,6 +20,9 @@ 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.example.doctor_app_flutter.R;
import com.opentok.android.Session;
import com.opentok.android.Stream;
import com.opentok.android.Publisher;
@ -40,31 +42,32 @@ import pub.devrel.easypermissions.EasyPermissions;
public class VideoCallActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks,
Session.SessionListener,
Publisher.PublisherListener,
Subscriber.VideoListener {
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;
private Runnable mVolRunnable;
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 callDuration;
private String warningDuration;
private String appLang;
private String apiKey;
private String sessionId;
private String token;
private String appLang;
private String baseUrl;
private boolean isSwitchCameraClicked;
private boolean isCameraClicked;
@ -82,6 +85,10 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
private TextView progressBarTextView;
private RelativeLayout progressBarLayout;
private boolean isConnected = false;
private GetSessionStatusModel sessionStatusModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -132,11 +139,14 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
apiKey = getIntent().getStringExtra("apiKey");
sessionId = getIntent().getStringExtra("sessionId");
token = getIntent().getStringExtra("token");
// callDuration = getIntent().getStringExtra("callDuration");
// warningDuration = getIntent().getStringExtra("warningDuration");
appLang=getIntent().getStringExtra("appLang");
appLang = getIntent().getStringExtra("appLang");
baseUrl = getIntent().getStringExtra("baseUrl");
sessionStatusModel = getIntent().getParcelableExtra("sessionStatusModel");
controlPanel = findViewById(R.id.control_panel);
videoCallPresenter = new VideoCallPresenterImpl(this, baseUrl);
controlPanel=findViewById(R.id.control_panel);
mCallBtn = findViewById(R.id.btn_call);
mCameraBtn = findViewById(R.id.btn_camera);
@ -144,17 +154,19 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
mspeckerBtn = findViewById(R.id.btn_specker);
mMicBtn = findViewById(R.id.btn_mic);
// progressBarLayout=findViewById(R.id.progressBar);
// progressBar=findViewById(R.id.progress_bar);
// 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);
mVolHandler.postDelayed(mVolRunnable, 5 * 1000);
return true;
});
@ -164,16 +176,25 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
}
private void checkClientConnected() {
mConnectedHandler = new Handler();
mConnectedRunnable = () -> {
if (!isConnected) {
videoCallPresenter.callClintConnected(sessionStatusModel);
}
};
mConnectedHandler.postDelayed(mConnectedRunnable, 30 * 1000);
}
private void hiddenButtons(){
private void hiddenButtons() {
mVolHandler = new Handler();
mVolRunnable = new Runnable() {
public void run() {
controlPanel.setVisibility(View.GONE);
}
};
mVolHandler.postDelayed(mVolRunnable,5*1000);
mVolHandler.postDelayed(mVolRunnable, 5 * 1000);
}
@Override
@ -225,7 +246,7 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
mPublisherViewContainer.addView(mPublisher.getView());
if (mPublisher.getView() instanceof GLSurfaceView){
if (mPublisher.getView() instanceof GLSurfaceView) {
((GLSurfaceView) mPublisher.getView()).setZOrderOnTop(true);
}
@ -250,10 +271,11 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
@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);
}
@ -325,6 +347,7 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
private void disconnectSession() {
if (mSession == null) {
setResult(Activity.RESULT_CANCELED);
finish();
return;
}
@ -343,7 +366,7 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
mPublisher = null;
}
mSession.disconnect();
if(countDownTimer!=null) {
if (countDownTimer != null) {
countDownTimer.cancel();
}
finish();
@ -375,7 +398,9 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
mspeckerBtn.setImageResource(res);
}
}
public void onMicClicked(View view) {
if (mPublisher != null) {
isMicClicked = !isMicClicked;
mPublisher.setPublishAudio(!isMicClicked);
@ -387,4 +412,19 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi
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() {
}
}

@ -0,0 +1,18 @@
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);
}
}

@ -0,0 +1,49 @@
package com.example.doctor_app_flutter.ui;
import com.example.doctor_app_flutter.Model.GetSessionStatusModel;
import com.example.doctor_app_flutter.Model.SessionStatusModel;
import com.example.doctor_app_flutter.Service.AppRetrofit;
import com.example.doctor_app_flutter.Service.SessionStatusAPI;
import org.jetbrains.annotations.NotNull;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class VideoCallPresenterImpl implements VideoCallContract.VideoCallPresenter {
private VideoCallContract.VideoCallView view;
private SessionStatusAPI sessionStatusAPI;
private String baseUrl;
public VideoCallPresenterImpl(VideoCallContract.VideoCallView view, String baseUrl) {
this.view = view;
this.baseUrl = baseUrl;
}
@Override
public void callClintConnected(GetSessionStatusModel statusModel) {
sessionStatusAPI = AppRetrofit.getRetrofit(baseUrl).create(SessionStatusAPI.class);
Call<SessionStatusModel> call = sessionStatusAPI.getSessionStatusModelData(statusModel);
call.enqueue(new Callback<SessionStatusModel>() {
@Override
public void onResponse(@NotNull Call<SessionStatusModel> call, @NotNull Response<SessionStatusModel> response) {
if (response.isSuccessful()) {
view.onCallSuccessful(response.body());
} else
view.onFailure();
}
@Override
public void onFailure(@NotNull Call<SessionStatusModel> call, @NotNull Throwable t) {
view.onFailure();
}
});
}
}

@ -1,45 +1,101 @@
package com.example.doctor_app_flutter
import android.app.Activity
import android.content.Intent
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
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 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() {
class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler {
private val CHANNEL = "Dr.cloudSolution/videoCall"
private var result: MethodChannel.Result? = null
private var call: MethodCall? = null
private val LAUNCH_VIDEO: Int = 1
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "openVideoCall") {
val apiKey = call.argument<String>("kApiKey")
val sessionId = call.argument<String>("kSessionId")
val token = call.argument<String>("kToken")
// val callDuration = call.argument<String>("callDuration")
// val warningDuration = call.argument<String>("warningDuration")
val appLang = call.argument<String>("appLang")
openVideoCall(apiKey,sessionId,token/*,callDuration,warningDuration*/,appLang)
} else {
result.notImplemented()
}
}
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler(this)
}
private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?/*, callDuration: String?, warningDuration: String?*/, appLang: String?) {
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")
// Session Status model
val VC_ID = call.argument<Int>("VC_ID")
val tokenID = call.argument<String>("TokenID")
val generalId = call.argument<String>("generalId")
val doctorId = call.argument<Int>("DoctorId")
val sessionStatusModel = GetSessionStatusModel(VC_ID, tokenID, generalId, doctorId)
openVideoCall(apiKey, sessionId, token, appLang, baseUrl, sessionStatusModel)
} else {
result.notImplemented()
}
}
private fun openVideoCall(apiKey: String?, sessionId: String?, token: String?, appLang: String?, baseUrl: String?, sessionStatusModel: GetSessionStatusModel) {
// val videoCallActivity = VideoCallActivity()
val intent = Intent(this, VideoCallActivity::class.java)
intent.putExtra("apiKey", apiKey)
intent.putExtra("sessionId", sessionId)
intent.putExtra("token", token)
// intent.putExtra("callDuration", callDuration)
//intent.putExtra("warningDuration", warningDuration)
intent.putExtra("appLang", appLang)
startActivity(intent)
intent.putExtra("baseUrl", baseUrl)
intent.putExtra("sessionStatusModel", sessionStatusModel)
startActivityForResult(intent, LAUNCH_VIDEO)
}
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)
}
}
}
}

@ -4,7 +4,7 @@
android:id="@+id/activity_clingo_video_call"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".VideoCallActivity">
tools:context=".ui.VideoCallActivity">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"

@ -64,7 +64,7 @@ target 'Runner' do
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
pod 'OpenTok'
pod 'Alamofire'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock

@ -1,4 +1,5 @@
PODS:
- Alamofire (4.9.1)
- barcode_scan (0.0.1):
- Flutter
- MTBBarcodeScanner
@ -41,6 +42,7 @@ PODS:
- Flutter
DEPENDENCIES:
- Alamofire
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- connectivity (from `.symlinks/plugins/connectivity/ios`)
- connectivity_macos (from `.symlinks/plugins/connectivity_macos/ios`)
@ -62,6 +64,7 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- Alamofire
- MTBBarcodeScanner
- OpenTok
- Reachability
@ -104,6 +107,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_web/ios"
SPEC CHECKSUMS:
Alamofire: 85e8a02c69d6020a0d734f6054870d7ecb75cf18
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
connectivity: 6e94255659cc86dcbef1d452ad3e0491bb1b3e75
connectivity_macos: e2e9731b6b22dda39eb1b128f6969d574460e191
@ -126,6 +130,6 @@ SPEC CHECKSUMS:
url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
PODFILE CHECKSUM: ad71cae222b2dc22820a69b80873417b35fef79e
PODFILE CHECKSUM: 649616dc336b3659ac6b2b25159d8e488e042b69
COCOAPODS: 1.9.3

@ -13,7 +13,8 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
9CE61EBD24AB366E008D68DD /* ViewControlleraa.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61EBC24AB366E008D68DD /* ViewControlleraa.swift */; };
9CE61EBD24AB366E008D68DD /* VideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61EBC24AB366E008D68DD /* VideoViewController.swift */; };
9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */; };
B650DC3076E9D70CB188286A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93A5F83B23AB032D1E096663 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
@ -46,7 +47,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9CE61EBC24AB366E008D68DD /* ViewControlleraa.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControlleraa.swift; sourceTree = "<group>"; };
9CE61EBC24AB366E008D68DD /* VideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = "<group>"; };
9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICallProtocoll.swift; sourceTree = "<group>"; };
9D4B7DB43C6A6C849D2387CE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
E698D7B14B12DF768FE47A1A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -115,7 +117,8 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
9CE61EBC24AB366E008D68DD /* ViewControlleraa.swift */,
9CE61EBC24AB366E008D68DD /* VideoViewController.swift */,
9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */,
);
path = Runner;
sourceTree = "<group>";
@ -282,8 +285,9 @@
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
9CE61EBD24AB366E008D68DD /* ViewControlleraa.swift in Sources */,
9CE61EBD24AB366E008D68DD /* VideoViewController.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
9CE61ECD24ADBB4C008D68DD /* ICallProtocoll.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

@ -6,18 +6,30 @@ import OpenTok
// Copyright © 2020 Cloud. All rights reserved.
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
@objc class AppDelegate: FlutterAppDelegate ,ICallProtocol {
var result: FlutterResult?
func sessionDone(res:Any) {
self.result?(res)
}
func sessionNotResponded(res:Any) {
self.result?(res)
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall",
binaryMessenger: controller.binaryMessenger)
videoCallChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
self.result = result
switch call.method {
case "openVideoCall":
do {
@ -26,7 +38,13 @@ import OpenTok
let kSessionId = arguments!["kSessionId"] as? String
let kToken = arguments!["kToken"] as? String
let appLang = arguments!["appLang"] as? String
self.openVideoChat(result: result,kApiKey: kApiKey!,kSessionId:kSessionId!,kToken: kToken!, appLang: appLang!)
let vC_ID = arguments!["VC_ID"] as? Int
let tokenID = arguments!["TokenID"] as? String
let generalId = arguments!["generalId"] as? String
let doctorId = arguments!["DoctorId"] as? Int
let baseUrl = arguments!["baseUrl"] as? String
self.openVideoChat(result: result,kApiKey: kApiKey!,kSessionId:kSessionId!,kToken: kToken!, appLang: appLang!, vC_ID: vC_ID!,tokenID: tokenID!,generalId: generalId!,doctorId: doctorId!, baseUrl: baseUrl!)
}
default:
result(FlutterMethodNotImplemented)
@ -37,9 +55,10 @@ import OpenTok
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func openVideoChat(result: FlutterResult,kApiKey: String, kSessionId: String,kToken: String,appLang:String) {
private func openVideoChat(result: FlutterResult,kApiKey: String, kSessionId: String,kToken: String,appLang:String, vC_ID: Int,tokenID:String,generalId:String,doctorId:Int,baseUrl:String) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let identifier = "ViewControllerNav"
@ -48,6 +67,12 @@ import OpenTok
videoVC.kApiKey=kApiKey
videoVC.kSessionId=kSessionId
videoVC.kToken=kToken
videoVC.VC_ID = vC_ID
videoVC.generalid = generalId
videoVC.TokenID = tokenID
videoVC.DoctorId = doctorId
videoVC.baseUrl = baseUrl
videoVC.callBack = self
videoVC.navigationController?.setNavigationBarHidden(true, animated: false)
navVC.modalPresentationStyle = .fullScreen
window.rootViewController?.present(navVC, animated: true, completion: nil)

@ -0,0 +1,15 @@
//
// ICallProtocol.swift
// Runner
//
// Created by Elham Rababah && Mohammad Aljammal on 7/2/20.
// Copyright © 2020 The Chromium Authors. All rights reserved.
//
import Foundation
protocol ICallProtocol {
func sessionDone(res:Any)
func sessionNotResponded(res: Any)
}

@ -8,6 +8,7 @@
import UIKit
import OpenTok
import Alamofire
class ViewController: UIViewController {
@ -22,6 +23,17 @@ class ViewController: UIViewController {
var kToken:String = ""
var VC_ID: Int = 0
var TokenID: String = ""
var generalid : String = ""
var DoctorId: Int = 0
var baseUrl:String = ""
var callBack: ICallProtocol?
var timer = Timer()
var seconds = 30
var isUserConnect : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
@ -34,6 +46,46 @@ class ViewController: UIViewController {
// Do any additional setup after loading the view.
}
private func getSessionStatus() {
let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/GetSessionStatus"
let headers: HTTPHeaders = [
"Content-Type":"application/json",
"Accept":"application/json",
]
let parameters = [
"VC_ID": VC_ID,
"TokenID": TokenID,
"generalid": generalid,
"DoctorId" : DoctorId ,
] as [String : Any]
Alamofire.request(URL_USER_REGISTER, method: .post,parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON{
response in
if self.isUserConnect {
} else {
if let result = response.result.value {
let jsonData = result as! NSObject
if((jsonData.value(forKey: "SessionStatus")) as! Int == 2 || (jsonData.value(forKey: "SessionStatus")) as! Int == 3) {
//jsonData
let jsonObject: [String: Any] = [
"sessionStatus": result ,
"callResponse": "CallNotRespond",
]
self.callBack?.sessionNotResponded(res: jsonObject)
}
}
self.sessionDisconnect();
self.timer.invalidate()
}
//getting json value from the server
}
}
func setupButtons() {
perform(#selector(hideControlButtons), with: nil, afterDelay: 3)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(remoteVideoTapped(_:)))
@ -102,6 +154,7 @@ class ViewController: UIViewController {
}
@IBAction func hangUp(_ sender: UIButton) {
callBack?.sessionDone(res:["callResponse":"CallEnd"])
sessionDisconnect()
}
@ -204,6 +257,15 @@ class ViewController: UIViewController {
@IBOutlet weak var localVideoMutedIndicator: UIImageView!
@objc func updateTimer(){
seconds -= 1 //This will decrement(count down)the seconds.
print(seconds)
if seconds == 0 {
getSessionStatus()
}
}
}
@ -212,11 +274,17 @@ extension ViewController: OTSessionDelegate {
func sessionDidConnect(_ session: OTSession) {
print("The client connected to the OpenTok session.")
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
setupPublisher()
}
func setupPublisher() {
let settings = OTPublisherSettings()
settings.name = UIDevice.current.name
@ -300,6 +368,18 @@ extension ViewController: OTSessionDelegate {
subscriber?.view!.removeFromSuperview()
subscriber = nil
}
func session(
_ session: OTSession?,
connectionCreated connection: OTConnection?
) {
// startTimer(callDuration, warningDuration)
if let connectionId = connection?.connectionId {
print("session connectionCreated (\(connectionId))")
}
isUserConnect = true
timer.invalidate()
}
}

@ -0,0 +1,28 @@
class SessionStatusModel {
bool isAuthenticated;
int messageStatus;
String result;
int sessionStatus;
SessionStatusModel(
{this.isAuthenticated,
this.messageStatus,
this.result,
this.sessionStatus});
SessionStatusModel.fromJson(Map<dynamic, dynamic> json) {
isAuthenticated = json['IsAuthenticated'];
messageStatus = json['MessageStatus'];
result = json['Result'];
sessionStatus = json['SessionStatus'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['IsAuthenticated'] = this.isAuthenticated;
data['MessageStatus'] = this.messageStatus;
data['Result'] = this.result;
data['SessionStatus'] = this.sessionStatus;
return data;
}
}

@ -1,9 +1,12 @@
import 'dart:convert';
import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/config/size_config.dart';
import 'package:doctor_app_flutter/icons_app/doctor_app_icons.dart';
import 'package:doctor_app_flutter/models/doctor/clinic_model.dart';
import 'package:doctor_app_flutter/models/doctor/doctor_profile_model.dart';
import 'package:doctor_app_flutter/models/doctor/profile_req_Model.dart';
import 'package:doctor_app_flutter/models/livecare/session_status_model.dart';
import 'package:doctor_app_flutter/providers/auth_provider.dart';
import 'package:doctor_app_flutter/providers/doctor_reply_provider.dart';
import 'package:doctor_app_flutter/providers/hospital_provider.dart';
@ -115,12 +118,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
InkWell(
onTap: () {
showCupertinoPicker(
decKey: '',
context: context,
actionList:
projectsProvider.doctorClinicsList);
onTap: () async {
showCupertinoPicker(
decKey: '',context: context,
actionList: projectsProvider.doctorClinicsList);
},
child: Container(
margin:

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:doctor_app_flutter/models/livecare/session_status_model.dart';
import 'package:doctor_app_flutter/providers/livecare_provider.dart';
import 'package:doctor_app_flutter/util/VideoChannel.dart';
import 'package:doctor_app_flutter/util/dr_app_shared_pref.dart';
@ -37,15 +38,28 @@ class _VideoCallPageState extends State<VideoCallPage> {
_isInit = false;
}
void connectOpenTok(tokenData) {
void connectOpenTok(tokenData) async {
_tokenData = tokenData;
/* opentok functionalites need to be written */
VideoChannel.openVideoCallScreen(
kApiKey: '46209962',
kSessionId: _tokenData["OpenSessionID"],
kToken: _tokenData["OpenTokenID"],
);
await VideoChannel.openVideoCallScreen(
kToken:
'T1==cGFydG5lcl9pZD00NjgwMzIyNCZzaWc9NWRhNmExMzU4ZDViZGU3OTA5NDY4ODRhNzI4ZGUxZTRmMjZmNzcwMjpzZXNzaW9uX2lkPTFfTVg0ME5qZ3dNekl5Tkg1LU1UVTVNelk0TXpZek9EWXdNMzV1Y0V4V1lWUlZTbTVIY3k5dVdHWm1NMWxPYTNjelpIVi1mZyZjcmVhdGVfdGltZT0xNTkzNjgzNjYyJm5vbmNlPTAuODAxMzMzMzUxMDQwNzE5NSZyb2xlPXB1Ymxpc2hlciZleHBpcmVfdGltZT0xNTk2Mjc1NjYyJmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9',
kSessionId:
'1_MX40NjgwMzIyNH5-MTU5MzY4MzYzODYwM35ucExWYVRVSm5Hcy9uWGZmM1lOa3czZHV-fg',
kApiKey: '46803224',
vcId: 3245,
tokenID: "hfkjshdf347r8743",
generalId: "Cs2020@2016\$2958",
doctorId: 1485,
onFailure: (String error) {
//TODO handling Failure
},
onCallEnd: () {
//TODO handling onCallEnd
},
onCallNotRespond: (SessionStatusModel sessionStatusModel) {
//TODO handling onCalcallNotRespondlEnd
});
}
String getTimerTime(int start) {

@ -1,28 +1,44 @@
import 'dart:convert';
import 'dart:io' show Platform;
import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/models/livecare/session_status_model.dart';
import 'package:flutter/services.dart';
class VideoChannel{
/// channel name
static const _channel = const MethodChannel("Dr.cloudSolution/videoCall");
static Future<dynamic> openVideoCallScreen(
{kApiKey, kSessionId, kToken, callDuration, warningDuration}) {
static openVideoCallScreen(
{kApiKey, kSessionId, kToken, callDuration, warningDuration,int vcId,String tokenID,String generalId,int doctorId, Function() onCallEnd , Function(SessionStatusModel sessionStatusModel) onCallNotRespond ,Function(String error) onFailure}) async {
var result;
try {
result = _channel.invokeMethod(
result = await _channel.invokeMethod(
'openVideoCall',
{
"kApiKey": kApiKey,
"kSessionId": kSessionId,
"kToken": kToken,
/* "callDuration": callDuration,
"warningDuration": warningDuration,*/
"appLang": "en",
"baseUrl": BASE_URL,
"VC_ID": vcId,
"TokenID": tokenID,
"generalId": generalId,
"DoctorId": doctorId ,
},
);
} on PlatformException catch (e) {
result = e.toString();
if(result['callResponse'] == 'CallEnd') {
onCallEnd();
}
else {
SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(Platform.isIOS ?result['sessionStatus'] :json.decode(result['sessionStatus']));
onCallNotRespond(sessionStatusModel);
}
} catch (e) {
onFailure(e.toString());
}
return result;
}

Loading…
Cancel
Save