From 8db2f059baeb0d58d534361262c03ca16d417a03 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Thu, 2 Jul 2020 11:14:28 +0300 Subject: [PATCH 1/8] add call back fun for end call --- ios/Runner.xcodeproj/project.pbxproj | 12 ++++++++---- ios/Runner/AppDelegate.swift | 15 +++++++++++++-- ios/Runner/ICallProtocoll.swift | 14 ++++++++++++++ ...rolleraa.swift => VideoViewController.swift} | 6 +++++- lib/screens/dashboard_screen.dart | 17 +++++++++++++---- 5 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 ios/Runner/ICallProtocoll.swift rename ios/Runner/{ViewControlleraa.swift => VideoViewController.swift} (99%) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 0550eac7..dcd750d8 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -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 = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9CE61EBC24AB366E008D68DD /* ViewControlleraa.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControlleraa.swift; sourceTree = ""; }; + 9CE61EBC24AB366E008D68DD /* VideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = ""; }; + 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICallProtocoll.swift; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; /* 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 = ""; @@ -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; }; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 5e32b165..e763b11d 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -6,7 +6,15 @@ import OpenTok // Copyright © 2020 Cloud. All rights reserved. @UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { +@objc class AppDelegate: FlutterAppDelegate ,ICallProtocol { + + var result: FlutterResult? + + + func sessionDone() { + self.result?("Session Done") + } + override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? @@ -17,7 +25,8 @@ import OpenTok 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 { @@ -37,6 +46,7 @@ import OpenTok return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + private func openVideoChat(result: FlutterResult,kApiKey: String, kSessionId: String,kToken: String,appLang:String) { @@ -48,6 +58,7 @@ import OpenTok videoVC.kApiKey=kApiKey videoVC.kSessionId=kSessionId videoVC.kToken=kToken + videoVC.callBack = self videoVC.navigationController?.setNavigationBarHidden(true, animated: false) navVC.modalPresentationStyle = .fullScreen window.rootViewController?.present(navVC, animated: true, completion: nil) diff --git a/ios/Runner/ICallProtocoll.swift b/ios/Runner/ICallProtocoll.swift new file mode 100644 index 00000000..1e267a17 --- /dev/null +++ b/ios/Runner/ICallProtocoll.swift @@ -0,0 +1,14 @@ +// +// 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() +} diff --git a/ios/Runner/ViewControlleraa.swift b/ios/Runner/VideoViewController.swift similarity index 99% rename from ios/Runner/ViewControlleraa.swift rename to ios/Runner/VideoViewController.swift index 6e7c17f3..507e3d87 100644 --- a/ios/Runner/ViewControlleraa.swift +++ b/ios/Runner/VideoViewController.swift @@ -22,6 +22,8 @@ class ViewController: UIViewController { var kToken:String = "" + var callBack: ICallProtocol? + override func viewDidLoad() { super.viewDidLoad() @@ -33,7 +35,7 @@ class ViewController: UIViewController { setupSession() // Do any additional setup after loading the view. } - + func setupButtons() { perform(#selector(hideControlButtons), with: nil, afterDelay: 3) let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(remoteVideoTapped(_:))) @@ -102,6 +104,7 @@ class ViewController: UIViewController { } @IBAction func hangUp(_ sender: UIButton) { + sessionDisconnect() } @@ -110,6 +113,7 @@ class ViewController: UIViewController { if (session != nil) { print("disconnecting....") session!.disconnect(nil) + callBack?.sessionDone() dismiss(animated: true) return } diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index ad64d89a..f972e5d3 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -101,10 +101,19 @@ class _DashboardScreenState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ InkWell( - onTap: () { - showCupertinoPicker( - context: context, - actionList: authProvider.doctorsClinicList); + onTap: () async { + + var asd = await VideoChannel.openVideoCallScreen( + kToken: "T1==cGFydG5lcl9pZD00NjgwMzIyNCZzaWc9ZTUxZGI0NGJiNjhjOGY2YzZkZGVjNTQ0M2Q5ZDJkODY2MjBlYjJjYTpzZXNzaW9uX2lkPTJfTVg0ME5qZ3dNekl5Tkg1LU1UVTVNekEzTkRrMk1qUXhOSDVRZWt3clkxb3lhSGRuYmpWU2FFTmtlbWx2TkZWcWVFSi1mZyZjcmVhdGVfdGltZT0xNTkzMDc1MDA3Jm5vbmNlPTAuNjQ2OTA2MTAwMTU0ODY3NSZyb2xlPXB1Ymxpc2hlciZleHBpcmVfdGltZT0xNTkzNjc5ODA2JmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9", + kSessionId: '2_MX40NjgwMzIyNH5-MTU5MzA3NDk2MjQxNH5QekwrY1oyaHdnbjVSaENkemlvNFVqeEJ-fg', + kApiKey: '46803224' + ); + + print(asd); + + // showCupertinoPicker( + // context: context, + // actionList: authProvider.doctorsClinicList); }, child: Container( margin: From 1e27edf09f9a6d3370045f96712d630e6b378569 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Thu, 2 Jul 2020 17:38:12 +0300 Subject: [PATCH 2/8] kill the session after 30 second --- ios/Runner/VideoViewController.swift | 31 +++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/ios/Runner/VideoViewController.swift b/ios/Runner/VideoViewController.swift index 507e3d87..357c696f 100644 --- a/ios/Runner/VideoViewController.swift +++ b/ios/Runner/VideoViewController.swift @@ -23,6 +23,8 @@ class ViewController: UIViewController { var kToken:String = "" var callBack: ICallProtocol? + var timer = Timer() + var seconds = 30 override func viewDidLoad() { @@ -208,6 +210,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 { + sessionDisconnect(); + timer.invalidate() + + } + } } @@ -216,11 +227,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 @@ -304,6 +321,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))") + } + + timer.invalidate() + } } From d22ce32cdb79ba3ea93877ff63eb8e1ac78090c1 Mon Sep 17 00:00:00 2001 From: Mohammad ALjammal Date: Sun, 5 Jul 2020 14:09:16 +0300 Subject: [PATCH 3/8] add call back android --- android/app/build.gradle | 5 + android/app/src/main/AndroidManifest.xml | 2 +- .../Model/GetSessionStatusModel.java | 115 ++++++++++++++++++ .../Model/SessionStatusModel.java | 106 ++++++++++++++++ .../Service/AppRetrofit.java | 69 +++++++++++ .../Service/SessionStatusAPI.java | 15 +++ .../{ => ui}/VideoCallActivity.java | 92 ++++++++++---- .../ui/VideoCallContract.java | 18 +++ .../ui/VideoCallPresenterImpl.java | 49 ++++++++ .../doctor_app_flutter/MainActivity.kt | 102 ++++++++++++---- .../main/res/layout/activity_video_call.xml | 2 +- lib/models/livecare/session_status_model.dart | 28 +++++ lib/screens/dashboard_screen.dart | 20 ++- lib/util/VideoChannel.dart | 31 +++-- 14 files changed, 592 insertions(+), 62 deletions(-) create mode 100644 android/app/src/main/java/com/example/doctor_app_flutter/Model/GetSessionStatusModel.java create mode 100644 android/app/src/main/java/com/example/doctor_app_flutter/Model/SessionStatusModel.java create mode 100644 android/app/src/main/java/com/example/doctor_app_flutter/Service/AppRetrofit.java create mode 100644 android/app/src/main/java/com/example/doctor_app_flutter/Service/SessionStatusAPI.java rename android/app/src/main/java/com/example/doctor_app_flutter/{ => ui}/VideoCallActivity.java (82%) create mode 100644 android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallContract.java create mode 100644 android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallPresenterImpl.java create mode 100644 lib/models/livecare/session_status_model.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 048dea59..ae87782e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -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' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index fda3b312..51b33a46 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -15,7 +15,7 @@ android:name="io.flutter.app.FlutterApplication" android:icon="@mipmap/ic_launcher" android:label="doctor_app_flutter"> - + CREATOR = new Creator() { + @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); + } + } +} diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/Model/SessionStatusModel.java b/android/app/src/main/java/com/example/doctor_app_flutter/Model/SessionStatusModel.java new file mode 100644 index 00000000..da6bba1d --- /dev/null +++ b/android/app/src/main/java/com/example/doctor_app_flutter/Model/SessionStatusModel.java @@ -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 CREATOR = new Creator() { + @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); + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/Service/AppRetrofit.java b/android/app/src/main/java/com/example/doctor_app_flutter/Service/AppRetrofit.java new file mode 100644 index 00000000..6646bd6f --- /dev/null +++ b/android/app/src/main/java/com/example/doctor_app_flutter/Service/AppRetrofit.java @@ -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(); + } +} diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/Service/SessionStatusAPI.java b/android/app/src/main/java/com/example/doctor_app_flutter/Service/SessionStatusAPI.java new file mode 100644 index 00000000..fbc8d1d3 --- /dev/null +++ b/android/app/src/main/java/com/example/doctor_app_flutter/Service/SessionStatusAPI.java @@ -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 getSessionStatusModelData(@Body GetSessionStatusModel getSessionStatusModel); +} diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/VideoCallActivity.java b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java similarity index 82% rename from android/app/src/main/java/com/example/doctor_app_flutter/VideoCallActivity.java rename to android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java index 146a3d54..adc32d38 100644 --- a/android/app/src/main/java/com/example/doctor_app_flutter/VideoCallActivity.java +++ b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java @@ -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, 7 * 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() { + + } } \ No newline at end of file diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallContract.java b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallContract.java new file mode 100644 index 00000000..21122239 --- /dev/null +++ b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallContract.java @@ -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); + } +} diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallPresenterImpl.java b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallPresenterImpl.java new file mode 100644 index 00000000..363d1ca8 --- /dev/null +++ b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallPresenterImpl.java @@ -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 call = sessionStatusAPI.getSessionStatusModelData(statusModel); + + call.enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if (response.isSuccessful()) { + view.onCallSuccessful(response.body()); + } else + view.onFailure(); + } + + @Override + public void onFailure(@NotNull Call call, @NotNull Throwable t) { + view.onFailure(); + } + }); + + } +} diff --git a/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt b/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt index d1d710ad..1a203368 100644 --- a/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt @@ -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("kApiKey") - val sessionId = call.argument("kSessionId") - val token = call.argument("kToken") - // val callDuration = call.argument("callDuration") - // val warningDuration = call.argument("warningDuration") - val appLang = call.argument("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("kApiKey") + val sessionId = call.argument("kSessionId") + val token = call.argument("kToken") + val appLang = call.argument("appLang") + val baseUrl = call.argument("baseUrl") + + // Session Status model + val VC_ID = call.argument("VC_ID") + val tokenID = call.argument("TokenID") + val generalId = call.argument("generalId") + val doctorId = call.argument("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 = HashMap() + + val sessionStatus : HashMap = HashMap() + val gson = GsonBuilder().serializeNulls().create() + + callResponse["callResponse"] = "CallNotRespond" + val jsonRes = gson.toJson(result) + callResponse["sessionStatus"] = jsonRes + + this.result?.success(gson.toJson(callResponse)) + } + if (resultCode == Activity.RESULT_CANCELED) { + val callResponse : HashMap = HashMap() + callResponse["callResponse"] = "CallEnd" + + result?.success(callResponse) + } + } } + + } diff --git a/android/app/src/main/res/layout/activity_video_call.xml b/android/app/src/main/res/layout/activity_video_call.xml index c7500b6c..2dcf2ba4 100644 --- a/android/app/src/main/res/layout/activity_video_call.xml +++ b/android/app/src/main/res/layout/activity_video_call.xml @@ -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"> json) { + isAuthenticated = json['IsAuthenticated']; + messageStatus = json['MessageStatus']; + result = json['Result']; + sessionStatus = json['SessionStatus']; + } + + Map toJson() { + final Map data = new Map(); + data['IsAuthenticated'] = this.isAuthenticated; + data['MessageStatus'] = this.messageStatus; + data['Result'] = this.result; + data['SessionStatus'] = this.sessionStatus; + return data; + } +} diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index ad64d89a..52ecf34f 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -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'; @@ -101,10 +104,19 @@ class _DashboardScreenState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ InkWell( - onTap: () { - showCupertinoPicker( - context: context, - actionList: authProvider.doctorsClinicList); + onTap: () async { + await VideoChannel.openVideoCallScreen( + kToken: 'T1==cGFydG5lcl9pZD00NjgwMzIyNCZzaWc9NWRhNmExMzU4ZDViZGU3OTA5NDY4ODRhNzI4ZGUxZTRmMjZmNzcwMjpzZXNzaW9uX2lkPTFfTVg0ME5qZ3dNekl5Tkg1LU1UVTVNelk0TXpZek9EWXdNMzV1Y0V4V1lWUlZTbTVIY3k5dVdHWm1NMWxPYTNjelpIVi1mZyZjcmVhdGVfdGltZT0xNTkzNjgzNjYyJm5vbmNlPTAuODAxMzMzMzUxMDQwNzE5NSZyb2xlPXB1Ymxpc2hlciZleHBpcmVfdGltZT0xNTk2Mjc1NjYyJmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9', + kSessionId: '1_MX40NjgwMzIyNH5-MTU5MzY4MzYzODYwM35ucExWYVRVSm5Hcy9uWGZmM1lOa3czZHV-fg', + kApiKey: '46803224', + onFailure: (String error) {}, + onCallEnd: () {}, + callNotRespond: (SessionStatusModel sessionStatusModel) {}); + + +// showCupertinoPicker( +// context: context, +// actionList: authProvider.doctorsClinicList); }, child: Container( margin: diff --git a/lib/util/VideoChannel.dart b/lib/util/VideoChannel.dart index c5bf278e..73b17930 100644 --- a/lib/util/VideoChannel.dart +++ b/lib/util/VideoChannel.dart @@ -1,28 +1,45 @@ +import 'dart:convert'; + +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 openVideoCallScreen( - {kApiKey, kSessionId, kToken, callDuration, warningDuration}) { + static openVideoCallScreen( + {kApiKey, kSessionId, kToken, callDuration, warningDuration, Function() onCallEnd , Function(SessionStatusModel sessionStatusModel) callNotRespond ,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": 3245, + "TokenID": "hfkjshdf347r8743", + "generalId": 'Cs2020@2016\$2958', + "DoctorId": 1485 , }, ); + if(result['callResponse'] == 'CallEnd') { + onCallEnd(); + } + else { + var asd = result['sessionStatus']; + var parsed = json.decode(result['sessionStatus']); + SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(parsed); + callNotRespond(sessionStatusModel); + } + } on PlatformException catch (e) { - result = e.toString(); + onFailure(e.toString()); } - return result; + } From 693effd6b7953ea1faf90f5a8109583920620b5a Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 5 Jul 2020 14:10:18 +0300 Subject: [PATCH 4/8] first step form calling API --- ios/Podfile | 2 +- ios/Podfile.lock | 6 +++- ios/Runner/AppDelegate.swift | 9 ++++-- ios/Runner/ICallProtocoll.swift | 3 +- ios/Runner/VideoViewController.swift | 42 +++++++++++++++++++++++++--- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 3b20de57..bebf8f5b 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -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 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ab95eb7c..70b9d103 100644 --- a/ios/Podfile.lock +++ b/ios/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 diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index e763b11d..e4992e16 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -11,8 +11,12 @@ import OpenTok var result: FlutterResult? - func sessionDone() { - self.result?("Session Done") + func sessionDone(res:Any) { + self.result?(res) + + } + func sessionNotResponded(res:Any) { + self.result?(res) } override func application( @@ -20,7 +24,6 @@ import OpenTok didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let videoCallChannel = FlutterMethodChannel(name: "Dr.cloudSolution/videoCall", binaryMessenger: controller.binaryMessenger) diff --git a/ios/Runner/ICallProtocoll.swift b/ios/Runner/ICallProtocoll.swift index 1e267a17..197be424 100644 --- a/ios/Runner/ICallProtocoll.swift +++ b/ios/Runner/ICallProtocoll.swift @@ -10,5 +10,6 @@ import Foundation protocol ICallProtocol { - func sessionDone() + func sessionDone(res:Any) + func sessionNotResponded(res: Any) } diff --git a/ios/Runner/VideoViewController.swift b/ios/Runner/VideoViewController.swift index 357c696f..d9834fea 100644 --- a/ios/Runner/VideoViewController.swift +++ b/ios/Runner/VideoViewController.swift @@ -8,6 +8,7 @@ import UIKit import OpenTok +import Alamofire class ViewController: UIViewController { @@ -25,6 +26,7 @@ class ViewController: UIViewController { var callBack: ICallProtocol? var timer = Timer() var seconds = 30 + var isUserConnect : Bool = false override func viewDidLoad() { @@ -37,6 +39,38 @@ class ViewController: UIViewController { setupSession() // Do any additional setup after loading the view. } + + + private func callApi() { + let URL_USER_REGISTER = "https://uat.hmgwebservices.com/LiveCareApi/DoctorApp/GetSessionStatus" + let headers: HTTPHeaders = [ + "Content-Type":"application/json", + "Accept":"application/json", + + ] + + let parameters = [ + "VC_ID": 3245, + "TokenID": "hfkjshdf347r8743", + "generalid": "Cs2020@2016$2958", + "DoctorId" : 1485 , + ] 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! NSDictionary + self.callBack?.sessionNotResponded(res: ["sessionStatus":jsonData, "callResponse":"CallNotRespond"]) + + } + self.sessionDisconnect(); + self.timer.invalidate() + } + //getting json value from the server + + } + } func setupButtons() { perform(#selector(hideControlButtons), with: nil, afterDelay: 3) @@ -115,7 +149,7 @@ class ViewController: UIViewController { if (session != nil) { print("disconnecting....") session!.disconnect(nil) - callBack?.sessionDone() + callBack?.sessionDone(res:["callResponse":"CallEnd"]) dismiss(animated: true) return } @@ -214,10 +248,10 @@ class ViewController: UIViewController { seconds -= 1 //This will decrement(count down)the seconds. print(seconds) if seconds == 0 { - sessionDisconnect(); - timer.invalidate() + callApi() } + } } @@ -330,7 +364,7 @@ extension ViewController: OTSessionDelegate { if let connectionId = connection?.connectionId { print("session connectionCreated (\(connectionId))") } - + isUserConnect = true timer.invalidate() } From d5825ccb85cfab99510687dc45bf9d7b0ff97948 Mon Sep 17 00:00:00 2001 From: Mohammad ALjammal Date: Sun, 5 Jul 2020 16:54:07 +0300 Subject: [PATCH 5/8] fix issues --- .../kotlin/com/example/doctor_app_flutter/MainActivity.kt | 2 +- lib/models/livecare/session_status_model.dart | 2 +- lib/screens/dashboard_screen.dart | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt b/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt index 1a203368..4aada798 100644 --- a/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/doctor_app_flutter/MainActivity.kt @@ -86,7 +86,7 @@ class MainActivity : FlutterFragmentActivity(), MethodChannel.MethodCallHandler val jsonRes = gson.toJson(result) callResponse["sessionStatus"] = jsonRes - this.result?.success(gson.toJson(callResponse)) + this.result?.success(callResponse) } if (resultCode == Activity.RESULT_CANCELED) { val callResponse : HashMap = HashMap() diff --git a/lib/models/livecare/session_status_model.dart b/lib/models/livecare/session_status_model.dart index ad9a1142..7e7a3e43 100644 --- a/lib/models/livecare/session_status_model.dart +++ b/lib/models/livecare/session_status_model.dart @@ -10,7 +10,7 @@ class SessionStatusModel { this.result, this.sessionStatus}); - SessionStatusModel.fromJson(Map json) { + SessionStatusModel.fromJson(Map json) { isAuthenticated = json['IsAuthenticated']; messageStatus = json['MessageStatus']; result = json['Result']; diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 52ecf34f..5ce0973d 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -111,7 +111,9 @@ class _DashboardScreenState extends State { kApiKey: '46803224', onFailure: (String error) {}, onCallEnd: () {}, - callNotRespond: (SessionStatusModel sessionStatusModel) {}); + callNotRespond: (SessionStatusModel sessionStatusModel) { + var asd =""; + }); // showCupertinoPicker( From 6ea72f5ffaf1f38b9e7301c9bb6cb2a57c77d15c Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 5 Jul 2020 16:54:41 +0300 Subject: [PATCH 6/8] make things daynamic --- ios/Runner/AppDelegate.swift | 13 +++++-- ios/Runner/VideoViewController.swift | 34 +++++++++++++------ lib/models/livecare/session_status_model.dart | 2 +- lib/util/VideoChannel.dart | 6 ++-- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index e4992e16..0a5ed700 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -38,7 +38,11 @@ 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 + self.openVideoChat(result: result,kApiKey: kApiKey!,kSessionId:kSessionId!,kToken: kToken!, appLang: appLang!, vC_ID: vC_ID!,tokenID: tokenID!,generalId: generalId!,doctorId: doctorId!) } default: result(FlutterMethodNotImplemented) @@ -52,7 +56,7 @@ import OpenTok - 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) { let storyboard = UIStoryboard(name: "Main", bundle: nil) let identifier = "ViewControllerNav" @@ -61,6 +65,11 @@ 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.callBack = self videoVC.navigationController?.setNavigationBarHidden(true, animated: false) navVC.modalPresentationStyle = .fullScreen diff --git a/ios/Runner/VideoViewController.swift b/ios/Runner/VideoViewController.swift index d9834fea..3ff2eef5 100644 --- a/ios/Runner/VideoViewController.swift +++ b/ios/Runner/VideoViewController.swift @@ -23,6 +23,11 @@ class ViewController: UIViewController { var kToken:String = "" + var VC_ID: Int = 0 + var TokenID: String = "" + var generalid : String = "" + var DoctorId: Int = 0 + var callBack: ICallProtocol? var timer = Timer() var seconds = 30 @@ -41,7 +46,7 @@ class ViewController: UIViewController { } - private func callApi() { + private func getSessionStatus() { let URL_USER_REGISTER = "https://uat.hmgwebservices.com/LiveCareApi/DoctorApp/GetSessionStatus" let headers: HTTPHeaders = [ "Content-Type":"application/json", @@ -50,19 +55,27 @@ class ViewController: UIViewController { ] let parameters = [ - "VC_ID": 3245, - "TokenID": "hfkjshdf347r8743", - "generalid": "Cs2020@2016$2958", - "DoctorId" : 1485 , + "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! NSDictionary - self.callBack?.sessionNotResponded(res: ["sessionStatus":jsonData, "callResponse":"CallNotRespond"]) - + 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() @@ -140,7 +153,7 @@ class ViewController: UIViewController { } @IBAction func hangUp(_ sender: UIButton) { - + callBack?.sessionDone(res:["callResponse":"CallEnd"]) sessionDisconnect() } @@ -149,7 +162,6 @@ class ViewController: UIViewController { if (session != nil) { print("disconnecting....") session!.disconnect(nil) - callBack?.sessionDone(res:["callResponse":"CallEnd"]) dismiss(animated: true) return } @@ -248,7 +260,7 @@ class ViewController: UIViewController { seconds -= 1 //This will decrement(count down)the seconds. print(seconds) if seconds == 0 { - callApi() + getSessionStatus() } diff --git a/lib/models/livecare/session_status_model.dart b/lib/models/livecare/session_status_model.dart index ad9a1142..7e7a3e43 100644 --- a/lib/models/livecare/session_status_model.dart +++ b/lib/models/livecare/session_status_model.dart @@ -10,7 +10,7 @@ class SessionStatusModel { this.result, this.sessionStatus}); - SessionStatusModel.fromJson(Map json) { + SessionStatusModel.fromJson(Map json) { isAuthenticated = json['IsAuthenticated']; messageStatus = json['MessageStatus']; result = json['Result']; diff --git a/lib/util/VideoChannel.dart b/lib/util/VideoChannel.dart index 73b17930..9f4195af 100644 --- a/lib/util/VideoChannel.dart +++ b/lib/util/VideoChannel.dart @@ -1,5 +1,6 @@ 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'; @@ -30,9 +31,8 @@ class VideoChannel{ onCallEnd(); } else { - var asd = result['sessionStatus']; - var parsed = json.decode(result['sessionStatus']); - SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(parsed); + + SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(Platform.isIOS ?result['sessionStatus'] :json.decode(result['sessionStatus'])); callNotRespond(sessionStatusModel); } From 287bb20d12acda4877215f8e117161109984ca48 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 5 Jul 2020 17:10:56 +0300 Subject: [PATCH 7/8] fix issues ios --- .../ui/VideoCallActivity.java | 2 +- lib/screens/dashboard_screen.dart | 17 ++--------- lib/screens/live_care/video_call.dart | 28 ++++++++++++++----- lib/util/VideoChannel.dart | 15 +++++----- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java index adc32d38..2e7c32a7 100644 --- a/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java +++ b/android/app/src/main/java/com/example/doctor_app_flutter/ui/VideoCallActivity.java @@ -183,7 +183,7 @@ public class VideoCallActivity extends AppCompatActivity implements EasyPermissi videoCallPresenter.callClintConnected(sessionStatusModel); } }; - mConnectedHandler.postDelayed(mConnectedRunnable, 7 * 1000); + mConnectedHandler.postDelayed(mConnectedRunnable, 30 * 1000); } diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 5ce0973d..fe41913b 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -105,20 +105,9 @@ class _DashboardScreenState extends State { children: [ InkWell( onTap: () async { - await VideoChannel.openVideoCallScreen( - kToken: 'T1==cGFydG5lcl9pZD00NjgwMzIyNCZzaWc9NWRhNmExMzU4ZDViZGU3OTA5NDY4ODRhNzI4ZGUxZTRmMjZmNzcwMjpzZXNzaW9uX2lkPTFfTVg0ME5qZ3dNekl5Tkg1LU1UVTVNelk0TXpZek9EWXdNMzV1Y0V4V1lWUlZTbTVIY3k5dVdHWm1NMWxPYTNjelpIVi1mZyZjcmVhdGVfdGltZT0xNTkzNjgzNjYyJm5vbmNlPTAuODAxMzMzMzUxMDQwNzE5NSZyb2xlPXB1Ymxpc2hlciZleHBpcmVfdGltZT0xNTk2Mjc1NjYyJmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9', - kSessionId: '1_MX40NjgwMzIyNH5-MTU5MzY4MzYzODYwM35ucExWYVRVSm5Hcy9uWGZmM1lOa3czZHV-fg', - kApiKey: '46803224', - onFailure: (String error) {}, - onCallEnd: () {}, - callNotRespond: (SessionStatusModel sessionStatusModel) { - var asd =""; - }); - - -// showCupertinoPicker( -// context: context, -// actionList: authProvider.doctorsClinicList); + showCupertinoPicker( + context: context, + actionList: authProvider.doctorsClinicList); }, child: Container( margin: diff --git a/lib/screens/live_care/video_call.dart b/lib/screens/live_care/video_call.dart index 02abdc5b..4d7d4170 100644 --- a/lib/screens/live_care/video_call.dart +++ b/lib/screens/live_care/video_call.dart @@ -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 { _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) { diff --git a/lib/util/VideoChannel.dart b/lib/util/VideoChannel.dart index 9f4195af..bf255b54 100644 --- a/lib/util/VideoChannel.dart +++ b/lib/util/VideoChannel.dart @@ -10,7 +10,7 @@ class VideoChannel{ /// channel name static const _channel = const MethodChannel("Dr.cloudSolution/videoCall"); static openVideoCallScreen( - {kApiKey, kSessionId, kToken, callDuration, warningDuration, Function() onCallEnd , Function(SessionStatusModel sessionStatusModel) callNotRespond ,Function(String error) onFailure}) async { + {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 = await _channel.invokeMethod( @@ -21,22 +21,21 @@ class VideoChannel{ "kToken": kToken, "appLang": "en", "baseUrl": BASE_URL, - "VC_ID": 3245, - "TokenID": "hfkjshdf347r8743", - "generalId": 'Cs2020@2016\$2958', - "DoctorId": 1485 , + "VC_ID": vcId, + "TokenID": tokenID, + "generalId": generalId, + "DoctorId": doctorId , }, ); if(result['callResponse'] == 'CallEnd') { onCallEnd(); } else { - SessionStatusModel sessionStatusModel = SessionStatusModel.fromJson(Platform.isIOS ?result['sessionStatus'] :json.decode(result['sessionStatus'])); - callNotRespond(sessionStatusModel); + onCallNotRespond(sessionStatusModel); } - } on PlatformException catch (e) { + } catch (e) { onFailure(e.toString()); } From 7c7916af5a82c491040477d7999445bdf5f6d420 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 5 Jul 2020 18:12:59 +0300 Subject: [PATCH 8/8] make base url daynamic --- ios/Runner/AppDelegate.swift | 8 +++++--- ios/Runner/VideoViewController.swift | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 0a5ed700..4512a3b1 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -42,7 +42,9 @@ import OpenTok let tokenID = arguments!["TokenID"] as? String let generalId = arguments!["generalId"] as? String let doctorId = arguments!["DoctorId"] as? Int - self.openVideoChat(result: result,kApiKey: kApiKey!,kSessionId:kSessionId!,kToken: kToken!, appLang: appLang!, vC_ID: vC_ID!,tokenID: tokenID!,generalId: generalId!,doctorId: doctorId!) + 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) @@ -56,7 +58,7 @@ import OpenTok - private func openVideoChat(result: FlutterResult,kApiKey: String, kSessionId: String,kToken: String,appLang:String, vC_ID: Int,tokenID:String,generalId:String,doctorId:Int) { + 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" @@ -69,7 +71,7 @@ import OpenTok videoVC.generalid = generalId videoVC.TokenID = tokenID videoVC.DoctorId = doctorId - + videoVC.baseUrl = baseUrl videoVC.callBack = self videoVC.navigationController?.setNavigationBarHidden(true, animated: false) navVC.modalPresentationStyle = .fullScreen diff --git a/ios/Runner/VideoViewController.swift b/ios/Runner/VideoViewController.swift index 3ff2eef5..8609c018 100644 --- a/ios/Runner/VideoViewController.swift +++ b/ios/Runner/VideoViewController.swift @@ -27,6 +27,7 @@ class ViewController: UIViewController { var TokenID: String = "" var generalid : String = "" var DoctorId: Int = 0 + var baseUrl:String = "" var callBack: ICallProtocol? var timer = Timer() @@ -47,7 +48,7 @@ class ViewController: UIViewController { private func getSessionStatus() { - let URL_USER_REGISTER = "https://uat.hmgwebservices.com/LiveCareApi/DoctorApp/GetSessionStatus" + let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/GetSessionStatus" let headers: HTTPHeaders = [ "Content-Type":"application/json", "Accept":"application/json",