Compare commits

...

31 Commits

Author SHA1 Message Date
Mariya
657b9aea65 removed Unwanted code 2023-11-22 17:10:40 +05:30
Mariya
90590ee535 removed Unwanted code 2023-11-22 17:10:06 +05:30
Mariya
3d39c43c22 Digital Counselling Card , All is finished 2023-11-22 16:31:46 +05:30
Mariya
47fabf036f Merge branch 'DigitalCard' into DigitalPreprodCombine
# Conflicts:
#	app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt
#	app/src/main/java/com/example/hpostesting/data/model/patient/UserData.kt
2023-11-21 14:19:36 +05:30
Mariya
d7a41e8f31 updated preprod changes added 2023-11-21 14:17:48 +05:30
Mariya
f26f3098bb updated preprod changes added 2023-11-21 14:15:55 +05:30
Mariya
4d454ea031 Merge remote-tracking branch 'origin/preprod' into preprod 2023-11-21 14:08:37 +05:30
Pritimay Sarkar
fc3e4d506a Merge branch 'unit-tests' into 'preprod'
add setup for two unit tests

See merge request sminnovations/hpos!14
2023-11-18 01:14:42 +00:00
Pritimay Sarkar
60fbd70f2d correct strings msg 2023-11-17 18:20:33 +05:30
Pritimay Sarkar
7f2cafeef4 add two test 2023-11-17 14:48:53 +05:30
Pritimay Sarkar
1d22fa54c9 add constants 2023-11-17 11:09:57 +05:30
Pritimay Sarkar
3b3bc1adf4 Merge branch 'variable-buffer-thresholds' into 'preprod'
add variable thresholds parameters across devices

See merge request sminnovations/hpos!13
2023-11-16 10:03:07 +00:00
Pritimay Sarkar
a1206dbe0d Merge branch 'preprod' into 'variable-buffer-thresholds'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/data/constant/Constants.kt
2023-11-16 10:00:22 +00:00
Pritimay Sarkar
6e9850c492 add variable thresholds paramters across devices 2023-11-16 15:26:53 +05:30
Pritimay Sarkar
5982ce822f Merge branch 'battery-instrumentation' into 'preprod'
Battery instrumentation

See merge request sminnovations/hpos!12
2023-11-16 06:50:50 +00:00
Pritimay Sarkar
5c32a17871 add battery instrumentation and fix classification msg 2023-11-16 12:19:29 +05:30
Pritimay Sarkar
16528bd165 fix device constant error 2023-11-16 12:18:01 +05:30
Pritimay Sarkar
f86caf0448 move if conditions outside apply 2023-11-16 07:04:51 +05:30
Pritimay Sarkar
a7a57c7ff4 Merge branch 'deoxy-check' into 'preprod'
Deoxy check

See merge request sminnovations/hpos!11
2023-11-15 12:17:18 +00:00
Pritimay Sarkar
3c70142c15 check deoxygenation and classify with abs 2023-11-15 14:18:01 +05:30
Pritimay Sarkar
467dde9a24 add fields in converter 2023-11-15 13:11:54 +05:30
Pritimay Sarkar
ae50d6a603 filter local data based on test status 2023-11-15 13:11:07 +05:30
Pritimay Sarkar
78763d8624 Merge branch 'Develop_Offline_Incubation_and_Blood_Group_Feature' of https://gitlab.com/sminnovations/hpos into deoxy-check 2023-11-15 08:37:55 +05:30
Pritimay Sarkar
fcac603ce0 change user messages 2023-11-15 08:26:55 +05:30
Pritimay Sarkar
0a2f1ba2fd refactor 2023-11-15 06:16:30 +05:30
mohamedkaif356
dcc7a921a0 Offline Incubation time 2023-11-14 22:58:34 +05:30
Mariya
b6f8999078 Merge remote-tracking branch 'origin/preprod' into preprod
# Conflicts:
#	app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
2023-11-14 11:55:49 +05:30
Pritimay Sarkar
74ad03bf8b add buffer validation withn bounds 2023-11-14 00:22:40 +05:30
Pritimay Sarkar
d3083c8dbc add environment name in gradle 2023-11-13 08:06:24 +05:30
Pritimay Sarkar
29846ddf7d show result processing message 2023-11-09 08:14:38 +05:30
Pritimay Sarkar
9deac8e278 fix device ratio calc 2023-11-09 08:08:04 +05:30
27 changed files with 1195 additions and 363 deletions

View File

@@ -14,12 +14,13 @@ android {
compileSdk 34 compileSdk 34
namespace 'in.sminnovations.hpostesting' namespace 'in.sminnovations.hpostesting'
// prod - production, preprod - preproduction, quality - qc,
defaultConfig { defaultConfig {
applicationId "in.sminnovations.hpostesting" applicationId "in.sminnovations.hpostesting"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 24 versionCode 30
versionName "2.1.24" versionName "2.1.30"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -54,9 +55,10 @@ dependencies {
implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1' 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.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'androidx.fragment:fragment-ktx:1.6.2'
//firebase //firebase
implementation platform('com.google.firebase:firebase-bom:32.1.0') implementation platform('com.google.firebase:firebase-bom:32.1.0')
@@ -71,14 +73,20 @@ dependencies {
implementation 'com.google.android.gms:play-services-location:21.0.1' 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.gms:play-services-ads-identifier:18.0.1'
implementation 'com.google.android.things:androidthings:1.0' implementation 'com.google.android.things:androidthings:1.0'
implementation 'com.google.firebase:firebase-appdistribution: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-beta10") implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta11")
// Testing // Testing
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
// Mockito dependencies
testImplementation 'org.mockito:mockito-core:3.12.4'
androidTestImplementation 'org.mockito:mockito-android:3.12.4'
androidTestImplementation 'org.mockito:mockito-inline:3.12.4'
testImplementation "androidx.arch.core:core-testing:2.2.0"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"

View File

@@ -5,6 +5,9 @@
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_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.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
@@ -29,6 +32,9 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting" android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.hemocube.DigitalCardActivity"
android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity" android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity"
android:exported="false" /> android:exported="false" />

View File

@@ -74,4 +74,40 @@ object Constants {
const val BUFFER_VALUE_3 = "BufferValue3" const val BUFFER_VALUE_3 = "BufferValue3"
const val BUFFER_VALUE_4 = "BufferValue4" const val BUFFER_VALUE_4 = "BufferValue4"
const val DEVICE_ID = "DEVICE_ID" const val DEVICE_ID = "DEVICE_ID"
const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 24500
val DEVICE_CONFIGURATION: Map<String, List<List<Double>>> = mapOf<String, List<List<Double>>>(
"HCV-000-3001" to listOf(
listOf(1.264817, -0.85965), // LED1, 435nm
listOf(0.581462456, -0.58502), // LED2, 415nm
listOf(0.184991, 0.001704), // LED3, 555nm
listOf(1.0, 0.0) // LED4
),
"HCV-000-3002" to listOf(
listOf(1.264817, -0.85965),
listOf(0.581462456, -0.58502),
listOf(0.184991, 0.001704),
listOf(1.0, 0.0)
),
)
const val INCUBATION_TIME_MIN = 15
const val INCUBATION_TIME_MAX = 30
val BUFFER_INTENSITY_THRESHOLDS: Map<String, List<List<Int>>> = mapOf<String, List<List<Int>>>(
"HCV-000-3001" to listOf(
listOf(24000, 24500),
listOf(21000, 24500),
listOf(21000, 24500),
listOf(21000, 24500),
),
"HCV-000-3002" to listOf(
listOf(21000, 24500),
listOf(21000, 24500),
listOf(21000, 24500),
listOf(21000, 24500),
)
)
} }

View File

@@ -11,7 +11,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.google.android.datatransport.runtime.dagger.Provides import com.google.android.datatransport.runtime.dagger.Provides
import javax.inject.Singleton import javax.inject.Singleton
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 6, exportSchema = false) @Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 9, exportSchema = false)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() { abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao abstract fun userDao(): UserDao

View File

@@ -8,10 +8,11 @@ data class HemoCubeTestData(
@PrimaryKey @PrimaryKey
var _id: String = "", var _id: String = "",
var name: String = "", var name: String = "",
var incubationTime: String = "",
var bloodGroup: String = "",
var birthYear: String = "", var birthYear: String = "",
var state: String = "", var state: String = "",
var abhaId: String = "", var abhaId: String = "",
var bloodGroup: String = "",
var userImageURL: String = "", var userImageURL: String = "",
var location: UserData.Location? = null, var location: UserData.Location? = null,
var reportUploadTime: String? = "", var reportUploadTime: String? = "",
@@ -38,8 +39,19 @@ data class HemoCubeTestData(
var led2Average: Double? = null, var led2Average: Double? = null,
var led3Average: Double? = null, var led3Average: Double? = null,
var led4Average: Double? = null, var led4Average: Double? = null,
var abs1: Double? = null,
var abs2: Double? = null,
var abs3: Double? = null,
var abs4: Double? = null,
var deviceRatio: Double? = null, var deviceRatio: Double? = null,
var calculatedRatio: Double? = null, var calculatedRatio: Double? = null,
var predictedDenovixRatio: Double? = null,
var coefficients: String? = "", var coefficients: String? = "",
var classificationResult: String = "" var classificationResult: String = "",
var prdClassification: String = "",
var batteryLevel: String = "",
var batteryCapacity: String = "",
var batteryMaxCapacity: String = "",
var batteryTemperature: String = "",
var batteryVoltage: String = "",
) )

View File

@@ -12,6 +12,7 @@ data class UserData(
var incubationTime: String = "", var incubationTime: String = "",
var birthYear: String = "", var birthYear: String = "",
var abhaId: String = "", var abhaId: String = "",
var bloodGroup: String = "",
var userImageURL: String = "", var userImageURL: String = "",
var gender: String ="", var gender: String ="",
var location: Location? = null, var location: Location? = null,
@@ -27,7 +28,8 @@ data class UserData(
var csvPath: String = "", var csvPath: String = "",
var reportPath: String = "", var reportPath: String = "",
var result: TestRightResultType? = null, var result: TestRightResultType? = null,
var resultRatio: Double? = null var resultRatio: Double? = null,
var prdClassification: String = ""
) { ) {
enum class Gender { enum class Gender {
MALE, MALE,
@@ -48,5 +50,10 @@ fun UserData.toHemoCubeTestData() = HemoCubeTestData(
userImageURL = userImageURL, userImageURL = userImageURL,
testStatus = testStatus, testStatus = testStatus,
location = location, location = location,
gender = gender gender = gender,
state = state,
abhaId = abhaId,
bloodGroup = bloodGroup,
prdClassification = prdClassification,
testTime = testTime
) )

View File

@@ -15,13 +15,14 @@ import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage import com.google.firebase.storage.ktx.storage
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import java.io.File import java.io.File
import javax.inject.Inject
class DatabaseRepository : Repository { class DatabaseRepository @Inject constructor() : Repository {
private val db: FirebaseFirestore = Firebase.firestore private val db: FirebaseFirestore = Firebase.firestore
private val storage = Firebase.storage private val storage = Firebase.storage
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> { override suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try { return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await() val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) { if (userdata.documents.isNotEmpty()) {
@@ -36,7 +37,7 @@ class DatabaseRepository : Repository {
} }
} }
suspend fun addTestToDatabase(data: UserData?): Response<String> { override suspend fun addTestToDatabase(data: UserData?): Response<String> {
return try { return try {
val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await() val userdata = db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) { if (userdata.documents.isNotEmpty()) {
@@ -52,7 +53,7 @@ class DatabaseRepository : Repository {
} }
} }
suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> { override suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> {
return try { return try {
db.collection("buffers").add(data!!).await() db.collection("buffers").add(data!!).await()
Response.Success(data!!.kitno) Response.Success(data!!.kitno)
@@ -62,7 +63,7 @@ class DatabaseRepository : Repository {
} }
} }
suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> { override suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> {
return try { return try {
db.collection("diagnostics").add(data!!).await() db.collection("diagnostics").add(data!!).await()
Response.Success(data!!.deviceId) Response.Success(data!!.deviceId)
@@ -72,7 +73,7 @@ class DatabaseRepository : Repository {
} }
} }
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> { override suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> {
try { try {
val file = Uri.fromFile(File(filePath)) val file = Uri.fromFile(File(filePath))
@@ -131,7 +132,7 @@ class DatabaseRepository : Repository {
return db.collection("devices").get().await().toObjects(DeviceData::class.java) return db.collection("devices").get().await().toObjects(DeviceData::class.java)
} }
suspend fun getDeviceDataById(deviceId: String): DeviceData? { override suspend fun getDeviceDataById(deviceId: String): DeviceData? {
val querySnapshot = db.collection("devices").get().await() val querySnapshot = db.collection("devices").get().await()
val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java) val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java)

View File

@@ -1,5 +1,22 @@
package com.example.hpostesting.data.repository package com.example.hpostesting.data.repository
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
interface Repository { interface Repository {
// suspend fun addToDatabase(data: PatientDetails) suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String>
suspend fun addTestToDatabase(data: UserData?): Response<String>
suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String>
suspend fun addDiagnostics(data: DiagnosticsData?): Response<String>
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean>
suspend fun getDeviceDataById(deviceId: String): DeviceData?
} }

View File

@@ -9,6 +9,7 @@ import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.datasource.LocalFileDataSource import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.repository.DatabaseRepository import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.LocalFileRepository import com.example.hpostesting.data.repository.LocalFileRepository
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.SaveRawData import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest import com.example.hpostesting.domain.SaveRawDataTest
import dagger.Module import dagger.Module
@@ -69,4 +70,10 @@ object AppModule {
fun provideDatabaseRepository(): DatabaseRepository { fun provideDatabaseRepository(): DatabaseRepository {
return DatabaseRepository() return DatabaseRepository()
} }
@Provides
@Singleton
fun provideRepository(): Repository {
return DatabaseRepository()
}
} }

View File

@@ -0,0 +1,122 @@
package com.example.hpostesting.presentation.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.navigation.findNavController
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.OfflineUserListViewBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class OfflineUserListAdapter(private val view: View, private val batLevel: Int) :
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) :
RecyclerView.ViewHolder(binding.root)
private val differCallback = object : DiffUtil.ItemCallback<HemoCubeTestData>() {
override fun areItemsTheSame(
oldItem: HemoCubeTestData, newItem: HemoCubeTestData
): Boolean {
return oldItem._id == newItem._id
}
override fun areContentsTheSame(
oldItem: HemoCubeTestData, newItem: HemoCubeTestData
): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OfflineUserListViewHolder {
return OfflineUserListViewHolder(
OfflineUserListViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) {
val userList = differ.currentList[position]
holder.binding.apply {
userID.text = "User ID: ${userList._id}"
bloodGroup.text = "Blood group: ${userList.bloodGroup}"
time.text = "Time: ${userList.incubationTime}"
userCard.setOnClickListener {
if (batLevel < 40) {
Toast.makeText(
view.context,
"Battery level is low than 40%, please charge the device to continue testing",
Toast.LENGTH_SHORT
).show()
return@setOnClickListener
}
if (userList.testStatus != null) {
if (userList.testStatus!!) {
Toast.makeText(
view.context,
"Test has been already conducted for this user",
Toast.LENGTH_SHORT
).show()
} else {
if (userList.incubationTime != "") {
if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) {
Toast.makeText(
view.context,
"Incubation has not completed 15 minutes",
Toast.LENGTH_SHORT
).show()
} else if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText(
view.context,
"Incubation crossed 30 minutes, need to repeat the incubation",
Toast.LENGTH_SHORT
).show()
} else {
DataHolder.selectedTest = UserData(
_id = userList._id,
bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime
)
view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity)
}
} else {
Toast.makeText(
view.context,
"Incubation not started for this user",
Toast.LENGTH_SHORT
).show()
}
}
}
}
}
}
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!!
val currentTime = Calendar.getInstance().time
val diffMillis = currentTime.time - createdAtDate.time
return diffMillis / (60 * 1000)
}
}

View File

@@ -20,6 +20,7 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.KitScanActivity import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel import com.example.hpostesting.presentation.testRight.TestRightViewModel
@@ -33,6 +34,7 @@ import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
@@ -43,7 +45,9 @@ class HomeFragment : Fragment() {
private val viewModel: TestRightViewModel by activityViewModels() private val viewModel: TestRightViewModel by activityViewModels()
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var rvAdapter: UserListAdapter private lateinit var rvAdapter: UserListAdapter
private var batLevel: Int = 0 // Initialize with a default value, or obtain the actual battery level private var batLevel: Int =
0 // Initialize with a default value, or obtain the actual battery level
private lateinit var adapter: OfflineUserListAdapter
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
@@ -73,6 +77,19 @@ class HomeFragment : Fragment() {
} }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteHemoCubeIncompleteRegistrations(userData) deleteHemoCubeIncompleteRegistrations(userData)
if (userData.isNotEmpty()) {
val userList = mutableListOf<HemoCubeTestData>()
userData.forEach {
if (it.testStatus == false) {
userList.add(it)
}
}
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
adapter = OfflineUserListAdapter(binding.root, batLevel)
adapter.differ.submitList(userList)
binding.rvOrderOffline.adapter = adapter
}
} }
viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected -> viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) { if (isConnected) {
@@ -120,10 +137,18 @@ class HomeFragment : Fragment() {
private fun setUserId() { private fun setUserId() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString() val userId = binding.userId.text.toString()
if (userId.length >= 18) { val bloodGroup = binding.etBloodGroup.text
val userData = UserData(_id = userId) if (userId.length >= 18 && !bloodGroup.equals("Select Blood Group") || !bloodGroup.isNullOrBlank()) {
DataHolder.selectedTest = userData hemoCubeViewModel.addUser(
findNavController().navigate(R.id.action_nav_home_to_mainActivity) HemoCubeTestData(
_id = userId, bloodGroup = bloodGroup.toString(), incubationTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
)
)
// val userData = UserData(_id = userId)
// DataHolder.selectedTest = userData
// findNavController().navigate(R.id.action_nav_home_to_mainActivity)
} else { } else {
val errorMessage = getString(R.string.user_id_error_message) val errorMessage = getString(R.string.user_id_error_message)
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
@@ -155,10 +180,12 @@ class HomeFragment : Fragment() {
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
rvAdapter = view?.let { rvAdapter = view?.let {
UserListAdapter(requireContext(), hemoCubeViewModel, recyclerViewOptions, UserListAdapter(
it, batLevel, requireActivity()) requireContext(), hemoCubeViewModel, recyclerViewOptions,
}!! it, batLevel, requireActivity()
)
}!!
binding.rvOrder.adapter = rvAdapter binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening() rvAdapter.startListening()
@@ -206,8 +233,9 @@ class HomeFragment : Fragment() {
val partition = dateFormat.format(currentDate) val partition = dateFormat.format(currentDate)
val searchTerm = partition + search val searchTerm = partition + search
val searchField = field + "Search" val searchField = field + "Search"
val query = Firebase.firestore.collection("patientData").orderBy(searchField).startAt(searchTerm) val query =
.endAt(searchTerm + "\uf8ff") Firebase.firestore.collection("patientData").orderBy(searchField).startAt(searchTerm)
.endAt(searchTerm + "\uf8ff")
query.get().addOnSuccessListener { query.get().addOnSuccessListener {
userSearchTrace.stop() userSearchTrace.stop()
} }
@@ -218,7 +246,14 @@ class HomeFragment : Fragment() {
batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
rvAdapter = view?.let { rvAdapter = view?.let {
UserListAdapter(requireContext(), hemoCubeViewModel, recyclerViewOptions, it, batLevel, requireActivity()) UserListAdapter(
requireContext(),
hemoCubeViewModel,
recyclerViewOptions,
it,
batLevel,
requireActivity()
)
}!! }!!
binding.rvOrder.adapter = rvAdapter binding.rvOrder.adapter = rvAdapter
rvAdapter.startListening() rvAdapter.startListening()
@@ -272,7 +307,8 @@ class HomeFragment : Fragment() {
} }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val uploadDataVisibility = if (userDataList.any { !it.localFlag }) View.VISIBLE else View.GONE val uploadDataVisibility =
if (userDataList.any { !it.localFlag && it.testStatus == true}) View.VISIBLE else View.GONE
binding.uploadData.visibility = uploadDataVisibility binding.uploadData.visibility = uploadDataVisibility
} }
} }
@@ -331,7 +367,7 @@ class HomeFragment : Fragment() {
private fun deleteHemoCubeIncompleteRegistrations(userDataList: List<HemoCubeTestData>) { private fun deleteHemoCubeIncompleteRegistrations(userDataList: List<HemoCubeTestData>) {
userDataList.forEach { userData -> userDataList.forEach { userData ->
if (userData.testTime?.isEmpty() == true) { if (userData._id.isEmpty()) {
hemoCubeViewModel.deleteById(userData._id) hemoCubeViewModel.deleteById(userData._id)
} }
} }

View File

@@ -0,0 +1,39 @@
package com.example.hpostesting.presentation.hemocube
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
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.view.Menu
import androidx.activity.viewModels
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDigitalCardBinding
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
class DigitalCardActivity : AppCompatActivity() {
private lateinit var binding: ActivityDigitalCardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDigitalCardBinding.inflate(layoutInflater)
setContentView(binding.root)
moveToNext()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, DigitalCardFragment())
.commit()
}
}

View File

@@ -1,8 +1,10 @@
package com.example.hpostesting.presentation.hemocube package com.example.hpostesting.presentation.hemocube
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -14,13 +16,15 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale
class DigitalCardFragment : Fragment() { class DigitalCardFragment : Fragment() {
private lateinit var binding: FragmentDigitalCardBinding private lateinit var binding: FragmentDigitalCardBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
@@ -33,29 +37,47 @@ class DigitalCardFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
initViews() initViews()
} }
@SuppressLint("SetTextI18n")
private fun initViews() { private fun initViews() {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.progressBar.visibility = View.VISIBLE binding.progressBar.visibility = View.VISIBLE
} }
val originalDateStr = testDetails?.testTime Log.d("DigitalCardFragment", "Name: ${DataHolder.hemoCubeTestData?.name}")
val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") Log.d("DigitalCardFragment", "DOB: ${testDetails?.birthYear}")
val originalDate: Date? = originalDateFormat.parse(originalDateStr) Log.d("DigitalCardFragment", "Gender: ${testDetails?.gender}")
val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy") Log.d("DigitalCardFragment", "State: ${testDetails?.state}")
val formattedDate: String = originalDate?.let { desiredDateFormat.format(it) } ?: "N/A" Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}")
Log.d("DigitalCardFragment", "Blood Group: ${testDetails?.bloodGroup}")
Log.d("DigitalCardFragment", "Sickle-Cell: ${testDetails?.classificationResult}")
// Log.d("DigitalCardFragment", "Issue Date: $formattedDate")
activity?.runOnUiThread { activity?.runOnUiThread {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
binding.name.text = "Name: ${DataHolder.hemoCubeTestData?.name}"
binding.dob.text = "DOB: ${testDetails?.birthYear}"
binding.gender.text = "Gender: ${testDetails?.gender}"
binding.State.text = "State: ${testDetails?.state}"
binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}"
binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}"
binding.sicklecell.text = "Sickle-Cell: ${DataHolder.hemoCubeTestData?.prdClassification.toString()}"
} }
binding.name.text = "Name: ${testDetails?.name}" // Update the UI with the fetched details
binding.dob.text = "DOB: ${testDetails?.birthYear}" val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
binding.gender.text = "gender: ${testDetails?.gender}" val originalDate: Date? = originalDateFormat.parse(SimpleDateFormat(
binding.State.text = "state: ${testDetails?.state}" "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}" ).format(Calendar.getInstance().time))
binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}"
binding.sicklecell.text = "Sickle-Cell: ${testDetails?.classificationResult}" // Format the parsed date to "mm date, year"
binding.issueDate.text = "Issue Date: $formattedDate" val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault())
val formattedDate: String = originalDate?.let { desiredDateFormat.format(it) } ?: "N/A"
activity?.runOnUiThread {
binding.issueDate.text = "Issue Date: ${formattedDate}"
}
} }
} }

View File

@@ -5,10 +5,10 @@ import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
@@ -20,7 +20,7 @@ import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity import androidx.navigation.fragment.findNavController
import com.example.hpostesting.presentation.utils.MyDialogListener import com.example.hpostesting.presentation.utils.MyDialogListener
import com.example.hpostesting.presentation.utils.UIUtils import com.example.hpostesting.presentation.utils.UIUtils
import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.ktx.crashlytics
@@ -35,7 +35,7 @@ class HemoCubeFragment : Fragment() {
private lateinit var binding: FragmentHemoCubeReferenceBinding private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
private var isOnline = false private var isOnline = false
private var currentDeviceData: DeviceData? = null private var currentDeviceData: DeviceData? = null
private var resultData: String = "" private var resultData: String = ""
@@ -45,12 +45,19 @@ class HemoCubeFragment : Fragment() {
private val testingTrace = Firebase.performance.newTrace("testing_trace") private val testingTrace = Firebase.performance.newTrace("testing_trace")
private var led1BufferForDevice = 0.0 private var led1BufferForDevice = 0.0
private var led2BufferForDevice = 0.0 private var led2BufferForDevice = 0.0
private var led3BufferForDevice = 0.0 private var led3BufferForDevice = 0.0
private var led4BufferForDevice = 0.0 private var led4BufferForDevice = 0.0
private var led1SampleForDevice = 0.0 private var led1SampleForDevice = 0.0
private var led2SampleForDevice = 0.0 private var led2SampleForDevice = 0.0
private var led3SampleForDevice = 0.0 private var led3SampleForDevice = 0.0
private var led4SampleForDevice = 0.0 private var led4SampleForDevice = 0.0
private var fittedAbs1 = 0.0
private var fittedAbs2 = 0.0
private var fittedAbs3 = 0.0
private var fittedAbs4 = 0.0
private var _predictedDenovixRatio = 0.0
private var validationError = false
private var deviceHardwareId = ""
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
@@ -84,8 +91,8 @@ class HemoCubeFragment : Fragment() {
binding.nameEditText.visibility = View.GONE binding.nameEditText.visibility = View.GONE
binding.tvTitle.visibility = View.GONE binding.tvTitle.visibility = View.GONE
binding.btnGo.visibility = View.GONE binding.btnGo.visibility = View.GONE
binding.btnSubmit.isEnabled = true // binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = true // binding.btnSubmit.isClickable = false
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}" binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}"
@@ -94,10 +101,10 @@ class HemoCubeFragment : Fragment() {
binding.btnSamplestart.setOnClickListener { binding.btnSamplestart.setOnClickListener {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE binding.tvSubtitle4.visibility = View.VISIBLE
binding.tvSubtitle4.text = "Sample Started" // binding.tvSubtitle4.text = "Sample Started"
} }
startSampleProcess() startSampleProcess()
it.visibility = View.GONE it.visibility = View.GONE
} }
binding.btnPlacebuffer.setOnClickListener { binding.btnPlacebuffer.setOnClickListener {
@@ -106,10 +113,13 @@ class HemoCubeFragment : Fragment() {
} else { } else {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE binding.tvSubtitle4.visibility = View.VISIBLE
// binding.tvSubtitle4.text = "Buffer Started"
} }
checkAndStartProcess() checkAndStartProcess()
it.visibility = View.GONE
} }
it.visibility = View.GONE
} }
} }
@@ -119,17 +129,16 @@ class HemoCubeFragment : Fragment() {
if (result == "Success") { if (result == "Success") {
showToast("Test Results Uploaded Successfully") showToast("Test Results Uploaded Successfully")
val digitalCardFragment = DigitalCardFragment() activity?.runOnUiThread {
val transaction = parentFragmentManager.beginTransaction() binding.btnSubmit.visibility = View.GONE
transaction.replace(R.id.fragment_container, digitalCardFragment) binding.btnDigitalCard.visibility = View.VISIBLE
transaction.addToBackStack(null) binding.btnDigitalCard.setOnClickListener {
transaction.commit() val i = Intent(
requireContext().applicationContext, DigitalCardActivity::class.java
// val i = Intent( )
// requireContext().applicationContext, DashboardActivity::class.java startActivity(i)
// ) }
// startActivity(i) }
// (activity as HemocubeActivity).finish()
} }
if (result == "Local") { if (result == "Local") {
showToast("Internet not available, test details stored locally") showToast("Internet not available, test details stored locally")
@@ -290,6 +299,7 @@ class HemoCubeFragment : Fragment() {
val slData = stringData.split(" ") val slData = stringData.split(" ")
if (slData.size > 1) { if (slData.size > 1) {
val hardwareId = slData[1].trim() val hardwareId = slData[1].trim()
deviceHardwareId = hardwareId
with(sharedPreferences.edit()) { with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId) putString(Constants.DEVICE_ID, hardwareId)
apply() apply()
@@ -320,12 +330,16 @@ class HemoCubeFragment : Fragment() {
} }
stringData.contains("#SC") -> { stringData.contains("#SC") -> {
binding.tvSubtitle4.text = "Sample Completed" hemoCubeViewModel.messages.postValue("Sample Completed \nGathering data")
fetchResult() fetchResult()
testingTrace.stop() testingTrace.stop()
} }
resultData.contains("REND") -> { resultData.contains("REND") -> {
hemoCubeViewModel.messages.postValue(
"Data collected \n" +
" Processing data"
)
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim() var bufferIntensity = resultLines[1].split(' ')[1].trim()
led1BufferForDevice = if (isUsingExistingBuffer) { led1BufferForDevice = if (isUsingExistingBuffer) {
@@ -359,7 +373,8 @@ class HemoCubeFragment : Fragment() {
sampleIntensity = resultLines[7].split(' ')[1].trim() sampleIntensity = resultLines[7].split(' ')[1].trim()
led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
sampleIntensity = resultLines[8].split(' ')[1].split('\r')[0].trim() sampleIntensity = resultLines[8].split(' ')[1].split('\r')[0].trim()
led4SampleForDevice = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! led4SampleForDevice =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
processResult() processResult()
} }
} }
@@ -396,6 +411,7 @@ class HemoCubeFragment : Fragment() {
private fun processResult() { private fun processResult() {
try { try {
hemoCubeViewModel.messages.postValue("processing result")
val deviceLog = resultData val deviceLog = resultData
val pInfo = requireActivity().packageManager.getPackageInfo( val pInfo = requireActivity().packageManager.getPackageInfo(
@@ -407,11 +423,65 @@ class HemoCubeFragment : Fragment() {
val led2Average = log10(led2BufferForDevice?.div(led2SampleForDevice!!) ?: 0.0) val led2Average = log10(led2BufferForDevice?.div(led2SampleForDevice!!) ?: 0.0)
val led3Average = log10(led3BufferForDevice?.div(led3SampleForDevice!!) ?: 0.0) val led3Average = log10(led3BufferForDevice?.div(led3SampleForDevice!!) ?: 0.0)
val led4Average = log10(led4BufferForDevice?.div(led4SampleForDevice!!) ?: 0.0) val led4Average = log10(led4BufferForDevice?.div(led4SampleForDevice!!) ?: 0.0)
val deviceRatio = led1Average / led3Average val deviceRatio = led3Average / led1Average
if (led1Average < 0 || led2Average < 0) { if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)?.get(0)!!
|| led2BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(1)?.get(0)!!
|| led3BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(2)?.get(0)!!
|| led4BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(3)?.get(0)!!
) {
validationError = true
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = "Warning: Negative Abs. Retake Blank Reading" binding.errorMessage.text = "Error: Invalid Test. Improper buffer reading (low)"
binding.errorMessage.visibility = View.VISIBLE
}
}
if (led1BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)?.get(1)!!
|| led2BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(1)?.get(1)!!
|| led3BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(2)?.get(1)!!
|| led4BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(3)?.get(1)!!
) {
validationError = true
activity?.runOnUiThread {
binding.errorMessage.text =
"Error: Invalid Test. Improper buffer reading (high)"
binding.errorMessage.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
}
var gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0)
var constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1)
fittedAbs1 = gradient?.times(led1Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(1)
fittedAbs2 = gradient?.times(led2Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(1)
fittedAbs3 = gradient?.times(led3Average)?.plus(constant!!)!!
gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(0)
constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(1)
fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!!
_predictedDenovixRatio = fittedAbs3?.div(fittedAbs1!!)!!
if (fittedAbs1!! <= fittedAbs2!!) {
validationError = true
activity?.runOnUiThread {
binding.errorMessage.text = "Error: Invalid Test. Problem with de-oxygenation"
binding.errorMessage.visibility = View.VISIBLE
}
}
if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) {
validationError = true
activity?.runOnUiThread {
binding.errorMessage.text = "Error: Negative Abs. Retake Blank Reading"
binding.errorMessage.visibility = View.VISIBLE binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -431,28 +501,43 @@ class HemoCubeFragment : Fragment() {
this.led2Average = led2Average this.led2Average = led2Average
this.led3Average = led3Average this.led3Average = led3Average
this.led4Average = led4Average this.led4Average = led4Average
this.abs1 = fittedAbs1
this.abs2 = fittedAbs2
this.abs3 = fittedAbs3
this.abs4 = fittedAbs4
this.deviceRatio = deviceRatio this.deviceRatio = deviceRatio
this.calculatedRatio = calculateRatio(deviceRatio) this.calculatedRatio = calculateRatio(deviceRatio)
this.predictedDenovixRatio = _predictedDenovixRatio
this.coefficients = currentDeviceData?.coefficients?.get(0) this.coefficients = currentDeviceData?.coefficients?.get(0)
.toString() + ", " + currentDeviceData?.coefficients?.get(1).toString() .toString() + ", " + currentDeviceData?.coefficients?.get(1).toString()
this.classificationResult = findResult(calculatedRatio) this.classificationResult = findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue(this.classificationResult) this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio)
hemoCubeViewModel.messages.postValue(this.prdClassification)
this.resultData = deviceLog this.resultData = deviceLog
if (!isUsingExistingBuffer) { this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString()
with(sharedPreferences.edit()) { this.batteryCapacity = hemoCubeViewModel.getBatteryCapacity(requireContext()).toString()
putString(Constants.BUFFER_VALUE_1, led1BufferForDevice.toString()) this.batteryMaxCapacity = hemoCubeViewModel.getBatteryMaxCapacity(requireContext()).toString()
putString(Constants.BUFFER_VALUE_2, led2BufferForDevice.toString()) this.batteryTemperature = hemoCubeViewModel.getBatteryTemperature().toString()
putString(Constants.BUFFER_VALUE_3, led3BufferForDevice.toString()) this.batteryVoltage = hemoCubeViewModel.getBatteryVoltage(requireContext()).toString()
putString(Constants.BUFFER_VALUE_4, led4BufferForDevice.toString()) }
apply()
} if (!isUsingExistingBuffer) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_2, led2BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_3, led3BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_4, led4BufferForDevice.toString())
apply()
} }
activity?.runOnUiThread { }
binding.btnSubmit.visibility = View.VISIBLE
} if (!validationError) {
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true binding.btnSubmit.isClickable = true
binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
}
} }
} catch (e: Exception) { } catch (e: Exception) {
Toast.makeText( Toast.makeText(
@@ -464,8 +549,9 @@ class HemoCubeFragment : Fragment() {
} }
} }
private fun findResult(calculatedRatio: Double?): String { fun findResult(calculatedRatio: Double?): String {
try { try {
hemoCubeViewModel.messages.postValue("result classification")
if (calculatedRatio != null) { if (calculatedRatio != null) {
if (calculatedRatio < 0.05) if (calculatedRatio < 0.05)
return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume" return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume"
@@ -482,14 +568,39 @@ class HemoCubeFragment : Fragment() {
if (calculatedRatio > 0.35) if (calculatedRatio > 0.35)
return "Inconclusive. Repeat with test with lower volume of blood" return "Inconclusive. Repeat with test with lower volume of blood"
} else { } else {
return "NULL" return "INVALID"
} }
} catch (e: Exception) { } catch (e: Exception) {
showToast("error while performing classification") showToast("error while performing classification")
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
return "ERROR" return "ERROR"
} }
return "NULL" return "INVALID"
}
private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String {
try {
hemoCubeViewModel.messages.postValue("result classification")
if (predictedDenovixRatio != null) {
if (predictedDenovixRatio in 0.0..0.16)
return "Normal"
if (predictedDenovixRatio in 0.16..0.165)
return "Negative Borderline"
if (predictedDenovixRatio in 0.165..0.235)
return "Sickle Cell Trait"
if (predictedDenovixRatio in 0.235..0.24)
return "Positive Borderline"
if (predictedDenovixRatio in 0.24..1.0)
return "Sickle Cell Disease"
} else {
return "INVALID"
}
} catch (e: Exception) {
showToast("error while performing classification")
Firebase.crashlytics.recordException(e)
return "ERROR"
}
return "INVALID"
} }
private fun showToast(message: String) { private fun showToast(message: String) {

View File

@@ -1,8 +1,13 @@
package com.example.hpostesting.presentation.hemocube package com.example.hpostesting.presentation.hemocube
import android.app.Application
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.BatteryManager
import android.util.Log import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -15,8 +20,10 @@ import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.BufferCheckData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData 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.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@@ -27,169 +34,246 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class HemoCubeViewModel @Inject constructor( class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao, private val hemoCubeDao: HemoCubeDao,
private val repository: DatabaseRepository, private val repository: Repository,
context: Context, context: Context,
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences = private val sharedPreference: SharedPreferences =
context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) 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) // Get the device ID of the device you want to retrieve data for (e.g., the first device in the list)
private val _networkStatusLiveData = NetworkStatusLiveData(context) private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll() val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
val networkStatusLiveData: LiveData<Boolean> val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
val fireBaseBulkUpload = MutableLiveData<String>() val fireBaseBulkUpload = MutableLiveData<String>()
fun uploadHemoCubeResultToDatabase(isOnline: Boolean, testStatus: Boolean, kitSerial: String?) =
viewModelScope.launch { private val batteryStatus: Intent? =
if (kitSerial != null) { IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
testDetails?.kitSerial = kitSerial context.registerReceiver(null, ifilter)
} }
testDetails?.testStatus = testStatus
try { fun uploadHemoCubeResultToDatabase(
if (isOnline) { isOnline: Boolean,
parseData() testStatus: Boolean,
addResultTestToDb() kitSerial: String?
} else { ) =
parseData() viewModelScope.launch {
testDetails?.testTime = SimpleDateFormat( if (kitSerial != null) {
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() testDetails?.kitSerial = kitSerial
).format(Calendar.getInstance().time) }
hemoCubeDao.insertAll(testDetails!!) testDetails?.testStatus = testStatus
fireBaseUpload.postValue("Local")
try {
if (isOnline) {
parseData()
addResultTestToDb()
} else {
parseData()
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
hemoCubeDao.insertAll(testDetails!!)
fireBaseUpload.postValue("Local")
}
} catch (e: Exception) {
Log.e("Testdb", "Upload failed: ${e.message}")
} }
} catch (e: Exception) {
Log.e("Testdb", "Upload failed: ${e.message}")
} }
fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) =
viewModelScope.launch {
addResultTestToDbforbuffercheck(bufferCheckData)
}
fun getDeviceData(deviceId: String?) = viewModelScope.launch {
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
} }
private fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult
fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) = testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
viewModelScope.launch { testDetails?.location = DataHolder.location
addResultTestToDbforbuffercheck(bufferCheckData) testDetails?.testTime = SimpleDateFormat(
}
fun getDeviceData(deviceId: String?) = viewModelScope.launch {
deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) })
}
private fun parseData() {
testDetails?.deviceRatio = DataHolder.hemocubeResult
testDetails?.resultData = DataHolder.hemoCubeTestData?.resultData.toString()
testDetails?.location = DataHolder.location
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
testDetails?.deviceSerialNumber =
sharedPreference.getString(Constants.USER_ID, "").toString()
testDetails?.kitSerial = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
testDetails?.led1Buffer = DataHolder.hemoCubeTestData?.led1Buffer
testDetails?.led2Buffer = DataHolder.hemoCubeTestData?.led2Buffer
testDetails?.led3Buffer = DataHolder.hemoCubeTestData?.led3Buffer
testDetails?.led4Buffer = DataHolder.hemoCubeTestData?.led4Buffer
testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample
testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample
testDetails?.led3Sample = DataHolder.hemoCubeTestData?.led3Sample
testDetails?.led4Sample = DataHolder.hemoCubeTestData?.led4Sample
testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average
testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average
testDetails?.led3Average = DataHolder.hemoCubeTestData?.led3Average
testDetails?.led4Average = DataHolder.hemoCubeTestData?.led4Average
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
}
private fun addResultTestToDb() {
viewModelScope.launch {
try {
testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
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 -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
fun bulkAddResultTestToDb(userData: HemoCubeTestData) {
viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) { testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion
is Response.Success -> { testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId
fireBaseBulkUpload.postValue("Success") testDetails?.deviceSerialNumber =
updateLocalFlag(userData._id) sharedPreference.getString(Constants.USER_ID, "").toString()
} testDetails?.kitSerial = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
testDetails?.led1Buffer = DataHolder.hemoCubeTestData?.led1Buffer
testDetails?.led2Buffer = DataHolder.hemoCubeTestData?.led2Buffer
testDetails?.led3Buffer = DataHolder.hemoCubeTestData?.led3Buffer
testDetails?.led4Buffer = DataHolder.hemoCubeTestData?.led4Buffer
testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample
testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample
testDetails?.led3Sample = DataHolder.hemoCubeTestData?.led3Sample
testDetails?.led4Sample = DataHolder.hemoCubeTestData?.led4Sample
testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average
testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average
testDetails?.led3Average = DataHolder.hemoCubeTestData?.led3Average
testDetails?.led4Average = DataHolder.hemoCubeTestData?.led4Average
testDetails?.abs1 = DataHolder.hemoCubeTestData?.abs1
testDetails?.abs2 = DataHolder.hemoCubeTestData?.abs2
testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3
testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4
testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio
testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification =
DataHolder.hemoCubeTestData?.prdClassification.toString()
testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString()
testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString()
testDetails?.batteryMaxCapacity =
DataHolder.hemoCubeTestData?.batteryMaxCapacity.toString()
testDetails?.batteryTemperature =
DataHolder.hemoCubeTestData?.batteryTemperature.toString()
testDetails?.batteryVoltage = DataHolder.hemoCubeTestData?.batteryVoltage.toString()
}
else -> { private fun addResultTestToDb() {
fireBaseBulkUpload.postValue("Error") viewModelScope.launch {
try {
testDetails!!.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
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 updateLocalFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateFieldById(id = userId, true)
}
fun deleteById(userId: String) = viewModelScope.launch { private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) {
hemoCubeDao.deleteById(id = userId) 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 -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
fun bulkAddResultTestToDb(userData: HemoCubeTestData) {
viewModelScope.launch {
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
updateLocalFlag(userData._id)
}
else -> {
fireBaseBulkUpload.postValue("Error")
}
}
}
}
private fun updateLocalFlag(userId: String) = viewModelScope.launch {
hemoCubeDao.updateFieldById(id = userId, true)
}
fun addUser(userData: HemoCubeTestData) = viewModelScope.launch {
hemoCubeDao.insertAll(userData)
}
fun deleteById(userId: String) = viewModelScope.launch {
hemoCubeDao.deleteById(id = userId)
}
fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent ->
val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
level * 100 / scale.toFloat()
}
return batteryPct
}
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0
temperature.toFloat() / 10
}
return batteryTemp
}
fun getBatteryVoltage(context: Context): Float {
val batteryIntent =
context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
val voltage = batteryIntent?.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) ?: 0
// milli-volts to volts
return voltage.toFloat() / 1000
}
fun getBatteryCapacity(context: Context): Int {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
return currentCapacity
}
fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
// Calculate the estimated maximum battery capacity in mAh
val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
return maxCapacity
}
} }
}

View File

@@ -0,0 +1,38 @@
<?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:visibility="gone"
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/fghemocube"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/my_toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- NavHostFragment for navigation -->
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent" android:id="@+id/cl_parent"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -21,21 +19,17 @@
android:theme="@style/ToolbarTheme" android:theme="@style/ToolbarTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/> app:layout_constraintTop_toTopOf="parent" />
<FrameLayout <FrameLayout
android:id="@+id/fghemocube" android:id="@+id/fghemocube"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/my_toolbar" app:layout_constraintTop_toBottomOf="@id/my_toolbar"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:context=".presentation.hemocube.HemocubeActivity"> tools:context=".presentation.hemocube.HemocubeActivity">
</FrameLayout> </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -18,4 +18,6 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/dashboard_navigation" /> app:navGraph="@navigation/dashboard_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,14 +1,13 @@
<layout xmlns:android="http://schemas.android.com/apk/res/android" <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.hpostesting.presentation.hemocube.DigitalCardFragment"> tools:context="com.example.hpostesting.presentation.hemocube.DigitalCardFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_container">
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:id="@+id/userCard" android:id="@+id/userCard"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -19,6 +18,14 @@
app:cardElevation="0dp" app:cardElevation="0dp"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="@+id/fragment_container_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/background_light"/>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -30,37 +37,30 @@
android:layout_height="100dp" android:layout_height="100dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/karnataka" /> android:src="@drawable/karnataka" />
<ImageView <ImageView
android:id="@+id/userName" android:id="@+id/userName"
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_marginStart="46dp" android:layout_marginStart="16dp"
app:layout_constraintTop_toBottomOf="parent" app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/userImage" app:layout_constraintStart_toEndOf="@+id/userImage"
app:layout_constraintTop_toTopOf="@+id/userImage" app:layout_constraintTop_toTopOf="@+id/userImage"
tools:src="@drawable/sickle_cell_gov_logo"/> android:src="@drawable/sickle_cell_gov_logo"/>
<ImageView <ImageView
android:id="@+id/userImage3" android:id="@+id/userImage3"
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_marginStart="36dp" android:layout_marginStart="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/userName" app:layout_constraintStart_toEndOf="@+id/userName"
app:layout_constraintTop_toTopOf="@+id/userName" app:layout_constraintTop_toTopOf="@+id/userName"
tools:src="@drawable/indianoil"/> android:src="@drawable/indianoil"/>
<ImageView
android:id="@+id/userImage4"
android:layout_width="80dp"
android:layout_height="100dp"
android:layout_marginTop="30dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage"
tools:src="@drawable/person" />
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
@@ -71,7 +71,6 @@
app:cardBackgroundColor="#FFFFFF" app:cardBackgroundColor="#FFFFFF"
app:cardCornerRadius="5dp" app:cardCornerRadius="5dp"
app:layout_constraintTop_toBottomOf="@id/userImage" app:layout_constraintTop_toBottomOf="@id/userImage"
app:layout_constraintStart_toEndOf="@+id/userImage4"
app:cardElevation="0dp"> app:cardElevation="0dp">
<TextView <TextView
@@ -86,7 +85,7 @@
android:textSize="10sp" android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage" app:layout_constraintTop_toBottomOf="@id/userImage"
android:text="Name: Mariya" /> android:text="name: Mariya" />
<TextView <TextView
@@ -124,9 +123,9 @@
<TextView <TextView
android:id="@+id/State" android:id="@+id/State"
style="@style/title1_1" style="@style/title1_1"
android:layout_width="80dp" android:layout_width="130dp"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_marginStart="16dp"
android:gravity="center" android:gravity="center"
android:layout_marginTop="70dp" android:layout_marginTop="70dp"
android:textColor="@color/black" android:textColor="@color/black"
@@ -181,11 +180,11 @@
style="@style/title1_1" style="@style/title1_1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_marginStart="16dp" android:layout_marginStart="6dp"
android:layout_marginTop="50dp" android:layout_marginTop="50dp"
android:gravity="start" android:gravity="start"
android:textColor="@color/black" android:textColor="@color/black"
android:textSize="8sp" android:textSize="10sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/userImage3" app:layout_constraintTop_toBottomOf="@id/userImage3"
android:text="Sickle-Cell: Normal (HbA)" /> android:text="Sickle-Cell: Normal (HbA)" />
@@ -240,4 +239,3 @@
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -205,7 +205,19 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" /> app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button
android:visibility="gone"
android:id="@+id/btn_digitalCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="DigitalCard View"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -22,7 +22,7 @@
android:id="@+id/internetNotAvailableCL" android:id="@+id/internetNotAvailableCL"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" android:visibility="visible"
android:padding="24dp"> android:padding="24dp">
<TextView <TextView
@@ -57,6 +57,27 @@
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<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="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_name">
<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>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_submit" android:id="@+id/btn_submit"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -66,7 +87,18 @@
app:cornerRadius="100dp" app:cornerRadius="100dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_name" /> app:layout_constraintTop_toBottomOf="@+id/til_blood_group" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_order_offline"
android:layout_width="0dp"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_submit"
tools:listitem="@layout/offline_user_list_view" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
@@ -74,7 +106,7 @@
android:id="@+id/internetAvailableCL" android:id="@+id/internetAvailableCL"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="visible" android:visibility="gone"
android:padding="24dp"> android:padding="24dp">
<TextView <TextView

View File

@@ -0,0 +1,71 @@
<?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="wrap_content">
<androidx.cardview.widget.CardView
android:id="@+id/userCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:cardBackgroundColor="@color/primary_light"
app:cardCornerRadius="25dp"
app:cardElevation="0dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp">
<TextView
android:id="@+id/userID"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Name: MohamedKaif" />
<TextView
android:id="@+id/bloodGroup"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userID"
tools:text="UserID: MohamedKaif" />
<TextView
android:id="@+id/time"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bloodGroup"
tools:text="Test Status: Completed" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/navigation_graph"
app:startDestination="@id/hemoCubeFragment">
<fragment
android:id="@+id/hemoCubeFragment"
android:name="com.example.hpostesting.presentation.hemocube.HemoCubeFragment"
android:label="fragment_hemo_cube_reference"
tools:layout="@layout/fragment_hemo_cube_reference" >
<action
android:id="@+id/action_hemoCubeFragment_to_digitalCardFragment"
app:destination="@id/digitalCardFragment" />
</fragment>
<fragment
android:id="@+id/digitalCardFragment"
android:name="com.example.hpostesting.presentation.hemocube.DigitalCardFragment"
android:label="fragment_digital_card"
tools:layout="@layout/fragment_digital_card" />
</navigation>

View File

@@ -184,10 +184,10 @@
<string name="user_list">User List</string> <string name="user_list">User List</string>
<string name="user_id">User ID</string> <string name="user_id">User ID</string>
<string name="aadhar_id">Aadhar ID</string> <string name="aadhar_id">Aadhar ID</string>
<string name="internet_not_available_please_enter_the_user_id_manually">Internet not available, please enter the user ID manually</string> <string name="internet_not_available_please_enter_the_user_id_manually">Internet not available, please enter the user ID and blood group manually</string>
<string name="user_id_error_message">User ID should be 18 digits</string> <string name="user_id_error_message">User ID should be 18 digits and please select the blood group</string>
<string name="upload_db_registration_title">Upload DB Registration</string> <string name="upload_db_registration_title">Upload DB Tests</string>
<string name="upload_db_registration_message">Do you want to upload the local DB Registration to the cloud?</string> <string name="upload_db_registration_message">Do you want to upload the local DB tests to the cloud?</string>
<string name="upload">Upload</string> <string name="upload">Upload</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="upload_success_message">Upload done successfully</string> <string name="upload_success_message">Upload done successfully</string>

View File

@@ -0,0 +1,127 @@
package com.example.hpostesting
import android.content.Context
import android.content.SharedPreferences
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.LiveData
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.presentation.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.util.TestCoroutineRule
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
class HemoCubeViewModelTest {
// Add rule for testing LiveData
@get:Rule
val rule = InstantTaskExecutorRule()
// Add rule for testing coroutines
@get:Rule
val coroutineRule = TestCoroutineRule()
// Mock dependencies
@Mock
lateinit var hemoCubeDao: HemoCubeDao
@Mock
lateinit var repository: Repository
// Mock context
@Mock
lateinit var context: Context
// Mock LiveData for testing
@Mock
lateinit var networkStatusLiveData: LiveData<Boolean>
// Initialize the ViewModel
lateinit var viewModel: HemoCubeViewModel
private lateinit var hemoCubeFragment: HemoCubeFragment
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
// viewModel = HemoCubeViewModel(hemoCubeDao, repository, context)
hemoCubeFragment = HemoCubeFragment()
}
@Test
fun `uploadHemoCubeResultToDatabase with online status should call addResultTestToDb`() =
coroutineRule.runBlockingTest {
// Mock data and setup
val isOnline = true
val testStatus = true
val kitSerial = "12345"
// Mock the necessary methods
`when`(repository.addTestToDatabase(viewModel.testDetails!!))
.thenReturn(Response.Success("Success"))
// Call the function to be tested
viewModel.uploadHemoCubeResultToDatabase(isOnline, testStatus, kitSerial)
// Verify that addResultTestToDb is called
advanceUntilIdle()
assertEquals("Local", viewModel.fireBaseUpload.value)
}
// Similar tests can be written for other methods in HemoCubeViewModel
@Mock
private lateinit var mockSharedPreferences: SharedPreferences
@Mock
private lateinit var mockActivity: HemocubeActivity // Replace with your actual Activity class
@Mock
private lateinit var mockBinding: FragmentHemoCubeReferenceBinding // Replace with your actual Binding class
@Test
fun `findResult with valid input`() {
// Arrange
val validString = "valid string"
val fullReadOutput = "full read output"
`when`(mockSharedPreferences.getString(anyString(), anyString())).thenReturn("dummy_value")
`when`(mockActivity.runOnUiThread(any())).thenAnswer {
val runnable = it.getArgument(0, Runnable::class.java)
runnable.run()
}
// Act
val result = hemoCubeFragment.findResult(calculatedRatio = 0.06)
// Assert
// Add appropriate assertions based on the behavior you expect
// verify(mockSharedPreferences).edit()
// verify(mockBinding).btnSubmit.visibility = View.VISIBLE
// verify(mockBinding).btnSubmit.isEnabled = true
// Add more verifications as needed
assertEquals("Normal", result)
}
}

View File

@@ -11,91 +11,91 @@ import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
class TestRightViewModelTest { class TestRightViewModelTest {
private val viewModel = TestRightViewModel() // private val viewModel = TestRightViewModel()
private val data = InputData() // private val data = InputData()
//
@Test
fun test_mapDeviceConstants() {
viewModel.mapDeviceConstants(data.inputRead)
assertEquals("0", DataHolder.deviceConstant!!.a)
assertEquals("1.69989422e-06", DataHolder.deviceConstant!!.b)
assertEquals("1.60642711e-01", DataHolder.deviceConstant!!.c)
assertEquals("3.85754470e+02", DataHolder.deviceConstant!!.d)
}
@Test
fun test_mapPixelNumberToWavelength() {
viewModel.mapDeviceConstants(data.inputRead)
viewModel.mapPixelNumberToWavelength()
val outputList = TestDataGenerator().getOutputMapPixelNumberToWavelength()
assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, DataHolder.wavelengthToPixelArray.size)
assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, outputList.size)
val df = DecimalFormat("#.###")
df.roundingMode = RoundingMode.FLOOR
for (i in 0 until Constants.TEST_RIGHT_TOTAL_PIXEL){
assertEquals(df.format(outputList[i]), df.format(DataHolder.wavelengthToPixelArray[i]))
}
}
// @Test // @Test
// fun test_mapIntensityValues() { // fun test_mapDeviceConstants() {
// val inputReference = TestDataGenerator().getInputReferenceMapIntensityValues() // viewModel.mapDeviceConstants(data.inputRead)
// val inputSample = TestDataGenerator().getInputSampleMapIntensityValues() // assertEquals("0", DataHolder.deviceConstant!!.a)
// // assertEquals("1.69989422e-06", DataHolder.deviceConstant!!.b)
// viewModel.mapIntensityValues(inputReference, true) // assertEquals("1.60642711e-01", DataHolder.deviceConstant!!.c)
// viewModel.mapIntensityValues(inputSample, false) // assertEquals("3.85754470e+02", DataHolder.deviceConstant!!.d)
// // }
// val outputReference = TestDataGenerator().getOutputReferenceMapIntensityValues() //
// val outputSample = TestDataGenerator().getOutputSampleMapIntensityValues() // @Test
// // fun test_mapPixelNumberToWavelength() {
// assertEquals(outputReference, DataHolder.intensityReferenceArray) // viewModel.mapDeviceConstants(data.inputRead)
// assertEquals(outputSample, viewModel.intensitySampleArray) // viewModel.mapPixelNumberToWavelength()
//
// val outputList = TestDataGenerator().getOutputMapPixelNumberToWavelength()
//
// assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, DataHolder.wavelengthToPixelArray.size)
// assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, outputList.size)
//
// val df = DecimalFormat("#.###")
// df.roundingMode = RoundingMode.FLOOR
//
// for (i in 0 until Constants.TEST_RIGHT_TOTAL_PIXEL){
// assertEquals(df.format(outputList[i]), df.format(DataHolder.wavelengthToPixelArray[i]))
// }
//
// }
//
//// @Test
//// fun test_mapIntensityValues() {
//// val inputReference = TestDataGenerator().getInputReferenceMapIntensityValues()
//// val inputSample = TestDataGenerator().getInputSampleMapIntensityValues()
////
//// viewModel.mapIntensityValues(inputReference, true)
//// viewModel.mapIntensityValues(inputSample, false)
////
//// val outputReference = TestDataGenerator().getOutputReferenceMapIntensityValues()
//// val outputSample = TestDataGenerator().getOutputSampleMapIntensityValues()
////
//// assertEquals(outputReference, DataHolder.intensityReferenceArray)
//// assertEquals(outputSample, viewModel.intensitySampleArray)
//// }
//
// @Test
// fun test_mapWavelengthToAbsorbance() {
//
// viewModel.mapDeviceConstants(data.inputRead)
// viewModel.mapPixelNumberToWavelength()
// viewModel.mapIntensityValues(TestDataGenerator().getInputReferenceMapIntensityValues(), true)
// viewModel.mapIntensityValues(TestDataGenerator().getInputSampleMapIntensityValues(), false)
// viewModel.patientDetails = PatientData("Surya", 2, "Male", TestRightResultType.UNDEFINED)
// viewModel.mapWavelengthToAbsorbance()
//
// val wavelengthList = TestDataGenerator().getOutputMapPixelNumberToWavelength()
// val absorbanceList = TestDataGenerator().getOutputMapWavelengthToAbsorbance()
//
// val df = DecimalFormat("#.###")
// df.roundingMode = RoundingMode.FLOOR
//
// assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, viewModel.wavelengthToAbsorbance.size)
// for (i in 0 until Constants.TEST_RIGHT_TOTAL_PIXEL){
// assertEquals(df.format(wavelengthList[i]), df.format(viewModel.wavelengthToAbsorbance[i][0]))
// assertEquals(df.format(absorbanceList[i]), df.format(viewModel.wavelengthToAbsorbance[i][1]))
// }
// }
//
//
// @Test
// fun testRightViewModel_calculateDataForCSV() {
//
// viewModel.mapDeviceConstants(data.inputRead)
// viewModel.mapPixelNumberToWavelength()
// viewModel.mapIntensityValues(data.printForReference, true)
// viewModel.mapIntensityValues(data.printForSample, false)
//// viewModel.patientDetails = PatientData("Surya", 2, "Male", null)
//// viewModel.calculateResults()
// viewModel.mapWavelengthToAbsorbance()
//
// for (each in viewModel.wavelengthToAbsorbance){
// println(each[0].toString() + " -> " + each[1])
// }
// } // }
@Test
fun test_mapWavelengthToAbsorbance() {
viewModel.mapDeviceConstants(data.inputRead)
viewModel.mapPixelNumberToWavelength()
viewModel.mapIntensityValues(TestDataGenerator().getInputReferenceMapIntensityValues(), true)
viewModel.mapIntensityValues(TestDataGenerator().getInputSampleMapIntensityValues(), false)
viewModel.patientDetails = PatientData("Surya", 2, "Male", TestRightResultType.UNDEFINED)
viewModel.mapWavelengthToAbsorbance()
val wavelengthList = TestDataGenerator().getOutputMapPixelNumberToWavelength()
val absorbanceList = TestDataGenerator().getOutputMapWavelengthToAbsorbance()
val df = DecimalFormat("#.###")
df.roundingMode = RoundingMode.FLOOR
assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, viewModel.wavelengthToAbsorbance.size)
for (i in 0 until Constants.TEST_RIGHT_TOTAL_PIXEL){
assertEquals(df.format(wavelengthList[i]), df.format(viewModel.wavelengthToAbsorbance[i][0]))
assertEquals(df.format(absorbanceList[i]), df.format(viewModel.wavelengthToAbsorbance[i][1]))
}
}
@Test
fun testRightViewModel_calculateDataForCSV() {
viewModel.mapDeviceConstants(data.inputRead)
viewModel.mapPixelNumberToWavelength()
viewModel.mapIntensityValues(data.printForReference, true)
viewModel.mapIntensityValues(data.printForSample, false)
// viewModel.patientDetails = PatientData("Surya", 2, "Male", null)
// viewModel.calculateResults()
viewModel.mapWavelengthToAbsorbance()
for (each in viewModel.wavelengthToAbsorbance){
println(each[0].toString() + " -> " + each[1])
}
}
} }

View File

@@ -0,0 +1,28 @@
package com.example.hpostesting.util
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.rules.TestWatcher
import org.junit.runner.Description
@ExperimentalCoroutinesApi
class TestCoroutineRule : TestWatcher(), TestCoroutineScope by TestCoroutineScope() {
private val testCoroutineDispatcher = TestCoroutineDispatcher()
override fun starting(description: Description?) {
super.starting(description)
Dispatchers.setMain(testCoroutineDispatcher)
}
override fun finished(description: Description?) {
super.finished(description)
Dispatchers.resetMain()
cleanupTestCoroutines()
}
}