no message
@ -1,51 +0,0 @@
|
||||
package com.cloud.diplomaticquarterapp
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import com.cloud.diplomaticquarterapp.utils.PlatformBridge
|
||||
import com.wang.avi.AVLoadingIndicatorView
|
||||
import io.flutter.embedding.android.FlutterView
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.embedding.engine.dart.DartExecutor
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.view.FlutterMain
|
||||
import org.jetbrains.anko.find
|
||||
import java.util.ArrayList
|
||||
|
||||
open class BaseActivity : AppCompatActivity() {
|
||||
|
||||
lateinit var loadingView:RelativeLayout
|
||||
lateinit var lblLoadingView:TextView
|
||||
lateinit var avLoadingView:AVLoadingIndicatorView
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun setContentView(layoutResID: Int) {
|
||||
super.setContentView(layoutResID)
|
||||
|
||||
loadingView = find(R.id.loadingView)
|
||||
lblLoadingView = find(R.id.lblLoadingView)
|
||||
avLoadingView = find(R.id.avLoadingView)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
package com.cloud.diplomaticquarterapp
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import com.cloud.diplomaticquarterapp.utils.PlatformBridge
|
||||
import io.flutter.embedding.android.FlutterView
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.embedding.engine.dart.DartExecutor
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.view.FlutterMain
|
||||
import java.util.ArrayList
|
||||
|
||||
class FlutterMainActivity : BaseActivity() {
|
||||
|
||||
|
||||
private var flutterView: FlutterView? = null
|
||||
companion object {
|
||||
private var flutterEngine: FlutterEngine? = null
|
||||
|
||||
private lateinit var instance:FlutterMainActivity
|
||||
fun getInstance() : FlutterMainActivity{
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// to get and check returned intent
|
||||
private fun getArgsFromIntent(intent: Intent): Array<String>? {
|
||||
// Before adding more entries to this list, consider that arbitrary
|
||||
// Android applications can generate intents with extra data and that
|
||||
// there are many security-sensitive args in the binary.
|
||||
val args = ArrayList<String>()
|
||||
if (intent.getBooleanExtra("trace-startup", false)) {
|
||||
args.add("--trace-startup")
|
||||
}
|
||||
if (intent.getBooleanExtra("start-paused", false)) {
|
||||
args.add("--start-paused")
|
||||
}
|
||||
if (intent.getBooleanExtra("enable-dart-profiling", false)) {
|
||||
args.add("--enable-dart-profiling")
|
||||
}
|
||||
if (!args.isEmpty()) {
|
||||
return args.toTypedArray()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val args = getArgsFromIntent(intent)
|
||||
|
||||
// check if flutterEngine is null
|
||||
if (flutterEngine == null) {
|
||||
println(args)
|
||||
flutterEngine = FlutterEngine(this, args)
|
||||
flutterEngine!!.dartExecutor.executeDartEntrypoint(
|
||||
// set which of dart methode will be used here
|
||||
DartExecutor.DartEntrypoint(FlutterMain.findAppBundlePath(), "main")
|
||||
)
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_flutter_main)
|
||||
|
||||
flutterView = findViewById(R.id.flutterView)
|
||||
flutterView!!.attachToFlutterEngine(flutterEngine!!)
|
||||
|
||||
PlatformBridge(flutterEngine!!.dartExecutor.binaryMessenger, this).create()
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
flutterEngine!!.lifecycleChannel.appIsResumed()
|
||||
instance = this
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
flutterEngine!!.lifecycleChannel.appIsInactive()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
flutterEngine!!.lifecycleChannel.appIsPaused()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
flutterView!!.detachFromFlutterEngine()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,23 @@
|
||||
package com.cloud.diplomaticquarterapp
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.util.Log
|
||||
import androidx.annotation.NonNull;
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
import com.cloud.diplomaticquarterapp.utils.FlutterText
|
||||
import com.cloud.diplomaticquarterapp.utils.PlatformBridge
|
||||
import io.flutter.embedding.android.FlutterFragmentActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugins.GeneratedPluginRegistrant
|
||||
|
||||
class MainActivity: FlutterFragmentActivity() {
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
// Create Flutter Platform Bridge
|
||||
PlatformBridge(flutterEngine.dartExecutor.binaryMessenger, this).create()
|
||||
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
package com.cloud.diplomaticquarterapp.hmgwifi
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.wifi.WifiConfiguration
|
||||
import android.net.wifi.WifiInfo
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.cloud.diplomaticquarterapp.MainActivity
|
||||
import com.cloud.diplomaticquarterapp.utils.FlutterText
|
||||
import com.cloud.diplomaticquarterapp.utils.HMGUtils
|
||||
|
||||
|
||||
class HMG_Guest(context: MainActivity) {
|
||||
private var wifiManager: WifiManager? = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
|
||||
private var connectivityManager: ConnectivityManager? = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||
private var context = context
|
||||
|
||||
private val TAG = "HMG_Guest"
|
||||
private val TEST = false
|
||||
private var SSID = """"HMG-MobileApp""""
|
||||
|
||||
private lateinit var completionListener: ((status: Boolean, message: String) -> Unit)
|
||||
|
||||
fun completionOnUiThread(status: Boolean, message: String){
|
||||
context.runOnUiThread {
|
||||
completionListener(status, message)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpful:
|
||||
* http://stackoverflow.com/questions/8818290/how-to-connect-to-a-specific-wifi-network-in-android-programmatically
|
||||
*/
|
||||
fun connectToHMGGuestNetwork(completion: (status: Boolean, message: String) -> Unit) {
|
||||
wifiManager?.let { wm ->
|
||||
completionListener = completion
|
||||
|
||||
if (!wm.isWifiEnabled){
|
||||
wm.isWifiEnabled = true
|
||||
HMGUtils.popFlutterText(context,"enablingWifi");
|
||||
HMGUtils.timer(2000,false){
|
||||
connect()
|
||||
}
|
||||
}else{
|
||||
connect()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun connect(){
|
||||
val security = "OPEN"
|
||||
val networkPass = ""
|
||||
Log.d(TAG, "Connecting to SSID \"$SSID\" with password \"$networkPass\" and with security \"$security\" ...")
|
||||
|
||||
// You need to create WifiConfiguration instance like this:
|
||||
val conf = WifiConfiguration()
|
||||
conf.SSID = SSID
|
||||
conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
|
||||
conf.networkId = ssidToNetworkId(SSID)
|
||||
|
||||
val wm = wifiManager!!
|
||||
|
||||
if (conf.networkId == -1) {
|
||||
wm.addNetwork(conf)
|
||||
} else {
|
||||
Log.v(TAG, "WiFi found - updating it.\n")
|
||||
wm.updateNetwork(conf)
|
||||
}
|
||||
|
||||
conf.networkId = ssidToNetworkId(SSID)
|
||||
Log.d(TAG, "Network ID: ${conf.networkId}")
|
||||
|
||||
val networkIdToConnect = conf.networkId
|
||||
if (networkIdToConnect >= 0) {
|
||||
Log.v(TAG, "Start connecting to $SSID Wifi...")
|
||||
|
||||
// We disable the network before connecting, because if this was the last connection before
|
||||
// a disconnect(), this will not reconnect.
|
||||
wm.disableNetwork(networkIdToConnect)
|
||||
val result = wm.enableNetwork(networkIdToConnect, true)
|
||||
if(result){
|
||||
HMGUtils.timer(8000,false){
|
||||
if(wm.getConnectionInfo().getSSID() == SSID){
|
||||
FlutterText.with("successConnectingHmgNetwork"){ localized ->
|
||||
completionOnUiThread(true, localized)
|
||||
}
|
||||
}else{
|
||||
errorConnecting()
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
errorConnecting()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}else{
|
||||
Log.v(TAG, "Cannot connect to $SSID network")
|
||||
errorConnecting()
|
||||
}
|
||||
}
|
||||
|
||||
private fun errorConnecting(){
|
||||
FlutterText.with("errorConnectingHmgNetwork"){ localized ->
|
||||
completionOnUiThread(false, localized)
|
||||
}
|
||||
}
|
||||
|
||||
// If CompileSDK is greater and equals to APILevel 29
|
||||
private fun connectNewer(wm:WifiManager){
|
||||
|
||||
// Log.e(TAG, "connection wifi Q")
|
||||
//
|
||||
// val wifiNetworkSpecifier: WifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
|
||||
// .setSsid(ssid)
|
||||
// .setWpa2Passphrase(password)
|
||||
// .build()
|
||||
//
|
||||
// val networkRequest: NetworkRequest = NetworkRequest.Builder()
|
||||
// .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
// .setNetworkSpecifier(wifiNetworkSpecifier)
|
||||
// .build()
|
||||
//
|
||||
// var connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
// var networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
// override fun onAvailable(network: Network) {
|
||||
// super.onAvailable(network)
|
||||
// connectivityManager.bindProcessToNetwork(network)
|
||||
// Log.e(TAG, "onAvailable")
|
||||
// }
|
||||
//
|
||||
// override fun onLosing(network: Network, maxMsToLive: Int) {
|
||||
// super.onLosing(network, maxMsToLive)
|
||||
// Log.e(TAG, "onLosing")
|
||||
// }
|
||||
//
|
||||
// override fun onLost(network: Network) {
|
||||
// super.onLost(network)
|
||||
// Log.e(TAG, "onLosing")
|
||||
// Log.e(TAG, "losing active connection")
|
||||
// }
|
||||
//
|
||||
// override fun onUnavailable() {
|
||||
// super.onUnavailable()
|
||||
// Log.e(TAG, "onUnavailable")
|
||||
// }
|
||||
// }
|
||||
// connectivityManager.requestNetwork(networkRequest, networkCallback)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method takes a given String, searches the current list of configured WiFi
|
||||
* networks, and returns the networkId for the network if the SSID matches. If not,
|
||||
* it returns -1.
|
||||
*/
|
||||
private fun ssidToNetworkId(ssid: String): Int {
|
||||
val currentNetworks = wifiManager!!.configuredNetworks
|
||||
var networkId = -1
|
||||
|
||||
// For each network in the list, compare the SSID with the given one
|
||||
for (test in currentNetworks) {
|
||||
if (test.SSID == ssid) {
|
||||
networkId = test.networkId
|
||||
break
|
||||
}
|
||||
}
|
||||
return networkId
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
package com.cloud.diplomaticquarterapp
|
||||
package com.cloud.diplomaticquarterapp.utils
|
||||
|
||||
class API {
|
||||
companion object{
|
||||
private val BASE = "https://uat.hmgwebservices.com"
|
||||
private val SERVICE = "Services/Patients.svc/REST"
|
||||
|
||||
val WIFI_CREDENTIALS = "$BASE/$SERVICE/Hmg_SMS_Get_By_ProjectID_And_PatientID"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.cloud.diplomaticquarterapp.utils
|
||||
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.Result
|
||||
|
||||
class FlutterText{
|
||||
|
||||
companion object{
|
||||
fun with(key:String, completion:(String)->Unit){
|
||||
HMGUtils.getPlatformChannel().invokeMethod("localizedValue",key, object:MethodChannel.Result{
|
||||
override fun success(result: Any?) {
|
||||
val localized = result as String?
|
||||
if (localized != null){
|
||||
completion(localized)
|
||||
}else{
|
||||
completion(key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun error(errorCode: String?, errorMessage: String?, errorDetails: Any?) {
|
||||
completion(key)
|
||||
require(false){
|
||||
"'localizedValue' $errorMessage"
|
||||
}
|
||||
}
|
||||
|
||||
override fun notImplemented() {
|
||||
require(false){
|
||||
"'localizedValue' method not implemented at flutter"
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".FlutterMainActivity">
|
||||
|
||||
<io.flutter.embedding.android.FlutterView
|
||||
android:background="#FFFFFF"
|
||||
android:id="@+id/flutterView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<include layout="@layout/loading_view" android:visibility="gone"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/loadingView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#B3000000">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_margin="60dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.wang.avi.AVLoadingIndicatorView
|
||||
android:id="@+id/avLoadingView"
|
||||
style="@style/AVLoadingIndicatorView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="visible"
|
||||
app:indicatorColor="#4CAF50"
|
||||
app:indicatorName="BallScaleMultipleIndicator"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="w,1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lblLoadingView"
|
||||
android:textSize="12sp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@ -1 +0,0 @@
|
||||
<resources></resources>
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 445 B |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 644 B After Width: | Height: | Size: 475 B |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 475 B |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 606 B |
|
After Width: | Height: | Size: 1.3 KiB |
@ -1 +1 @@
|
||||
c948a9de8d5fb4b791dcd366c30ba789
|
||||
4592a16118bc51c556d89309892cf794
|
||||
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="MainViewController" customModule="Runner" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iiB-nC-lWt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<connections>
|
||||
<segue destination="07U-8g-TSJ" kind="embed" id="0mo-Dk-ROY"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<view hidden="YES" alpha="0.90000000000000002" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zXb-Rz-9uK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BSu-be-Z1V" customClass="NVActivityIndicatorView" customModule="NVActivityIndicatorView">
|
||||
<rect key="frame" x="30" y="271" width="354" height="354"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="BSu-be-Z1V" secondAttribute="height" id="xGa-6d-w1R"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="typeName" value="ballGridBeat"/>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="color">
|
||||
<color key="value" red="0.34742879999999998" green="0.67916901529999996" blue="0.35416535329999999" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Wd-a2-Mgt">
|
||||
<rect key="frame" x="207" y="448" width="0.0" height="0.0"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="5Wd-a2-Mgt" firstAttribute="centerX" secondItem="BSu-be-Z1V" secondAttribute="centerX" id="4kE-50-iBD"/>
|
||||
<constraint firstItem="BSu-be-Z1V" firstAttribute="centerY" secondItem="zXb-Rz-9uK" secondAttribute="centerY" id="Ek3-H4-Tks"/>
|
||||
<constraint firstItem="5Wd-a2-Mgt" firstAttribute="centerY" secondItem="BSu-be-Z1V" secondAttribute="centerY" id="HTw-sL-a5g"/>
|
||||
<constraint firstItem="BSu-be-Z1V" firstAttribute="leading" secondItem="zXb-Rz-9uK" secondAttribute="leading" constant="30" id="Xas-Sl-2GU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="BSu-be-Z1V" secondAttribute="trailing" constant="30" id="jEB-tN-wf8"/>
|
||||
<constraint firstItem="BSu-be-Z1V" firstAttribute="centerX" secondItem="zXb-Rz-9uK" secondAttribute="centerX" id="yie-B7-m91"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="zXb-Rz-9uK" secondAttribute="trailing" id="DK6-ZR-0qc"/>
|
||||
<constraint firstItem="zXb-Rz-9uK" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="Msu-br-SZp"/>
|
||||
<constraint firstItem="zXb-Rz-9uK" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="W9Y-rE-AmS"/>
|
||||
<constraint firstAttribute="bottom" secondItem="zXb-Rz-9uK" secondAttribute="bottom" id="Zjo-yK-nHj"/>
|
||||
<constraint firstAttribute="trailing" secondItem="iiB-nC-lWt" secondAttribute="trailing" id="fcK-dc-bwG"/>
|
||||
<constraint firstItem="iiB-nC-lWt" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="idX-Jw-Ma9"/>
|
||||
<constraint firstItem="iiB-nC-lWt" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="uKn-QU-Ka7"/>
|
||||
<constraint firstAttribute="bottom" secondItem="iiB-nC-lWt" secondAttribute="bottom" id="zPu-2M-aXt"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="lblLoadingText" destination="5Wd-a2-Mgt" id="hGl-tJ-FUV"/>
|
||||
<outlet property="loading" destination="BSu-be-Z1V" id="4Nx-DH-P42"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="95.652173913043484" y="-21.428571428571427"/>
|
||||
</scene>
|
||||
<!--Main FlutterVC-->
|
||||
<scene sceneID="J1x-mD-FM4">
|
||||
<objects>
|
||||
<viewController id="07U-8g-TSJ" customClass="MainFlutterVC" customModule="Runner" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="dzx-FI-nKH"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="q3b-GI-trV"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="y53-TK-Smi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="jK2-7S-ThF" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1022" y="-21"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@ -1,96 +0,0 @@
|
||||
//
|
||||
// MainViewController.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by ZiKambrani on 26/03/1442 AH.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NVActivityIndicatorView
|
||||
|
||||
class MainViewController: UIViewController {
|
||||
@IBOutlet weak var lblLoadingText: UILabel!
|
||||
@IBOutlet weak var loading: NVActivityIndicatorView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
print(loading)
|
||||
}
|
||||
|
||||
func createBridge(flutterViewController:FlutterViewController){
|
||||
let connectHMGGuestWifi = FlutterMethodChannel(name: "HMG-Platform-Bridge",binaryMessenger: flutterViewController.binaryMessenger)
|
||||
connectHMGGuestWifi.setMethodCallHandler { (methodCall, result) in
|
||||
if methodCall.method == "connectHMGGuestWifi"{
|
||||
self.connectWifi(result: result)
|
||||
}else if methodCall.method == "loading"{
|
||||
self.showLoading(flutterMethodCall: methodCall)
|
||||
}else{
|
||||
|
||||
}
|
||||
print("")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Connect HMG-Guest Wifi and Internet
|
||||
func connectWifi(result: @escaping FlutterResult){
|
||||
showLoading(message: "Connecting...")
|
||||
HMG_GUEST.shared.connect { (status, message) in
|
||||
result(status ? 1 : 0)
|
||||
self.showLoading(false);
|
||||
if status{
|
||||
self.showMessage(title:"Congratulations", message:message)
|
||||
}else{
|
||||
self.showMessage(title:"Ooops,", message:message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Loading/Progress
|
||||
private func showLoading(flutterMethodCall:FlutterMethodCall){
|
||||
if let args = flutterMethodCall.arguments as? [Any],
|
||||
let message = args.first as? String, let show = args.last as? Bool{
|
||||
showLoading(message: message, show)
|
||||
}else{
|
||||
assert(true, "Missing or invalid arguments (Must have two argument 'String at 0' and Boolean at 1)")
|
||||
}
|
||||
}
|
||||
func showLoading(message:String = "Please wait...", _ show:Bool = true){
|
||||
DispatchQueue.main.async {
|
||||
if show{
|
||||
self.lblLoadingText.text = message
|
||||
self.loading.superview?.isHidden = false
|
||||
self.loading.startAnimating()
|
||||
}else{
|
||||
self.lblLoadingText.text = ""
|
||||
self.loading.superview?.isHidden = true
|
||||
self.loading.stopAnimating()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Message Dailog
|
||||
func showMessage(title:String, message:String){
|
||||
DispatchQueue.main.async {
|
||||
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert )
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .destructive, handler: nil))
|
||||
self.present(alert, animated: true) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if let flutterVC = segue.destination as? MainFlutterVC{
|
||||
flutterVC.root_view = self
|
||||
createBridge(flutterViewController: flutterVC)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
//
|
||||
// API.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by ZiKambrani on 04/04/1442 AH.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
fileprivate let DOMAIN = "https://uat.hmgwebservices.com"
|
||||
fileprivate let SERVICE = "Services/Patients.svc/REST"
|
||||
fileprivate let BASE_URL = "\(DOMAIN)/\(SERVICE)"
|
||||
|
||||
struct API {
|
||||
static let WIFI_CREDENTIALS = "\(BASE_URL)/Hmg_SMS_Get_By_ProjectID_And_PatientID"
|
||||
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
//
|
||||
// Extensions.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by ZiKambrani on 04/04/1442 AH.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
extension String{
|
||||
func toUrl() -> URL?{
|
||||
return URL(string: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Bundle {
|
||||
|
||||
func certificate(named name: String) -> SecCertificate {
|
||||
let cerURL = self.url(forResource: name, withExtension: "cer")!
|
||||
let cerData = try! Data(contentsOf: cerURL)
|
||||
let cer = SecCertificateCreateWithData(nil, cerData as CFData)!
|
||||
return cer
|
||||
}
|
||||
|
||||
func identity(named name: String, password: String) -> SecIdentity {
|
||||
let p12URL = self.url(forResource: name, withExtension: "p12")!
|
||||
let p12Data = try! Data(contentsOf: p12URL)
|
||||
|
||||
var importedCF: CFArray? = nil
|
||||
let options = [kSecImportExportPassphrase as String: password]
|
||||
let err = SecPKCS12Import(p12Data as CFData, options as CFDictionary, &importedCF)
|
||||
precondition(err == errSecSuccess)
|
||||
let imported = importedCF! as NSArray as! [[String:AnyObject]]
|
||||
precondition(imported.count == 1)
|
||||
|
||||
return (imported[0][kSecImportItemIdentity as String]!) as! SecIdentity
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension SecCertificate{
|
||||
func trust() -> Bool?{
|
||||
var optionalTrust: SecTrust?
|
||||
let policy = SecPolicyCreateBasicX509()
|
||||
|
||||
let status = SecTrustCreateWithCertificates([self] as AnyObject,
|
||||
policy,
|
||||
&optionalTrust)
|
||||
guard status == errSecSuccess else { return false}
|
||||
let trust = optionalTrust!
|
||||
|
||||
let stat = optionalTrust?.evaluateAllowing(rootCertificates: [self])
|
||||
return stat
|
||||
}
|
||||
|
||||
func secTrustObject() -> SecTrust?{
|
||||
var optionalTrust: SecTrust?
|
||||
let policy = SecPolicyCreateBasicX509()
|
||||
|
||||
let status = SecTrustCreateWithCertificates([self] as AnyObject,
|
||||
policy,
|
||||
&optionalTrust)
|
||||
return optionalTrust
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension SecTrust {
|
||||
|
||||
func evaluate() -> Bool {
|
||||
var trustResult: SecTrustResultType = .invalid
|
||||
let err = SecTrustEvaluate(self, &trustResult)
|
||||
guard err == errSecSuccess else { return false }
|
||||
return [.proceed, .unspecified].contains(trustResult)
|
||||
}
|
||||
|
||||
func evaluateAllowing(rootCertificates: [SecCertificate]) -> Bool {
|
||||
|
||||
// Apply our custom root to the trust object.
|
||||
|
||||
var err = SecTrustSetAnchorCertificates(self, rootCertificates as CFArray)
|
||||
guard err == errSecSuccess else { return false }
|
||||
|
||||
// Re-enable the system's built-in root certificates.
|
||||
|
||||
err = SecTrustSetAnchorCertificatesOnly(self, false)
|
||||
guard err == errSecSuccess else { return false }
|
||||
|
||||
// Run a trust evaluation and only allow the connection if it succeeds.
|
||||
|
||||
return self.evaluate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension UIView{
|
||||
func show(){
|
||||
self.alpha = 0.0
|
||||
self.isHidden = false
|
||||
UIView.animate(withDuration: 0.25, animations: {
|
||||
self.alpha = 1
|
||||
}) { (complete) in
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func hide(){
|
||||
UIView.animate(withDuration: 0.25, animations: {
|
||||
self.alpha = 0.0
|
||||
}) { (complete) in
|
||||
self.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
//
|
||||
// LocalizedFromFlutter.swift
|
||||
// Runner
|
||||
//
|
||||
// Created by ZiKambrani on 10/04/1442 AH.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FlutterText{
|
||||
|
||||
class func with(key:String,completion: @escaping (String)->Void){
|
||||
flutterMethodChannel?.invokeMethod("localizedValue", arguments: key, result: { (result) in
|
||||
if let localized = result as? String{
|
||||
completion(localized)
|
||||
}else{
|
||||
completion(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
////
|
||||
//// HMG_GUEST.swift
|
||||
//// HMG-iOS-Wifi
|
||||
////
|
||||
//// Created by ZiKambrani on 23/03/1442 AH.
|
||||
//// Copyright © 1442 ZiKambrani. All rights reserved.
|
||||
////
|
||||
//
|
||||
//import UIKit
|
||||
//import NetworkExtension
|
||||
//import SystemConfiguration.CaptiveNetwork
|
||||
//
|
||||
//
|
||||
//class HMG_GUEST{
|
||||
// static let shared = HMG_GUEST()
|
||||
// private let SSID = "GUEST-POC"
|
||||
// private let USER = "1301"
|
||||
// private let PASS = "8928"
|
||||
//
|
||||
// var complete:((_ status:Bool, _ message:String) -> Void)!
|
||||
// func connect(completion:@escaping ((_ status:Bool, _ message:String) -> Void)){
|
||||
// complete = completion
|
||||
//
|
||||
// if isAlreadyConnected() {
|
||||
// hasInternet { (has) in
|
||||
// if has == true{
|
||||
// self.complete(true, "You already connected to internet")
|
||||
// return
|
||||
// }else{
|
||||
// self.authenticate()
|
||||
// }
|
||||
// }
|
||||
// }else{
|
||||
// connect()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private func connect() {
|
||||
// let hotspotConfig = NEHotspotConfiguration(ssid: SSID)
|
||||
// hotspotConfig.joinOnce = true
|
||||
//
|
||||
// NEHotspotConfigurationManager.shared.apply(hotspotConfig) {[weak self] (error) in
|
||||
// guard let self = self else { return; }
|
||||
//
|
||||
// if let error = error {
|
||||
// self.complete(false, error.localizedDescription ?? "Error connecting to HMG wifi network" )
|
||||
// }else{
|
||||
// _ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
|
||||
// self.authenticate()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func authenticate(){
|
||||
//
|
||||
// func callLogin(){
|
||||
//
|
||||
// let parameters = "Login=Log%20In&cmd=authenticate&password=1820&user=2300"
|
||||
// let postData = parameters.data(using: .utf8)
|
||||
//
|
||||
// var request = URLRequest(url: URL(string: "https://captiveportal-login.hmg.com/cgi-bin/login")!,timeoutInterval: 5)
|
||||
// request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
||||
//
|
||||
// request.httpMethod = "POST"
|
||||
// request.httpBody = postData
|
||||
//
|
||||
// let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
// // guard let data = data else {
|
||||
// // self.complete(false, "Error at authentication")
|
||||
// // return
|
||||
// // }
|
||||
//
|
||||
// self.hasInternet { (has) in
|
||||
// self.complete(has, has ? "Successfully connected to the internet" : "Authentication failed or you are already using your credentials on another device")
|
||||
// }
|
||||
// }
|
||||
// task.resume()
|
||||
//
|
||||
// }
|
||||
//
|
||||
// self.hasInternet { (has) in
|
||||
// if has == true{
|
||||
// self.complete(true, "Your internet account is already authenticated")
|
||||
// }else{
|
||||
// callLogin()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private func isAlreadyConnected() -> Bool{
|
||||
// var currentSSID: String?
|
||||
// if let interfaces = CNCopySupportedInterfaces() as NSArray? {
|
||||
// for interface in interfaces {
|
||||
// if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
|
||||
// currentSSID = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// print("CurrentConnectedSSID: \(currentSSID)")
|
||||
// return currentSSID == SSID
|
||||
// }
|
||||
//
|
||||
//
|
||||
// func hasInternet( completion:@escaping ((Bool)->Void)){
|
||||
//
|
||||
// let testUrl = "https://captive.apple.com"
|
||||
// var request = URLRequest(url: URL(string: testUrl)!,timeoutInterval: 5)
|
||||
// request.httpMethod = "GET"
|
||||
// let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
// guard let data = data else {
|
||||
// completion(false)
|
||||
// return
|
||||
// }
|
||||
// let resp = String(data: data, encoding: .utf8)!
|
||||
// if resp.contains("<TITLE>Success</TITLE>"){
|
||||
// completion(true)
|
||||
// }else{
|
||||
// completion(false)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// task.resume()
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@ -0,0 +1,193 @@
|
||||
//
|
||||
// HMG_GUEST.swift
|
||||
// HMG-iOS-Wifi
|
||||
//
|
||||
// Created by ZiKambrani on 23/03/1442 AH.
|
||||
// Copyright © 1442 ZiKambrani. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NetworkExtension
|
||||
import SystemConfiguration.SCNetworkConnection
|
||||
|
||||
fileprivate var TEST = false
|
||||
fileprivate let SSID = "GUEST-POC"
|
||||
fileprivate var USER = ""
|
||||
fileprivate var PASS = ""
|
||||
|
||||
fileprivate func supportedEAPTypes() -> [NSNumber]{
|
||||
let peap = NEHotspotEAPSettings.EAPType.EAPPEAP.rawValue
|
||||
let fast = NEHotspotEAPSettings.EAPType.EAPFAST.rawValue
|
||||
let tls = NEHotspotEAPSettings.EAPType.EAPTLS.rawValue
|
||||
let ttls = NEHotspotEAPSettings.EAPType.EAPTTLS.rawValue
|
||||
return [NSNumber(value: peap), NSNumber(value: fast), NSNumber(value: tls), NSNumber(value: ttls)]
|
||||
}
|
||||
|
||||
class HMG_Internet{
|
||||
static let shared = HMG_Internet()
|
||||
|
||||
private var complete:((_ status:Bool, _ message:String) -> Void)!
|
||||
func connect(patientId:String, completion:@escaping ((_ status:Bool, _ message:String) -> Void)){
|
||||
complete = completion
|
||||
|
||||
if isAlreadyConnected() {
|
||||
hasInternet { (has) in
|
||||
if has == true{
|
||||
FlutterText.with(key: "alreadyConnectedHmgNetwork"){ localized in
|
||||
self.complete(true, localized)
|
||||
}
|
||||
return
|
||||
}else{
|
||||
FlutterText.with(key: "connectedToHmgNetworkWithNoInternet"){ localized in
|
||||
self.complete(false, localized)
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
connect(patientId: patientId)
|
||||
}
|
||||
}
|
||||
|
||||
private func connect(patientId:String) {
|
||||
|
||||
getWifiCredentials(patientId: patientId) {
|
||||
let trust_cert = Bundle.main.certificate(named: "GuestPOC_Certificate")
|
||||
guard trust_cert.trust() == true else{
|
||||
FlutterText.with(key: "notConnectedToHmgNetworkSecurityIssue"){ localized in
|
||||
self.complete(false,localized)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let eapSettings = NEHotspotEAPSettings()
|
||||
eapSettings.username = USER
|
||||
eapSettings.password = PASS
|
||||
eapSettings.trustedServerNames = ["*.hmg.com","onboard.hmg.com","hmg.com"]
|
||||
eapSettings.supportedEAPTypes = [supportedEAPTypes().first!]
|
||||
// eapSettings.isTLSClientCertificateRequired = true
|
||||
// eapSettings.ttlsInnerAuthenticationType = .eapttlsInnerAuthenticationMSCHAPv2 // MSCHAPv2
|
||||
// eapSettings.setIdentity(Bundle.main.identity(named: "GuestPOC_Certificate", password: "1"))
|
||||
// eapSettings.setTrustedServerCertificates([trust_cert])
|
||||
|
||||
let hotspotConfig = NEHotspotConfiguration(ssid: SSID, eapSettings: eapSettings)
|
||||
NEHotspotConfigurationManager.shared.apply(hotspotConfig) {[weak self] (error) in
|
||||
guard let self = self else { return; }
|
||||
|
||||
if let error = error {
|
||||
|
||||
FlutterText.with(key: "errorConnectingHmgNetwork"){ localized in
|
||||
self.complete(false,localized)
|
||||
}
|
||||
|
||||
}else{
|
||||
_ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { (timer) in
|
||||
self.hasInternet { (has) in
|
||||
if has == true{
|
||||
FlutterText.with(key: "connectedHmgNetworkWithInternet"){ localized in
|
||||
self.complete(true,localized)
|
||||
}
|
||||
return
|
||||
}else{
|
||||
FlutterText.with(key: "connectedToHmgNetworkWithNoInternet"){ localized in
|
||||
self.complete(false,localized)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func isAlreadyConnected() -> Bool{
|
||||
var currentSSID: String?
|
||||
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
|
||||
for interface in interfaces {
|
||||
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
|
||||
currentSSID = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
print("CurrentConnectedSSID: \(currentSSID)")
|
||||
return currentSSID == SSID
|
||||
}
|
||||
|
||||
|
||||
private func getWifiCredentials(patientId:String, success: @escaping (() -> Void)){
|
||||
if TEST {
|
||||
success()
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = API.WIFI_CREDENTIALS.toUrl() else { return assert(true, "Invalid URL: \(API.WIFI_CREDENTIALS)") }
|
||||
|
||||
// JSON Body for HTTP Request
|
||||
let json: [String: Any] = ["PatientID": patientId]
|
||||
let jsonData = try? JSONSerialization.data(withJSONObject: json)
|
||||
|
||||
var request = URLRequest(url: url, timeoutInterval: 20)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = jsonData
|
||||
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
guard let data = data else {
|
||||
self.somethingWentWrong()
|
||||
return
|
||||
}
|
||||
|
||||
if let responseJSON = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]{
|
||||
if let requiredData = (responseJSON["Hmg_SMS_Get_By_ProjectID_And_PatientIDList"] as? [[String:Any]])?.first,
|
||||
let userName = requiredData["UserName"] as? String, let password = requiredData["Password"] as? String{
|
||||
|
||||
USER = userName
|
||||
PASS = password
|
||||
success()
|
||||
|
||||
}else if let errorMessage = responseJSON["ErrorMessage"] as? String{
|
||||
self.complete(false, errorMessage)
|
||||
}else{
|
||||
self.somethingWentWrong()
|
||||
}
|
||||
}else{
|
||||
self.somethingWentWrong()
|
||||
}
|
||||
|
||||
}
|
||||
task.resume()
|
||||
|
||||
}
|
||||
|
||||
private func somethingWentWrong(){
|
||||
FlutterText.with(key: "somethingWentWrong") { (localized) in
|
||||
self.complete(false, localized)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func hasInternet( completion:@escaping ((Bool)->Void)){
|
||||
|
||||
let testUrl = "https://captive.apple.com"
|
||||
var request = URLRequest(url: URL(string: testUrl)!,timeoutInterval: 5)
|
||||
request.httpMethod = "GET"
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
guard let data = data else {
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
completion(
|
||||
String(data: data, encoding: .utf8)!
|
||||
.replacingOccurrences(of: " ", with: "")
|
||||
.replacingOccurrences(of: "\n", with: "")
|
||||
.lowercased()
|
||||
.contains("<title>success</title>")
|
||||
)
|
||||
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,172 @@
|
||||
//
|
||||
// HMG_GUEST.swift
|
||||
// HMG-iOS-Wifi
|
||||
//
|
||||
// Created by ZiKambrani on 23/03/1442 AH.
|
||||
// Copyright © 1442 ZiKambrani. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import NetworkExtension
|
||||
import SystemConfiguration.CaptiveNetwork
|
||||
|
||||
fileprivate var TEST = true
|
||||
fileprivate let SSID = "GUEST-POC"
|
||||
fileprivate var USER = "0696"
|
||||
fileprivate var PASS = "0000"
|
||||
|
||||
fileprivate func supportedEAPTypes() -> [NSNumber]{
|
||||
let peap = NEHotspotEAPSettings.EAPType.EAPPEAP.rawValue
|
||||
let fast = NEHotspotEAPSettings.EAPType.EAPFAST.rawValue
|
||||
let tls = NEHotspotEAPSettings.EAPType.EAPTLS.rawValue
|
||||
let ttls = NEHotspotEAPSettings.EAPType.EAPTTLS.rawValue
|
||||
return [NSNumber(value: peap), NSNumber(value: fast), NSNumber(value: tls), NSNumber(value: ttls)]
|
||||
}
|
||||
|
||||
class HMG_Internet{
|
||||
static let shared = HMG_Wifi()
|
||||
|
||||
private var complete:((_ status:Bool, _ message:String) -> Void)!
|
||||
func connect(patientId:String, completion:@escaping ((_ status:Bool, _ message:String) -> Void)){
|
||||
complete = completion
|
||||
|
||||
if isAlreadyConnected() {
|
||||
hasInternet { (has) in
|
||||
if has == true{
|
||||
self.complete(true, "You already connected to HMG network to access internet")
|
||||
return
|
||||
}else{
|
||||
self.complete(false, "You are connected to HMG network but it have no internet access")
|
||||
}
|
||||
}
|
||||
}else{
|
||||
connect(patientId: patientId)
|
||||
}
|
||||
}
|
||||
|
||||
private func connect(patientId:String) {
|
||||
|
||||
getWifiCredentials(patientId: patientId) {
|
||||
let trust_cert = Bundle.main.certificate(named: "GuestPOC_Certificate")
|
||||
guard trust_cert.trust() == true else{
|
||||
self.complete(false,"We are not able to connect you to HMG network due to security certificate")
|
||||
return
|
||||
}
|
||||
|
||||
let eapSettings = NEHotspotEAPSettings()
|
||||
eapSettings.username = USER
|
||||
eapSettings.password = PASS
|
||||
eapSettings.trustedServerNames = ["*.hmg.com","onboard.hmg.com","hmg.com"]
|
||||
eapSettings.supportedEAPTypes = [supportedEAPTypes().first!]
|
||||
// eapSettings.isTLSClientCertificateRequired = true
|
||||
// eapSettings.ttlsInnerAuthenticationType = .eapttlsInnerAuthenticationMSCHAPv2 // MSCHAPv2
|
||||
// eapSettings.setIdentity(Bundle.main.identity(named: "GuestPOC_Certificate", password: "1"))
|
||||
// eapSettings.setTrustedServerCertificates([trust_cert])
|
||||
|
||||
let hotspotConfig = NEHotspotConfiguration(ssid: SSID, eapSettings: eapSettings)
|
||||
NEHotspotConfigurationManager.shared.apply(hotspotConfig) {[weak self] (error) in
|
||||
guard let self = self else { return; }
|
||||
|
||||
if let error = error {
|
||||
self.complete(false, "Error connecting to HMG network" /*error.localizedDescription*/ )
|
||||
}else{
|
||||
_ = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { (timer) in
|
||||
self.hasInternet { (has) in
|
||||
if has == true{
|
||||
self.complete(true, "Successfully connected to the HMG network to access internet")
|
||||
return
|
||||
}else{
|
||||
self.complete(false, "Successfully connected to the HMG network but it have no internet access")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func isAlreadyConnected() -> Bool{
|
||||
var currentSSID: String?
|
||||
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
|
||||
for interface in interfaces {
|
||||
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
|
||||
currentSSID = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print("CurrentConnectedSSID: \(currentSSID)")
|
||||
return currentSSID == SSID
|
||||
}
|
||||
|
||||
|
||||
private func getWifiCredentials(patientId:String, completion: @escaping (() -> Void)){
|
||||
if TEST {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = API.WIFI_CREDENTIALS.toUrl() else { return assert(true, "Invalid URL: \(API.WIFI_CREDENTIALS)") }
|
||||
|
||||
// JSON Body for HTTP Request
|
||||
let json: [String: Any] = ["PatientID": patientId]
|
||||
let jsonData = try? JSONSerialization.data(withJSONObject: json)
|
||||
|
||||
var request = URLRequest(url: url, timeoutInterval: 20)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = jsonData
|
||||
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
guard let data = data else {
|
||||
self.complete(false, "Failed to get your internet credentials")
|
||||
return
|
||||
}
|
||||
|
||||
if let responseJSON = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]{
|
||||
if let requiredData = responseJSON["Hmg_SMS_Get_By_ProjectID_And_PatientIDList"] as? [String:Any],
|
||||
let userName = requiredData["UserName"] as? String, let password = requiredData["Password"] as? String{
|
||||
|
||||
USER = userName
|
||||
PASS = password
|
||||
completion()
|
||||
|
||||
}else if let errorMessage = responseJSON["ErrorMessage"] as? String{
|
||||
self.complete(false, errorMessage)
|
||||
}
|
||||
}else{
|
||||
self.complete(false, "Failed to get your internet credentials")
|
||||
}
|
||||
|
||||
}
|
||||
task.resume()
|
||||
|
||||
}
|
||||
|
||||
|
||||
func hasInternet( completion:@escaping ((Bool)->Void)){
|
||||
|
||||
let testUrl = "https://captive.apple.com"
|
||||
var request = URLRequest(url: URL(string: testUrl)!,timeoutInterval: 5)
|
||||
request.httpMethod = "GET"
|
||||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
guard let data = data else {
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
completion(
|
||||
String(data: data, encoding: .utf8)!
|
||||
.replacingOccurrences(of: " ", with: "")
|
||||
.replacingOccurrences(of: "\n", with: "")
|
||||
.lowercased()
|
||||
.contains("<title>success</title>")
|
||||
)
|
||||
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
class GetNotificationsRequestModel {
|
||||
int notificationStatusID;
|
||||
int pagingSize;
|
||||
int currentPage;
|
||||
|
||||
GetNotificationsRequestModel(
|
||||
{this.notificationStatusID, this.pagingSize, this.currentPage});
|
||||
|
||||
GetNotificationsRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
notificationStatusID = json['NotificationStatusID'];
|
||||
pagingSize = json['pagingSize'];
|
||||
currentPage = json['currentPage'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['NotificationStatusID'] = this.notificationStatusID;
|
||||
data['pagingSize'] = this.pagingSize;
|
||||
data['currentPage'] = this.currentPage;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
class GetNotificationsResponseModel {
|
||||
int id;
|
||||
int recordId;
|
||||
int patientID;
|
||||
bool projectOutSA;
|
||||
String deviceType;
|
||||
String deviceToken;
|
||||
String message;
|
||||
String messageType;
|
||||
String messageTypeData;
|
||||
dynamic videoURL;
|
||||
bool isQueue;
|
||||
String isQueueOn;
|
||||
String createdOn;
|
||||
String createdBy;
|
||||
String notificationType;
|
||||
bool isSent;
|
||||
String isSentOn;
|
||||
bool isRead;
|
||||
String isReadOn;
|
||||
int channelID;
|
||||
int projectID;
|
||||
|
||||
GetNotificationsResponseModel(
|
||||
{this.id,
|
||||
this.recordId,
|
||||
this.patientID,
|
||||
this.projectOutSA,
|
||||
this.deviceType,
|
||||
this.deviceToken,
|
||||
this.message,
|
||||
this.messageType,
|
||||
this.messageTypeData,
|
||||
this.videoURL,
|
||||
this.isQueue,
|
||||
this.isQueueOn,
|
||||
this.createdOn,
|
||||
this.createdBy,
|
||||
this.notificationType,
|
||||
this.isSent,
|
||||
this.isSentOn,
|
||||
this.isRead,
|
||||
this.isReadOn,
|
||||
this.channelID,
|
||||
this.projectID});
|
||||
|
||||
GetNotificationsResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['Id'];
|
||||
recordId = json['RecordId'];
|
||||
patientID = json['PatientID'];
|
||||
projectOutSA = json['ProjectOutSA'];
|
||||
deviceType = json['DeviceType'];
|
||||
deviceToken = json['DeviceToken'];
|
||||
message = json['Message'];
|
||||
messageType = json['MessageType'];
|
||||
messageTypeData = json['MessageTypeData'];
|
||||
videoURL = json['VideoURL'];
|
||||
isQueue = json['IsQueue'];
|
||||
isQueueOn = json['IsQueueOn'];
|
||||
createdOn = json['CreatedOn'];
|
||||
createdBy = json['CreatedBy'];
|
||||
notificationType = json['NotificationType'];
|
||||
isSent = json['IsSent'];
|
||||
isSentOn = json['IsSentOn'];
|
||||
isRead = json['IsRead'];
|
||||
isReadOn = json['IsReadOn'];
|
||||
channelID = json['ChannelID'];
|
||||
projectID = json['ProjectID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['Id'] = this.id;
|
||||
data['RecordId'] = this.recordId;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['ProjectOutSA'] = this.projectOutSA;
|
||||
data['DeviceType'] = this.deviceType;
|
||||
data['DeviceToken'] = this.deviceToken;
|
||||
data['Message'] = this.message;
|
||||
data['MessageType'] = this.messageType;
|
||||
data['MessageTypeData'] = this.messageTypeData;
|
||||
data['VideoURL'] = this.videoURL;
|
||||
data['IsQueue'] = this.isQueue;
|
||||
data['IsQueueOn'] = this.isQueueOn;
|
||||
data['CreatedOn'] = this.createdOn;
|
||||
data['CreatedBy'] = this.createdBy;
|
||||
data['NotificationType'] = this.notificationType;
|
||||
data['IsSent'] = this.isSent;
|
||||
data['IsSentOn'] = this.isSentOn;
|
||||
data['IsRead'] = this.isRead;
|
||||
data['IsReadOn'] = this.isReadOn;
|
||||
data['ChannelID'] = this.channelID;
|
||||
data['ProjectID'] = this.projectID;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
class MarkMessageAsReadRequestModel {
|
||||
int notificationPoolID;
|
||||
|
||||
MarkMessageAsReadRequestModel({this.notificationPoolID});
|
||||
|
||||
MarkMessageAsReadRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
notificationPoolID = json['NotificationPoolID'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['NotificationPoolID'] = this.notificationPoolID;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import 'package:diplomaticquarterapp/config/config.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/notifications/get_notifications_request_model.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/notifications/get_notifications_response_model.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/notifications/mark_message_as_read_request_model.dart';
|
||||
import 'package:diplomaticquarterapp/core/service/base_service.dart';
|
||||
|
||||
class NotificationService extends BaseService {
|
||||
List<GetNotificationsResponseModel> notificationsList = List();
|
||||
|
||||
Future getAllNotifications(GetNotificationsRequestModel getNotificationsRequestModel ) async {
|
||||
hasError = false;
|
||||
await baseAppClient.post(PUSH_NOTIFICATION_GET_ALL_NOTIFICATIONS,
|
||||
onSuccess: (dynamic response, int statusCode) {
|
||||
if(getNotificationsRequestModel.currentPage ==0)
|
||||
notificationsList.clear();
|
||||
response['List_GetAllNotificationsFromPool'].forEach((appoint) {
|
||||
notificationsList.add(GetNotificationsResponseModel.fromJson(appoint));
|
||||
});
|
||||
}, onFailure: (String error, int statusCode) {
|
||||
hasError = true;
|
||||
super.error = error;
|
||||
}, body: getNotificationsRequestModel.toJson());
|
||||
}
|
||||
Future markAsRead(MarkMessageAsReadRequestModel markMessageAsReadRequestModel ) async {
|
||||
hasError = false;
|
||||
await baseAppClient.post(PUSH_NOTIFICATION_SET_MESSAGES_FROM_POOL_AS_READ,
|
||||
onSuccess: (dynamic response, int statusCode) {
|
||||
updateNotification(markMessageAsReadRequestModel.notificationPoolID);
|
||||
}, onFailure: (String error, int statusCode) {
|
||||
hasError = true;
|
||||
super.error = error;
|
||||
}, body: markMessageAsReadRequestModel.toJson());
|
||||
}
|
||||
|
||||
updateNotification(id) {
|
||||
int index = notificationsList.indexWhere((element) => element.id == id);
|
||||
notificationsList[index].isRead = true;
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import 'package:diplomaticquarterapp/core/enum/viewstate.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/notifications/get_notifications_request_model.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/notifications/get_notifications_response_model.dart';
|
||||
import 'package:diplomaticquarterapp/core/model/notifications/mark_message_as_read_request_model.dart';
|
||||
import 'package:diplomaticquarterapp/core/service/notifications_service.dart';
|
||||
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../locator.dart';
|
||||
import 'base_view_model.dart';
|
||||
|
||||
class NotificationViewModel extends BaseViewModel {
|
||||
NotificationService _notificationService = locator<NotificationService>();
|
||||
|
||||
List<GetNotificationsResponseModel> get notifications =>
|
||||
_notificationService.notificationsList;
|
||||
|
||||
Future getNotifications(
|
||||
GetNotificationsRequestModel getNotificationsRequestModel, BuildContext context) async {
|
||||
if(getNotificationsRequestModel.currentPage == 0)
|
||||
setState(ViewState.Busy);
|
||||
|
||||
await _notificationService
|
||||
.getAllNotifications(getNotificationsRequestModel);
|
||||
if (_notificationService.hasError) {
|
||||
error = _notificationService.error;
|
||||
setState(ViewState.Error);
|
||||
} else {
|
||||
setState(ViewState.Idle);
|
||||
}
|
||||
}
|
||||
|
||||
Future markAsRead(id) async {
|
||||
// setState(ViewState.Busy);
|
||||
MarkMessageAsReadRequestModel markMessageAsReadRequestModel =
|
||||
new MarkMessageAsReadRequestModel(notificationPoolID: id);
|
||||
await _notificationService.markAsRead(markMessageAsReadRequestModel);
|
||||
setState(ViewState.Idle);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class ToDoCountProviderModel with ChangeNotifier {
|
||||
int _count;
|
||||
|
||||
int get count => _count == null ? 0 : _count;
|
||||
|
||||
void setState(int count) {
|
||||
_count = count;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||