From b136f63e409f417efa3fc68abaa7b79ff6269585 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Tue, 4 Jun 2024 14:48:17 +0300 Subject: [PATCH] Added SmartRingOperations --- android/app/src/main/AndroidManifest.xml | 1 + .../diplomaticquarterapp/MainActivity.kt | 1 + .../diplomaticquarterapp/ble/BleBridge.kt | 163 ++++++- .../smart_ring_2301/BaseActivity.kt | 6 +- .../smart_ring_2301/BleService.kt | 2 +- .../ble_devices_screen.dart | 1 + .../checkme_all_in-one_connect_screen.dart | 1 + .../smart_ring_connect_screen.dart | 78 ++-- .../smart_ring_info_screen.dart | 413 ++++++++++++++++++ .../ble_helpers/ble_connect_helper.dart | 102 ++++- .../ble_models/ble_devices_model.dart | 4 +- .../ble_models/smart_ring_models.dart | 76 ++++ .../my_trackers_view_model.dart | 172 +++++++- 13 files changed, 940 insertions(+), 80 deletions(-) create mode 100644 lib/pages/medical/my_trackers/ble_device_type_screens/smart_ring_info_screen.dart create mode 100644 lib/pages/medical/my_trackers/ble_models/smart_ring_models.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 41ab6bf3..3542eacd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -116,6 +116,7 @@ + diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt index 97e166d1..3f312cd7 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt @@ -22,6 +22,7 @@ class MainActivity : FlutterFragmentActivity() { PlatformBridge(flutterEngine, this).create() OpenTokPlatformBridge(flutterEngine, this).create() BleManager.init(this) + BleBridge(flutterEngine, this).createBleBridge(BleScanManager()) { name, bluetoothDevice -> // Handle the scan result here Log.d("MainActivity", "Received scan result: $name, $bluetoothDevice") diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt index 7da5d779..548e66ee 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt @@ -31,6 +31,11 @@ import com.cloud.diplomaticquarterapp.utils.UiChannel import com.google.gson.Gson import com.jeremyliao.liveeventbus.LiveEventBus import com.jstyle.blesdk2301.Util.BleSDK +import com.jstyle.blesdk2301.Util.BleSDK.GetDynamicHRWithMode +import com.jstyle.blesdk2301.Util.BleSDK.GetHRVDataWithMode +import com.jstyle.blesdk2301.Util.BleSDK.GetStaticHRWithMode +import com.jstyle.blesdk2301.Util.BleSDK.GetTemperature_historyData +import com.jstyle.blesdk2301.Util.BleSDK.Oxygen_data import com.jstyle.blesdk2301.callback.BleConnectionListener import com.jstyle.blesdk2301.constant.BleConst import com.lepu.blepro.event.EventMsgConst @@ -106,6 +111,11 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi private const val CONNECT_DEVICE_SMART_RING = "connectDeviceSmartRing" private const val DISCONNECT_DEVICE_SMART_RING = "disConnectDeviceSmartRing" private const val GET_BATTERY_LEVEL_SMART_RING = "getBatteryLevelSmartRing" + private const val GET_TEMPERATURE_SMART_RING = "getTemperatureSmartRing" + private const val GET_DYNAMIC_HEART_RATE_SMART_RING = "getDynamicHeartRateSmartRing" + private const val GET_STATIC_HEART_RATE_SMART_RING = "getStaticHeartRateSmartRing" + private const val GET_HRV_SMART_RING = "getHRVSmartRing" + private const val GET_BLOOD_OXYGEN_SMART_RING = "getBloodOxygenSmartRing" val scan = BleScanManager() @@ -120,6 +130,11 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi eventSink?.success(deviceInfoString) } + var modeStart: Byte = 0x00 //开始获取数据 start getting data + + var modeContinue: Byte = 0x02 //继续读取数据 continue reading data + + var modeDelete = 0x99.toByte() var mUserData: MutableList = java.util.ArrayList() @@ -243,6 +258,7 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi @SuppressLint("NewApi") fun createBleBridge(bleScanManager: BleScanManager, scanResultHandler: (String, BluetoothDevice) -> Unit) { + subscribeForSmartRingEvents(); channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) Echannel = EventChannel(flutterEngine.dartExecutor.binaryMessenger, EVENTCHANNEL) channel.setMethodCallHandler { methodCall: MethodCall, result: MethodChannel.Result -> @@ -292,6 +308,16 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi disConnectDeviceSmartRing() } else if (methodCall.method == GET_BATTERY_LEVEL_SMART_RING) { getBatteryLevelSmartRing(); + } else if (methodCall.method == GET_TEMPERATURE_SMART_RING) { + getTemperatureSmartRing(modeStart); + } else if (methodCall.method == GET_DYNAMIC_HEART_RATE_SMART_RING) { + getDynamicHeartRateSmartRing(modeStart); + } else if (methodCall.method == GET_STATIC_HEART_RATE_SMART_RING) { + getStaticHeartRateSmartRing(modeStart); + } else if (methodCall.method == GET_HRV_SMART_RING) { + getHRVSmartRing(modeStart); + } else if (methodCall.method == GET_BLOOD_OXYGEN_SMART_RING) { + getBloodOxygenSmartRing(modeStart); } else { result.notImplemented() } @@ -1054,6 +1080,7 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi override fun ConnectionSucceeded() { //连接设备成功 Successfully connected the device Log.e("BleStatus", "ConnectionSucceeded") + getBatteryLevelSmartRing() } override fun Connecting() { //设备连接中 Device is connected @@ -1072,7 +1099,6 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi Log.e("BleStatus", "BluetoothSwitchIsTurnedOff") } }) - } private fun disConnectDeviceSmartRing() { @@ -1084,15 +1110,150 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi sendValue(BleSDK.GetDeviceBatteryLevel()); } + private fun getTemperatureSmartRing(mode: Byte) { + sendValue(GetTemperature_historyData(mode, "")) + } + + private fun getDynamicHeartRateSmartRing(mode: Byte) { + sendValue(GetDynamicHRWithMode(mode, "")) + } + + private fun getStaticHeartRateSmartRing(mode: Byte) { + sendValue(GetStaticHRWithMode(mode, "")) + } + + private fun getHRVSmartRing(mode: Byte) { + + sendValue(GetHRVDataWithMode(mode, "")) + } + + private fun getBloodOxygenSmartRing(mode: Byte) { + + sendValue(Oxygen_data(mode)) + } + + private var temperatureDataCount = 0 + private var dynamicHeartRateDataCount = 0 + private var staticHeartRateDataCount = 0 + private var hrvDataCount = 0 + private var bloodOxygenDataCount = 0 override fun dataCallback(maps: Map?) { super.dataCallback(maps) val dataType = getDataType(maps) Log.d("dataCallbackType", dataType.toString()) + val finish = getEnd(maps!!) when (dataType) { BleConst.GetDeviceBatteryLevel -> { Log.d("BatteryLevel", maps.toString()) + val returnData = mapOf("type" to "BatteryLevelSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } + + BleConst.Temperature_history -> { + temperatureDataCount++ + if (finish) { + temperatureDataCount = 0 + Log.d("TemperatureSmartRing", maps.toString()) + val returnData = mapOf("type" to "TemperatureSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } + if (temperatureDataCount == 50) { + temperatureDataCount = 0 + if (finish) { + Log.d("TemperatureSmartRing", maps.toString()) + val returnData = mapOf("type" to "TemperatureSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } else { + getTemperatureSmartRing(modeContinue) + } + } + } + + BleConst.GetDynamicHR -> { + dynamicHeartRateDataCount++ + if (finish) { + dynamicHeartRateDataCount = 0 + Log.d("DynamicHRSmartRing", maps.toString()) + val returnData = mapOf("type" to "DynamicHeartRateSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } + if (dynamicHeartRateDataCount == 50) { + dynamicHeartRateDataCount = 0 + if (finish) { + Log.d("DynamicHRSmartRing", maps.toString()) + val returnData = mapOf("type" to "DynamicHeartRateSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } else { + getDynamicHeartRateSmartRing(modeContinue) + } + } + + } + + + BleConst.GetStaticHR -> { + staticHeartRateDataCount++ + if (finish) { + staticHeartRateDataCount = 0 + Log.d("StaticHRSmartRing", maps.toString()) + val returnData = mapOf("type" to "StaticHeartRateSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } + if (staticHeartRateDataCount == 50) { + staticHeartRateDataCount = 0 + if (finish) { + Log.d("StaticHRSmartRing", maps.toString()) + val returnData = mapOf("type" to "StaticHeartRateSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } else { + getStaticHeartRateSmartRing(modeContinue) + } + } + + } + + BleConst.GetHRVData -> { + hrvDataCount++ + if (finish) { + hrvDataCount = 0 + Log.d("HrvSmartRing", maps.toString()) + val returnData = mapOf("type" to "HrvSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } + if (hrvDataCount == 50) { + if (finish) { + hrvDataCount = 0 + Log.d("HrvSmartRing", maps.toString()) + val returnData = mapOf("type" to "HrvSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } else { + getHRVSmartRing(modeContinue) + } + } + } + + BleConst.Blood_oxygen -> { + bloodOxygenDataCount++ + if (finish) { + bloodOxygenDataCount = 0 + Log.d("BloodOxygenSmartRing", maps.toString()) + val returnData = mapOf("type" to "BloodOxygenSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } + if (bloodOxygenDataCount == 50) { + bloodOxygenDataCount = 0 + if (finish) { + bloodOxygenDataCount = 0 + Log.d("BloodOxygenSmartRing", maps.toString()) + val returnData = mapOf("type" to "BloodOxygenSmartRing", "data" to gson.toJson(maps)) + eventSink?.success(returnData) + } else { + + getBloodOxygenSmartRing(modeContinue) + } + } } } } diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BaseActivity.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BaseActivity.kt index 8aca9482..4748d532 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BaseActivity.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BaseActivity.kt @@ -19,12 +19,12 @@ import javax.annotation.Nullable open class BaseActivity : AppCompatActivity(), DataListener2301 { private var subscription: Disposable? = null - override fun onCreate(@Nullable savedInstanceState: Bundle?) { + public override fun onCreate(@Nullable savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - subscribe() +// subscribeForSmartRingEvents() } - protected open fun subscribe() { + protected open fun subscribeForSmartRingEvents() { subscription = RxBus.instance.toObservable(BleData::class.java).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe { bleData -> val action = bleData.action if (action == BleService.ACTION_DATA_AVAILABLE) { diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BleService.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BleService.kt index bdefbb24..3c868808 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BleService.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/smart_ring_2301/BleService.kt @@ -1 +1 @@ -package com.cloud.diplomaticquarterapp.smart_ring_2301 import android.annotation.SuppressLint import android.app.Service import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCallback import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattDescriptor import android.bluetooth.BluetoothGattService import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile import android.content.Context import android.content.Intent import android.os.Binder import android.os.Build import android.os.Handler import android.os.IBinder import android.os.Looper import android.text.TextUtils import android.util.Log import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.BleData import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.ResolveData.byte2Hex import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.ResolveData.decodeDeviceName import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.RxBus.Companion.instance import com.jstyle.blesdk2301.callback.BleConnectionListener import java.util.LinkedList import java.util.Queue import java.util.UUID @SuppressLint("MissingPermission") class BleService : Service() { private var NeedReconnect = false var fastconnect = false //是否连接成功过设备 var hasp = HashMap() private val kBinder: IBinder = LocalBinder() private val gattHash = HashMap() private var bluetoothManager: BluetoothManager? = null private var mBluetoothAdapter: BluetoothAdapter? = null private var mGatt: BluetoothGatt? = null var isConnected = false private set private val handler = Handler() override fun onBind(intent: Intent): IBinder? { initAdapter() return kBinder } override fun onUnbind(intent: Intent): Boolean { return super.onUnbind(intent) } /** * 初始化BLE 如果已经连接就不用再次连 * * @param bleDevice * @return */ private var address: String? = null private var mContext: Context? = null protected var bleConnectionListener: BleConnectionListener? = null fun initBluetoothDevice(address: String?, context: Context?, needReconnect: Boolean, bleConnectionListener1: BleConnectionListener?) { if (null != bleConnectionListener1) { bleConnectionListener = bleConnectionListener1 NeedReconnect = needReconnect } //MyLog.i("开始连接"); fastconnect = false this.address = address mContext = context val device = mBluetoothAdapter!!.getRemoteDevice(address) if (isConnected) return if (null != mGatt) { refreshDeviceCache(mGatt) mGatt = null } mGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { device.connectGatt(context, false, bleGattCallback, BluetoothDevice.TRANSPORT_LE) } else { device.connectGatt(context, false, bleGattCallback) } if (mGatt == null) { println(device.address + "gatt is null") } if (null != bleConnectionListener) { bleConnectionListener!!.Connecting() } // this.mContext=context; // reconnect(true); } private var scanToConnect = true private var isScaning = false @SuppressLint("MissingPermission") fun startScan(enable: Boolean) { Log.i(TAG, "startScan: $enable") if (!mBluetoothAdapter!!.isEnabled) { return } if (scanToConnect) { startScanDevice(true) } else { initBluetoothDevice(address, mContext, NeedReconnect, bleConnectionListener) } scanToConnect = !scanToConnect } @SuppressLint("MissingPermission") private fun startScanDevice(enable: Boolean) { if (enable) { if (isScaning) return handler.postDelayed({ mBluetoothAdapter!!.stopLeScan(mLeScanCallback) isScaning = false startScan(true) }, 20000) fastconnect = false mBluetoothAdapter!!.startLeScan(mLeScanCallback) } else { if (isScaning) { mBluetoothAdapter!!.stopLeScan(mLeScanCallback) handler.removeCallbacksAndMessages(null) } } isScaning = enable } private val mLeScanCallback = BluetoothAdapter.LeScanCallback { device, rssi, scanRecord -> if (device.address == address) { val name = decodeDeviceName(device, scanRecord) if (!TextUtils.isEmpty(name) && name == "DfuTarg") return@LeScanCallback if (mGatt != null) return@LeScanCallback handler.post { startScanDevice(false) mGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { device.connectGatt(mContext, false, bleGattCallback, BluetoothDevice.TRANSPORT_LE) } else { device.connectGatt(mContext, false, bleGattCallback) } if (mGatt == null) { println("gatt is null ") } } } } private fun initAdapter() { if (bluetoothManager == null) { bluetoothManager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager if (bluetoothManager == null) { return } } mBluetoothAdapter = bluetoothManager!!.adapter } /** * 断开连接 */ fun disconnect() { NeedReconnect = false broadcastUpdate(ACTION_GATT_DISCONNECTED) if (mGatt != null) { mGatt = if (isConnected) { mGatt!!.disconnect() mGatt!!.close() null } else { Log.i(TAG, "close: ") mGatt!!.close() null } } isConnected = false } /** * 根据设备的Mac地址断开连接 * * @param address */ fun disconnect(address: String) { val gatts = ArrayList() for (gatt in arrayGatts) { if (gatt != null && gatt.device.address == address) { gatts.add(gatt) // gatt.disconnect(); gatt.close() // gatt = null; } } arrayGatts.removeAll(gatts) } inner class LocalBinder : Binder() { val service: BleService get() = this@BleService } private var discoverCount = 0 private val ob = Any() private val bleGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { var gatt: BluetoothGatt? = gatt if (status == 133 || newState == 0) { if (null != bleConnectionListener) { bleConnectionListener!!.BleStatus(status, newState) } if (mGatt != null) { mGatt!!.disconnect() mGatt!!.close() refreshDeviceCache(mGatt) mGatt = null } if (gatt != null) { gatt.disconnect() gatt.close() refreshDeviceCache(gatt) gatt = null } if (NeedReconnect) startScan(true) return } var action: String? = null Log.i(TAG, "onConnectionStateChange: status$status newstate $newState") if (newState == BluetoothProfile.STATE_CONNECTED) { try { gatt!!.discoverServices() } catch (e: Exception) { e.printStackTrace() } } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { if (null != bleConnectionListener) { bleConnectionListener!!.ConnectionFailed() } isConnected = false Log.i(TAG, "onConnectionStateChange: " + ACTION_GATT_DISCONNECTED) if (mGatt != null) { mGatt!!.close() mGatt = null } queues.clear() if (!NeedReconnect) { action = ACTION_GATT_DISCONNECTED broadcastUpdate(action) } if (!NeedReconnect) { } else { if (fastconnect) { fastconnect = false Log.e(TAG, "发送异常断开") } if (status == 133) { refreshDeviceCache(gatt) } if (null != bleConnectionListener) { bleConnectionListener!!.OnReconnect() } startScan(true) } } else { Log.e("MainActivity", "onConnectionStateChange: status$status newstate $newState") if (0 == status && 0 == newState) { if (null != bleConnectionListener) { bleConnectionListener!!.BluetoothSwitchIsTurnedOff() } } else { if (null != bleConnectionListener) { bleConnectionListener!!.BleStatus(status, newState) } } } } /* * 搜索device中的services (non-Javadoc) * * @see * android.bluetooth.BluetoothGattCallback#onServicesDiscovered(android * .bluetooth.BluetoothGatt, int) */ override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { super.onServicesDiscovered(gatt, status) // if (mGatt == null) // return; if (status == BluetoothGatt.GATT_SUCCESS) { val address = gatt.device.address val name = mBluetoothAdapter!!.getRemoteDevice(address) .name setCharacteristicNotification(true) /* if (gatt != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { gatt.requestMtu(512); }else{ setCharacteristicNotification(true); }*/discoverCount = 0 } else { // mGatt = null; Log.w( "servieDiscovered", "onServicesDiscovered received: " + status ) } } override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { super.onMtuChanged(gatt, mtu, status) if (BluetoothGatt.GATT_SUCCESS == status) { setCharacteristicNotification(true) } else { gatt.requestMtu(153) } } /* * 读取特征�?(non-Javadoc) * * @see * android.bluetooth.BluetoothGattCallback#onCharacteristicRead(android * .bluetooth.BluetoothGatt, * android.bluetooth.BluetoothGattCharacteristic, int) */ override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { super.onCharacteristicRead(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate( ACTION_DATA_AVAILABLE, characteristic, gatt .device.address ) } else { } } override fun onDescriptorWrite( gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int ) { super.onDescriptorWrite(gatt, descriptor, status) if (status == BluetoothGatt.GATT_SUCCESS) { nextQueue() isConnected = true broadcastUpdate(ACTION_GATT_onDescriptorWrite) if (null != bleConnectionListener) { bleConnectionListener!!.ConnectionSucceeded() } } else { Log.i(TAG, "onDescriptorWrite: failed") } } /* * 特征值的变化 (non-Javadoc) * * @see * android.bluetooth.BluetoothGattCallback#onCharacteristicChanged(android * .bluetooth.BluetoothGatt, * android.bluetooth.BluetoothGattCharacteristic) */ override fun onCharacteristicChanged( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic ) { super.onCharacteristicChanged(gatt, characteristic) if (mGatt == null) return Log.i(TAG, "onCharacteristicChanged: " + byte2Hex(characteristic.value)) // SDUtil.saveBTLog("log", "Receiving: " + ResolveData.byte2Hex(characteristic.getValue())); broadcastUpdate( ACTION_DATA_AVAILABLE, characteristic, gatt .device.address ) // SendData.sendBus(ACTION_DATA_AVAILABLE, characteristic.getValue()); } override fun onCharacteristicWrite( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int ) { super.onCharacteristicWrite(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { nextQueue() } else { // MyLog.i("status" + status); } } } fun refreshDeviceCache(gatt: BluetoothGatt?): Boolean { try { val localMethod = gatt!!.javaClass.getMethod( "refresh", *arrayOfNulls(0) ) if (localMethod != null) { return localMethod.invoke( gatt, *arrayOfNulls(0) ) as Boolean } } catch (localException: Exception) { Log.e("s", "An exception occured while refreshing device") } return false } /** * 广播 * * @param action */ private fun broadcastUpdate(action: String?) { val bleData = BleData() bleData.action = action instance.post(bleData) //Intent intent = new Intent(action); //sendBroadcast(intent); } /** * 发�?带蓝牙信息的到广�? * * * @param action * @param characteristic */ private fun broadcastUpdate( action: String, characteristic: BluetoothGattCharacteristic, mac: String ) { // Intent intent = new Intent(action); val data = characteristic.value val bleData = BleData() bleData.action = action bleData.value = data instance.post(bleData) } /** * 读取设备数据 * * @param * @param characteristic */ fun readValue(characteristic: BluetoothGattCharacteristic?) { if (mGatt == null) return mGatt!!.readCharacteristic(characteristic) } /** * 写入设备数据 */ fun writeValue(value: ByteArray?) { Handler(Looper.getMainLooper()).postDelayed(Runnable { if (mGatt == null || value == null) return@Runnable val service = mGatt!!.getService(SERVICE_DATA) ?: return@Runnable val characteristic = service.getCharacteristic(DATA_Characteristic) ?: return@Runnable if (value[0] == 0x47.toByte()) { NeedReconnect = false } characteristic.value = value Log.i(TAG, "writeValue: " + byte2Hex(value)) mGatt!!.writeCharacteristic(characteristic) // SDUtil.saveBTLog("log", "writeValue: " + ResolveData.byte2Hex(value)); }, 500) } fun setCharacteristicNotification(enable: Boolean) { if (mGatt == null) return val service = mGatt!!.getService(SERVICE_DATA) ?: return val characteristic = service.getCharacteristic(NOTIY_Characteristic) ?: return mGatt!!.setCharacteristicNotification(characteristic, enable) try { Thread.sleep(20) } catch (e: InterruptedException) { e.printStackTrace() } val descriptor = characteristic.getDescriptor(NOTIY) ?: //MyLog.e("setCharacteristicNotification descriptor=null,所以不能发送使能数据"); return descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE if (mGatt == null) return mGatt!!.writeDescriptor(descriptor) } val supportedGattServices: List? /** * 获取services * * @return */ get() = if (mGatt == null) { //MyLog.e("getServices, gatt is null "); null } else mGatt!!.services /** * 根据设备的Mac地址从已经连接的设备中匹配对应的BluetoothGatt对象 * * @param device * @return */ private fun getBluetoothGatt(device: BluetoothDevice): BluetoothGatt? { return mGatt } /** * //读取信号 * * @param device */ fun readRssi(device: BluetoothDevice?) { mGatt!!.readRemoteRssi() } override fun onDestroy() { super.onDestroy() } var queues: Queue = LinkedList() fun offerValue(value: ByteArray) { queues.offer(value) } fun nextQueue() { val requests = queues val data = if (requests != null) requests.poll() else null writeValue(data) } companion object { private const val TAG = "BleService" private val NOTIY = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") private val SERVICE_DATA = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb") private val DATA_Characteristic = UUID.fromString("0000fff6-0000-1000-8000-00805f9b34fb") private val NOTIY_Characteristic = UUID.fromString("0000fff7-0000-1000-8000-00805f9b34fb") const val ACTION_GATT_onDescriptorWrite = "com.jstylelife.ble.service.onDescriptorWrite" const val ACTION_GATT_CONNECTED = "com.jstylelife.ble.service.ACTION_GATT_CONNECTED" const val ACTION_GATT_DISCONNECTED = "com.jstylelife.ble.service.ACTION_GATT_DISCONNECTED" const val ACTION_DATA_AVAILABLE = "com.jstylelife.ble.service.ACTION_DATA_AVAILABLE" private val arrayGatts = ArrayList() // 存放BluetoothGatt的集�? var colorCharacteristic: BluetoothGattCharacteristic? = null } } \ No newline at end of file +package com.cloud.diplomaticquarterapp.smart_ring_2301 import android.annotation.SuppressLint import android.app.Service import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCallback import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattDescriptor import android.bluetooth.BluetoothGattService import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile import android.content.Context import android.content.Intent import android.os.Binder import android.os.Build import android.os.Handler import android.os.IBinder import android.os.Looper import android.text.TextUtils import android.util.Log import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.BleData import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.ResolveData.byte2Hex import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.ResolveData.decodeDeviceName import com.cloud.diplomaticquarterapp.smart_ring_2301.Util.RxBus.Companion.instance import com.jstyle.blesdk2301.callback.BleConnectionListener import java.util.LinkedList import java.util.Queue import java.util.UUID @SuppressLint("MissingPermission") class BleService : Service() { private var NeedReconnect = false var fastconnect = false //是否连接成功过设备 var hasp = HashMap() private val kBinder: IBinder = LocalBinder() private val gattHash = HashMap() private var bluetoothManager: BluetoothManager? = null private var mBluetoothAdapter: BluetoothAdapter? = null private var mGatt: BluetoothGatt? = null var isConnected = false private set private val handler = Handler() override fun onBind(intent: Intent): IBinder? { initAdapter() return kBinder } override fun onUnbind(intent: Intent): Boolean { return super.onUnbind(intent) } /** * 初始化BLE 如果已经连接就不用再次连 * * @param bleDevice * @return */ private var address: String? = null private var mContext: Context? = null protected var bleConnectionListener: BleConnectionListener? = null fun initBluetoothDevice(address: String?, context: Context?, needReconnect: Boolean, bleConnectionListener1: BleConnectionListener?) { if (null != bleConnectionListener1) { bleConnectionListener = bleConnectionListener1 NeedReconnect = needReconnect } //MyLog.i("开始连接"); fastconnect = false this.address = address mContext = context val device = mBluetoothAdapter!!.getRemoteDevice(address) if (isConnected) return if (null != mGatt) { refreshDeviceCache(mGatt) mGatt = null } mGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { device.connectGatt(context, false, bleGattCallback, BluetoothDevice.TRANSPORT_LE) } else { device.connectGatt(context, false, bleGattCallback) } if (mGatt == null) { println(device.address + "gatt is null") } if (null != bleConnectionListener) { bleConnectionListener!!.Connecting() } // this.mContext=context; // reconnect(true); } private var scanToConnect = true private var isScaning = false @SuppressLint("MissingPermission") fun startScan(enable: Boolean) { Log.i(TAG, "startScan: $enable") if (!mBluetoothAdapter!!.isEnabled) { return } if (scanToConnect) { startScanDevice(true) } else { initBluetoothDevice(address, mContext, NeedReconnect, bleConnectionListener) } scanToConnect = !scanToConnect } @SuppressLint("MissingPermission") private fun startScanDevice(enable: Boolean) { if (enable) { if (isScaning) return handler.postDelayed({ mBluetoothAdapter!!.stopLeScan(mLeScanCallback) isScaning = false startScan(true) }, 20000) fastconnect = false mBluetoothAdapter!!.startLeScan(mLeScanCallback) } else { if (isScaning) { mBluetoothAdapter!!.stopLeScan(mLeScanCallback) handler.removeCallbacksAndMessages(null) } } isScaning = enable } private val mLeScanCallback = BluetoothAdapter.LeScanCallback { device, rssi, scanRecord -> if (device.address == address) { val name = decodeDeviceName(device, scanRecord) if (!TextUtils.isEmpty(name) && name == "DfuTarg") return@LeScanCallback if (mGatt != null) return@LeScanCallback handler.post { startScanDevice(false) mGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { device.connectGatt(mContext, false, bleGattCallback, BluetoothDevice.TRANSPORT_LE) } else { device.connectGatt(mContext, false, bleGattCallback) } if (mGatt == null) { println("gatt is null ") } } } } private fun initAdapter() { if (bluetoothManager == null) { bluetoothManager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager if (bluetoothManager == null) { return } } mBluetoothAdapter = bluetoothManager!!.adapter } /** * 断开连接 */ fun disconnect() { NeedReconnect = false broadcastUpdate(ACTION_GATT_DISCONNECTED) if (mGatt != null) { mGatt = if (isConnected) { mGatt!!.disconnect() mGatt!!.close() null } else { Log.i(TAG, "close: ") mGatt!!.close() null } } isConnected = false } /** * 根据设备的Mac地址断开连接 * * @param address */ fun disconnect(address: String) { val gatts = ArrayList() for (gatt in arrayGatts) { if (gatt != null && gatt.device.address == address) { gatts.add(gatt) // gatt.disconnect(); gatt.close() // gatt = null; } } arrayGatts.removeAll(gatts) } inner class LocalBinder : Binder() { val service: BleService get() = this@BleService } private var discoverCount = 0 private val ob = Any() private val bleGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { var gatt: BluetoothGatt? = gatt if (status == 133 || newState == 0) { if (null != bleConnectionListener) { bleConnectionListener!!.BleStatus(status, newState) } if (mGatt != null) { mGatt!!.disconnect() mGatt!!.close() refreshDeviceCache(mGatt) mGatt = null } if (gatt != null) { gatt.disconnect() gatt.close() refreshDeviceCache(gatt) gatt = null } if (NeedReconnect) startScan(true) return } var action: String? = null Log.i(TAG, "onConnectionStateChange: status$status newstate $newState") if (newState == BluetoothProfile.STATE_CONNECTED) { try { gatt!!.discoverServices() } catch (e: Exception) { e.printStackTrace() } } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { if (null != bleConnectionListener) { bleConnectionListener!!.ConnectionFailed() } isConnected = false Log.i(TAG, "onConnectionStateChange: " + ACTION_GATT_DISCONNECTED) if (mGatt != null) { mGatt!!.close() mGatt = null } queues.clear() if (!NeedReconnect) { action = ACTION_GATT_DISCONNECTED broadcastUpdate(action) } if (!NeedReconnect) { } else { if (fastconnect) { fastconnect = false Log.e(TAG, "发送异常断开") } if (status == 133) { refreshDeviceCache(gatt) } if (null != bleConnectionListener) { bleConnectionListener!!.OnReconnect() } startScan(true) } } else { Log.e("MainActivity", "onConnectionStateChange: status$status newstate $newState") if (0 == status && 0 == newState) { if (null != bleConnectionListener) { bleConnectionListener!!.BluetoothSwitchIsTurnedOff() } } else { if (null != bleConnectionListener) { bleConnectionListener!!.BleStatus(status, newState) } } } } /* * 搜索device中的services (non-Javadoc) * * @see * android.bluetooth.BluetoothGattCallback#onServicesDiscovered(android * .bluetooth.BluetoothGatt, int) */ override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { super.onServicesDiscovered(gatt, status) // if (mGatt == null) // return; if (status == BluetoothGatt.GATT_SUCCESS) { val address = gatt.device.address val name = mBluetoothAdapter!!.getRemoteDevice(address) .name setCharacteristicNotification(true) /* if (gatt != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { gatt.requestMtu(512); }else{ setCharacteristicNotification(true); }*/discoverCount = 0 } else { // mGatt = null; Log.w( "servieDiscovered", "onServicesDiscovered received: " + status ) } } override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) { super.onMtuChanged(gatt, mtu, status) if (BluetoothGatt.GATT_SUCCESS == status) { setCharacteristicNotification(true) } else { gatt.requestMtu(153) } } /* * 读取特征�?(non-Javadoc) * * @see * android.bluetooth.BluetoothGattCallback#onCharacteristicRead(android * .bluetooth.BluetoothGatt, * android.bluetooth.BluetoothGattCharacteristic, int) */ override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { super.onCharacteristicRead(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate( ACTION_DATA_AVAILABLE, characteristic, gatt .device.address ) } else { } } override fun onDescriptorWrite( gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int ) { super.onDescriptorWrite(gatt, descriptor, status) if (status == BluetoothGatt.GATT_SUCCESS) { nextQueue() isConnected = true broadcastUpdate(ACTION_GATT_onDescriptorWrite) if (null != bleConnectionListener) { bleConnectionListener!!.ConnectionSucceeded() } } else { Log.i(TAG, "onDescriptorWrite: failed") } } /* * 特征值的变化 (non-Javadoc) * * @see * android.bluetooth.BluetoothGattCallback#onCharacteristicChanged(android * .bluetooth.BluetoothGatt, * android.bluetooth.BluetoothGattCharacteristic) */ override fun onCharacteristicChanged( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic ) { super.onCharacteristicChanged(gatt, characteristic) if (mGatt == null) return Log.i(TAG, "onCharacteristicChanged: " + byte2Hex(characteristic.value)) // SDUtil.saveBTLog("log", "Receiving: " + ResolveData.byte2Hex(characteristic.getValue())); broadcastUpdate( ACTION_DATA_AVAILABLE, characteristic, gatt .device.address ) // SendData.sendBus(ACTION_DATA_AVAILABLE, characteristic.getValue()); } override fun onCharacteristicWrite( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int ) { super.onCharacteristicWrite(gatt, characteristic, status) if (status == BluetoothGatt.GATT_SUCCESS) { nextQueue() } else { // MyLog.i("status" + status); } } } fun refreshDeviceCache(gatt: BluetoothGatt?): Boolean { try { val localMethod = gatt!!.javaClass.getMethod( "refresh", *arrayOfNulls(0) ) if (localMethod != null) { return localMethod.invoke( gatt, *arrayOfNulls(0) ) as Boolean } } catch (localException: Exception) { Log.e("s", "An exception occured while refreshing device") } return false } /** * 广播 * * @param action */ private fun broadcastUpdate(action: String?) { val bleData = BleData() bleData.action = action instance.post(bleData) //Intent intent = new Intent(action); //sendBroadcast(intent); } /** * 发�?带蓝牙信息的到广�? * * * @param action * @param characteristic */ private fun broadcastUpdate( action: String, characteristic: BluetoothGattCharacteristic, mac: String ) { // Intent intent = new Intent(action); val data = characteristic.value val bleData = BleData() bleData.action = action bleData.value = data instance.post(bleData) } /** * 读取设备数据 * * @param * @param characteristic */ fun readValue(characteristic: BluetoothGattCharacteristic?) { if (mGatt == null) return mGatt!!.readCharacteristic(characteristic) } /** * 写入设备数据 */ fun writeValue(value: ByteArray?) { Handler(Looper.getMainLooper()).postDelayed(Runnable { if (mGatt == null || value == null) return@Runnable val service = mGatt!!.getService(SERVICE_DATA) ?: return@Runnable val characteristic = service.getCharacteristic(DATA_Characteristic) ?: return@Runnable if (value[0] == 0x47.toByte()) { NeedReconnect = false } characteristic.value = value Log.i(TAG, "writeValue: " + byte2Hex(value)) mGatt!!.writeCharacteristic(characteristic) // SDUtil.saveBTLog("log", "writeValue: " + ResolveData.byte2Hex(value)); }, 500) } fun setCharacteristicNotification(enable: Boolean) { if (mGatt == null) return val service = mGatt!!.getService(SERVICE_DATA) ?: return val characteristic = service.getCharacteristic(NOTIY_Characteristic) ?: return mGatt!!.setCharacteristicNotification(characteristic, enable) try { Thread.sleep(20) } catch (e: InterruptedException) { e.printStackTrace() } val descriptor = characteristic.getDescriptor(NOTIY) ?: //MyLog.e("setCharacteristicNotification descriptor=null,所以不能发送使能数据"); return descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE if (mGatt == null) return mGatt!!.writeDescriptor(descriptor) } val supportedGattServices: List? /** * 获取services * * @return */ get() = if (mGatt == null) { //MyLog.e("getServices, gatt is null "); null } else mGatt!!.services /** * 根据设备的Mac地址从已经连接的设备中匹配对应的BluetoothGatt对象 * * @param device * @return */ private fun getBluetoothGatt(device: BluetoothDevice): BluetoothGatt? { return mGatt } /** * //读取信号 * * @param device */ fun readRssi(device: BluetoothDevice?) { mGatt!!.readRemoteRssi() } override fun onDestroy() { super.onDestroy() } var queues: Queue = LinkedList() fun offerValue(value: ByteArray) { queues.offer(value) } fun nextQueue() { val requests = queues val data = if (requests != null) requests.poll() else null writeValue(data) } companion object { private const val TAG = "BleService" private val NOTIY = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") private val SERVICE_DATA = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb") private val DATA_Characteristic = UUID.fromString("0000fff6-0000-1000-8000-00805f9b34fb") private val NOTIY_Characteristic = UUID.fromString("0000fff7-0000-1000-8000-00805f9b34fb") const val ACTION_GATT_onDescriptorWrite = "com.jstylelife.ble.service.onDescriptorWrite" const val ACTION_GATT_CONNECTED = "com.jstylelife.ble.service.ACTION_GATT_CONNECTED" const val ACTION_GATT_DISCONNECTED = "com.jstylelife.ble.service.ACTION_GATT_DISCONNECTED" const val ACTION_DATA_AVAILABLE = "com.jstylelife.ble.service.ACTION_DATA_AVAILABLE" private val arrayGatts = ArrayList() // 存放BluetoothGatt的集�? var colorCharacteristic: BluetoothGattCharacteristic? = null private var bleServiceInstance: BleService? = null fun getInstance(): BleService? { return bleServiceInstance } } } \ No newline at end of file diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart index 7f801a77..07bd5419 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart @@ -30,6 +30,7 @@ class _BleDevicesScreenState extends State { @override void dispose() { FlutterBluePlus.stopScan(); + myTrackersVm.stopNativeScan(); myTrackersVm.resetList(); super.dispose(); } diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in-one_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in-one_connect_screen.dart index a079c2da..56b32ada 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in-one_connect_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in-one_connect_screen.dart @@ -85,6 +85,7 @@ class _CheckMeAllInOneConnectScreenState extends State onTrackerTypePressed(TrackerTypeEnum trackerTypeEnum, MyTrackersViewModel myTrackersViewModel) async { - switch (trackerTypeEnum) { - case TrackerTypeEnum.BloodPressureTracker: - case TrackerTypeEnum.BloodSugarTracker: + Future onTrackerTypePressed(SmartRingOperationsEnum smartRingOperationsEnum, MyTrackersViewModel myTrackersViewModel) async { + switch (smartRingOperationsEnum) { + case SmartRingOperationsEnum.Temperature: + myTrackersViewModel.getTemperatureSmartRing(); + Navigator.of(context).push(FadePage(page: SmartRingInfoScreen(smartRingOperationsEnum))); break; - case TrackerTypeEnum.OxymeterTracker: + case SmartRingOperationsEnum.HeartRateStatic: + myTrackersViewModel.getStaticHeartRateSmartRing(); + Navigator.of(context).push(FadePage(page: SmartRingInfoScreen(smartRingOperationsEnum))); break; - case TrackerTypeEnum.ECGTracker: - myTrackersViewModel.getBatteryLevelSmartRing(); + case SmartRingOperationsEnum.HeartRateDynamic: + myTrackersViewModel.getDynamicHeartRateSmartRing(); + Navigator.of(context).push(FadePage(page: SmartRingInfoScreen(smartRingOperationsEnum))); + break; + case SmartRingOperationsEnum.HRV: + myTrackersViewModel.getHRVSmartRing(); + Navigator.of(context).push(FadePage(page: SmartRingInfoScreen(smartRingOperationsEnum))); break; - case TrackerTypeEnum.Temperature: + case SmartRingOperationsEnum.BloodOxygen: + myTrackersViewModel.getBloodOxygenSmartRing(); + // Navigator.of(context).push(FadePage(page: SmartRingInfoScreen(smartRingOperationsEnum))); + break; + case SmartRingOperationsEnum.BatteryLevel: + myTrackersViewModel.getBatteryLevelSmartRing(); + Navigator.of(context).push(FadePage(page: SmartRingInfoScreen(smartRingOperationsEnum))); break; - case TrackerTypeEnum.Spirometer: - case TrackerTypeEnum.WeightScale: - case TrackerTypeEnum.SmartRing: - case TrackerTypeEnum.AllInOneTracker: + default: break; } } @@ -87,7 +91,7 @@ class _SmartRingAllInOneConnectScreenState extends State SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + SmartRingGenericModel smartRingTemp = myTrackersVm.smartRingTemperatureHistory[index]; + return InkWell( + onTap: () => Navigator.pop(context), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Temperature: ${smartRingTemp.value}"), + mHeight(4.0), + Text("Date: ${smartRingTemp.date}"), + ], + ), + ), + ); + }, + ), + ); + } else { + return getNoDataWidget(context); + } + } + + Widget buildHeartRateDynamicWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + if (myTrackersVm.filesLoader) { + return Center(child: CircularProgressIndicator()); + } else if (myTrackersVm.smartRingHeartRateDynamicHistory != null && myTrackersVm.smartRingHeartRateDynamicHistory.isNotEmpty) { + return Expanded( + child: ListView.separated( + itemCount: myTrackersVm.smartRingHeartRateDynamicHistory.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + SmartRingGenericModel smartRingHr = myTrackersVm.smartRingHeartRateDynamicHistory[index]; + return InkWell( + onTap: () => Navigator.pop(context), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("arrayDynamicHR: ${smartRingHr.value}"), + mHeight(4.0), + Text("Date: ${smartRingHr.date}"), + ], + ), + ), + ); + }, + ), + ); + } else { + return getNoDataWidget(context); + } + } + + Widget buildHeartRateStaticWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + if (myTrackersVm.filesLoader) { + return Center(child: CircularProgressIndicator()); + } else if (myTrackersVm.smartRingHeartRateStaticHistory != null && myTrackersVm.smartRingHeartRateStaticHistory.isNotEmpty) { + return Expanded( + child: ListView.separated( + itemCount: myTrackersVm.smartRingHeartRateStaticHistory.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + SmartRingGenericModel smartRingHr = myTrackersVm.smartRingHeartRateStaticHistory[index]; + return InkWell( + onTap: () => Navigator.pop(context), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("onceHeartValue: ${smartRingHr.value}"), + mHeight(4.0), + Text("Date: ${smartRingHr.date}"), + ], + ), + ), + ); + }, + ), + ); + } else { + return getNoDataWidget(context); + } + } + + Widget buildHrvWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + if (myTrackersVm.filesLoader) { + return Center(child: CircularProgressIndicator()); + } else if (myTrackersVm.smartRingHrvHistory != null && myTrackersVm.smartRingHrvHistory.isNotEmpty) { + return Expanded( + child: ListView.separated( + itemCount: myTrackersVm.smartRingHrvHistory.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + SmartRingHrvModel smartRingHrvModel = myTrackersVm.smartRingHrvHistory[index]; + return InkWell( + onTap: () => Navigator.pop(context), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("highBP: ${smartRingHrvModel.highBP}"), + mHeight(4.0), + Text("lowBP: ${smartRingHrvModel.lowBP}"), + mHeight(4.0), + Text("stress: ${smartRingHrvModel.stress}"), + mHeight(4.0), + Text("heartRate: ${smartRingHrvModel.heartRate}"), + mHeight(4.0), + Text("hrv: ${smartRingHrvModel.hrv}"), + mHeight(4.0), + Text("vascularAging: ${smartRingHrvModel.vascularAging}"), + ], + ), + ), + ); + }, + ), + ); + } else { + return getNoDataWidget(context); + } + } + + Widget buildBatteryLevelWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + if (myTrackersVm.filesLoader) { + return Center(child: CircularProgressIndicator()); + } else if (myTrackersVm.smartRingBatteryLevel != null && myTrackersVm.smartRingBatteryLevel.isNotEmpty) { + return Center( + child: Text("Battery Level: ${myTrackersVm.smartRingBatteryLevel}"), + ); + } else { + return getNoDataWidget(context); + } + } + + Widget buildECGWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + if (myTrackersVm.filesLoader) ...[ + Center(child: CircularProgressIndicator()) + ] else if (myTrackersVm.checkMeEcg != null && myTrackersVm.checkMeEcg.isNotEmpty) ...[ + Material( + child: ListView.separated( + itemCount: myTrackersVm.checkMeEcg.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + CheckMeECGModel checkMeECGModel = myTrackersVm.checkMeEcg[index]; + return InkWell( + onTap: () { + myTrackersVm.getEcgWaveDataFromCheckMePro(checkMeECGModel.timeString); + // Navigator.push(context, MaterialPageRoute(builder: (context) => CheckMeECGInfoScreen(SmartRingOperationsEnum.ECGTracker))); + }, + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Date: ${checkMeECGModel.date}"), + mHeight(8), + Text("TimeString: ${checkMeECGModel.timeString}"), + ], + ), + ), + ); + }, + ), + ) + ] else ...[ + getNoDataWidget(context), + ] + ], + ); + } + + Widget buildOxiWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + if (myTrackersVm.filesLoader) ...[ + Center(child: CircularProgressIndicator()) + ] else if (myTrackersVm.checkMeOxi != null && myTrackersVm.checkMeOxi.isNotEmpty) ...[ + Material( + child: ListView.separated( + itemCount: myTrackersVm.checkMeOxi.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + CheckMeOxiModel checkMeOxiModel = myTrackersVm.checkMeOxi[index]; + return InkWell( + onTap: () => Navigator.pop(context), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("PR: ${checkMeOxiModel.pr} PI: ${checkMeOxiModel.pi}"), + mHeight(4.0), + Text("Oxi: ${checkMeOxiModel.oxy}"), + mHeight(4.0), + Text("Date: ${checkMeOxiModel.date}"), + ], + ), + ), + ); + }, + ), + ) + ] else ...[ + getNoDataWidget(context), + ] + ], + ); + } + + Widget buildBPWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + if (myTrackersVm.filesLoader) ...[ + Center(child: CircularProgressIndicator()) + ] else if (myTrackersVm.checkMeBP != null && myTrackersVm.checkMeBP.isNotEmpty) ...[ + Material( + child: ListView.separated( + itemCount: myTrackersVm.checkMeBP.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + CheckMeBPModel checkMeBPModel = myTrackersVm.checkMeBP[index]; + return InkWell( + onTap: () => Navigator.pop(context), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("DIA: ${checkMeBPModel.dia} SYS: ${checkMeBPModel.sys}"), + mHeight(4.0), + Text("PR: ${checkMeBPModel.pr}"), + mHeight(4.0), + Text("Date: ${checkMeBPModel.date}"), + ], + ), + ), + ); + }, + ), + ) + ] else ...[ + getNoDataWidget(context), + ] + ], + ); + } + + Widget buildGlucoseWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + if (myTrackersVm.filesLoader) ...[ + Center(child: CircularProgressIndicator()) + ] else if (myTrackersVm.checkMeGlucose != null && myTrackersVm.checkMeGlucose.isNotEmpty) ...[ + Material( + child: ListView.separated( + itemCount: myTrackersVm.checkMeGlucose.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + CheckMeGlucoseModel checkMeGlucoseModel = myTrackersVm.checkMeGlucose[index]; + return InkWell( + onTap: () => null, + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Glucose: ${checkMeGlucoseModel.glu}"), + mHeight(4.0), + Text("Date: ${checkMeGlucoseModel.date}"), + ], + ), + ), + ); + }, + ), + ) + ] else ...[ + getNoDataWidget(context), + ] + ], + ); + } + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: "${getTrackerNameByEnum(smartRingOperationsEnum)}", + showNewAppBar: true, + isShowDecPage: false, + showNewAppBarTitle: true, + backgroundColor: Color(0xffF8F8F8), + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + children: [ + Consumer( + builder: (BuildContext context, MyTrackersViewModel myTrackersVm, Widget child) { + return getAllInOneOperationWidgets(myTrackersVm, smartRingOperationsEnum, context); + }, + ), + ], + )), + ); + } +} diff --git a/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart b/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart index b0a7ad87..261a0c7a 100644 --- a/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart +++ b/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart @@ -18,7 +18,7 @@ class BleChannel { result = await platform.invokeMethod('scanForCheckMePro'); print("----------Flutter scanCheckMeProNative Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -33,7 +33,7 @@ class BleChannel { result = await platform.invokeMethod('scanDevices', deviceType); print("----------Flutter Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -49,7 +49,7 @@ class BleChannel { result = await platform.invokeMethod('stopScanCheckMe'); print("----------Flutter Result stopNativeScan -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -64,7 +64,7 @@ class BleChannel { result = await platform.invokeMethod('connectDevice', device); print("----------Flutter Result connectDevice -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -79,7 +79,7 @@ class BleChannel { result = await platform.invokeMethod('connectDeviceCheckMe', device); print("----------Flutter Result connectDeviceCheckMe -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -91,7 +91,7 @@ class BleChannel { print("----------Flutter getECGFilesList -------"); final String result = await platform.invokeMethod('ecgFilesList', device); print("----------Flutter Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -103,7 +103,7 @@ class BleChannel { print("----------Flutter duoEkFactoryReset -------"); final String result = await platform.invokeMethod('factoryResetECG', device); print("----------Flutter Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -115,7 +115,7 @@ class BleChannel { print("----------Flutter getBP2FilesList -------"); final String result = await platform.invokeMethod('bp2FilesList', deviceType); print("----------Flutter Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -128,7 +128,7 @@ class BleChannel { final String result = await platform.invokeMethod('disconnectDevice'); final String result2 = await platform.invokeMethod('disconnectCheckMe'); print("----------Flutter Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -140,7 +140,7 @@ class BleChannel { print("----------Flutter getDeviceInfoCheckMePro -------"); final String result = await platform.invokeMethod('getDeviceInfoCheckMePro'); print("----------Flutter getDeviceInfoCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -152,7 +152,7 @@ class BleChannel { print("----------Flutter getDeviceInfoCheckMePro -------"); final String result = await platform.invokeMethod('getGlucoseDataFromCheckMePro', userId); print("----------Flutter getDeviceInfoCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -164,7 +164,7 @@ class BleChannel { print("----------Flutter getBPDataFromCheckMePro -------"); final String result = await platform.invokeMethod('getBPDataFromCheckMePro', userId); print("----------Flutter getBPDataFromCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -176,7 +176,7 @@ class BleChannel { print("----------Flutter getOxiDataFromCheckMePro -------"); final String result = await platform.invokeMethod('getOxiDataFromCheckMePro'); print("----------Flutter getOxiDataFromCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -188,7 +188,7 @@ class BleChannel { print("----------Flutter getTempDataFromCheckMePro -------"); final String result = await platform.invokeMethod('getTempDataFromCheckMePro'); print("----------Flutter getTempDataFromCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -200,7 +200,7 @@ class BleChannel { print("----------Flutter getEcgDataFromCheckMePro -------"); final String result = await platform.invokeMethod('getEcgDataFromCheckMePro'); print("----------Flutter getEcgDataFromCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -212,7 +212,7 @@ class BleChannel { print("----------Flutter getEcgWaveFromCheckMePro -------"); final String result = await platform.invokeMethod('getEcgWaveFromCheckMePro', timeString); print("----------Flutter getEcgWaveFromCheckMePro result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -229,7 +229,7 @@ class BleChannel { result = await platform.invokeMethod('scanForSmartRing'); print("----------Flutter scanForSmartRing Result -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -244,7 +244,7 @@ class BleChannel { result = await platform.invokeMethod('connectDeviceSmartRing', deviceAddress); print("----------Flutter Result connectDeviceSmartRing -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -259,7 +259,7 @@ class BleChannel { result = await platform.invokeMethod('disConnectDeviceSmartRing'); print("----------Flutter Result disConnectDeviceSmartRing -------"); - print(result); + return result; } catch (e) { return "Error: $e"; @@ -271,10 +271,72 @@ class BleChannel { print("----------Flutter getBatteryLevelSmartRing -------"); final String result = await platform.invokeMethod('getBatteryLevelSmartRing'); print("----------Flutter getBatteryLevelSmartRing result -------"); - print(result); + + return result; + } catch (e) { + return "Error: $e"; + } + } + + static Future getTemperatureSmartRing() async { + try { + print("----------Flutter getTemperatureSmartRing -------"); + final String result = await platform.invokeMethod('getTemperatureSmartRing'); + print("----------Flutter getTemperatureSmartRing result -------"); + + return result; + } catch (e) { + return "Error: $e"; + } + } + + static Future getDynamicHeartRateSmartRing() async { + try { + print("----------Flutter getDynamicHeartRateSmartRing -------"); + final String result = await platform.invokeMethod('getDynamicHeartRateSmartRing'); + print("----------Flutter getDynamicHeartRateSmartRing result -------"); + + return result; + } catch (e) { + return "Error: $e"; + } + } + + static Future getStaticHeartRateSmartRing() async { + try { + print("----------Flutter getStaticHeartRateSmartRing -------"); + final String result = await platform.invokeMethod('getStaticHeartRateSmartRing'); + print("----------Flutter getStaticHeartRateSmartRing result -------"); + return result; } catch (e) { return "Error: $e"; } } + + static Future getHRVSmartRing() async { + try { + print("----------Flutter getHRVSmartRing -------"); + final String result = await platform.invokeMethod('getHRVSmartRing'); + print("----------Flutter getHRVSmartRing result -------"); + + return result; + } catch (e) { + return "Error: $e"; + } + } + + static Future getBloodOxygenSmartRing() async { + try { + print("----------Flutter getBloodOxygenSmartRing -------"); + final String result = await platform.invokeMethod('getBloodOxygenSmartRing'); + print("----------Flutter getBloodOxygenSmartRing result -------"); + + return result; + } catch (e) { + return "Error: $e"; + } + } + + } diff --git a/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart b/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart index 11f528a3..86e403a9 100644 --- a/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart @@ -11,12 +11,12 @@ class BleDeviceModel { BleDeviceModel({this.macAddr, this.model, this.name, this.rssi, this.andesfitBluetoothDevice}); - BleDeviceModel.fromJson(Map json) { + BleDeviceModel.fromJson(Map json, TrackerTypeEnum trackerType) { macAddr = json['macAddr']; model = json['model']; name = json['name']; rssi = json['rssi']; - deviceType = TrackerTypeEnum.AllInOneTracker; + deviceType = trackerType; andesfitBluetoothDevice = null; } diff --git a/lib/pages/medical/my_trackers/ble_models/smart_ring_models.dart b/lib/pages/medical/my_trackers/ble_models/smart_ring_models.dart new file mode 100644 index 00000000..491a4c69 --- /dev/null +++ b/lib/pages/medical/my_trackers/ble_models/smart_ring_models.dart @@ -0,0 +1,76 @@ +//TEMPERATURE + +import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; + +String getValueKeyBySmartRingOperation(SmartRingOperationsEnum smartRingOperationsEnum) { + switch (smartRingOperationsEnum) { + case SmartRingOperationsEnum.Temperature: + return "temperature"; + case SmartRingOperationsEnum.HeartRateStatic: + return "onceHeartValue"; + case SmartRingOperationsEnum.HeartRateDynamic: + return "arrayDynamicHR"; + case SmartRingOperationsEnum.HRV: + // TODO: Handle this case. + break; + case SmartRingOperationsEnum.BloodOxygen: + // TODO: Handle this case. + break; + case SmartRingOperationsEnum.BatteryLevel: + return "batteryLevel"; + } + return "batteryLevel"; +} + +class SmartRingGenericModel { + DateTime date; + String value; + + SmartRingGenericModel({this.date, this.value}); + + SmartRingGenericModel.fromJson(Map json, SmartRingOperationsEnum smartRingOperationsEnum) { + date = json['date'] != null ? DateTime.parse(((json["date"] as String).replaceAll(".", "-"))) : DateTime.now(); + value = json['${getValueKeyBySmartRingOperation(smartRingOperationsEnum)}']; + } + + Map toJson(SmartRingOperationsEnum smartRingOperationsEnum) { + final Map data = new Map(); + data['date'] = this.date; + data['arrayDynamicHR'] = getValueKeyBySmartRingOperation(smartRingOperationsEnum); + return data; + } +} + +class SmartRingHrvModel { + String date; + String highBP; + String stress; + String lowBP; + String heartRate; + String hrv; + String vascularAging; + + SmartRingHrvModel({this.date, this.highBP, this.stress, this.lowBP, this.heartRate, this.hrv, this.vascularAging}); + + SmartRingHrvModel.fromJson(Map json) { + date = json['date']; + highBP = json['highBP']; + stress = json['stress']; + lowBP = json['lowBP']; + heartRate = json['heartRate']; + hrv = json['hrv']; + vascularAging = json['vascularAging']; + } + + Map toJson() { + final Map data = new Map(); + data['date'] = this.date; + data['highBP'] = this.highBP; + data['stress'] = this.stress; + data['lowBP'] = this.lowBP; + data['heartRate'] = this.heartRate; + data['hrv'] = this.hrv; + data['vascularAging'] = this.vascularAging; + return data; + } +} diff --git a/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart b/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart index ae4e4f79..f708d27f 100644 --- a/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart +++ b/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart @@ -14,6 +14,7 @@ import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkm import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_oxi_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_temperature_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_user_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/smart_ring_models.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart'; @@ -25,7 +26,6 @@ import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart'; @@ -34,6 +34,8 @@ import 'package:provider/provider.dart'; enum TrackerTypeEnum { OxymeterTracker, BloodPressureTracker, BloodSugarTracker, ECGTracker, WeightScale, Temperature, Spirometer, SmartRing, AllInOneTracker } +enum SmartRingOperationsEnum { Temperature, HeartRateStatic, HeartRateDynamic, HRV, BloodOxygen, BatteryLevel } + //NativeEventNames String kRealTimeDataBPMeasuring = "RealTimeDataBPMeasuring"; @@ -55,6 +57,11 @@ String kBPCheckMePro = "BPCheckMePro"; String kDevicesListSmartRing = "DevicesListSmartRing"; String kBatteryLevelSmartRing = "BatteryLevelSmartRing"; +String kTemperatureSmartRing = "TemperatureSmartRing"; +String kDynamicHeartRateSmartRing = "DynamicHeartRateSmartRing"; +String kStaticHeartRateSmartRing = "StaticHeartRateSmartRing"; +String kHrvSmartRing = "HrvSmartRing"; +String kBloodOxygenSmartRing = "BloodOxygenSmartRing"; class MyTrackersViewModel extends ChangeNotifier { EventChannel eventChannel = EventChannel('BLE-Platform-Bridge-Event'); @@ -90,7 +97,7 @@ class MyTrackersViewModel extends ChangeNotifier { {"model": "BLE-MSA"}, ], "SmartRing": [ - {"model": ""}, + {"model": "2301A"}, ], "AllInOneTracker": [ {"model": "Checkme 1316"}, @@ -120,7 +127,7 @@ class MyTrackersViewModel extends ChangeNotifier { {"model": "BLE-MSA"}, ], "SmartRing": [ - {"model": "2301A"}, + {"model": ""}, ], "AllInOneTracker": [ {"model": "Checkme 1316"}, @@ -136,11 +143,13 @@ class MyTrackersViewModel extends ChangeNotifier { TrackerTypeEnum.BloodSugarTracker, TrackerTypeEnum.ECGTracker, ]; - List smartRingTrackers = [ - TrackerTypeEnum.Temperature, - TrackerTypeEnum.OxymeterTracker, - TrackerTypeEnum.BloodSugarTracker, - TrackerTypeEnum.ECGTracker, + List smartRingTrackers = [ + SmartRingOperationsEnum.Temperature, + SmartRingOperationsEnum.HeartRateStatic, + SmartRingOperationsEnum.HeartRateDynamic, + SmartRingOperationsEnum.HRV, + SmartRingOperationsEnum.BloodOxygen, + SmartRingOperationsEnum.BatteryLevel, ]; List andesFitDevices = [ @@ -358,7 +367,7 @@ class MyTrackersViewModel extends ChangeNotifier { // if(Platform.isIOS) { // parsesDevicesList(json.decode(event['data'])); // } else if(Platform.isAndroid) { - parsesDevicesList(json.decode(event['data']) as List); + parsesDevicesList(json.decode(event['data']) as List, currentSelectedTrackerType); // } } @@ -406,8 +415,8 @@ class MyTrackersViewModel extends ChangeNotifier { await scanDevicesNative(currentSelectedTrackerType); } - void parsesDevicesList(List returnData) { - var devicesList = List.generate(returnData.length, (index) => BleDeviceModel.fromJson(returnData[index])); + void parsesDevicesList(List returnData, TrackerTypeEnum trackerType) { + var devicesList = List.generate(returnData.length, (index) => BleDeviceModel.fromJson(returnData[index], trackerType)); log("devicesList: ${devicesList.toString()}"); filterOutTheSearchedDevicesNative(devicesList); } @@ -433,7 +442,7 @@ class MyTrackersViewModel extends ChangeNotifier { if (currentSelectedTrackerType == TrackerTypeEnum.AllInOneTracker) { await BleChannel.connectDeviceCheckMe([device.name, device.model.toString(), currentSelectedTrackerType.name]); } else if (currentSelectedTrackerType == TrackerTypeEnum.SmartRing) { - await BleChannel.connectDeviceSmartRing("CA:59:D9:7E:3E:D6"); //TODO: NEED TO VERIFY IF IT KEEPS CHANGING OR NO + await BleChannel.connectDeviceSmartRing(device.macAddr); } else { await BleChannel.connectDevice([device.name, device.model.toString(), currentSelectedTrackerType.name]); } @@ -1125,9 +1134,9 @@ class MyTrackersViewModel extends ChangeNotifier { if (event['type'] == kDevicesListCheckMe) { if (Platform.isAndroid) { List list = [json.decode(event['data'])]; - parsesDevicesList(list); + parsesDevicesList(list, currentSelectedTrackerType); } else { - parsesDevicesList(json.decode(event['data'])); + parsesDevicesList(json.decode(event['data']), currentSelectedTrackerType); } } if (event['type'] == kCheckMeUsersList) { @@ -1372,12 +1381,36 @@ class MyTrackersViewModel extends ChangeNotifier { if (event['type'] == kDevicesListSmartRing) { if (Platform.isAndroid) { List list = [json.decode(event['data'])]; - parsesDevicesList(list); + parsesDevicesList(list, currentSelectedTrackerType); } else {} } if (event['type'] == kBatteryLevelSmartRing) { - updateCheckMeTemperatureInfoModel(json.decode(event['data'])); + updateSmartRingBatteryLevelModel(json.decode(event['data'])); + } + + if (event['type'] == kTemperatureSmartRing) { + logger.i(event['data']); + updateSmartRingTemperatureHistory(json.decode(event['data'])); + } + + if (event['type'] == kBloodOxygenSmartRing) { + logger.i(event['data']); + } + + if (event['type'] == kHrvSmartRing) { + logger.i(event['data']); + updateSmartRingHrvHistory(json.decode(event['data'])); + } + + if (event['type'] == kStaticHeartRateSmartRing) { + logger.i(event['data']); + updateSmartRingHeartRateStaticHistory(json.decode(event['data'])); + } + + if (event['type'] == kDynamicHeartRateSmartRing) { + logger.i(event['data']); + updateSmartRingHeartRateDynamicHistory(json.decode(event['data'])); } }); @@ -1420,8 +1453,115 @@ class MyTrackersViewModel extends ChangeNotifier { await device.connect(timeout: Duration(seconds: 35)); } + Future getTemperatureSmartRing() async { + if (smartRingTemperatureHistory != null) { + smartRingTemperatureHistory.clear(); + smartRingTemperatureHistory = null; + } + String data = await BleChannel.getTemperatureSmartRing(); + logger.i(jsonEncode(data.toString())); + } + Future getBatteryLevelSmartRing() async { String data = await BleChannel.getBatteryLevelSmartRing(); logger.i(jsonEncode(data.toString())); } + + Future getDynamicHeartRateSmartRing() async { + String data = await BleChannel.getDynamicHeartRateSmartRing(); + logger.i(jsonEncode(data.toString())); + } + + Future getStaticHeartRateSmartRing() async { + String data = await BleChannel.getStaticHeartRateSmartRing(); + logger.i(jsonEncode(data.toString())); + } + + Future getHRVSmartRing() async { + String data = await BleChannel.getHRVSmartRing(); + logger.i(jsonEncode(data.toString())); + } + + Future getBloodOxygenSmartRing() async { + String data = await BleChannel.getBloodOxygenSmartRing(); + logger.i(jsonEncode(data.toString())); + } + + String smartRingBatteryLevel; + + void updateSmartRingBatteryLevelModel(dynamic returnData) { + if (smartRingBatteryLevel != null) { + return; + } + Map data = returnData; + smartRingBatteryLevel = (data["dicData"]["batteryLevel"]).toString(); + notifyListeners(); + } + + //TEMPERATURE + + List smartRingTemperatureHistory; + + void updateSmartRingTemperatureHistory(dynamic returnData) { + Map data = returnData; + List response = (data["dicData"]) as List; + + List list = List.generate(response.length, (index) => SmartRingGenericModel.fromJson(response[index], SmartRingOperationsEnum.Temperature)); + if (smartRingTemperatureHistory == null) { + smartRingTemperatureHistory = list; + } else { + smartRingTemperatureHistory.addAll(list); + } + notifyListeners(); + } + + //HEART RATE DYNAMIC + + List smartRingHeartRateDynamicHistory; + + void updateSmartRingHeartRateDynamicHistory(dynamic returnData) { + Map data = returnData; + List response = (data["dicData"]) as List; + + List list = List.generate(response.length, (index) => SmartRingGenericModel.fromJson(response[index], SmartRingOperationsEnum.HeartRateDynamic)); + if (smartRingHeartRateDynamicHistory == null) { + smartRingHeartRateDynamicHistory = list; + } else { + smartRingHeartRateDynamicHistory.addAll(list); + } + log("smartRingHeartRateDynamicHistory: ${smartRingHeartRateDynamicHistory.length}"); + notifyListeners(); + } + + List smartRingHeartRateStaticHistory; + + void updateSmartRingHeartRateStaticHistory(dynamic returnData) { + Map data = returnData; + List response = (data["dicData"]) as List; + + List list = List.generate(response.length, (index) => SmartRingGenericModel.fromJson(response[index], SmartRingOperationsEnum.HeartRateStatic)); + if (smartRingHeartRateStaticHistory == null) { + smartRingHeartRateStaticHistory = list; + } else { + smartRingHeartRateStaticHistory.addAll(list); + } + log("smartRingHeartRateStaticHistory: ${smartRingHeartRateStaticHistory.length}"); + notifyListeners(); + } + + List smartRingHrvHistory; + + void updateSmartRingHrvHistory(dynamic returnData) { + Map data = returnData; + List response = (data["dicData"]) as List; + + List list = List.generate(response.length, (index) => SmartRingHrvModel.fromJson(response[index])); + if (smartRingHrvHistory == null) { + smartRingHrvHistory = list; + } else { + smartRingHrvHistory.addAll(list); + } + log("smartRingHrvHistory: ${smartRingHrvHistory.length}"); + notifyListeners(); + } }