Compare commits

...

58 Commits

Author SHA1 Message Date
Mariya
6d8d33dfc9 Coefficients Adding issue fixed, and
the data stored locally itself
  with or without internet,
2023-12-08 22:27:31 +05:30
Pritimay Sarkar
babb3dd364 Merge branch 'fix-kit-check' into 'Homocube'
fix diagnostics reading and kit check

See merge request sminnovations/hpos!10
2023-10-31 03:46:32 +00:00
Pritimay Sarkar
51f3e31f27 fix diagnostics reading
- show and hide start button
	- show toast message after db upload
	- fix deviceid blank
2023-10-31 01:57:49 +05:30
Pritimay Sarkar
044c5db161 add coefficients in models and save coeffs in db 2023-10-30 23:48:49 +05:30
Pritimay Sarkar
f4085545ea use calculated ratio for class and save coeffs 2023-10-30 23:25:45 +05:30
Pritimay Sarkar
8872e484a1 refactoring 2023-10-30 21:08:02 +05:30
Pritimay Sarkar
88aab7c527 negative abs warning 2023-10-29 15:23:00 +05:30
Pritimay Sarkar
81298f9634 Merge branch 'hc-deviceid' into 'Homocube'
device in diagnostics and warning for loginid mismatch

See merge request sminnovations/hpos!9
2023-10-29 08:22:02 +00:00
Pritimay Sarkar
8824fb6b11 run deviceid command and store deviceid in spref 2023-10-29 13:33:18 +05:30
Pritimay Sarkar
0e847bad0a show warning msg for loginid mismatch 2023-10-29 13:16:30 +05:30
Pritimay Sarkar
9d06a77091 clean 2023-10-29 12:17:00 +05:30
Pritimay Sarkar
7ece136cb5 add deviceid constant 2023-10-29 12:16:40 +05:30
Pritimay Sarkar
5f44666387 clean functions 2023-10-29 12:15:40 +05:30
Pritimay Sarkar
2cccfc6a63 add testing trace 2023-10-29 12:06:39 +05:30
Pritimay Sarkar
50bfd3f962 stringData in device log 2023-10-29 12:01:07 +05:30
Pritimay Sarkar
d750930b7a show toast if download is greater than 0 2023-10-29 11:00:27 +05:30
Pritimay Sarkar
4214c32829 hide app update success toast 2023-10-29 06:48:38 +05:30
Pritimay Sarkar
481169a181 add diag data model 2023-10-29 06:37:54 +05:30
Pritimay Sarkar
441e7d14b8 add device connection code in diag activity 2023-10-29 06:37:20 +05:30
Pritimay Sarkar
71f3169ee3 add diaggnostics run in diag fragment 2023-10-29 06:36:02 +05:30
Pritimay Sarkar
5edeef0021 change diag activity layout 2023-10-29 06:34:40 +05:30
Pritimay Sarkar
5f5037f300 change diagnostics fragment 2023-10-29 06:34:04 +05:30
Pritimay Sarkar
a99c24dd86 add diagnostics data log fun in viewmodel 2023-10-29 06:31:57 +05:30
Pritimay Sarkar
feabcebd92 add diagnostics fun in repository 2023-10-29 06:31:15 +05:30
Pritimay Sarkar
5df58a3630 fix calculatedRatio value in kit checks 2023-10-29 06:30:26 +05:30
Pritimay Sarkar
c6d2e2a7c5 add diagonistics activity 2023-10-29 03:40:32 +05:30
Mariya
e974637744 Diagnostics code added 2023-10-29 03:39:39 +05:30
Mariya
220fea4c2e Added code for diagnostics 2023-10-29 03:36:01 +05:30
Pritimay Sarkar
f67dc04916 call calculateRatio fun 2023-10-27 10:54:58 +05:30
Pritimay Sarkar
d90dfc0695 measure user search trace after success 2023-10-25 14:42:16 +05:30
Pritimay Sarkar
2b1f8a07ae fix display of name and user id in testing screen
- show name and sample id while testing
	- hide the same in buffer check
	- change bg color after classification
2023-10-23 05:04:03 +05:30
Pritimay Sarkar
26246cd902 add parition based search
- optimize user search based on partition and denormalization
2023-10-23 05:00:58 +05:30
Pritimay Sarkar
f2f927cd23 add user search trace 2023-10-22 18:28:33 +05:30
Pritimay Sarkar
3249811c0d hide testing instructions label 2023-10-22 18:27:42 +05:30
Pritimay Sarkar
c076da3bb4 hide labels in testing screen 2023-10-17 09:21:16 +05:30
Pritimay Sarkar
1f31b0bff0 refactor 2023-10-17 09:01:56 +05:30
Pritimay Sarkar
8b833ca02d fix calculated ratio= 0 and submit btn 2023-10-17 08:58:05 +05:30
Pritimay Sarkar
2c50890b0d add testtime 2023-10-17 08:39:25 +05:30
Kaif
0b52dc42b0 Fixed merge config 2023-10-16 14:03:28 +05:30
Pritimay Sarkar
137eb7dd55 compiler error 2023-10-16 13:21:47 +05:30
Pritimay Sarkar
12df83db7b Merge 'BuffercheckDatabaseUpload' into Homocube 2023-10-16 11:51:41 +05:30
Pritimay Sarkar
9849921833 Merge branch 'Homocube' of https://gitlab.com/sminnovations/hpos into Homocube 2023-10-15 13:06:01 +05:30
Pritimay Sarkar
8662e03dad activity finish on success 2023-10-15 13:05:14 +05:30
Kaif
ac2bb91648 Buffer result uploaded successfully 2023-10-15 12:30:27 +05:30
Kaif
0408ef3fbd Save Data in Local storage in ever condition 2023-10-13 19:42:34 +05:30
Mariya
9db8e962d7 BufferCheckData uploaded to database code pending 2023-10-13 18:50:57 +05:30
Pritimay Sarkar
7c4717ebb7 added view model, laytouts 2023-10-12 19:12:40 +05:30
Pritimay Sarkar
eb668c631c hide bloodgroup and incubate btn after action 2023-10-12 09:53:44 +05:30
Pritimay Sarkar
3e362a22fa add view model for buffer check 2023-10-12 07:19:24 +05:30
Pritimay Sarkar
e2c07d6252 Merge branch 'BuffercheckDatabaseUpload' into 'Homocube'
buffer precheck data upload to database

See merge request sminnovations/hpos!7
2023-10-12 01:38:09 +00:00
Pritimay Sarkar
497a61c16b Merge branch 'Homocube' into 'BuffercheckDatabaseUpload'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt
2023-10-12 01:27:44 +00:00
Pritimay Sarkar
acd9262dfe incubate while bloodgrouping 2023-10-12 06:30:52 +05:30
Mariya
f8ac0e81ce Buffercheck data Database Upload 2023-10-11 23:22:11 +05:30
Mariya
5a7a09817f Buffercheck data Database Upload 2023-10-11 17:19:10 +05:30
Mariya
ab09c659b9 Blood Group Updation in database added , from user card successfully added 2023-10-11 15:17:16 +05:30
Mariya
14c15bb9ab Added Blood group pop up dialog in user card 2023-10-11 15:16:32 +05:30
Mariya
0ca4083c16 Database upload completed 2023-10-11 12:32:07 +05:30
Mariya
662e2644f2 Added Blood group pop up dialog in user card 2023-10-11 11:21:50 +05:30
31 changed files with 1465 additions and 293 deletions

View File

@@ -18,8 +18,8 @@ android {
applicationId "in.sminnovations.hpostesting"
minSdk 21
targetSdk 34
versionCode 20
versionName "2.1.21"
versionCode 24
versionName "2.1.24"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -54,12 +54,14 @@ dependencies {
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 'com.google.android.material:material:1.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'com.opencsv:opencsv:5.5'
//firebase
implementation platform('com.google.firebase:firebase-bom:32.1.0')
implementation("com.google.firebase:firebase-perf-ktx")
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")
implementation 'com.google.firebase:firebase-firestore-ktx'
@@ -70,8 +72,8 @@ dependencies {
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")
implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11'
implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta11")
// Testing
@@ -81,13 +83,12 @@ dependencies {
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'
implementation "androidx.fragment:fragment-ktx:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.6.2"
// CSV read, write
implementation 'com.opencsv:opencsv:4.6'
implementation 'com.opencsv:opencsv:5.5'
// Barcode scanner
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
@@ -96,22 +97,22 @@ 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.1"
implementation "androidx.room:room-runtime:2.6.1"
kapt ("androidx.room:room-compiler:2.6.1")
//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.5"
implementation "androidx.navigation:navigation-ui-ktx:2.7.5"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.46"
kapt "com.google.dagger:hilt-android-compiler:2.46"
kapt "androidx.hilt:hilt-compiler:1.0.0"
kapt "androidx.hilt:hilt-compiler:1.1.0"
// Retrofit + GSON
implementation "com.squareup.retrofit2:retrofit:2.9.0"

View File

@@ -3,8 +3,8 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
@@ -13,8 +13,11 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<application
android:name="com.example.hpostesting.HPOSTestingApplication"
android:allowBackup="true"
@@ -26,6 +29,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity"
android:exported="false" />
<activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false"
@@ -101,7 +107,6 @@
android:screenOrientation="portrait"
android:stateNotNeeded="true"
tools:replace="android:screenOrientation" />
</application>
</manifest>

View File

@@ -0,0 +1,18 @@
package com.example.hpostesting.data
import com.opencsv.CSVWriter
import java.io.FileWriter
import java.io.IOException
class CsvHelper {
companion object {
@Throws(IOException::class)
fun writeToCsv(filePath: String, data: List<Array<String>>) {
CSVWriter(FileWriter(filePath)).use { csvWriter ->
data.forEach { row ->
csvWriter.writeNext(row)
}
}
}
}
}

View File

@@ -69,4 +69,5 @@ object Constants {
const val KIT_COUNT = "KitCount"
const val BUFFER_VALUE_1 = "BufferValue1"
const val BUFFER_VALUE_2 = "BufferValue2"
const val DEVICE_ID = "DEVICE_ID"
}

View File

@@ -2,7 +2,8 @@ package com.example.hpostesting.data.constant
enum class HemoCubeCommands(val command: String) {
startBuffer("B\r"),
getBuffer("Q\r"),
runDiagnostics("D\r"),
startSample("S\r"),
getSample("P\r"),
getDeviceId("I\r"),
}

View File

@@ -20,4 +20,7 @@ interface HemoCubeDao {
@Query("DELETE FROM hemo_cube_test_table WHERE _id = :id")
suspend fun deleteById(id: String)
@Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id")
suspend fun updateFieldById(id: String, newValue: Boolean)
}

View File

@@ -0,0 +1,9 @@
package com.example.hpostesting.data.model.diagnostics
data class DiagnosticsData (
var deviceId: String = "",
var appVersion: String? = "",
var deviceType: String = "HEMOCUBE",
var deviceData: String = "",
var runTime: String = ""
)

View File

@@ -0,0 +1,21 @@
package com.example.hpostesting.data.model.patient
data class BufferCheckData(
var kitno: String = "",
var deviceId: String? = "",
var appVersion:String? = "",
var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE",
var resultData: String = "",
var led1Buffer: Double? = null,
var led2Buffer: Double? = null,
var led1Sample: Double? = null,
var led2Sample: Double? = null,
var led1Average: Double? = null,
var led2Average: Double? = null,
var deviceRatio: Double? = null,
var calculatedRatio: Double? = null,
var coefficients: String? = "",
var classificationResult: String = "",
var testTime: String = ""
)

View File

@@ -8,6 +8,7 @@ data class HemoCubeTestData(
@PrimaryKey
var _id: String = "",
var name: String = "",
var bloodGroup: String = "",
var birthYear: String = "",
var userImageURL: String = "",
var location: UserData.Location? = null,
@@ -30,5 +31,6 @@ data class HemoCubeTestData(
var led2Average: Double? = null,
var deviceRatio: Double? = null,
var calculatedRatio: Double? = null,
var coefficients: String? = "",
var classificationResult: String = ""
)

View File

@@ -1,25 +1,20 @@
package com.example.hpostesting.data.repository
import android.content.Context
import android.net.Uri
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.example.hpostesting.data.model.PendingUploads
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.BufferCheckData
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.google.android.datatransport.runtime.dagger.Provides
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 com.google.firebase.storage.ktx.storage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import java.io.File
import javax.inject.Singleton
class DatabaseRepository : Repository {
@@ -57,6 +52,26 @@ class DatabaseRepository : Repository {
}
}
suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> {
return try {
db.collection("buffers").add(data!!).await()
Response.Success(data!!.kitno)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> {
return try {
db.collection("diagnostics").add(data!!).await()
Response.Success(data!!.deviceId)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> {
try {

View File

@@ -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

View File

@@ -1,6 +1,10 @@
package com.example.hpostesting.presentation.adapter
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.Context.INPUT_METHOD_SERVICE
import android.view.inputmethod.InputMethodManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -12,17 +16,27 @@ import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.UserData
import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import android.widget.AutoCompleteTextView
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.firebase.firestore.FirebaseFirestore
class UserListAdapter(
options: FirestoreRecyclerOptions<UserData>, private val view: View, private val batLevel: Int
private val context: Context,
private val hemoCubeViewModel: HemoCubeViewModel,
options: FirestoreRecyclerOptions<UserData>,
private val view: View,
private val batLevel: Int,
private val requireActivity: FragmentActivity
) : FirestoreRecyclerAdapter<UserData, UserListAdapter.OrderItemViewHolder>(options) {
class OrderItemViewHolder(val binding: UserItemViewBinding) :
@@ -40,7 +54,7 @@ class UserListAdapter(
userName.text = "Name: ${model.name}"
userId.text = "User ID:${model._id}"
if (model.incubationTime == "") {
btnStartIncubation.visibility = View.VISIBLE
btnBlood.visibility = View.VISIBLE
} else {
userId.text =
"User ID:${model._id} \n Time: ${isBetween15And30Minutes(model.incubationTime)} \n Started at: ${
@@ -50,7 +64,7 @@ class UserListAdapter(
).parse(model.incubationTime)!!
)
}"
btnStartIncubation.visibility = View.GONE
btnBlood.visibility = View.GONE
}
@@ -61,26 +75,119 @@ class UserListAdapter(
} else {
teststatus.text = "Test is Pending"
}
btnStartIncubation.setOnClickListener {
it.visibility = View.GONE
Firebase.firestore.collection("patientData").whereEqualTo("_id", model._id).get()
.addOnSuccessListener { data ->
if (data.documents.isNotEmpty()) {
data.documents.forEach { userData ->
Firebase.firestore.collection("patientData").document(userData.id)
.update(
"incubationTime", SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
).addOnSuccessListener {
Toast.makeText(
view.context, "Incubation started", Toast.LENGTH_SHORT
).show()
startListening()
}
holder.binding.btnBlood.setOnClickListener {
val view: View? = requireActivity.currentFocus
// on below line checking if view is not null.
if (view != null) {
// on below line we are creating a variable
// for input manager and initializing it.
val inputMethodManager =
context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
// on below line hiding our keyboard.
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
val inflater = LayoutInflater.from(context)
val dialogView = inflater.inflate(R.layout.dialog_custom, null)
val builder = AlertDialog.Builder(context)
.setView(dialogView)
.setTitle("Add Blood Group")
val etBloodGroup = dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group)
builder.setPositiveButton("OK") { dialog, which ->
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.equals("Select Blood Group") || bloodGroup.isNullOrBlank()) {
etBloodGroup.error = "Please enter your blood group"
Toast.makeText(
context,
"Please enter your blood group",
Toast.LENGTH_SHORT
).show()
} else {
// Check if hemoCubeViewModel and testDetails are not null
val db: FirebaseFirestore = FirebaseFirestore.getInstance()
db.collection("patientData")
.whereEqualTo("_id", model._id)
.get()
.addOnSuccessListener { userdata ->
try {
val document = userdata.documents[0]
db.collection("patientData")
.document(document.id)
.update("bloodGroup", bloodGroup,
"incubationTime", SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
)
.addOnSuccessListener {
Toast.makeText(
context,
"Blood group updated successfully",
Toast.LENGTH_SHORT
).show()
btnBlood.visibility = View.GONE
}
.addOnFailureListener { e ->
Toast.makeText(
context,
"Failed to update blood group: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
} catch (e: IndexOutOfBoundsException) {
// Handle the case where no documents are found for the specified ID
Toast.makeText(
context,
"No user data found for the specified ID",
Toast.LENGTH_SHORT
).show()
}
}
.addOnFailureListener { e ->
Toast.makeText(
context,
"Error fetching user data: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
// Handle the selected blood group here
}
builder.setNegativeButton("Cancel") { dialog, which ->
dialog.dismiss()
}
val alertDialog = builder.create()
alertDialog.show()
}
btnStartIncubation.setOnClickListener {
// it.visibility = View.GONE
// Firebase.firestore.collection("patientData").whereEqualTo("_id", model._id).get()
// .addOnSuccessListener { data ->
// if (data.documents.isNotEmpty()) {
// data.documents.forEach { userData ->
// Firebase.firestore.collection("patientData").document(userData.id)
// .update(
// "incubationTime", SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time).toString()
// ).addOnSuccessListener {
// Toast.makeText(
// view.context, "Incubation started", Toast.LENGTH_SHORT
// ).show()
// startListening()
// }
// }
// }
// }
}
userCard.setOnClickListener {
if (batLevel < 40) {
@@ -130,6 +237,8 @@ class UserListAdapter(
}
}
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!!
@@ -140,6 +249,4 @@ class UserListAdapter(
return diffMillis / (60 * 1000)
}
}

View File

@@ -1,21 +1,26 @@
package com.example.hpostesting.presentation.buffercheck
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.core.content.ContextCompat
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.BufferCheckData
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.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils
@@ -24,6 +29,9 @@ import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlin.math.log10
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class HemoCubeBufferCheckFragment : Fragment() {
@@ -32,6 +40,8 @@ class HemoCubeBufferCheckFragment : Fragment() {
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private var kitno: String = ""
private var isOnline = false
private val messages = MutableLiveData<String>()
private var isTestOngoing = false
private var startListening = MutableLiveData(false)
@@ -51,15 +61,44 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
private fun initViews() {
binding.btnKit.visibility = View.GONE
binding.btnSubmit.visibility = View.GONE
binding.etBloodGroup.visibility = View.GONE
listenToHemoCube()
startBufferProcess()
binding.nameEditText.setText("SMI/SC/")
binding.tvTitle.visibility = View.GONE
binding.tvName.visibility = View.GONE
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
kitno = serialNumber
listenToHemoCube()
startBufferProcess()
} else {
Toast.makeText(context, "Invalid KIT Number", Toast.LENGTH_LONG).show()
return@setOnClickListener
}
activity?.runOnUiThread {
binding.tvSubtitle2.visibility = View.GONE
binding.etAbhaId.visibility = View.GONE
binding.tvTitle.visibility = View.GONE
binding.tvTitle2.visibility = View.GONE
binding.btnGo.visibility = View.GONE
}
}
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
binding.btnSubmit.setOnClickListener {
}
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
}
private fun observeViewModel() {
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
@@ -69,11 +108,20 @@ class HemoCubeBufferCheckFragment : Fragment() {
hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
} else {
Toast.makeText(
requireContext(),
"No internet connection avaiable",
Toast.LENGTH_SHORT
requireContext(), "No internet connection avaiable", Toast.LENGTH_SHORT
).show()
}
isOnline = isNetworkAvailable
}
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Kit result uploaded successfully")
}
if (result == "Local") {
showToast("Kit result uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
messages.observe(viewLifecycleOwner) {
@@ -118,10 +166,14 @@ class HemoCubeBufferCheckFragment : Fragment() {
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("#Sample Completed") -> {
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
fetchResult()
}
stringData.contains("RESULT") || resultData.contains("REND") -> {
var validString: String
@@ -143,40 +195,6 @@ class HemoCubeBufferCheckFragment : Fragment() {
}
}
private fun showError500Dialog() {
UIUtils.createAlertDialog(requireContext(),
"BUFFER ERROR",
"Do you want to continue with existing buffer?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startBufferProcess()
}
})
}
private fun showError501Dialog() {
UIUtils.createAlertDialog(requireContext(),
"SAMPLE ERROR",
"Do you want to continue with Sample?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
private fun showStartSampleDialog() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
@@ -199,6 +217,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
try {
val result = validString.split(" ")
if (result.size == 8) {
val deviceId = result[2]
val led1BufferForDevice = result[3].toDoubleOrNull()
val led2BufferForDevice = result[4].toDoubleOrNull()
val led1Sample = result[5].toDoubleOrNull()
@@ -206,9 +225,28 @@ class HemoCubeBufferCheckFragment : Fragment() {
val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0)
val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0)
val deviceRatio = led1Average / led2Average
val calculatedRatio = calculateRatio(deviceRatio)
val classificationResult = findResult(calculatedRatio)
val calculateRatio = calculateRatio(deviceRatio)
val classificationResult = findResult(calculateRatio)
messages.postValue(classificationResult)
val bufferData = BufferCheckData(
deviceId= deviceId,
kitno = kitno,
led1Buffer = led1BufferForDevice,
led2Buffer = led2BufferForDevice,
led1Average = led1Average,
led2Average = led2Average,
led1Sample = led1Sample,
led2Sample = led2Sample,
deviceRatio = deviceRatio,
calculatedRatio = calculateRatio,
coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString(),
classificationResult = classificationResult,
deviceSerialNumber = sharedPreferences.getString(Constants.USER_ID, "").toString(),
testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
)
hemoCubeViewModel.uploadHemoCubeResultToDatabaseforbuffercheckN(bufferData)
}
} catch (e: Exception) {
Toast.makeText(
@@ -245,8 +283,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun startBufferProcess() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.startBuffer,
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -257,8 +294,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun startSampleProcess() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.startSample,
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -269,8 +305,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun fetchResult() {
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.getSample,
(activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -300,6 +335,15 @@ class HemoCubeBufferCheckFragment : Fragment() {
return ""
}
private fun isSerialValid(s: String): Boolean {
if (s.length != 17) {
binding.nameEditText.error = getString(R.string.invalid_kit)
return false
}
return true
}
private fun isValidResult(line: String): String {
return if (line.contains("RESULT") && line.split(" ").size == 8) {
line

View File

@@ -66,11 +66,14 @@ class DashboardActivity : AppCompatActivity() {
val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
firebaseAppDistribution.updateIfNewReleaseAvailable()
.addOnProgressListener { updateProgress ->
Toast.makeText(
this,
"${updateProgress.updateStatus}. ${updateProgress.apkBytesDownloaded / 1048576} /${updateProgress.apkFileTotalBytes / 1048576} MB",
Toast.LENGTH_SHORT
).show()
if (updateProgress.apkBytesDownloaded > 0) {
Toast.makeText(
this,
"${updateProgress.updateStatus}. ${updateProgress.apkBytesDownloaded / 1048576} /${updateProgress.apkFileTotalBytes / 1048576} MB",
Toast.LENGTH_SHORT
).show()
}
}
.addOnFailureListener { e ->
// (Optional) Handle errors.
@@ -82,14 +85,18 @@ class DashboardActivity : AppCompatActivity() {
else -> {
// Handle other errors.
Toast.makeText(this, "AppDistribution error, status: ${e.errorCode}", Toast.LENGTH_SHORT).show()
Toast.makeText(
this,
"AppDistribution error, status: ${e.errorCode}",
Toast.LENGTH_SHORT
).show()
}
}
FirebaseCrashlytics.getInstance().recordException(e)
}
}
.addOnSuccessListener {
Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show()
// Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show()
}
}
}

View File

@@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
@@ -35,6 +36,12 @@ class GalleryFragment : Fragment() {
binding.btnSubmit.setOnClickListener {
startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java))
}
binding.btnDiagnostics.setOnClickListener {
startActivity(Intent(requireContext(), DiagnosticsActivity::class.java))
}
return root
}

View File

@@ -15,6 +15,7 @@ import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.CsvHelper
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.HemoCubeTestData
@@ -28,9 +29,11 @@ import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.firestore.Query
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@@ -42,6 +45,9 @@ class HomeFragment : Fragment() {
private val viewModel: TestRightViewModel by activityViewModels()
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var rvAdapter: UserListAdapter
private var batLevel: Int = 0 // Initialize with a default value, or obtain the actual battery level
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
@@ -151,8 +157,12 @@ class HomeFragment : Fragment() {
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root, batLevel)
rvAdapter = view?.let {
UserListAdapter(requireContext(), hemoCubeViewModel, recyclerViewOptions,
it, batLevel, requireActivity())
}!!
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
@@ -184,24 +194,38 @@ class HomeFragment : Fragment() {
}
private fun getData(search: String?, field: String) {
val userSearchTrace = Firebase.performance.newTrace("user_search_trace")
userSearchTrace.start()
search?.replaceFirstChar {
if (search.lowercase()
.startsWith(it.lowercase())
) it.titlecase(Locale.getDefault()) else it.toString()
}
val query = Firebase.firestore.collection("patientData").orderBy(field).startAt(search)
.endAt(search + "\uf8ff")
val currentDate = Date()
val dateFormat = SimpleDateFormat("yyyyMMdd")
val partition = dateFormat.format(currentDate)
val searchTerm = partition + search
val searchField = field + "Search"
val query = Firebase.firestore.collection("patientData").orderBy(searchField).startAt(searchTerm)
.endAt(searchTerm + "\uf8ff")
query.get().addOnSuccessListener {
userSearchTrace.stop()
}
val recyclerViewOptions =
FirestoreRecyclerOptions.Builder<UserData>().setQuery(query, UserData::class.java)
.build()
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
rvAdapter = UserListAdapter(recyclerViewOptions, binding.root, batLevel)
rvAdapter = view?.let {
UserListAdapter(requireContext(), hemoCubeViewModel, recyclerViewOptions, it, batLevel, requireActivity())
}!!
binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening()
userSearchTrace.stop()
}
private fun setSearch() {
@@ -250,7 +274,7 @@ class HomeFragment : Fragment() {
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.isEmpty()) View.GONE else View.VISIBLE
val uploadDataVisibility = if (userDataList.any { !it.localFlag }) View.VISIBLE else View.GONE
binding.uploadData.visibility = uploadDataVisibility
}
}
@@ -289,15 +313,13 @@ class HomeFragment : Fragment() {
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (userDataList.isEmpty()) {
dialog.dismiss()
} else {
userDataList.forEach { userData ->
userDataList.forEach { userData ->
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
dialog.dismiss()
}
dialog.dismiss()
}
}
@@ -317,6 +339,25 @@ class HomeFragment : Fragment() {
}
}
private fun downloadCsv() {
val csvData = hemoCubeViewModel.getLocalUserDataForCsv()
try {
val filePath = requireContext().getExternalFilesDir(null)?.absolutePath + "/userdata.csv"
CsvHelper.writeToCsv(filePath, csvData)
showToast("CSV downloaded successfully at: $filePath")
} catch (e: IOException) {
showToast("Error downloading CSV")
e.printStackTrace()
}
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@@ -0,0 +1,176 @@
package com.example.hpostesting.presentation.diagnostics
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
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.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.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.UsbService
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.ActivityDiagnosticsBinding
@AndroidEntryPoint
class DiagnosticsActivity : AppCompatActivity() {
private lateinit var binding: ActivityDiagnosticsBinding
val viewModel: DiagnosticsViewModel by viewModels()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "HemoCube"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
viewModel.isServiceConnected = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDiagnosticsBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
private fun setupListener() {
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)
} else {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
}
}
}
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)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgDiagnostics.id, DiagnosticsFragment())
.commit()
}
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
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
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HOMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -0,0 +1,197 @@
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.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.UsbServiceListener
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDiagnosticsBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
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<String>()
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)
initViews()
observeViewModel()
}
private fun initViews() {
binding.btnSubmit.visibility = View.GONE
listenToHemoCube()
getDeviceId()
binding.btnSubmit.setOnClickListener {
binding.btnSubmit.visibility = View.GONE
runDeviceDiagnostics()
}
}
private fun observeViewModel() {
diagnosticsViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
Log.e("diagnostics",binding.tvSubtitle4.text.toString())
}
diagnosticsViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Diagnostics data uploaded successfully")
}
if (result == "Local") {
showToast("Diagnostics uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
}
private fun getDeviceId() {
diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.getDeviceId,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
diagnosticsViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
}
private fun runDeviceDiagnostics() {
diagnosticsViewModel.progressBar.postValue(true)
(activity as DiagnosticsActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.runDiagnostics,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
}
private fun listenToHemoCube() {
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)
diagnosticsViewModel.messages.postValue(stringData)
fullReadOutput.append(stringData)
resultData += stringData
binding.tvSubtitle4.text = resultData
if (stringData.contains("SN")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
val hardwareId = slData[1].trim()
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
}
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
}
}
}
if (resultData.contains("END") || fullReadOutput.contains("END")) {
diagnosticsViewModel.addDiagnosticsDataToDb(DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
deviceData = resultData,
runTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
))
}
// val inputData = mutableListOf<String>()
// while (true) {
// if (fullReadOutput.toString().lowercase() == "end") {
// break
// }
// inputData.add(fullReadOutput.toString())
// }
//
// val parsedData = parseData(inputData)
// Log.i("D-Data", parsedData.toString())
}
override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
fun parseData(inputData: List<String>): List<Pair<String, String>> {
val pattern = Regex("([A-Z]+)\\s(\\d+)")
val parsedData = mutableListOf<Pair<String, String>>()
for (item in inputData) {
val matchResult = pattern.find(item)
if (matchResult != null) {
val (letters, numbers) = matchResult.destructured
parsedData.add(Pair(letters, numbers))
}
}
return parsedData
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -0,0 +1,65 @@
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.diagnostics.DiagnosticsData
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 messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>()
fun addDiagnosticsDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (val response = repository.addDiagnostics(data)) {
is Response.Success -> {
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")
}
}
}
}

View File

@@ -3,6 +3,7 @@ package com.example.hpostesting.presentation.hemocube
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -12,27 +13,20 @@ 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
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.KitScanActivity
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 com.google.firebase.perf.ktx.performance
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import kotlin.math.log10
class HemoCubeFragment : Fragment() {
@@ -47,6 +41,8 @@ class HemoCubeFragment : Fragment() {
private var isUsingExistingBuffer = false
private var isTestOngoing = false
private var startListening = MutableLiveData<Boolean>(false)
val testingTrace = Firebase.performance.newTrace("testing_trace")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
@@ -65,100 +61,50 @@ class HemoCubeFragment : Fragment() {
private fun initViews() {
binding.btnSubmit.setOnClickListener {
val bloodGroupText = binding.etBloodGroup.text.toString()
if (bloodGroupText.isEmpty()) {
binding.etBloodGroup.error = "Please enter your blood group"
} else {
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE
}
hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, "")
)
}
if (isTestOngoing) {
binding.btnKit.visibility = View.GONE
binding.btnKit.isEnabled = false
binding.btnKit.isClickable = false
// binding.btnKit.visibility = View.GONE
// binding.btnKit.isEnabled = false
// binding.btnKit.isClickable = false
}
binding.tvTitle2.visibility = View.GONE
binding.etAbhaId.visibility = View.GONE
binding.nameEditText.visibility = View.GONE
binding.tvTitle.visibility = View.GONE
binding.btnGo.visibility = View.GONE
binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false
binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}"
Log.e("nametext",binding.tvName.text.toString())
binding.btnKit.setOnClickListener {
if (isTestOngoing) {
val title = "WARNING"
val message = "There is a on going test, do you want to stop it"
val negativeText = getString(R.string.no)
val positiveText = "Yes"
UIUtils.createAlertDialog(requireContext(),
title,
message,
negativeText,
positiveText,
object : MyDialogListener {
override fun onClickNegativeButton() {
}
override fun onClickPositiveButton() {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
})
} else {
resetKitCount()
val intent = Intent(context, KitScanActivity::class.java)
startActivity(intent)
(activity as HemocubeActivity).finish()
}
}
}
private suspend fun checkBloodGroup() {
binding.apply {
val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.isEmpty()) {
etBloodGroup.error = "Please enter your blood group"
} else {
val db: FirebaseFirestore = Firebase.firestore
val userdata = db.collection("patientData")
.whereEqualTo("_id", hemoCubeViewModel.testDetails?._id).get().await()
if (userdata.documents.isNotEmpty()) {
db.collection("patientData").document(userdata.documents[0].id)
.update("bloodGroup", bloodGroup)
withContext(Dispatchers.Main) {
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
(activity as HemocubeActivity).finish()
}
}
}
}
Log.e("nametext", binding.tvName.text.toString())
}
private fun observeViewModel() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Test Results Uploaded Successfully")
lifecycleScope.launch {
checkBloodGroup()
}
val i = Intent(
requireContext().applicationContext, DashboardActivity::class.java
)
startActivity(i)
(activity as HemocubeActivity).finish()
}
if (result == "Local") {
showToast("Internet not available, test details stored locally")
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
if (result == "Error") {
showToast("Error uploading data, test details stored locally")
startActivity(Intent(requireActivity(), DashboardActivity::class.java))
}
binding.progressBar.visibility = View.GONE
}
@@ -176,7 +122,6 @@ class HemoCubeFragment : Fragment() {
val coefficient1 = coefficients[0]
val coefficient2 = coefficients[1]
val result = coefficient1 * coefficient2
showToast("coefficients: $coefficient1, $coefficient2")
}
}
isOnline = isNetworkAvailable
@@ -287,18 +232,13 @@ class HemoCubeFragment : Fragment() {
isTestOngoing = true
}
resultData += fullReadOutput.toString()
resultData += stringData
when {
stringData.contains("ERROR 500") -> showError500Dialog()
stringData.contains("ERROR 501") -> showError501Dialog()
stringData.contains("#Buffer Completed") -> showStartSampleDialog()
stringData.contains("#Sample Completed") -> {
activity?.runOnUiThread {
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
fetchResult()
testingTrace.stop()
}
stringData.contains("RESULT") || resultData.contains("REND") -> {
@@ -339,23 +279,6 @@ class HemoCubeFragment : Fragment() {
}
}
private fun showError500Dialog() {
UIUtils.createAlertDialog(requireContext(),
"BUFFER ERROR",
"Do you want to continue with existing buffer?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startBufferProcess()
}
})
}
fun handleBackButtonPress() {
if (isTestOngoing) {
// If the test is ongoing, don't allow the back button action
@@ -368,23 +291,6 @@ class HemoCubeFragment : Fragment() {
}
}
private fun showError501Dialog() {
UIUtils.createAlertDialog(requireContext(),
"SAMPLE ERROR",
"Do you want to continue with Sample?",
getString(R.string.noo),
"Yes",
object : MyDialogListener {
override fun onClickNegativeButton() {}
override fun onClickPositiveButton() {
listenToHemoCube()
startSampleProcess()
}
})
}
private fun showStartSampleDialog() {
activity?.runOnUiThread {
UIUtils.createAlertDialog(requireContext(),
@@ -406,8 +312,20 @@ class HemoCubeFragment : Fragment() {
private fun handleValidResult(validString: String, fullReadOutput: String) {
try {
val result = validString.split(" ")
val deviceLog = resultData
if (result.size == 8) {
val deviceSerialNo = result[2]
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, deviceSerialNo)
apply()
}
val loginId = sharedPreferences.getString(Constants.USER_ID, "").toString()
if (checkDeviceIdMismatch(deviceSerialNo, loginId)) {
activity?.runOnUiThread {
binding.errorMessage.text = "Warning: Login Id is different"
binding.errorMessage.visibility = View.VISIBLE
}
}
val led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()
} else {
@@ -436,9 +354,15 @@ class HemoCubeFragment : Fragment() {
// }
// }
// }
if (led1Average < 0 || led2Average < 0) {
activity?.runOnUiThread{
binding.errorMessage.text = "Warning: Negative Abs. Retake Blank Reading"
binding.errorMessage.visibility = View.VISIBLE
}
}
DataHolder.hemoCubeTestData?.apply {
deviceId = deviceSerialNo
led1Buffer = led1BufferForDevice
led2Buffer = led2BufferForDevice
@@ -449,9 +373,10 @@ class HemoCubeFragment : Fragment() {
this.led2Average = led2Average
this.deviceRatio = deviceRatio
this.calculatedRatio = calculateRatio(deviceRatio)
this.coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString()
this.classificationResult = findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue(this.classificationResult)
this.resultData = fullReadOutput
this.resultData = deviceLog
if (!isUsingExistingBuffer) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1Buffer.toString())
@@ -459,6 +384,12 @@ class HemoCubeFragment : Fragment() {
apply()
}
}
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
}
}
}
} catch (e: Exception) {
@@ -517,6 +448,7 @@ class HemoCubeFragment : Fragment() {
}
private fun startSampleProcess() {
testingTrace.start()
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample,
@@ -571,11 +503,9 @@ class HemoCubeFragment : Fragment() {
}
}
private fun resetKitCount() {
with(sharedPreferences.edit()) {
putString(Constants.KIT_NUMBER, "")
putInt(Constants.KIT_COUNT, 0)
apply()
}
private fun checkDeviceIdMismatch(deviceId: String, loginId: String): Boolean {
if (!deviceId.isNullOrEmpty() && !loginId.isNullOrEmpty() && deviceId.last() != loginId.last())
return true
return false
}
}

View File

@@ -12,6 +12,7 @@ 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.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
@@ -69,6 +70,13 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) =
viewModelScope.launch {
addResultTestToDbforbuffercheck(bufferCheckData)
}
fun getDeviceData(deviceId: String?) = viewModelScope.launch {
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
}
@@ -93,6 +101,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
}
@@ -112,6 +121,32 @@ class HemoCubeViewModel @Inject constructor(
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
hemoCubeDao.insertAll(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.insertAll(testDetails)
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
try {
when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
@@ -134,7 +169,7 @@ class HemoCubeViewModel @Inject constructor(
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
deleteById(userData._id)
updateLocalFlag(userData._id)
}
else -> {
@@ -144,6 +179,10 @@ class HemoCubeViewModel @Inject constructor(
}
}
private fun updateLocalFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateFieldById(id = userId, true)
}
fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId)
}

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:titleTextColor="#FFFFFF"
android:elevation="4dp"
app:menu="@menu/my_menu"
android:theme="@style/ToolbarTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<FrameLayout
android:id="@+id/fg_hc_buffer_check"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/my_toolbar"
app:layout_constraintBottom_toBottomOf="parent"
tools:context=".presentation.buffercheck.HemocubeBufferCheckActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="@+id/my_toolbar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="?attr/actionBarSize"-->
<!-- android:background="?attr/colorPrimary"-->
<!-- app:titleTextColor="#FFFFFF"-->
<!-- android:elevation="4dp"-->
<!-- app:menu="@menu/my_menu"-->
<!-- android:theme="@style/ToolbarTheme"-->
<!-- app:popupTheme="@style/ThemeOverlay.AppCompat.Light"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
<FrameLayout
android:id="@+id/fg_diagnostics"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:context=".presentation.diagnostics.DiagnosticsActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<AutoCompleteTextView
android:id="@+id/et_blood_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/select_blood_group"
android:inputType="none"
android:labelFor="@id/til_blood_group"
app:simpleItems="@array/blood_group" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.diagnostics.DiagnosticsFragment">
<!-- <TextView-->
<!-- android:id="@+id/tv_title"-->
<!-- style="@style/title1"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:text="@string/diagnostics"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/diagnostics"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_subtitle3"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="380dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Start"
android:textColor="@color/red"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Start"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -21,4 +21,16 @@
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_diagnostics"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/diagnostics"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,187 @@
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.hpostesting.presentation.buffercheck.HemoCubeBufferCheckFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_title"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/Instructions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/step4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<!-- <TextView-->
<!-- android:id="@+id/tv_subtitle3"-->
<!-- style="@style/title2"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- android:text="@string/step5"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />-->
<TextView
android:id="@+id/tv_name"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_submit" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<!-- <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"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/submit"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<!-- <com.google.android.material.textfield.TextInputLayout-->
<!-- android:id="@+id/til_blood_group"-->
<!-- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle4">-->
<!-- <AutoCompleteTextView-->
<!-- android:id="@+id/et_blood_group"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:hint="@string/select_blood_group"-->
<!-- android:inputType="none"-->
<!-- android:labelFor="@id/til_blood_group"-->
<!-- app:simpleItems="@array/blood_group" />-->
<!-- </com.google.android.material.textfield.TextInputLayout>-->
<!-- <Button-->
<!-- android:id="@+id/btn_kit"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="10dp"-->
<!-- android:text="@string/new_kit"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- <Button-->
<!-- android:id="@+id/btn_buffer"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/new_buffer"-->
<!-- android:textColor="@color/white"-->
<!-- android:layout_margin="10dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintEnd_toStartOf="@id/btn_kit"/>-->
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -27,7 +27,6 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/step4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
@@ -50,9 +49,14 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:gravity="center"
android:padding="12dp"
android:layout_marginTop="26dp"
android:textFontWeight="700"
android:text="Name: SMI\n ID: 1672282828"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_submit" />
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/tv_subtitle4"
@@ -60,13 +64,13 @@
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:layout_marginTop="72dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
app:layout_constraintTop_toBottomOf="@id/et_abha_id" />
<!-- <Button-->
@@ -98,7 +102,55 @@
<!-- app:layout_constraintTop_toBottomOf="@id/btn_submit" />-->
<TextView
android:id="@+id/tv_title2"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="48dp"
android:text="@string/enter_kit_serial_number_manually"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_abha_id"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toStartOf="@id/btn_go"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/name_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="17"
android:inputType="text"
android:hint="@string/serial_number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_go"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:text="@string/go"
app:cornerRadius="16dp"
app:layout_constraintBottom_toBottomOf="@id/et_abha_id"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/et_abha_id"
app:layout_constraintTop_toTopOf="@id/et_abha_id" />
<Button
android:visibility="gone"
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -109,40 +161,55 @@
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/til_blood_group" />
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_blood_group"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
<TextView
android:id="@+id/error_message"
style="@style/title1_1"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="80dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:layout_marginTop="172dp"
android:gravity="center"
android:textColor="@color/red"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4">
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<AutoCompleteTextView
android:id="@+id/et_blood_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/select_blood_group"
android:inputType="none"
android:labelFor="@id/til_blood_group"
app:simpleItems="@array/blood_group" />
<!-- <com.google.android.material.textfield.TextInputLayout-->
<!-- android:id="@+id/til_blood_group"-->
<!-- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_subtitle4">-->
</com.google.android.material.textfield.TextInputLayout>
<!-- <AutoCompleteTextView-->
<!-- android:id="@+id/et_blood_group"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:hint="@string/select_blood_group"-->
<!-- android:inputType="none"-->
<!-- android:labelFor="@id/til_blood_group"-->
<!-- app:simpleItems="@array/blood_group" />-->
<Button
android:id="@+id/btn_kit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/new_kit"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- </com.google.android.material.textfield.TextInputLayout>-->
<!-- <Button-->
<!-- android:id="@+id/btn_kit"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="10dp"-->
<!-- android:text="@string/new_kit"-->
<!-- android:textColor="@color/white"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- <Button-->
<!-- android:id="@+id/btn_buffer"-->
@@ -181,7 +248,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
</layout>

View File

@@ -78,10 +78,19 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/start_incubation"
android:visibility="gone"
android:textColor="@color/white"
app:layout_constraintStart_toEndOf="@+id/userImage"
app:layout_constraintTop_toBottomOf="@+id/teststatus" />
app:layout_constraintStart_toEndOf="@+id/btn_blood"
app:layout_constraintBottom_toBottomOf="@+id/btn_blood" />
<Button
android:id="@+id/btn_blood"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/blood_group"
android:textColor="@color/white"
app:layout_constraintEnd_toStartOf="@+id/btn_startIncubation"
app:layout_constraintTop_toBottomOf="@id/teststatus" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -112,6 +112,7 @@
<string name="sickle_cert">Sickle Cert</string>
<string name="sickle_find">Sickle Find</string>
<string name="submit">Submit</string>
<string name="diagnostics">Device Diagnostics</string>
<string name="place_buffer">Start Buffer</string>
<string name="Start_Sample">Start Sample</string>
<string name="new_kit">New Kit</string>

View File

@@ -4,8 +4,8 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.google.firebase:firebase-appdistribution-gradle:4.0.0'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.google.firebase:firebase-appdistribution-gradle:4.0.1'
}
repositories {
mavenCentral()