From aad071ac6702607666c8576f09a0dc01dee95e5a Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Mon, 25 Oct 2021 15:14:36 +0300 Subject: [PATCH] Packages and Offers apply token --- .../opentok/LocalVideo.kt | 58 ++++++ .../diplomaticquarterapp/opentok/OpenTok.kt | 48 +++-- .../opentok/{Video.kt => RemoteVideo.kt} | 29 ++- .../utils/OpenTokPlatformBridge.kt | 10 +- ios/Flutter/.last_build_id | 2 +- ios/Runner.xcodeproj/project.pbxproj | 8 + ios/Runner/OpenTok/OpenTok.swift | 130 ++----------- .../OpenTok/OpenTokLocalVideoFactory.swift | 91 +++++++++ .../OpenTok/OpenTokRemoteVideoFactory.swift | 91 +++++++++ lib/config/config.dart | 4 +- lib/config/localized_values.dart | 4 + .../requests/CreateCustomerRequestModel.dart | 35 +++- lib/core/service/client/base_app_client.dart | 64 ++++++- .../PackagesOffersServices.dart | 75 ++++++-- .../PackagesOffersViewModel.dart | 2 + lib/main.dart | 1 + .../fragments/home_page_fragment2.dart | 4 +- .../CreateCustomerDailogPage.dart | 12 +- .../packages_offers/OfferAndPackagesPage.dart | 50 ++++- lib/pages/webRTC/OpenTok/OpenTok.dart | 180 ++++++++++++++++++ .../webRTC/OpenTok/OpenTokPlatformBridge.dart | 86 +++++++++ lib/routes.dart | 8 +- lib/uitl/translations_delegate_base.dart | 1 + .../offers_packages/PackagesCartItemCard.dart | 2 +- 24 files changed, 783 insertions(+), 212 deletions(-) create mode 100644 android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/LocalVideo.kt rename android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/{Video.kt => RemoteVideo.kt} (53%) create mode 100644 ios/Runner/OpenTok/OpenTokLocalVideoFactory.swift create mode 100644 ios/Runner/OpenTok/OpenTokRemoteVideoFactory.swift create mode 100644 lib/pages/webRTC/OpenTok/OpenTok.dart create mode 100644 lib/pages/webRTC/OpenTok/OpenTokPlatformBridge.dart diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/LocalVideo.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/LocalVideo.kt new file mode 100644 index 00000000..cfebfe65 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/LocalVideo.kt @@ -0,0 +1,58 @@ +package com.ejada.hmg.opentok + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import android.widget.LinearLayout +import com.ejada.hmg.R +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory + +class LocalVideoFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) { + + companion object { + private lateinit var view: LocalVideoPlatformView + + fun getViewInstance(context: Context): LocalVideoPlatformView { + if(!this::view.isInitialized) { + view = LocalVideoPlatformView(context) + } + + return view + } + } + + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + return getViewInstance(context) + } +} + +class LocalVideoPlatformView(context: Context) : PlatformView { + private val videoContainer: LocalVideoContainer = LocalVideoContainer(context) + + val container get() = videoContainer.publisherContainer + + override fun getView(): View { + return videoContainer + } + + override fun dispose() {} +} + +class LocalVideoContainer @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0, + defStyleRes: Int = 0 +) : LinearLayout(context, attrs, defStyle, defStyleRes) { + + var publisherContainer: FrameLayout private set + + init { + val view = LayoutInflater.from(context).inflate(R.layout.local_video, this, true) + publisherContainer = view.findViewById(R.id.publisher_container) + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/OpenTok.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/OpenTok.kt index 5606343f..0cdc3751 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/OpenTok.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/OpenTok.kt @@ -1,25 +1,17 @@ -package com.example.basic_video_chat_flutter +package com.ejada.hmg.opentok import android.content.Context import android.os.Handler import android.os.Looper -import android.util.AttributeSet import android.util.Log -import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.FrameLayout -import android.widget.LinearLayout import com.opentok.android.* import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -enum class SdkState { +enum class OpenTokSDKState { LOGGED_OUT, LOGGED_IN, WAIT, @@ -27,15 +19,21 @@ enum class SdkState { } class OpenTok(private var context: Context, private var flutterEngine: FlutterEngine){ - private lateinit var opentokVideoPlatformView: OpentokVideoPlatformView + private lateinit var remoteVideoPlatformView: RemoteVideoPlatformView + private lateinit var localVideoPlatformView: LocalVideoPlatformView init { - opentokVideoPlatformView = OpentokVideoFactory.getViewInstance(context) + remoteVideoPlatformView = RemoteVideoFactory.getViewInstance(context) flutterEngine .platformViewsController .registry - // opentok-video-container is a custom platform-view-type - .registerViewFactory("opentok-video-container", OpentokVideoFactory()) + .registerViewFactory("remote-video-container", RemoteVideoFactory()) + + localVideoPlatformView = LocalVideoFactory.getViewInstance(context) + flutterEngine + .platformViewsController + .registry + .registerViewFactory("local-video-container", LocalVideoFactory()) } private var session: Session? = null @@ -54,15 +52,15 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn renderer?.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL) view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) - opentokVideoPlatformView.publisherContainer.addView(view) + localVideoPlatformView.container.addView(view) } - notifyFlutter(SdkState.LOGGED_IN) + notifyFlutter(OpenTokSDKState.LOGGED_IN) session.publish(publisher) } override fun onDisconnected(session: Session) { - notifyFlutter(SdkState.LOGGED_OUT) + notifyFlutter(OpenTokSDKState.LOGGED_OUT) } override fun onStreamReceived(session: Session, stream: Stream) { @@ -76,7 +74,7 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn setSubscriberListener(subscriberListener) session.subscribe(this) - opentokVideoPlatformView.subscriberContainer.addView(view) + remoteVideoPlatformView.container.addView(view) } } } @@ -90,13 +88,13 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn if (subscriber != null) { subscriber = null - opentokVideoPlatformView.subscriberContainer.removeAllViews() + remoteVideoPlatformView.container.removeAllViews() } } override fun onError(session: Session, opentokError: OpentokError) { Log.d("MainActivity", "Session error: " + opentokError.message) - notifyFlutter(SdkState.ERROR) + notifyFlutter(OpenTokSDKState.ERROR) } } @@ -111,7 +109,7 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn override fun onError(publisherKit: PublisherKit, opentokError: OpentokError) { Log.d("MainActivity", "PublisherKit onError: " + opentokError.message) - notifyFlutter(SdkState.ERROR) + notifyFlutter(OpenTokSDKState.ERROR) } } @@ -122,12 +120,12 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn override fun onDisconnected(subscriberKit: SubscriberKit) { Log.d("MainActivity", "onDisconnected: Subscriber disconnected. Stream: " + subscriberKit.stream.streamId) - notifyFlutter(SdkState.LOGGED_OUT) + notifyFlutter(OpenTokSDKState.LOGGED_OUT) } override fun onError(subscriberKit: SubscriberKit, opentokError: OpentokError) { Log.d("MainActivity", "SubscriberKit onError: " + opentokError.message) - notifyFlutter(SdkState.ERROR) + notifyFlutter(OpenTokSDKState.ERROR) } } @@ -137,7 +135,7 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn val sessionId = requireNotNull(call.argument("sessionId")) val token = requireNotNull(call.argument("token")) - notifyFlutter(SdkState.WAIT) + notifyFlutter(OpenTokSDKState.WAIT) session = Session.Builder(context, apiKey, sessionId).build() session?.setSessionListener(sessionListener) session?.connect(token) @@ -161,7 +159,7 @@ class OpenTok(private var context: Context, private var flutterEngine: FlutterEn result.success("") } - private fun notifyFlutter(state: SdkState) { + private fun notifyFlutter(state: OpenTokSDKState) { Handler(Looper.getMainLooper()).post { MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "OpenTok-Platform-Bridge") .invokeMethod("updateState", state.toString()) diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/Video.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/RemoteVideo.kt similarity index 53% rename from android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/Video.kt rename to android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/RemoteVideo.kt index 0153908a..9116a1e8 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/Video.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/opentok/RemoteVideo.kt @@ -1,4 +1,4 @@ -package com.example.basic_video_chat_flutter +package com.ejada.hmg.opentok import android.content.Context import android.util.AttributeSet @@ -6,18 +6,19 @@ import android.view.LayoutInflater import android.view.View import android.widget.FrameLayout import android.widget.LinearLayout +import com.ejada.hmg.R import io.flutter.plugin.common.StandardMessageCodec import io.flutter.plugin.platform.PlatformView import io.flutter.plugin.platform.PlatformViewFactory -class OpentokVideoFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) { +class RemoteVideoFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) { companion object { - private lateinit var view: OpentokVideoPlatformView + private lateinit var view: RemoteVideoPlatformView - fun getViewInstance(context: Context): OpentokVideoPlatformView { + fun getViewInstance(context: Context): RemoteVideoPlatformView { if(!this::view.isInitialized) { - view = OpentokVideoPlatformView(context) + view = RemoteVideoPlatformView(context) } return view @@ -29,11 +30,10 @@ class OpentokVideoFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) { } } -class OpentokVideoPlatformView(context: Context) : PlatformView { - private val videoContainer: OpenTokVideoContainer = OpenTokVideoContainer(context) +class RemoteVideoPlatformView(context: Context) : PlatformView { + private val videoContainer: RemoteVideoContainer = RemoteVideoContainer(context) - val subscriberContainer get() = videoContainer.subscriberContainer - val publisherContainer get() = videoContainer.publisherContainer + val container get() = videoContainer.subscriberContainer override fun getView(): View { return videoContainer @@ -42,22 +42,17 @@ class OpentokVideoPlatformView(context: Context) : PlatformView { override fun dispose() {} } -class OpenTokVideoContainer @JvmOverloads constructor( +class RemoteVideoContainer @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0, defStyleRes: Int = 0 ) : LinearLayout(context, attrs, defStyle, defStyleRes) { - var subscriberContainer: FrameLayout - private set - - var publisherContainer: FrameLayout - private set + var subscriberContainer: FrameLayout private set init { - val view = LayoutInflater.from(context).inflate(R.layout.view_video, this, true) + val view = LayoutInflater.from(context).inflate(R.layout.remote_video, this, true) subscriberContainer = view.findViewById(R.id.subscriber_container) - publisherContainer = view.findViewById(R.id.publisher_container) } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/OpenTokPlatformBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/OpenTokPlatformBridge.kt index 29ded185..6ac62546 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/OpenTokPlatformBridge.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/utils/OpenTokPlatformBridge.kt @@ -1,16 +1,8 @@ package com.ejada.hmg.utils -import android.content.Context -import android.net.wifi.WifiManager -import android.util.Log import com.ejada.hmg.MainActivity -import com.ejada.hmg.hmgwifi.HMG_Guest -import com.ejada.hmg.hmgwifi.HMG_Internet -import com.ejada.hmg.geofence.GeoZoneModel -import com.ejada.hmg.geofence.HMG_Geofence -import com.example.basic_video_chat_flutter.OpenTok +import com.ejada.hmg.opentok.OpenTok import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel diff --git a/ios/Flutter/.last_build_id b/ios/Flutter/.last_build_id index 3aa2cd1e..53427e0c 100644 --- a/ios/Flutter/.last_build_id +++ b/ios/Flutter/.last_build_id @@ -1 +1 @@ -3f3d14a0ae775b56806906c2cb14a1f0 \ No newline at end of file +3f8c659591fcdd0e47e3895f74af395c \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9505487e..6c02c983 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 301C79AE27200D9F0016307B /* OpenTokRemoteVideoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */; }; + 301C79B027200DED0016307B /* OpenTokLocalVideoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */; }; 306FE6C8271D790C002D6EFC /* OpenTokPlatformBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */; }; 306FE6CB271D8B73002D6EFC /* OpenTok.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306FE6CA271D8B73002D6EFC /* OpenTok.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; @@ -52,6 +54,8 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokRemoteVideoFactory.swift; sourceTree = ""; }; + 301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokLocalVideoFactory.swift; sourceTree = ""; }; 306FE6C7271D790C002D6EFC /* OpenTokPlatformBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTokPlatformBridge.swift; sourceTree = ""; }; 306FE6CA271D8B73002D6EFC /* OpenTok.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenTok.swift; sourceTree = ""; }; 308FEC658188F7D588BE7580 /* 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 = ""; }; @@ -107,6 +111,8 @@ isa = PBXGroup; children = ( 306FE6CA271D8B73002D6EFC /* OpenTok.swift */, + 301C79AF27200DED0016307B /* OpenTokLocalVideoFactory.swift */, + 301C79AD27200D9F0016307B /* OpenTokRemoteVideoFactory.swift */, ); path = OpenTok; sourceTree = ""; @@ -396,11 +402,13 @@ E91B5396256AAA6500E96549 /* GlobalHelper.swift in Sources */, E923EFD4258645C100E3E751 /* HMG_Geofence.swift in Sources */, E923EFD62587443800E3E751 /* HMGPlatformBridge.swift in Sources */, + 301C79AE27200D9F0016307B /* OpenTokRemoteVideoFactory.swift in Sources */, E9F7623B25922BCE00FB5CCF /* FlutterConstants.swift in Sources */, 306FE6CB271D8B73002D6EFC /* OpenTok.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, E9E27168256E3A4000F49B69 /* LocalizedFromFlutter.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 301C79B027200DED0016307B /* OpenTokLocalVideoFactory.swift in Sources */, E9C8C136256BACDA00EFFB62 /* HMG_Guest.swift in Sources */, E91B539B256AAA6500E96549 /* HMG_Internet.swift in Sources */, E91B5397256AAA6500E96549 /* Extensions.swift in Sources */, diff --git a/ios/Runner/OpenTok/OpenTok.swift b/ios/Runner/OpenTok/OpenTok.swift index 3cb7fdbe..9cc0b79a 100644 --- a/ios/Runner/OpenTok/OpenTok.swift +++ b/ios/Runner/OpenTok/OpenTok.swift @@ -7,6 +7,7 @@ import Foundation import OpenTok +import UIKit enum SdkState: String { case loggedOut = "LOGGED_OUT" @@ -18,16 +19,21 @@ enum SdkState: String { class OpenTok : NSObject{ private var mainViewController:MainFlutterVC! private var registrar:FlutterPluginRegistrar? + var methodChannel: FlutterMethodChannel? + init(mainViewController:MainFlutterVC, registrar:FlutterPluginRegistrar?){ self.mainViewController = mainViewController + self.methodChannel = FlutterMethodChannel(name: "OpenTok-Platform-Bridge", binaryMessenger: mainViewController.binaryMessenger) self.registrar = registrar - - let factory = OpentokVideoFactory(messenger: registrar!.messenger()) - registrar?.register(factory, withId: "opentok-video-container") + + let remoteVDOFactory = OpenTokRemoteVideoFactory(messenger: registrar!.messenger()) + registrar?.register(remoteVDOFactory, withId: "remote-video-container") + + let localVDOFactory = OpenTokLocalVideoFactory(messenger: registrar!.messenger()) + registrar?.register(localVDOFactory, withId: "local-video-container") } var otSession: OTSession? - var vonageChannel: FlutterMethodChannel? var subscriber: OTSubscriber? lazy var publisher: OTPublisher = { @@ -86,7 +92,7 @@ class OpenTok : NSObject{ func notifyFlutter(state: SdkState) { - vonageChannel?.invokeMethod("updateState", arguments: state.rawValue) + methodChannel?.invokeMethod("updateState", arguments: state.rawValue) } } @@ -106,10 +112,10 @@ extension OpenTok: OTSessionDelegate { if let pubView = self.publisher.view { pubView.frame = CGRect(x: 0, y: 0, width: 200, height: 300) - if OpentokVideoFactory.view == nil { - OpentokVideoFactory.viewToAddPub = pubView + if OpenTokLocalVideoFactory.view == nil { + OpenTokLocalVideoFactory.viewToAddPub = pubView } else { - OpentokVideoFactory.view?.addPublisherView(pubView) + OpenTokLocalVideoFactory.view?.addPublisherView(pubView) } } } @@ -156,12 +162,12 @@ extension OpenTok: OTSubscriberDelegate { print("Subscriber connected") if let subView = self.subscriber?.view { - subView.frame = CGRect(x: 0, y: 0, width: 200, height: 300) + subView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) - if OpentokVideoFactory.view == nil { - OpentokVideoFactory.viewToAddSub = subView + if OpenTokRemoteVideoFactory.view == nil { + OpenTokRemoteVideoFactory.viewToAddSub = subView } else { - OpentokVideoFactory.view?.addSubscriberView(subView) + OpenTokRemoteVideoFactory.view?.addSubscriberView(subView) } } } @@ -171,103 +177,3 @@ extension OpenTok: OTSubscriberDelegate { } } - -class OpentokVideoFactory: NSObject, FlutterPlatformViewFactory { - static var view: OpentokVideoPlatformView? - - static var viewToAddSub: UIView? - static var viewToAddPub: UIView? - - static func getViewInstance( - frame: CGRect, - viewId: Int64, - args: Any?, - messenger: FlutterBinaryMessenger? - ) -> OpentokVideoPlatformView{ - if(view == nil) { - view = OpentokVideoPlatformView() - if viewToAddSub != nil { - view?.addSubscriberView(viewToAddSub!) - } - if viewToAddPub != nil { - view?.addPublisherView(viewToAddPub!) - } - } - - return view! - } - - private var messenger: FlutterBinaryMessenger - - init(messenger: FlutterBinaryMessenger) { - self.messenger = messenger - super.init() - } - - func create( - withFrame frame: CGRect, - viewIdentifier viewId: Int64, - arguments args: Any? - ) -> FlutterPlatformView { - return OpentokVideoFactory.getViewInstance( - frame: frame, - viewId: viewId, - args: args, - messenger: messenger) - } -} - -class OpentokVideoPlatformView: NSObject, FlutterPlatformView { - private let videoContainer: OpenTokVideoContainer - - override init() { - videoContainer = OpenTokVideoContainer() - super.init() - } - - public func addSubscriberView(_ view: UIView) { - videoContainer.addSubscriberView(view) - } - - public func addPublisherView(_ view: UIView) { - videoContainer.addPublisherView(view) - } - - func view() -> UIView { - return videoContainer - } -} - -final class OpenTokVideoContainer: UIView { - private let subscriberContainer = UIView() - private let publisherContainer = UIView() - - init() { - super.init(frame: .zero) - addSubview(subscriberContainer) - addSubview(publisherContainer) - } - - - public func addSubscriberView(_ view: UIView) { - subscriberContainer.addSubview(view) - } - - public func addPublisherView(_ view: UIView) { - publisherContainer.addSubview(view) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - let width = frame.width - let height = frame.height - - let videoWidth = width / 2 - subscriberContainer.frame = CGRect(x: 0, y: 0, width: videoWidth, height: height) - publisherContainer.frame = CGRect(x: videoWidth, y: 0, width: videoWidth, height: height) - } -} diff --git a/ios/Runner/OpenTok/OpenTokLocalVideoFactory.swift b/ios/Runner/OpenTok/OpenTokLocalVideoFactory.swift new file mode 100644 index 00000000..361b482d --- /dev/null +++ b/ios/Runner/OpenTok/OpenTokLocalVideoFactory.swift @@ -0,0 +1,91 @@ +// +// OpenTokLocalVideoFactory.swift +// Runner +// +// Created by Zohaib Iqbal Kambrani on 20/10/2021. +// + +import Foundation + +class OpenTokLocalVideoFactory: NSObject, FlutterPlatformViewFactory { + static var view: LocalVideoPlatformView? + + static var viewToAddPub: UIView? + + static func getViewInstance( + frame: CGRect, + viewId: Int64, + args: Any?, + messenger: FlutterBinaryMessenger? + ) -> LocalVideoPlatformView{ + if(view == nil) { + view = LocalVideoPlatformView() + if viewToAddPub != nil { + view?.addPublisherView(viewToAddPub!) + } + } + + return view! + } + + private var messenger: FlutterBinaryMessenger + + init(messenger: FlutterBinaryMessenger) { + self.messenger = messenger + super.init() + } + + func create( + withFrame frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any? + ) -> FlutterPlatformView { + return OpenTokLocalVideoFactory.getViewInstance( + frame: frame, + viewId: viewId, + args: args, + messenger: messenger) + } +} + +class LocalVideoPlatformView: NSObject, FlutterPlatformView { + private let videoContainer: LocalVideoContainer + + override init() { + videoContainer = LocalVideoContainer() + super.init() + } + + public func addPublisherView(_ view: UIView) { + videoContainer.addPublisherView(view) + } + + func view() -> UIView { + return videoContainer + } +} + +final class LocalVideoContainer: UIView { + private let publisherContainer = UIView() + + init() { + super.init(frame: .zero) + addSubview(publisherContainer) + } + + public func addPublisherView(_ view: UIView) { + publisherContainer.addSubview(view) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + let width = frame.width + let height = frame.height + + publisherContainer.frame = CGRect(x: 0, y: 0, width: width, height: height) + } +} diff --git a/ios/Runner/OpenTok/OpenTokRemoteVideoFactory.swift b/ios/Runner/OpenTok/OpenTokRemoteVideoFactory.swift new file mode 100644 index 00000000..50dcf695 --- /dev/null +++ b/ios/Runner/OpenTok/OpenTokRemoteVideoFactory.swift @@ -0,0 +1,91 @@ +// +// OpenTokRemoteVideoFactory.swift +// Runner +// +// Created by Zohaib Iqbal Kambrani on 20/10/2021. +// + +import Foundation + +class OpenTokRemoteVideoFactory: NSObject, FlutterPlatformViewFactory { + static var view: RemoteVideoPlatformView? + + static var viewToAddSub: UIView? + + static func getViewInstance( + frame: CGRect, + viewId: Int64, + args: Any?, + messenger: FlutterBinaryMessenger? + ) -> RemoteVideoPlatformView{ + if(view == nil) { + view = RemoteVideoPlatformView() + if viewToAddSub != nil { + view?.addSubscriberView(viewToAddSub!) + } + } + + return view! + } + + private var messenger: FlutterBinaryMessenger + + init(messenger: FlutterBinaryMessenger) { + self.messenger = messenger + super.init() + } + + func create( + withFrame frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any? + ) -> FlutterPlatformView { + return OpenTokRemoteVideoFactory.getViewInstance( + frame: frame, + viewId: viewId, + args: args, + messenger: messenger) + } +} + +class RemoteVideoPlatformView: NSObject, FlutterPlatformView { + private let videoContainer: RemoteVideoContainer + + override init() { + videoContainer = RemoteVideoContainer() + super.init() + } + + public func addSubscriberView(_ view: UIView) { + videoContainer.addSubscriberView(view) + } + + func view() -> UIView { + return videoContainer + } +} + +final class RemoteVideoContainer: UIView { + private let subscriberContainer = UIView() + + init() { + super.init(frame: .zero) + addSubview(subscriberContainer) + } + + + public func addSubscriberView(_ view: UIView) { + subscriberContainer.addSubview(view) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + let width = frame.width + let height = frame.height + subscriberContainer.frame = CGRect(x: 0, y: 0, width: width, height: height) + } +} diff --git a/lib/config/config.dart b/lib/config/config.dart index acb8d80a..c1622769 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -6,8 +6,10 @@ import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; const MAX_SMALL_SCREEN = 660; // PACKAGES and OFFERS -const EXA_CART_API_BASE_URL = 'http://10.200.101.75:9000'; +const EXA_CART_API_BASE_URL = 'https://mdlaboratories.com/offersdiscounts'; +// const EXA_CART_API_BASE_URL = 'http://10.200.101.75:9000'; const PACKAGES_CATEGORIES = '/api/categories'; +const PACKAGES_TOKEN = '/api/token'; const PACKAGES_PRODUCTS = '/api/products'; const PACKAGES_CUSTOMER = '/api/customers'; const PACKAGES_SHOPPING_CART = '/api/shopping_cart_items'; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index c7a60f96..3bf6e2b2 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -822,6 +822,10 @@ const Map localizedValues = { }, "failedToAccessHmgServices": {"en": "Connected with HMG Network,\n\nBut failed to access HMG services", "ar": "Connected with HMG Network,\n\nBut failed to access HMG services"}, "offerAndPackages": {"en": "Offers and Packages", "ar": "العروض والباقات"}, + "offerAndPackagesDetails": { + "en": "This service allows you to view all HMG Offers:", + "ar": "This service allows you to view all HMG Offers:" + }, "InvoiceNo": {"en": "Invoice No", "ar": "رقم الفاتورة"}, "InvoiceDate": {"en": "Invoice Date", "ar": "تاريخ الفاتورة"}, "SpecialResult": {"en": " Special Result", "ar": "نتيجة خاصة"}, diff --git a/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart b/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart index 116545bd..9cc3d3b9 100644 --- a/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart +++ b/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart @@ -1,20 +1,41 @@ +import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:flutter/cupertino.dart'; class PackagesCustomerRequestModel { + String username; + String first_name; + String last_name; String email; - String phoneNumber; + String phone; + String national_id; + String date_of_birth; - PackagesCustomerRequestModel({@required this.email, @required this.phoneNumber}); + + PackagesCustomerRequestModel.fromUser(AuthenticatedUser user){ + this.username = "${user.patientID}"; + this.first_name = user.firstName; + this.last_name = user.lastName; + this.email = user.emailAddress; + this.phone = user.mobileNumber; + this.national_id = user.patientIdentificationNo; + this.date_of_birth = user.dateofBirth; + } Map json() { return { "customer" : { - "email": email, - "addresses": [{ - "email": email, - "phone_number": phoneNumber - }] + "email": email ?? '', + "username": username ?? '', + "national_id": national_id ?? '', + "phone": phone ?? '', + "date_of_birth": date_of_birth ?? '', + "first_name": first_name ?? '', + "last_name": last_name ?? '', + // "addresses": [{ + // "email": email, + // "phone_number": phoneNumber + // }] } }; } diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index ac96e35e..6ec6e8af 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -1,9 +1,11 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io' show Platform; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/service/medical/vital_sign_service.dart'; +import 'package:diplomaticquarterapp/core/service/packages_offers/PackagesOffersServices.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Appointments/toDoCountProviderModel.dart'; import 'package:diplomaticquarterapp/pages/appUpdatePage/app_update_page.dart'; @@ -468,7 +470,7 @@ class BaseAppClient { simplePost( String fullUrl, { - Map body, + Map body, Map headers, Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure, }) async { @@ -476,14 +478,17 @@ class BaseAppClient { print("URL Query String: $url"); if (await Utils.checkConnection()) { + headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.post( url.trim(), body: json.encode(body), - headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, + headers: headers, ); final int statusCode = response.statusCode; print("statusCode :$statusCode"); + if(await handleUnauthorized(statusCode, forUrl: fullUrl)) + simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); @@ -495,7 +500,7 @@ class BaseAppClient { } } - simpleGet(String fullUrl, {Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure, Map queryParams}) async { + simpleGet(String fullUrl, {Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure, Map queryParams, Map headers}) async { String url = fullUrl; print("URL Query String: $url"); @@ -507,13 +512,16 @@ class BaseAppClient { } if (await Utils.checkConnection()) { + headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.get( url.trim(), - headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, + headers: headers, ); final int statusCode = response.statusCode; print("statusCode :$statusCode"); + if(await handleUnauthorized(statusCode, forUrl: fullUrl)) + simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); @@ -525,19 +533,22 @@ class BaseAppClient { } } - simplePut(String fullUrl, {Map body, Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure}) async { + simplePut(String fullUrl, {Map body, Map headers, Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure}) async { String url = fullUrl; print("URL Query String: $url"); if (await Utils.checkConnection()) { + headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.put( url.trim(), body: json.encode(body), - headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, + headers: headers, ); final int statusCode = response.statusCode; print("statusCode :$statusCode"); + if(await handleUnauthorized(statusCode, forUrl: fullUrl)) + simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); @@ -549,7 +560,7 @@ class BaseAppClient { } } - simpleDelete(String fullUrl, {Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure, Map queryParams}) async { + simpleDelete(String fullUrl, {Function(dynamic response, int statusCode) onSuccess, Function(String error, int statusCode) onFailure, Map queryParams, Map headers}) async { String url = fullUrl; print("URL Query String: $url"); @@ -561,13 +572,16 @@ class BaseAppClient { } if (await Utils.checkConnection()) { + headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'}); final response = await http.delete( url.trim(), - headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, + headers: headers, ); final int statusCode = response.statusCode; print("statusCode :$statusCode"); + if(await handleUnauthorized(statusCode, forUrl: fullUrl)) + simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); @@ -579,6 +593,15 @@ class BaseAppClient { } } + Future handleUnauthorized(int statusCode, {String forUrl}) async{ + if(forUrl.startsWith(EXA_CART_API_BASE_URL) && statusCode == 401) { + final token = await generatePackagesToken(); + packagesAuthHeader['Authorization'] = 'Bearer $token'; + return token != null && (token is String); + } + return false; + } + logout() async { await sharedPref.remove(LOGIN_TOKEN_ID); await sharedPref.remove(PHARMACY_CUSTOMER_ID); @@ -770,4 +793,29 @@ class BaseAppClient { onFailure(e.toString(), -1); } } + + + + Future generatePackagesToken() async { + var url = EXA_CART_API_BASE_URL + PACKAGES_TOKEN; + var body = { + "api_client": { + "client_id": "a4ab6be4-424f-4836-b032-46caed88e184", + "client_secret": "3c1a3e07-4a40-4510-9fb0-ee5f0a72752c" + } + }; + String token; + final completer = Completer(); + simplePost(url, body: body, headers: {}, onSuccess: (dynamic stringResponse, int statusCode) { + if (statusCode == 200) { + var jsonResponse = json.decode(stringResponse); + token = jsonResponse['auth_token']; + completer.complete(); + } + }, onFailure: (String error, int statusCode) { + completer.complete(); + }); + await completer.future; + return token; + } } diff --git a/lib/core/service/packages_offers/PackagesOffersServices.dart b/lib/core/service/packages_offers/PackagesOffersServices.dart index 479f59d3..dbc32029 100644 --- a/lib/core/service/packages_offers/PackagesOffersServices.dart +++ b/lib/core/service/packages_offers/PackagesOffersServices.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:diplomaticquarterapp/config/config.dart'; +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/model/ResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/CreateCustomerRequestModel.dart'; @@ -13,10 +14,15 @@ import 'package:diplomaticquarterapp/core/model/packages_offers/responses/Packag import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/order_response_model.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart'; +import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:flutter/cupertino.dart'; +var packagesAuthHeader = {'Authorization' : ''}; class OffersAndPackagesServices extends BaseService { + AuthenticatedUser patientUser; List categoryList = List(); List productList = List(); List latestOffersList = List(); @@ -25,13 +31,14 @@ class OffersAndPackagesServices extends BaseService { List cartItemList = List(); String cartItemCount = ""; + PackagesCustomerResponseModel customer; Future> getAllCategories(OffersCategoriesRequestModel request) async { Future errorThrow; var url = EXA_CART_API_BASE_URL + PACKAGES_CATEGORIES; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['categories'].forEach((json) { @@ -39,7 +46,6 @@ class OffersAndPackagesServices extends BaseService { }); } }, onFailure: (String error, int statusCode) { - log(error); }, queryParams: request.toFlatMap()); return categoryList; @@ -52,7 +58,7 @@ class OffersAndPackagesServices extends BaseService { productList = List(); var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['products'].forEach((json) { @@ -60,7 +66,6 @@ class OffersAndPackagesServices extends BaseService { }); } }, onFailure: (String error, int statusCode) { - log(error); }, queryParams: request.toFlatMap()); return productList; @@ -69,7 +74,7 @@ class OffersAndPackagesServices extends BaseService { Future> getLatestOffers({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['products'].forEach((json) { @@ -86,7 +91,7 @@ class OffersAndPackagesServices extends BaseService { Future> getBestSellers({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['products'].forEach((json) { @@ -103,7 +108,7 @@ class OffersAndPackagesServices extends BaseService { Future> getBanners({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['products'].forEach((json) { @@ -121,6 +126,22 @@ class OffersAndPackagesServices extends BaseService { var finished = 0; var totalCalls = 3; + final auth_token = await baseAppClient.generatePackagesToken(); + if(auth_token == null){ + throw 'Something went wrong while authentication, Please try again letter'; + } + packagesAuthHeader["Authorization"] = 'Bearer $auth_token'; + + + // Check and Create Customer + if(patientUser != null){ + customer = await getCurrentCustomer(context: context, showLoading: showLoading); + if(customer == null){ + createCustomer(PackagesCustomerRequestModel.fromUser(patientUser), context: context); + } + } + + completedAll(){ finished++; @@ -162,24 +183,42 @@ class OffersAndPackagesServices extends BaseService { _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_CUSTOMER; - await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ - _hideLoading(context, showLoading); + await baseAppClient.simplePost(url, headers: packagesAuthHeader, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ var jsonResponse = json.decode(stringResponse); var customerJson = jsonResponse['customers'].first; customer = PackagesCustomerResponseModel.fromJson(customerJson); }, onFailure: (String error, int statusCode){ - _hideLoading(context, showLoading); errorThrow = Future.error(error); log(error); }); + _hideLoading(context, showLoading); await Future.delayed(Duration(seconds: 1)); return errorThrow ?? customer; } + Future getCurrentCustomer({@required BuildContext context, bool showLoading = true}) async{ + if(customer != null) + return Future.value(customer); + + _showLoading(context, showLoading); + var url = EXA_CART_API_BASE_URL + PACKAGES_CUSTOMER + "/username/${patientUser.patientID}"; + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode){ + var jsonResponse = json.decode(stringResponse); + var customerJson = jsonResponse['customers'].first; + customer = PackagesCustomerResponseModel.fromJson(customerJson); + + }, onFailure: (String error, int statusCode){ + log(error); + }); + + _hideLoading(context, showLoading); + return customer; + } + // -------------------- @@ -191,7 +230,7 @@ class OffersAndPackagesServices extends BaseService { cartItemList.clear(); _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART + '/${customer.id}'; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { _hideLoading(context, showLoading); var jsonResponse = json.decode(stringResponse); @@ -216,7 +255,7 @@ class OffersAndPackagesServices extends BaseService { _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART; - await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ + await baseAppClient.simplePost(url, headers: packagesAuthHeader, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ _hideLoading(context, showLoading); var jsonResponse = json.decode(stringResponse); @@ -237,7 +276,7 @@ class OffersAndPackagesServices extends BaseService { _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART + '/$cartItemID'; - await baseAppClient.simplePut(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ + await baseAppClient.simplePut(url, headers: packagesAuthHeader, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ _hideLoading(context, showLoading); var jsonResponse = json.decode(stringResponse); @@ -257,7 +296,7 @@ class OffersAndPackagesServices extends BaseService { _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART + '/$cartItemID'; - await baseAppClient.simpleDelete(url, onSuccess: (dynamic stringResponse, int statusCode){ + await baseAppClient.simpleDelete(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode){ _hideLoading(context, showLoading); // var jsonResponse = json.decode(stringResponse); @@ -280,8 +319,8 @@ class OffersAndPackagesServices extends BaseService { "order": { "customer_id" : customer.id, "billing_address": { - "email": customer.email, - "phone_number": customer.addresses.first.phoneNumber + "email": patientUser.emailAddress, + "phone_number": patientUser.mobileNumber }, "payment_method_system_name": "Payments.PayFort", "payment_option": paymentOption @@ -291,7 +330,7 @@ class OffersAndPackagesServices extends BaseService { int order_id; _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_ORDERS; - await baseAppClient.simplePost(url, body: jsonBody, onSuccess: (dynamic stringResponse, int statusCode){ + await baseAppClient.simplePost(url, headers: packagesAuthHeader, body: jsonBody, onSuccess: (dynamic stringResponse, int statusCode){ _hideLoading(context, showLoading); var jsonResponse = json.decode(stringResponse); @@ -312,7 +351,7 @@ class OffersAndPackagesServices extends BaseService { _showLoading(context, showLoading); var url = EXA_CART_API_BASE_URL + PACKAGES_ORDERS + '/$id'; - await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + await baseAppClient.simpleGet(url, headers: packagesAuthHeader, onSuccess: (dynamic stringResponse, int statusCode) { _hideLoading(context, showLoading); var jsonResponse = json.decode(stringResponse); diff --git a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart index ad950b5d..1b68e9d7 100644 --- a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart +++ b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart @@ -4,6 +4,7 @@ import 'package:diplomaticquarterapp/core/model/packages_offers/responses/Packag import 'package:diplomaticquarterapp/core/service/packages_offers/PackagesOffersServices.dart'; import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart'; import 'package:diplomaticquarterapp/locator.dart'; +import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; class OfferCategoriesViewModel extends BaseViewModel{ OffersAndPackagesServices service = locator(); @@ -14,6 +15,7 @@ class OfferCategoriesViewModel extends BaseViewModel{ class PackagesViewModel extends BaseViewModel { OffersAndPackagesServices service = locator(); + List get categoryList => service.categoryList; List get productList => service.productList; List get latestOffersList => service.latestOffersList; diff --git a/lib/main.dart b/lib/main.dart index 49d37919..230e38dd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -144,6 +144,7 @@ class _MyApp extends State { // ), // ), initialRoute: SPLASH, + // initialRoute: OPENTOK_CALL_PAGE, // initialRoute: PACKAGES_OFFERS, // initialRoute: PACKAGES_ORDER_COMPLETED, routes: routes, diff --git a/lib/pages/landing/fragments/home_page_fragment2.dart b/lib/pages/landing/fragments/home_page_fragment2.dart index c6807ebb..7fcfecae 100644 --- a/lib/pages/landing/fragments/home_page_fragment2.dart +++ b/lib/pages/landing/fragments/home_page_fragment2.dart @@ -1,5 +1,6 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/core/service/packages_offers/PackagesOffersServices.dart'; import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart'; @@ -280,7 +281,8 @@ class _HomePageFragment2State extends State { flex: 1, child: InkWell( onTap: () { - Navigator.of(context).push(MaterialPageRoute(builder: (context) => PackagesHomePage())); + final user = projectViewModel.user; + Navigator.of(context).push(MaterialPageRoute(builder: (context) => PackagesHomePage(user))); }, child: Container( width: double.infinity, diff --git a/lib/pages/packages_offers/CreateCustomerDailogPage.dart b/lib/pages/packages_offers/CreateCustomerDailogPage.dart index d7a98a64..70291a88 100644 --- a/lib/pages/packages_offers/CreateCustomerDailogPage.dart +++ b/lib/pages/packages_offers/CreateCustomerDailogPage.dart @@ -152,12 +152,12 @@ class _CreateCustomerDialogPageState extends State wit createCustomer() async{ setState(() => _enableInput = false); - loading(true); - var request = PackagesCustomerRequestModel(email: _emailTextController.text, phoneNumber: _phoneTextController.text); - viewModel().service - .createCustomer(request, context: context, showLoading: false) - .then((value) => success()) - .catchError((error) => showError(error)); + // loading(true); + // var request = PackagesCustomerRequestModel(email: _emailTextController.text, phoneNumber: _phoneTextController.text); + // viewModel().service + // .createCustomer(request, context: context, showLoading: false) + // .then((value) => success()) + // .catchError((error) => showError(error)); } diff --git a/lib/pages/packages_offers/OfferAndPackagesPage.dart b/lib/pages/packages_offers/OfferAndPackagesPage.dart index b3b0605d..4005f835 100644 --- a/lib/pages/packages_offers/OfferAndPackagesPage.dart +++ b/lib/pages/packages_offers/OfferAndPackagesPage.dart @@ -1,16 +1,22 @@ import 'package:after_layout/after_layout.dart'; import 'package:carousel_slider/carousel_slider.dart'; +import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/model/ImagesInfo.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/packages_offers/PackagesOffersViewModel.dart'; +import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; +import 'package:diplomaticquarterapp/models/Authentication/select_device_imei_res.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/ClinicOfferAndPackagesPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/CreateCustomerDailogPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackageDetailPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesCartPage.dart'; +import 'package:diplomaticquarterapp/routes.dart'; +import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart' as auth; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart' as utils; @@ -26,8 +32,8 @@ import 'package:flutter_material_pickers/flutter_material_pickers.dart'; dynamic languageID; class PackagesHomePage extends StatefulWidget { - dynamic offersModel; - PackagesHomePage({@required this.offersModel}); + final AuthenticatedUser user; + PackagesHomePage(this.user); @override _PackagesHomePageState createState() => _PackagesHomePageState(); @@ -47,6 +53,7 @@ class _PackagesHomePageState extends State with AfterLayoutMix @override void afterFirstLayout(BuildContext context) async{ + viewModel.service.patientUser = widget.user; viewModel.service.loadOffersPackagesDataForMainPage(context: context, completion: (){ setState((){}); }); @@ -81,9 +88,11 @@ class _PackagesHomePageState extends State with AfterLayoutMix } onProductCartClick(PackagesResponseModel product) async { - if(viewModel.service.customer == null) - viewModel.service.customer = await CreateCustomerDialogPage(context: context).show(); - + if(viewModel.service.customer == null) { + // viewModel.service.customer = await CreateCustomerDialogPage(context: context).show(); + loginCheck(context); + } + if(viewModel.service.customer != null) { var request = AddProductToCartRequestModel(product_id: product.id, customer_id: viewModel.service.customer.id); await viewModel.service.addProductToCart(request, context: context).then((response){ @@ -104,6 +113,8 @@ class _PackagesHomePageState extends State with AfterLayoutMix return appScaffold = AppScaffold( + description: TranslationBase.of(context).offerAndPackagesDetails, + imagesInfo: [ImagesInfo(imageAr: 'https://hmgwebservices.com/Images/MobileApp/CMC/ar/0.png', imageEn: 'https://hmgwebservices.com/Images/MobileApp/CMC/en/0.png')], appBarTitle: TranslationBase.of(context).offerAndPackages, isShowAppBar: true, isPharmacy: false, @@ -409,4 +420,33 @@ class _PackagesHomePageState extends State with AfterLayoutMix )), ); } + + + + loginCheck(context) async { + var data = await sharedPref.getObject(IMEI_USER_DATA); + sharedPref.remove(REGISTER_DATA_FOR_LOGIIN); + if (data != null) { + Navigator.of(context).pushNamed(CONFIRM_LOGIN); + } else { + GifLoaderDialogUtils.showMyDialog(context); + + auth.AuthProvider().selectDeviceImei(DEVICE_TOKEN).then((SelectDeviceIMEIRES value) { + GifLoaderDialogUtils.hideDialog(context); + if (value != null) { + sharedPref.setObject(IMEI_USER_DATA, value); + Navigator.of(context).pushNamed(CONFIRM_LOGIN); + } else { + Navigator.of(context).pushNamed( + WELCOME_LOGIN, + ); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + Navigator.of(context).pushNamed( + WELCOME_LOGIN, + ); + }); + } + } } diff --git a/lib/pages/webRTC/OpenTok/OpenTok.dart b/lib/pages/webRTC/OpenTok/OpenTok.dart new file mode 100644 index 00000000..7abcfca5 --- /dev/null +++ b/lib/pages/webRTC/OpenTok/OpenTok.dart @@ -0,0 +1,180 @@ +import 'package:diplomaticquarterapp/pages/conference/draggable_publisher.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; + +import 'OpenTokPlatformBridge.dart'; + + +class OpenTokConnectCallPage extends StatefulWidget{ + final String sessionId; + final String token; + final String apiKey; + OpenTokConnectCallPage({@required this.sessionId, @required this.token, @required this.apiKey}); + + @override + State createState() => OpenTokState(); + +} + +class OpenTokState extends State{ + OpenTokPlatformBridge openTokPlatform; + OpenTokSDKState sdkState = OpenTokSDKState.LOGGED_OUT; + + initOpenTok(){ + openTokPlatform = OpenTokPlatformBridge.init( + apiKey: widget.apiKey, + sessionID: widget.sessionId, + token: widget.token, + onStateChange: (state) { + setState(() => sdkState = state); + } + ); + } + + @override + void initState() { + initOpenTok(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + actions: [ + TextButton(onPressed: (){ + initOpenTok(); + }, child: Icon(Icons.connect_without_contact_outlined, color: Colors.green,)) + ], + ), + body: Column( + children: [ + Expanded( + child: Stack( + children: [ + if(sdkState == OpenTokSDKState.LOGGED_IN) + ...platformVideoViews(), + + + if(sdkState == OpenTokSDKState.LOGGED_OUT) + Center(child: Text("Logged Out"),), + + if(sdkState == OpenTokSDKState.ERROR) + Center(child: Text("Error opening session"),), + + if(sdkState == OpenTokSDKState.WAIT) + Center(child: CircularProgressIndicator(),), + + if(sdkState == OpenTokSDKState.ON_CALL) + Container(), + ], + ), + ), + Row( + children: [ + Expanded( + child: ElevatedButton( + child: Text('Mute Video') ,onPressed: () => openTokPlatform.toggleVideo() + ), + ), + SizedBox(width: 20,), + Expanded( + child: ElevatedButton( + child: Text('Mute Audio') ,onPressed: () => openTokPlatform.toggleAudio() + ), + ), + SizedBox(width: 20,), + Expanded( + child: ElevatedButton( + child: Text('Change Camera') ,onPressed: () => openTokPlatform.swapCamera() + ), + ), + ], + ) + ], + ), + ); + } + + bool remoteVideoOnFull = true; + List platformVideoViews(){ + return [ + SizedBox( + width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, + child: remoteVideoOnFull ? remotePlatformVideoView() : localPlatformVideoView() + ), + + DraggablePublisher( + onButtonBarHeight: ((double)async*{}(50)), + onButtonBarVisible: ((bool)async*{}(true)), + availableScreenSize: MediaQuery.of(context).size, + child: InkWell( + child: (remoteVideoOnFull ? localPlatformVideoView() : remotePlatformVideoView()), + onTap: (){ + print(''); + }, + ), + ) + ]; + } + + Widget localPlatformVideoView(){ + return PlatformViewLink( + viewType: 'local-video-container', // custom platform-view-type + surfaceFactory: + (BuildContext context, PlatformViewController controller) { + return AndroidViewSurface( + controller: controller, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + + onCreatePlatformView: (PlatformViewCreationParams params) { + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: 'local-video-container', + // custom platform-view-type, + layoutDirection: TextDirection.ltr, + creationParams: {}, + creationParamsCodec: StandardMessageCodec(), + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, + ); + } + + Widget remotePlatformVideoView(){ + return PlatformViewLink( + viewType: 'remote-video-container', // custom platform-view-type + surfaceFactory: + (BuildContext context, PlatformViewController controller) { + return AndroidViewSurface( + controller: controller, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + onCreatePlatformView: (PlatformViewCreationParams params) { + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: 'remote-video-container', + // custom platform-view-type, + layoutDirection: TextDirection.ltr, + creationParams: {}, + creationParamsCodec: StandardMessageCodec(), + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, + ); + } + +} \ No newline at end of file diff --git a/lib/pages/webRTC/OpenTok/OpenTokPlatformBridge.dart b/lib/pages/webRTC/OpenTok/OpenTokPlatformBridge.dart new file mode 100644 index 00000000..bfdb8fb4 --- /dev/null +++ b/lib/pages/webRTC/OpenTok/OpenTokPlatformBridge.dart @@ -0,0 +1,86 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:permission_handler/permission_handler.dart'; + +enum OpenTokSDKState{ LOGGED_OUT, LOGGED_IN, WAIT, ON_CALL, ERROR } +final _platformMethodChannel = const MethodChannel('OpenTok-Platform-Bridge'); + +class OpenTokPlatformBridge{ + + + OpenTokSDKState _sdkState = OpenTokSDKState.LOGGED_OUT; + bool _publishAudio = true; + bool _publishVideo = true; + + final void Function(OpenTokSDKState) onStateChange; + + OpenTokPlatformBridge.init({@required String sessionID, @required String token, @required String apiKey, this.onStateChange}){ + _initSession({'apiKey':apiKey, 'sessionId':sessionID, 'token':token, }); + _platformMethodChannel.setMethodCallHandler(incomingMethodHadler); + } + + Future incomingMethodHadler(MethodCall methodCall) async { + switch (methodCall.method) { + case 'updateState': + { + var arguments = 'OpenTokSDKState.${methodCall.arguments}'; + _sdkState = OpenTokSDKState.values.firstWhere((v) { + return v.toString() == arguments; + }); + onStateChange(_sdkState); + } + break; + default: + throw MissingPluginException('notImplemented'); + } + } + + + Future _initSession(Map openTokCredentials) async { + await requestPermissions(); + try { + await _platformMethodChannel.invokeMethod('initSession', openTokCredentials); + } on PlatformException catch (e) { + print(e); + } + } + + Future makeCall() async { + try { + await requestPermissions(); + + await _platformMethodChannel.invokeMethod('makeCall'); + } on PlatformException catch (e) { + print(e); + } + } + + Future requestPermissions() async { + await [Permission.microphone, Permission.camera].request(); + } + + Future swapCamera() async { + try { + await _platformMethodChannel.invokeMethod('swapCamera'); + } on PlatformException catch (e) {} + } + + Future toggleAudio() async { + _publishAudio = !_publishAudio; + dynamic params = {'publishAudio': _publishAudio}; + + try { + await _platformMethodChannel.invokeMethod('publishAudio', params); + } on PlatformException catch (e) {} + } + + Future toggleVideo() async { + _publishVideo = !_publishVideo; + dynamic params = {'publishVideo': _publishVideo}; + + try { + await _platformMethodChannel.invokeMethod('toggleVideo', params); + } on PlatformException catch (e) {} + } +} diff --git a/lib/routes.dart b/lib/routes.dart index 5d4ebea4..a8d850e1 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -20,6 +20,7 @@ import 'package:diplomaticquarterapp/pages/settings/settings.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/info.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/select-gender.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/symtom-checker.dart'; +import 'package:diplomaticquarterapp/pages/webRTC/OpenTok/OpenTok.dart'; import 'package:diplomaticquarterapp/splashPage.dart'; const String INIT_ROUTE = '/'; @@ -45,6 +46,7 @@ const String PACKAGES_OFFERS = 'packages-offers'; const String PACKAGES_OFFERS_CART = 'packages-offers-cart'; const String PACKAGES_ORDER_COMPLETED = 'packages-offers-cart'; const String TEST_PAGE = 'test-page'; +const String OPENTOK_CALL_PAGE = 'OPENTOK_CALL_PAGE'; const String HEALTH_WEATHER = 'health-weather'; const APP_UPDATE = 'app-update'; @@ -66,11 +68,15 @@ var routes = { SYMPTOM_CHECKER_INFO: (_) => SymptomInfo(), SELECT_GENDER: (_) => SelectGender(), SETTINGS: (_) => Settings(), - PACKAGES_OFFERS: (_) => PackagesHomePage(), PACKAGES_OFFERS_CART: (_) => PackagesCartPage(), PACKAGES_ORDER_COMPLETED: (_) => PackageOrderCompletedPage(), TEST_PAGE: (_) => TestPage(), HEALTH_WEATHER: (_) => HealthWeatherIndicator(), APP_UPDATE: (_) => AppUpdatePage(), SETTINGS: (_) => Settings(), + OPENTOK_CALL_PAGE: (_) => OpenTokConnectCallPage( + apiKey: '46209962', + sessionId: '1_MX40NjIwOTk2Mn5-MTYzNDY0ODM3NDY2Nn5PcnpnNGM0R1Q3ODZ6UXlFQ01lMDF5YWJ-fg', + token: 'T1==cGFydG5lcl9pZD00NjIwOTk2MiZzaWc9Y2ZhZjMzZjA3MWFkMjkxN2JmYjEwZDkxYTRkOTdhN2NmNWE4YjMyYTpzZXNzaW9uX2lkPTFfTVg0ME5qSXdPVGsyTW41LU1UWXpORFkwT0RNM05EWTJObjVQY25wbk5HTTBSMVEzT0RaNlVYbEZRMDFsTURGNVlXSi1mZyZjcmVhdGVfdGltZT0xNjM0NjQ4Mzc1Jm5vbmNlPTAuNzczMzcxNDUxMDgzMjQyMyZyb2xlPW1vZGVyYXRvciZleHBpcmVfdGltZT0xNjM0NzM0Nzc1JmluaXRpYWxfbGF5b3V0X2NsYXNzX2xpc3Q9' + ), }; diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 09b50632..4d014a2f 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -1387,6 +1387,7 @@ class TranslationBase { String get enablingWifi => localizedValues['enablingWifi'][locale.languageCode]; String get offerAndPackages => localizedValues['offerAndPackages'][locale.languageCode]; + String get offerAndPackagesDetails => localizedValues['offerAndPackagesDetails'][locale.languageCode]; String get invoiceNo => localizedValues['InvoiceNo'][locale.languageCode]; diff --git a/lib/widgets/offers_packages/PackagesCartItemCard.dart b/lib/widgets/offers_packages/PackagesCartItemCard.dart index 3ae405c6..c59c08cd 100644 --- a/lib/widgets/offers_packages/PackagesCartItemCard.dart +++ b/lib/widgets/offers_packages/PackagesCartItemCard.dart @@ -82,8 +82,8 @@ class PackagesCartItemCardState extends State { left: 10, child: Row( children: [ - _totalPrice((widget.itemModel.product.price * widget.itemModel.quantity), context: context), _totalLabel(context: context), + _totalPrice((widget.itemModel.product.price * widget.itemModel.quantity), context: context), ], ), )