From 220fea4c2ed004595a28d757cecc0a5fd8e7d6d8 Mon Sep 17 00:00:00 2001 From: Mariya Date: Thu, 28 Sep 2023 16:50:44 +0530 Subject: [PATCH] Added code for diagnostics --- app/build.gradle | 10 +- .../data/constant/HemoCubeCommands.kt | 2 +- .../presentation/KitScanActivity.kt | 1 + .../diagnostics/DiagnosticsFragment.kt | 207 ++++++++++++++++++ .../diagnostics/DiagnosticsViewModel.kt | 150 +++++++++++++ .../main/res/layout/fragment_diagnostics.xml | 181 +++++++++++++++ 6 files changed, 545 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt create mode 100644 app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsViewModel.kt create mode 100644 app/src/main/res/layout/fragment_diagnostics.xml diff --git a/app/build.gradle b/app/build.gradle index 4bd7456..55ec74c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -97,17 +97,17 @@ dependencies { implementation 'com.google.android.gms:play-services-code-scanner:16.1.0' //Room - implementation "androidx.room:room-ktx:2.6.0-beta01" - implementation "androidx.room:room-runtime:2.6.0-beta01" - kapt ("androidx.room:room-compiler:2.6.0-beta01") + implementation "androidx.room:room-ktx:2.6.0-rc01" + implementation "androidx.room:room-runtime:2.6.0-rc01" + kapt ("androidx.room:room-compiler:2.6.0-rc01") //image implementation 'com.github.bumptech.glide:glide:4.13.2' annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2' // Navigation Component - implementation "androidx.navigation:navigation-fragment-ktx:2.7.2" - implementation "androidx.navigation:navigation-ui-ktx:2.7.2" + implementation "androidx.navigation:navigation-fragment-ktx:2.7.3" + implementation "androidx.navigation:navigation-ui-ktx:2.7.3" //Dagger - Hilt implementation "com.google.dagger:hilt-android:2.46" diff --git a/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt b/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt index dc6893f..28acdab 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt @@ -2,7 +2,7 @@ package com.example.hpostesting.data.constant enum class HemoCubeCommands(val command: String) { startBuffer("B\r"), - getBuffer("Q\r"), + getBuffer("D\r"), startSample("S\r"), getSample("P\r"), } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt index 6aa46be..53f8fd3 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt @@ -11,6 +11,7 @@ import androidx.appcompat.app.AppCompatActivity import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.presentation.dashboard.DashboardActivity +import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity import com.example.hpostesting.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.testRight.TestRightActivity import com.google.android.material.snackbar.Snackbar diff --git a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt new file mode 100644 index 0000000..953022e --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt @@ -0,0 +1,207 @@ +package com.example.hpostesting.presentation.diagnostics + +import android.content.Context +import android.content.SharedPreferences +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.MutableLiveData +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.constant.HemoCubeCommands +import com.example.hpostesting.data.model.patient.DeviceData +import com.example.hpostesting.data.model.patient.toHemoCubeTestData +import com.example.hpostesting.presentation.UsbServiceListener +import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel +import com.example.hpostesting.presentation.utils.MyDialogListener +import com.example.hpostesting.presentation.utils.UIUtils +import com.google.firebase.crashlytics.ktx.crashlytics +import com.google.firebase.ktx.Firebase +import `in`.sminnovations.hpostesting.R +import `in`.sminnovations.hpostesting.databinding.FragmentDiagnosticsBinding + +class DiagnosticsFragment : Fragment() { + + private lateinit var binding: FragmentDiagnosticsBinding + private val diagnosticsViewModel: DiagnosticsViewModel by activityViewModels() + private lateinit var sharedPreferences: SharedPreferences + private var currentDeviceData: DeviceData? = null + private var resultData: String = "" + private val messages = MutableLiveData() + private var isTestOngoing = false + private var startListening = MutableLiveData(false) + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, + ): View { + binding = FragmentDiagnosticsBinding.inflate(inflater, container, false) + sharedPreferences = + requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + getBufferdiagnostics() + initViews() + observeViewModel() + } + + + private fun initViews() { + binding.btnKit.visibility = View.GONE + binding.btnSubmit.visibility = View.GONE + binding.etBloodGroup.visibility = View.GONE + listenToHemoCube() + getBufferdiagnostics() + } + + + private fun observeViewModel() { + + diagnosticsViewModel.deviceData.observe(viewLifecycleOwner) { + currentDeviceData = it + } + + diagnosticsViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable -> + if (isNetworkAvailable) { + diagnosticsViewModel.getDeviceData( + sharedPreferences.getString( + Constants.USER_ID, + "" + ) + ) + } else { + Toast.makeText( + requireContext(), + "No internet connection avaiable", + Toast.LENGTH_SHORT + ).show() + } + } + + messages.observe(viewLifecycleOwner) { + binding.tvSubtitle4.text = it + Log.e("diagnostics",binding.tvSubtitle4.text.toString()) + } + } + + private fun listenToHemoCube() { + if (DataHolder.hemoCubeTestData == null) { + DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData() + } + + val fullReadOutput = StringBuilder() + startListening.postValue(true) + + try { + (activity as DiagnosticsActivity).mService.listenToHemoCube(object : + UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + data?.let { + val stringData = String(it) + fullReadOutput.append(stringData) + handleUsbData(stringData, fullReadOutput) + } + } + + override fun onUsbError(e: Exception?) { + } + }) + } catch (e: Exception) { + showToast("test is going on") + Firebase.crashlytics.recordException(e) + } + } + + + private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) { + if (stringData.contains("#")) { + messages.postValue(stringData) + isTestOngoing = true + } + + resultData += fullReadOutput.toString() + + when { +// stringData.contains("ERROR 500") -> showError500Dialog() +// stringData.contains("ERROR 501") -> showError501Dialog() +// stringData.contains("#Buffer Completed") -> showStartSampleDialog() +// stringData.contains("#Sample Completed") -> fetchResult() + + stringData.contains("RESULT") || resultData.contains("REND") -> { + var validString: String + val results: List + if (stringData.contains("RESULT")) { + validString = isValidResult(stringData) + if (validString.isEmpty()) { + results = resultData.split("\n") + validString = parseResult(results) + } + } else { + results = resultData.split("\n") + validString = parseResult(results) + } + if (validString.isNotEmpty()) { +// handleValidResult(validString) + } + } + } + } + + + private fun parseResult(frames: List): String { + val lines = mutableListOf() + for (frame in frames.reversed()) { + if (frame.contains("REND") || frame.contains("RESULT")) lines += frame + if (frame.contains("RESULT")) { + break + } + } + val line = lines.reversed().joinToString("").trim() + if (line.contains("RESULT") && line.split(" ").size == 8) { + return line + } + return "" + } + + private fun isValidResult(line: String): String { + return if (line.contains("RESULT") && line.split(" ").size == 8) { + line + } else { + "" + } + } + + + private fun showToast(message: String) { + Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() + } + + + private fun getBufferdiagnostics() { + diagnosticsViewModel.progressBar.postValue(true) + (activity as DiagnosticsActivity).mService.sendAndListenToHemoCube( + HemoCubeCommands.getBuffer, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) {} + + override fun onUsbError(e: Exception?) { + diagnosticsViewModel.progressBar.postValue(false) + } + }) + } + + + + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsViewModel.kt new file mode 100644 index 0000000..3991891 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsViewModel.kt @@ -0,0 +1,150 @@ +package com.example.hpostesting.presentation.diagnostics + +import android.content.Context +import android.content.SharedPreferences +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.data.NetworkStatusLiveData +import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.dao.HemoCubeDao +import com.example.hpostesting.data.model.Response +import com.example.hpostesting.data.model.patient.DeviceData +import com.example.hpostesting.data.model.patient.HemoCubeTestData +import com.example.hpostesting.data.model.patient.toHemoCubeTestData +import com.example.hpostesting.data.repository.DatabaseRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale +import javax.inject.Inject +@HiltViewModel +class DiagnosticsViewModel @Inject constructor( + private val hemoCubeDao: HemoCubeDao, + private val repository: DatabaseRepository, + context: Context +) : ViewModel() { + var isServiceConnected = false + val progressBar = MutableLiveData(false) + val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() + val messages = MutableLiveData() + private val sharedPreference: SharedPreferences = + context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + + // Get the device ID of the device you want to retrieve data for (e.g., the first device in the list) + + private val _networkStatusLiveData = NetworkStatusLiveData(context) + val allUserData = hemoCubeDao.getAll() + val deviceData = MutableLiveData() + val networkStatusLiveData: LiveData + get() = _networkStatusLiveData + val fireBaseUpload = MutableLiveData() + + + + + fun uploadHemoCubeResultToDatabase(isOnline: Boolean, testStatus: Boolean, kitSerial: String?) = + viewModelScope.launch { + if (kitSerial != null) { + testDetails?.kitSerial = kitSerial + } + testDetails?.testStatus = testStatus + + try { + if (isOnline) { + parseData() + addResultTestToDb() + } else { + parseData() + testDetails?.testTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + hemoCubeDao.insertAll(testDetails!!) + fireBaseUpload.postValue("Local") + } + } catch (e: Exception) { + Log.e("Testdb", "Upload failed: ${e.message}") + } + } + + fun getDeviceData(deviceId: String?) = viewModelScope.launch { + deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) }) + } + + private fun parseData() { + testDetails?.deviceRatio = DataHolder.hemocubeResult + testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString() + testDetails?.location = DataHolder.location + testDetails?.testTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion + testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId + testDetails?.deviceSerialNumber = + sharedPreference.getString(Constants.USER_ID, "").toString() + testDetails?.kitSerial = sharedPreference.getString(Constants.KIT_NUMBER, "").toString() + testDetails?.led1Buffer = DataHolder.hemoCubeTestData?.led1Buffer + testDetails?.led2Buffer = DataHolder.hemoCubeTestData?.led2Buffer + testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample + testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample + testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average + testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average + testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio + testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio + testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! + } + + private fun addResultTestToDb() { + viewModelScope.launch { + try { + testDetails!!.reportUploadTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + + when (val response = repository.addTestToDatabase(testDetails)) { + is Response.Success -> { + val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0) + with(sharedPreference.edit()) { + putInt(Constants.KIT_COUNT, kitCount.plus(1)) + apply() + } + Log.i("Testdb", "Data uploaded to Firestore successfully") + fireBaseUpload.postValue("Success") + } + + is Response.Error -> { + Log.e("Testdb", "Error uploading data to Firestore: $response") + fireBaseUpload.postValue("Error") + } + } + } catch (e: Exception) { + Log.e("Testdb", "Exception during data upload: ${e.message}") + fireBaseUpload.postValue("Error") + } + } + } + + fun bulkAddResultTestToDb(userData: HemoCubeTestData) { + viewModelScope.launch { + userData.reportUploadTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + when (repository.addTestToDatabase(userData)) { + is Response.Success -> { + fireBaseUpload.postValue("Success") + deleteById(userData._id) + } + + else -> {} + } + } + } + + fun deleteById(userId: String) = viewModelScope.launch { + hemoCubeDao.deleteById(id = userId) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_diagnostics.xml b/app/src/main/res/layout/fragment_diagnostics.xml new file mode 100644 index 0000000..4c01236 --- /dev/null +++ b/app/src/main/res/layout/fragment_diagnostics.xml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +