Compare commits

...

19 Commits

Author SHA1 Message Date
smileomi18@gmail.com
5966af95eb added separate buttons for place buffer and sample in new branch, and also buffer made compulsory for every test 2023-09-21 11:02:36 +05:30
Pritimay Sarkar
095f9fb027 sorting user list in decending order
- create index
2023-09-18 14:40:58 +05:30
Pritimay Sarkar
1fb938bd0d release 2.1.10 2023-09-18 11:11:05 +05:30
Pritimay Sarkar
865922e90e disable app distribution for stoping its alert 2023-09-18 11:08:06 +05:30
Pritimay Sarkar
e71496e423 remove start buffer and sample button from prod build
- add firebase exception log
2023-09-18 10:57:02 +05:30
Pritimay Sarkar
472b50562b ignore keys 2023-09-18 02:33:27 +05:30
Pritimay Sarkar
81e8567b49 remove BuildConfig 2023-09-18 02:26:22 +05:30
Pritimay Sarkar
3f8b931684 Merge branch 'classification' into Homocube 2023-09-18 02:19:47 +05:30
Pritimay Sarkar
270cee7a9c show classification in screen message before db save 2023-09-18 02:01:23 +05:30
Pritimay Sarkar
515ab24ce6 add result classification
- add result classification
	- add sample start command for positive confirmation
	- remove toast on result screen
2023-09-17 23:46:30 +05:30
Pritimay Sarkar
e455cacf69 Merge branch 'CrashIssues' into 'Homocube'
production errors

See merge request sminnovations/hpos!4
2023-09-16 05:43:27 +00:00
Mariya Varghese
45613b2709 production errors 2023-09-16 05:43:27 +00:00
smileomi18@gmail.com
34bed4e5fe app version -updation- notifying user 2023-09-15 17:26:38 +05:30
smileomi18@gmail.com
f019e1897d Added placebuffer and sample buttons for the new feature 2023-09-15 17:03:03 +05:30
Pritimay Sarkar
1d542f5562 Merge branch 'kitscan_fix' into Homocube 2023-09-11 09:22:06 +05:30
Pritimay Sarkar
4289d1c399 release version 2.1.3 2023-09-11 09:20:55 +05:30
Pritimay Sarkar
38f2122444 add version name in the settings 2023-09-10 23:59:54 +05:30
Pritimay Sarkar
d6bacd578c show users in ordered, latest first 2023-09-10 23:58:02 +05:30
Pritimay Sarkar
f8a7bff5b2 add new kit button
- device data processing error toast
2023-09-10 23:55:24 +05:30
17 changed files with 430 additions and 119 deletions

2
app/.gitignore vendored
View File

@@ -1,3 +1,3 @@
/build
/google-services.json
/google-services*
/idea

View File

@@ -18,8 +18,8 @@ android {
applicationId "in.sminnovations.hpostesting"
minSdk 21
targetSdk 34
versionCode 2
versionName "2.0.1"
versionCode 10
versionName "2.1.10"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -52,11 +52,11 @@ android {
dependencies {
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
//firebase
implementation platform('com.google.firebase:firebase-bom:32.1.0')
@@ -66,10 +66,13 @@ dependencies {
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.firebaseui:firebase-ui-firestore:8.0.2'
implementation 'com.google.android.gms:play-services-auth:20.6.0'
implementation 'com.google.android.gms:play-services-auth:20.7.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
implementation 'com.google.android.things:androidthings:1.0'
implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta10'
implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta10")
// Testing
testImplementation 'junit:junit:4.13.2'
@@ -77,7 +80,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
implementation 'com.opencsv:opencsv:4.6'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
@@ -102,8 +105,8 @@ dependencies {
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
// Navigation Component
implementation "androidx.navigation:navigation-fragment-ktx:2.7.1"
implementation "androidx.navigation:navigation-ui-ktx:2.7.1"
implementation "androidx.navigation:navigation-fragment-ktx:2.7.2"
implementation "androidx.navigation:navigation-ui-ktx:2.7.2"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.46"

View File

@@ -5,6 +5,8 @@ import android.content.Context
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.google.android.datatransport.runtime.dagger.Provides
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.FirebaseFirestoreSettings
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -15,5 +17,14 @@ import javax.inject.Singleton
class HPOSTestingApplication: Application() {
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onCreate() {
super.onCreate()
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(true) // Enable offline persistence if needed
.build()
val firestore = FirebaseFirestore.getInstance()
firestore.firestoreSettings = firestoreSettings
}
}

View File

@@ -9,15 +9,15 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
@Dao
interface HemoCubeDao {
@Query("SELECT * from HemocubeTest_table")
@Query("SELECT * from hemo_cube_test_table")
fun getAll(): LiveData<List<HemoCubeTestData>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(hemoCubeTestData: HemoCubeTestData)
@Query("SELECT * FROM hemocubetest_table WHERE _id = :id")
@Query("SELECT * FROM hemo_cube_test_table WHERE _id = :id")
suspend fun getUserByID(id: String): HemoCubeTestData
@Query("DELETE FROM hemocubetest_table WHERE _id = :id")
@Query("DELETE FROM hemo_cube_test_table WHERE _id = :id")
suspend fun deleteById(id: String)
}

View File

@@ -3,7 +3,7 @@ package com.example.hpostesting.data.model.patient
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "HemocubeTest_table")
@Entity(tableName = "hemo_cube_test_table")
data class HemoCubeTestData(
@PrimaryKey
var _id: String = "",
@@ -29,5 +29,6 @@ data class HemoCubeTestData(
var led1Average: Double? = null,
var led2Average: Double? = null,
var deviceRatio: Double? = null,
var calculatedRatio: Double? = null
var calculatedRatio: Double? = null,
var classificationResult: String = ""
)

View File

@@ -5,6 +5,7 @@ import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.DataHolder
@@ -12,6 +13,8 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
@@ -52,20 +55,48 @@ class KitScanActivity : AppCompatActivity() {
moveToNext()
}
if (checkHemoCubeKitData()) {
DataHolder.selectedTest!!.kitSerial =
sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
moveToNext()
} else {
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
apply()
// if (checkHemoCubeKitData()) {
// DataHolder.selectedTest!!.kitSerial =
// sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
// moveToNext()
// } else {
// with(sharedPreference.edit()) {
// putString(Constants.KIT_NUMBER, "")
// putInt(Constants.KIT_COUNT, 0)
// putString(Constants.BUFFER_VALUE_1, "")
// putString(Constants.BUFFER_VALUE_2, "")
// apply()
// }
// }
try {
if (checkHemoCubeKitData()) {
DataHolder.selectedTest!!.kitSerial =
sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
moveToNext()
} else {
// Handle the case when checkHemoCubeKitData() returns false
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
putString(Constants.BUFFER_VALUE_1, "")
putString(Constants.BUFFER_VALUE_2, "")
apply()
}
}
} catch (e: NullPointerException) {
// Handle the NullPointerException here
e.printStackTrace() // You can log the exception for debugging
FirebaseCrashlytics.getInstance().recordException(e)
val errorMessage = "An error occurred: ${e.message}"
val rootView = findViewById<View>(android.R.id.content)
Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show()
// Optionally, show a user-friendly error message to the user
// Toast.makeText(applicationContext, "An error occurred", Toast.LENGTH_SHORT).show()
}
binding.nameEditText.setText("SMI/SC/")
setSupportActionBar(binding.toolbar)

View File

@@ -20,7 +20,10 @@ import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.android.gms.location.*
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.hoho.android.usbserial.driver.UsbSerialProber
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
@@ -83,6 +86,11 @@ class MainActivity : AppCompatActivity() {
}
}
if (DataHolder.selectedTest == null) {
startActivity(Intent(this, DashboardActivity::class.java))
finish()
}
// val crashButton = Button(this)
// crashButton.text = "Test Crash"
@@ -159,12 +167,14 @@ class MainActivity : AppCompatActivity() {
DataHolder.selectedTestType = TestType.SICKLECERT
val i = Intent(applicationContext, KitScanActivity::class.java)
startActivity(i)
finish()
}
binding.cvItem2.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLEFIND
val i = Intent(applicationContext, KitScanActivity::class.java)
startActivity(i)
finish()
}
DataHolder.usbConnected.observe(this) {
@@ -234,18 +244,46 @@ class MainActivity : AppCompatActivity() {
return
}
// fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
// location?.let {
// DataHolder.selectedTest!!.location =
// UserData.Location(location.latitude, location.longitude)
// DataHolder.location =
// UserData.Location(location.latitude, location.longitude)
// } ?: run {
// requestLocationUpdates()
// }
// }.addOnFailureListener { exception: Exception ->
// exception.printStackTrace()
// }
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
location?.let {
DataHolder.selectedTest!!.location =
UserData.Location(location.latitude, location.longitude)
if (DataHolder.selectedTest != null) {
DataHolder.selectedTest!!.location =
UserData.Location(location.latitude, location.longitude)
} else {
startActivity(Intent(this, DashboardActivity::class.java))
finish()
}
DataHolder.location =
UserData.Location(location.latitude, location.longitude)
} ?: run {
requestLocationUpdates()
}
}.addOnFailureListener { exception: Exception ->
// Handle the exception here
exception.printStackTrace()
FirebaseCrashlytics.getInstance().recordException(exception)
// Display an error message to the user using a Snackbar
val errorMessage = "An error occurred: ${exception.message}"
val rootView = findViewById<View>(android.R.id.content)
Snackbar.make(rootView, errorMessage, Snackbar.LENGTH_LONG).show()
}
}
private fun requestLocationUpdates() {

View File

@@ -39,7 +39,7 @@ class SplashActivity : AppCompatActivity() {
binding = ActivitySplashBinding.inflate(layoutInflater)
setContentView(binding.root)
setupFirestoreCache()
// setupFirestoreCache()
setupStaticConstants()
requestPermissions()
@@ -50,12 +50,12 @@ class SplashActivity : AppCompatActivity() {
Settings.Secure.getString(applicationContext.contentResolver, Settings.Secure.ANDROID_ID)
}
private fun setupFirestoreCache() {
val settings = FirebaseFirestoreSettings.Builder()
.setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
.build()
Firebase.firestore.firestoreSettings = settings
}
// private fun setupFirestoreCache() {
// val settings = FirebaseFirestoreSettings.Builder()
// .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
// .build()
// Firebase.firestore.firestoreSettings = settings
// }
private fun requestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

View File

@@ -2,6 +2,7 @@ package com.example.hpostesting.presentation.dashboard
import android.os.Bundle
import android.view.Menu
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController
@@ -10,6 +11,8 @@ import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.navigation.NavigationView
//import com.google.firebase.appdistribution.FirebaseAppDistribution
//import com.google.firebase.appdistribution.FirebaseAppDistributionException
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
@@ -25,7 +28,6 @@ class DashboardActivity : AppCompatActivity() {
binding = ActivityDashboardBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar)
val drawerLayout: DrawerLayout = binding.drawerLayout
@@ -53,4 +55,31 @@ class DashboardActivity : AppCompatActivity() {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
override fun onResume() {
super.onResume()
// Copy and paste this into any part of your app - for example, in your main
// activity's onResume method.
// val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
// firebaseAppDistribution.updateIfNewReleaseAvailable()
// .addOnProgressListener { updateProgress ->
// Toast.makeText(this, "Updating", Toast.LENGTH_SHORT).show()
// }
// .addOnFailureListener { e ->
// // (Optional) Handle errors.
// if (e is FirebaseAppDistributionException) {
// when (e.errorCode) {
// FirebaseAppDistributionException.Status.NOT_IMPLEMENTED -> {
// // SDK did nothing. This is expected when building for Play.
// }
//
// else -> {
// // Handle other errors.
// }
// }
// }
// }
}
}

View File

@@ -25,7 +25,7 @@ class GalleryFragment : Fragment() {
// val galleryViewModel =
// ViewModelProvider(this).get(GalleryViewModel::class.java)
// _binding = FragmentGalleryBinding.inflate(inflater, container, false)
_binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root
// val textView: TextView = binding.textGallery

View File

@@ -20,6 +20,7 @@ import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.Query
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import dagger.hilt.android.AndroidEntryPoint
@@ -37,8 +38,16 @@ class HomeFragment : Fragment() {
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
// Check if _binding is null
if (_binding == null) {
// Handle the case where binding could not be initialized
// You may want to log an error or return a default view in this case
return super.onCreateView(inflater, container, savedInstanceState)
}
sharedPreference = requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
DataHolder.selectedTest = null
@@ -90,6 +99,7 @@ class HomeFragment : Fragment() {
}
}
private fun loadUserData() {
// val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false).orderBy("createdAt", Query.Direction.DESCENDING)
val query = Firebase.firestore.collection("patientData").whereEqualTo("testStatus", false)
query.get().addOnSuccessListener {
if (it.documents.isEmpty()) {
@@ -154,8 +164,10 @@ class HomeFragment : Fragment() {
binding.aadharIdRadioButton.isChecked -> "aadharId"
else -> null
}
field?.let { getData(query, it) }
false
} else {
loadUserData()
false
@@ -252,7 +264,7 @@ class HomeFragment : Fragment() {
private fun deleteHemoCubeIncompleteRegistrations(userDataList: List<HemoCubeTestData>) {
userDataList.forEach { userData ->
if (userData.testTime?.isEmpty() == false) {
if (userData.testTime?.isEmpty() == true) {
hemoCubeViewModel.deleteById(userData._id)
}
}

View File

@@ -9,6 +9,7 @@ import androidx.lifecycle.ViewModelProvider
import com.example.hpostesting.presentation.dashboard.ui.slideshow.SlideshowViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
class SlideshowFragment : Fragment() {
private var _binding: FragmentSlideshowBinding? = null
@@ -20,7 +21,7 @@ class SlideshowFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
savedInstanceState: Bundle?,
): View {
val slideshowViewModel =
ViewModelProvider(this).get(SlideshowViewModel::class.java)
@@ -28,6 +29,12 @@ class SlideshowFragment : Fragment() {
_binding = FragmentSlideshowBinding.inflate(inflater, container, false)
val root: View = binding.root
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
binding.textSlideshow.text = version
// val textView: TextView = binding.textSlideshow
// slideshowViewModel.text.observe(viewLifecycleOwner) {
// textView.text = it

View File

@@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.lifecycleScope
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
@@ -21,13 +22,14 @@ import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
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.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.BuildConfig
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
@@ -43,9 +45,9 @@ class HemoCubeFragment : Fragment() {
private var resultData: String = ""
private var isUsingExistingBuffer = false
private var isTestOngoing = false
private var bloodGroup: String = ""
private var startListening = MutableLiveData<Boolean>(false)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences =
@@ -57,7 +59,7 @@ class HemoCubeFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
checkAndStartProcess()
// checkAndStartProcess()
}
private fun initViews() {
@@ -78,10 +80,25 @@ class HemoCubeFragment : Fragment() {
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
binding.btnSamplestart.setOnClickListener {
startSampleProcess()
it.visibility = View.GONE
}
binding.btnPlacebuffer.setOnClickListener {
checkAndStartProcess()
it.visibility = View.GONE
}
binding.btnKit.setOnClickListener {
if (isTestOngoing) {
val title = "WARNING"
val message = "There is a on going test, do you want to stop it"
val message =
"There is a on going test, do you want to stop it. if Yes please disconnect the device and connect it again, once you reached to kitDetails Screen"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
@@ -102,6 +119,11 @@ class HemoCubeFragment : Fragment() {
(activity as HemocubeActivity).finish()
}
})
} else {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
}
}
@@ -150,26 +172,50 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
showToast(calculateRatio(0.17).toString())
}
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
isOnline = isNetworkAvailable
apply {
DataHolder.hemoCubeTestData?.let {
currentDeviceData?.coefficients?.let { coefficients ->
val coefficient1 = coefficients[0]
val coefficient2 = coefficients[1]
val result = coefficient1 * coefficient2
showToast("coefficients: $coefficient1, $coefficient2")
}
}
isOnline = isNetworkAvailable
}
}
hemoCubeViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
// startListening.observe(viewLifecycleOwner) {
// if (it) {
// lifecycleScope.launch {
// delay(1000)
// if (binding.tvSubtitle4.text.toString().isEmpty()) {
// (activity as HemocubeActivity).reconnectDevice()
// if (isBufferValueAvailable()) {
// showBufferAlertDialog()
// } else {
// listenToHemoCube()
// startBufferProcess()
// }
// }
// }
// }
// }
}
private fun checkAndStartProcess() {
if (isBufferValueAvailable()) {
showBufferAlertDialog()
} else {
// if (isBufferValueAvailable()) {
// showBufferAlertDialog()
// } else {
listenToHemoCube()
startBufferProcess()
}
// }
}
private fun isBufferValueAvailable(): Boolean {
@@ -218,19 +264,26 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder()
(activity as HemocubeActivity).mService.listenToHemoCube(object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
handleUsbData(stringData, fullReadOutput)
}
}
startListening.postValue(true)
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
try {
(activity as HemocubeActivity).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?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
showToast("test is going on")
Firebase.crashlytics.recordException(e)
}
}
private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
@@ -242,9 +295,18 @@ class HemoCubeFragment : Fragment() {
resultData += fullReadOutput.toString()
when {
stringData.contains("ERROR 500") -> showError500Dialog()
stringData.contains("ERROR 500") ->
// showError500Dialog()
checkAndStartProcess()
stringData.contains("ERROR 501") -> showError501Dialog()
stringData.contains("#Buffer Completed") -> showStartSampleDialog()
stringData.contains("#Buffer Completed") ->
// showStartSampleDialog()
activity?.runOnUiThread {
binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true
}
stringData.contains("#Sample Completed") -> {
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
@@ -272,6 +334,25 @@ class HemoCubeFragment : Fragment() {
}
}
private fun showError() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
"Device Error",
"Something is wrong with the device, please disconnect and reconnect the device and test the user again",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
})
}
}
private fun showError500Dialog() {
UIUtils.createAlertDialog(requireContext(),
"BUFFER ERROR",
@@ -288,6 +369,19 @@ class HemoCubeFragment : Fragment() {
})
}
fun handleBackButtonPress() {
if (isTestOngoing) {
// If the test is ongoing, don't allow the back button action
// You can optionally show a message to the user indicating why the back button is disabled
// For example, show a Toast or Snackbar.
showToast("Test is ongoing. Cannot go back.")
} else {
// If the test is not ongoing, you can trigger the back action of the hosting activity
activity?.onBackPressed()
}
}
private fun showError501Dialog() {
UIUtils.createAlertDialog(requireContext(),
"SAMPLE ERROR",
@@ -315,7 +409,8 @@ class HemoCubeFragment : Fragment() {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
@@ -336,21 +431,24 @@ class HemoCubeFragment : Fragment() {
} else {
result[4].toDoubleOrNull()
}
val version = BuildConfig.VERSION_NAME
val pInfo = requireActivity().packageManager.getPackageInfo(
requireActivity().packageName, 0
)
val version = pInfo.versionName
val led1Sample = result[5].toDoubleOrNull()
val led2Sample = result[6].toDoubleOrNull()
val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0)
val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0)
val deviceRatio = led1Average / led2Average
if (led1BufferForDevice!! > 20000 && led1BufferForDevice < 24000 && led2BufferForDevice!! > 20000 && led2BufferForDevice < 24000) {
if (led1Sample!! < led1BufferForDevice && led1Sample < 24000 && led2Sample!! < led2BufferForDevice && led2Sample < 24000) {
if (deviceRatio < 0.08) {
if (deviceRatio > 1.07) {
}
}
}
}
// if (led1BufferForDevice!! > 20000 && led1BufferForDevice < 24000 && led2BufferForDevice!! > 20000 && led2BufferForDevice < 24000) {
// if (led1Sample!! < led1BufferForDevice && led1Sample < 24000 && led2Sample!! < led2BufferForDevice && led2Sample < 24000) {
// if (deviceRatio < 0.08) {
// if (deviceRatio > 1.07) {
//
// }
// }
// }
// }
DataHolder.hemoCubeTestData?.apply {
deviceId = deviceSerialNo
led1Buffer = led1BufferForDevice
@@ -362,6 +460,8 @@ class HemoCubeFragment : Fragment() {
this.led2Average = led2Average
this.deviceRatio = deviceRatio
this.calculatedRatio = calculateRatio(deviceRatio)
this.classificationResult = findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue(this.classificationResult)
this.resultData = fullReadOutput
if (!isBufferValueAvailable()) {
with(sharedPreferences.edit()) {
@@ -370,16 +470,50 @@ class HemoCubeFragment : Fragment() {
apply()
}
}
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
}
}
} catch (_: Exception) {
} catch (e: Exception) {
Toast.makeText(
requireContext(),
"Error while processing device data",
Toast.LENGTH_SHORT
).show()
Firebase.crashlytics.recordException(e)
}
}
private fun findResult(calculatedRatio: Double?): String {
try {
if (calculatedRatio != null) {
if (calculatedRatio < 0.085)
return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume"
if (calculatedRatio in 0.085..0.155)
return "Normal"
if (calculatedRatio in 0.155..0.175)
return "Negative Borderline. Repeat Test"
if (calculatedRatio in 0.175..0.22)
return "Sickle Cell Trait"
if (calculatedRatio in 0.22..0.25)
return "Positive for Sickle Cell. HPLC for Confirmation"
if (calculatedRatio in 0.25..0.35)
return "Sickle Cell Disease"
if (calculatedRatio > 0.35)
return "Inconclusive. Repeat with test with lower volume of blood"
} else {
return "NULL"
}
} catch (e: Exception) {
showToast("error while performing classification")
Firebase.crashlytics.recordException(e)
return "ERROR"
}
return "NULL"
}
private fun showToast(message: String) {

View File

@@ -14,7 +14,6 @@ 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.UserData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -34,7 +33,8 @@ class HemoCubeViewModel @Inject constructor(
val progressBar = MutableLiveData(false)
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences = context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
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)
@@ -53,8 +53,10 @@ class HemoCubeViewModel @Inject constructor(
try {
if (isOnline) {
parseData()
addResultTestToDb()
} else {
parseData()
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
@@ -70,7 +72,7 @@ class HemoCubeViewModel @Inject constructor(
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
}
private fun addResultTestToDb() {
private fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location
@@ -79,7 +81,8 @@ class HemoCubeViewModel @Inject constructor(
).format(Calendar.getInstance().time)
testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
testDetails?.deviceSerialNumber = sharedPreference.getString(Constants.USER_ID, "").toString()
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
@@ -89,7 +92,10 @@ class HemoCubeViewModel @Inject constructor(
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(
@@ -100,7 +106,7 @@ class HemoCubeViewModel @Inject constructor(
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1) ?: 0)
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
@@ -108,14 +114,9 @@ class HemoCubeViewModel @Inject constructor(
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: ${response}")
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
else -> {
Log.e("Testdb", "Unknown response from repository: $response")
fireBaseUpload.postValue("Unknown")
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
@@ -132,6 +133,7 @@ class HemoCubeViewModel @Inject constructor(
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
deleteById(userData._id)
}
else -> {}

View File

@@ -3,7 +3,6 @@ package com.example.hpostesting.presentation.hemocube
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.ContentValues.TAG
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
@@ -11,32 +10,26 @@ import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.testRight.TestRightExpReference
import com.example.hpostesting.presentation.testRight.TestRightExpSample
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import com.example.hpostesting.presentation.testRight.UsbService
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
@AndroidEntryPoint
class HemocubeActivity : AppCompatActivity() {
open class HemocubeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>()
private var myMenu: Menu? = null
@@ -91,18 +84,20 @@ class HemocubeActivity : AppCompatActivity() {
}
private fun setupListener() {
DataHolder.usbConnected.observe(this){
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it){
myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} else {
myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
private fun connectUsb(permissionGranted: Boolean) {
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
@@ -126,10 +121,7 @@ class HemocubeActivity : AppCompatActivity() {
val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_MUTABLE
this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
@@ -145,30 +137,46 @@ class HemocubeActivity : AppCompatActivity() {
manager.requestPermission(device, mPendingIntent)
}
private fun setupService() {
fun setupService() {
val intent = Intent(this, UsbService::class.java)
// startService(intent)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed)
return
supportFragmentManager.beginTransaction()
.replace(binding.fghemocube.id, HemoCubeFragment()).commit()
open fun reconnectDevice() {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
connectUsb(true)
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeFragment())
.commit()
}
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(R.id.fghemocube)
if (fragment is HemoCubeFragment) {
fragment.handleBackButtonPress()
} else {
super.onBackPressed()
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing)
onBackPressed()
if (!isFinishing) onBackPressed()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {

View File

@@ -58,6 +58,40 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
<Button
android:visibility="gone"
android:id="@+id/btn_samplestart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/Start_Sample"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/til_blood_group" />
<Button
android:id="@+id/btn_placebuffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/place_buffer"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
@@ -71,7 +105,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/til_blood_group" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"

View File

@@ -112,6 +112,8 @@
<string name="sickle_cert">Sickle Cert</string>
<string name="sickle_find">Sickle Find</string>
<string name="submit">Submit</string>
<string name="place_buffer">Start Buffer</string>
<string name="Start_Sample">Start Sample</string>
<string name="new_kit">New Kit</string>
<string name="new_buffer">New Buffer</string>
<string name="name_error_2">Invalid character, Allowed characters are Letters, Numbers and ( ) _ - , . only</string>