Compare commits

..

3 Commits

Author SHA1 Message Date
Sathwik C S
7785f24441 Edit FirebaseManage.kt 2025-02-17 07:32:32 +00:00
chandrashekhar reddy
5f2d5fed85 app version 131 2025-02-17 11:26:44 +05:30
chandrashekhar reddy
c312bf0f39 app version 131 2025-01-23 10:07:07 +05:30
21 changed files with 326 additions and 696 deletions

View File

@@ -1,5 +1,3 @@
# Latest hpos app version
## current version : 2.1.132
### Release key

View File

@@ -18,10 +18,10 @@ android {
// server -> for server switching for internal test
defaultConfig {
applicationId "in.sminnovations.hpostesting.server"
minSdk 30
minSdk 21
targetSdk 34
versionCode 134
versionName "2.1.132"
versionCode 133
versionName "2.1.131"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -30,7 +30,6 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
compileOptions {

View File

@@ -1,33 +1,33 @@
{
"project_info": {
"project_number": "1012719870714",
"project_id": "hpos-prod",
"storage_bucket": "hpos-prod.appspot.com"
"project_number": "650071678820",
"project_id": "hpos-af3cc",
"storage_bucket": "hpos-af3cc.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1012719870714:android:d8d7c962d96f4097de5f43",
"mobilesdk_app_id": "1:650071678820:android:f6fd45e2f6a63aef6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.server"
}
},
"oauth_client": [
{
"client_id": "1012719870714-uli6cdjea3lfnnueh6e4r15i10ei1vlj.apps.googleusercontent.com",
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs"
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "1012719870714-uli6cdjea3lfnnueh6e4r15i10ei1vlj.apps.googleusercontent.com",
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]

View File

@@ -4,15 +4,15 @@
"type": "APK",
"kind": "Directory"
},
"applicationId": "in.sminnovations.hpostesting.dev",
"applicationId": "in.sminnovations.hpostesting.server",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 127,
"versionName": "2.1.127",
"versionCode": 133,
"versionName": "2.1.131",
"outputFile": "app-release.apk"
}
],

View File

@@ -47,7 +47,6 @@ object Constants {
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 34
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM = 9
const val MAXIMUM_TEST_ALLOWED_SINGLE_TEST = 0
const val RANGE_IN_RESULT_CALCULATIONS = 10
@@ -1587,7 +1586,6 @@ object Constants {
//Trueheme for 10mm
//Before changing below values review before
//classification borderline metric
const val TEST_FOR_10MM = "SMI/SC-2-D10/"
const val positiveBoderLineMetricCheck10mmMin = 1.3
const val positiveBoderLineMetricCheck10mmMax = 1.66
const val negativeBoderLineMetricCheck10mmMin = 2.0
@@ -1605,7 +1603,6 @@ object Constants {
const val sickleCellDiseaseMax10mm = 0.7
//Trueheme for 2mm
//classification borderline metric
const val TEST_FOR_2MM = "SMI/SC/"
const val positiveBoderLineMetricCheck2mmMin = 0.8
const val positiveBoderLineMetricCheck2mmMax = 1.1
const val negativeBoderLineMetricCheck2mmMin = 1.5
@@ -1622,25 +1619,6 @@ object Constants {
const val sickleCellDiseaseMin2mm = 0.45
const val sickleCellDiseaseMax2mm = 0.7
//Trueheme for 10mm Single Test
//classification borderline metric
const val singleTest = "SMI/SC-ST/"
const val positiveBoderLineMetricCheck2mmStMin = 1.3
const val positiveBoderLineMetricCheck2mmStMax = 1.66
const val negativeBoderLineMetricCheck2mmStMin = 2.0
const val negativeBoderLineMetricCheck2mmStMax = 2.4
//classification device ratio
const val normalMinSt2mm = 0.07
const val normalMaxSt2mm = 0.23
const val negativeBorderlineMinSt2mm = 0.23
const val negativeBorderlineMaxSt2mm = 0.27
const val sickleCellTraitMinSt2mm = 0.27
const val sickleCellTraitMaxSt2mm = 0.31
const val positiveForSickleCellMinSt2mm = 0.31
const val positiveForSickleCellMaxSt2mm = 0.39
const val sickleCellDiseaseMinSt2mm = 0.39
const val sickleCellDiseaseMaxSt2mm = 0.7
const val min2mmLed1 = 0.34
const val max2mmLed1 = 1.48
const val min2mmLed2 = 0.04

View File

@@ -38,16 +38,15 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
}
override fun exportDataToCSV(
filePath: String, dataList: List<HemoCubeTestData>,
fileName: String, dataList: List<HemoCubeTestData>,
): Boolean {
try {
// Create the file directly from the provided path
val file = File(filePath)
// Ensure parent directory exists
file.parentFile?.mkdirs()
val writer = FileWriter(file)
val formattedFileName = fileName.replace(
Regex("[^a-zA-Z0-9.-]"),
"_"
) // Replace special characters with underscores
val filePath = File(getExternalStorageDirectory(), formattedFileName)
val writer = FileWriter(filePath)
val csvWriter = CSVWriter(writer)
// Write CSV header
val header = arrayOf(
@@ -104,8 +103,8 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
csvWriter.writeNext(header)
// Filter and write data rows where testStatus is true
// val filteredDataList = dataList.filter { it.testStatus == true }
for (data in dataList) {
val filteredDataList = dataList.filter { it.testStatus == true }
for (data in filteredDataList) {
val row = arrayOf(
data._id,
data.name,
@@ -227,8 +226,8 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
csvWriter.writeNext(header)
// Filter and write data rows where testStatus is true
//val filteredDataList = dataList.filter { it.testStatus == true }
for (data in dataList) {
val filteredDataList = dataList.filter { it.testStatus == true }
for (data in filteredDataList) {
val row = arrayOf(
data._id,
data.name,

View File

@@ -38,7 +38,6 @@ import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.utils.UsbServiceListenerImpl
import com.example.hpostesting.util.NetworkMonitor
import com.example.hpostesting.util.PropertyProvider
import com.example.hpostesting.util.PropertyProviderImpl
import com.google.firebase.firestore.FirebaseFirestore
@@ -241,11 +240,8 @@ object AppModule {
return UsbServiceListenerImpl(context)
}
@Provides
@Singleton
fun provideNetworkMonitor(@ApplicationContext context: Context): NetworkMonitor {
return NetworkMonitor(context)
}
}

View File

@@ -14,7 +14,6 @@ package com.example.hpostesting.firebase
import android.content.Context
import android.content.Intent
import android.os.Process
import androidx.core.content.edit
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.firestore.FirebaseFirestore
@@ -28,8 +27,8 @@ import javax.inject.Inject
class FirebaseManager @Inject constructor(private val context: Context) {
private val sharedPreferencesServerConfig = context.getSharedPreferences("FirebaseConfigPrefs", Context.MODE_PRIVATE)
private val sharedPreferencesDev = context.getSharedPreferences("DevMode",Context.MODE_PRIVATE)
private val sharedPreferences =
context.getSharedPreferences("FirebaseConfigPrefs", Context.MODE_PRIVATE)
private var currentFirestore: FirebaseFirestore = FirebaseFirestore.getInstance()
private var currentStorage: FirebaseStorage = FirebaseStorage.getInstance()
@@ -37,7 +36,7 @@ class FirebaseManager @Inject constructor(private val context: Context) {
private val defaultServers = listOf(
// i have it in different place look down
firebaseConfigProd, firebaseConfigDev , firebaseConfigQaQc, firebaseConfigPreProd
firebaseConfig1, firebaseConfig2, firebaseConfig3,
)
init {
@@ -45,18 +44,6 @@ class FirebaseManager @Inject constructor(private val context: Context) {
switchServer(lastSelectedServer)
}
fun setDevModeOn(state : Boolean){
sharedPreferencesDev.edit {
putBoolean( "isDevModeOn",state )
}
}
fun getDevMode(): Boolean {
return sharedPreferencesDev.getBoolean("isDevModeOn",false)
}
fun getCurrentFirestore(): FirebaseFirestore = currentFirestore
fun getCurrentStorage(): FirebaseStorage = currentStorage
@@ -86,7 +73,7 @@ class FirebaseManager @Inject constructor(private val context: Context) {
}
private fun saveSelectedServer(firebaseConfig: FirebaseConfig) {
with(sharedPreferencesServerConfig.edit()) {
with(sharedPreferences.edit()) {
putString("selectedServerName", firebaseConfig.serverName)
putString("projectId", firebaseConfig.projectId)
putString("appId", firebaseConfig.appId)
@@ -106,12 +93,12 @@ class FirebaseManager @Inject constructor(private val context: Context) {
fun getLastSelectedServer(): FirebaseConfig {
val selectedServerName =
sharedPreferencesServerConfig.getString("selectedServerName", defaultServers.first().serverName)
val projectId = sharedPreferencesServerConfig.getString("projectId", defaultServers.first().projectId)
val appId = sharedPreferencesServerConfig.getString("appId", defaultServers.first().appId)
val apiKey = sharedPreferencesServerConfig.getString("apiKey", defaultServers.first().apiKey)
sharedPreferences.getString("selectedServerName", defaultServers.first().serverName)
val projectId = sharedPreferences.getString("projectId", defaultServers.first().projectId)
val appId = sharedPreferences.getString("appId", defaultServers.first().appId)
val apiKey = sharedPreferences.getString("apiKey", defaultServers.first().apiKey)
val storageBucket =
sharedPreferencesServerConfig.getString("storageBucket", defaultServers.first().storageBucket)
sharedPreferences.getString("storageBucket", defaultServers.first().storageBucket)
return FirebaseConfig(
serverName = selectedServerName ?: defaultServers.first().serverName,
@@ -141,7 +128,7 @@ fun delayedRestart(context: Context) {
}
}
private val firebaseConfigDev = FirebaseConfig(
private val firebaseConfig1 = FirebaseConfig(
serverName = "dev",
apiKey = "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I",
appId = "1:650071678820:android:a53292637abb7c0d6c6471",
@@ -149,7 +136,7 @@ private val firebaseConfigDev = FirebaseConfig(
storageBucket = "hpos-af3cc.appspot.com"
)
private val firebaseConfigQaQc = FirebaseConfig(
private val firebaseConfig2 = FirebaseConfig(
serverName = "qc-qa",
apiKey = "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs",
appId = "1:1004619739289:android:3dbcefb10ea99654e5c808",
@@ -157,18 +144,10 @@ private val firebaseConfigQaQc = FirebaseConfig(
storageBucket = "hpos-qa.appspot.com"
)
private val firebaseConfigProd = FirebaseConfig(
serverName = "prod",
apiKey = "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs",
appId = "1:1012719870714:android:d8d7c962d96f4097de5f43",
projectId = "hpos-prod",
storageBucket = "hpos-prod.appspot.com"
)
private val firebaseConfigPreProd = FirebaseConfig(
serverName = "pre prod",
private val firebaseConfig3 = FirebaseConfig(
serverName = " pre prod",
apiKey = "AIzaSyDYySi27LioZGNisP1NfnNU5inJX_0FT38",
appId = "1:121176529204:android:e6841fdac57bdc95bbed61",
appId = "1:121176529204:android:a7bc0842f61e5095bbed61",
projectId = "hpos-preprod",
storageBucket = "hpos-preprod.appspot.com"
)

View File

@@ -24,9 +24,6 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.Constants.TEST_FOR_10MM
import com.example.hpostesting.data.constant.Constants.TEST_FOR_2MM
import com.example.hpostesting.data.constant.Constants.singleTest
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.main_base.DashboardActivity
@@ -55,7 +52,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
private var fromWhere = "Home"
private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding
private var maxTest = 9
private lateinit var sharedPreference: SharedPreferences
var sdkHandler: SDKHandler? = null
@@ -74,27 +71,20 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
}
private fun processScannedData(contents: String) {//edited auto selection of cuvette size
if(contents.contains(TEST_FOR_2MM)){
if(contents.contains("SMI/SC/")){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
}else if(contents.contains(TEST_FOR_10MM)){
}else if(contents.contains("SMI/SC-2-D10/")){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
}else if(contents.contains(singleTest)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mmSt")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm for single test", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
}else{
Toast.makeText(this, R.string.invalid_kit, Toast.LENGTH_LONG).show()
}
@@ -143,19 +133,14 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
setContentView(binding.root)
binding.toolbar.title = "Kit Serial Number"
fromWhere = intent.getStringExtra("fromWhere").toString()
if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm"){
maxTest = Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
}else if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "10mm"){
maxTest = Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM
} else if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mmSt").toString() == "10mmSt"){
maxTest = Constants.MAXIMUM_TEST_ALLOWED_SINGLE_TEST
val maxTest = if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm"){
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
}else{
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM
}
val time = timeDifference(sharedPreference.getString(Constants.KIT_TIME, "").toString())
val kitNum = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
// Toast.makeText(this@KitScanActivity,"Test MAx time"+ time+"-Test count-"+kitNum,Toast.LENGTH_SHORT).show()
// if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
// moveToNext()
// }else{
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
moveToNext()
}else{
@@ -224,27 +209,19 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
if(serialNumber.contains(TEST_FOR_2MM)){
if(serialNumber.contains("SMI/SC/")){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
}else if(serialNumber.contains(TEST_FOR_10MM)){
}else if(serialNumber.contains("SMI/SC-2-D10/")){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show()
}else if(serialNumber.contains(singleTest)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mmSt")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm for single test", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(serialNumber)
}
val kitTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
@@ -371,21 +348,16 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
// }
private fun isSerialValid(s: String): Boolean {
if (s.contains(TEST_FOR_2MM)) {
if (s.contains("SMI/SC/")) {
if(s.length != 17){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC/000/00/000"
return false
}
}else if(s.contains(TEST_FOR_10MM)){
}else if(s.contains("SMI/SC-2-D10/")){
if(s.length != 27){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC-2-D10/000000/000/000"
return false
}
}else if(s.contains(singleTest)){
if(s.length != 27){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC-ST/000000/000/000"
return false
}
}else{
return false
}

View File

@@ -2,7 +2,7 @@ package com.example.hpostesting.presentation.main_base
class AppVersionTapManager {
private var tapCount = 0
private var tapCount = 0
private val maxTapCount = 5
fun registerTap(onMaxTapsReached: () -> Unit) {

View File

@@ -13,59 +13,37 @@
package com.example.hpostesting.presentation.main_base
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import androidx.preference.SwitchPreferenceCompat
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseConfig
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage
import com.google.firebase.storage.ktx.storageMetadata
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
private var isLanguageChanged = false
class SlideshowFragment : Fragment() {
private var selectedItem = "10mm"
private val values = arrayOf("10mm", "2mm", "10mmSt")
private val values = arrayOf("10mm", "2mm")
private lateinit var binding: FragmentSlideshowBinding
private val trueHemeTestViewModel: TrueHemeTestViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
@@ -78,10 +56,9 @@ class SlideshowFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btnDownload.setOnClickListener {
sendData()
}
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, ""))
selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString()
binding.btnGo.setOnClickListener {
var labname = binding.nameEditText.text.toString()
@@ -102,10 +79,8 @@ class SlideshowFragment : Fragment() {
val pos: Int
if (selectedItem == "10mm") {
pos = 0
} else if (selectedItem == "2mm"){
pos = 1
} else {
pos = 2
pos = 1
}
binding.spinnerCuvette.adapter = adapter
@@ -122,7 +97,6 @@ class SlideshowFragment : Fragment() {
// Do nothing here
}
}
binding.spinnerCuvette.setSelection(pos)
binding.btnAddSize.setOnClickListener {
with(sharedPreferences.edit()) {
@@ -137,132 +111,26 @@ class SlideshowFragment : Fragment() {
childFragmentManager.beginTransaction().replace(binding.container.id, PrefsFragment())
.commit()
}
private fun sendData() {
//This data will saved in firebase storage check in HPOS-Prod
val dialog = AlertDialog.Builder(requireContext())
.setTitle("Downloading")
.setMessage("Please wait...")
.setCancelable(false)
.create()
dialog.show()
downloadLocalDBData(dialog)
}
private fun downloadLocalDBData(dialog: DialogInterface) {
var csvDownloaded = false
trueHemeTestViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (!csvDownloaded) {
val downloadList = mutableListOf<HemoCubeTestData>()
userDataList.forEach { userData ->
Log.d("DownloadDebug", "userData: $userData, isCSVCreated: ${userData.isCSVCreated}")
downloadList.add(userData)
}
if (downloadList.isNotEmpty()) {
// Set flag to prevent multiple executions due to observer
csvDownloaded = true
// Launch coroutine to handle CSV creation and upload
lifecycleScope.launch {
try {
// Call suspend function to create CSV and wait for result
val csvFile = trueHemeTestViewModel.createCSVNew(downloadList, requireContext())
if (csvFile != null && csvFile.exists() && csvFile.length() > 0) {
uploadToFirebaseStorage(csvFile)
Toast.makeText(
requireContext(),
"CSV file created successfully at ${csvFile.absolutePath}",
Toast.LENGTH_LONG
).show()
} else {
csvDownloaded = false // Reset flag if failed
Toast.makeText(
requireContext(),
"CSV file creation failed, please try again",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
csvDownloaded = false // Reset flag if exception
e.printStackTrace()
Toast.makeText(
requireContext(),
"Error creating CSV file: ${e.message}",
Toast.LENGTH_SHORT
).show()
} finally {
dialog.dismiss()
}
}
} else {
Toast.makeText(requireContext(), "No data to download", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
}
}
}
private fun uploadToFirebaseStorage(file: File) {
// Get Firebase Storage reference
val storage = Firebase.storage
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val storageRef = storage.reference.child("!!!csv_files/hemocube_data_$timestamp.csv")
// Create file metadata
val metadata = storageMetadata {
contentType = "text/csv"
}
// Upload file
val uploadTask = storageRef.putFile(Uri.fromFile(file), metadata)
uploadTask
.addOnSuccessListener {
Toast.makeText(
requireContext(),
"CSV file uploaded to Firebase successfully",
Toast.LENGTH_SHORT
).show()
}
.addOnFailureListener { exception ->
Log.e("FirebaseUpload", "Upload failed", exception)
Toast.makeText(
requireContext(),
"Failed to upload CSV to Firebase",
Toast.LENGTH_SHORT
).show()
}
.addOnProgressListener { taskSnapshot ->
val progress = (100.0 * taskSnapshot.bytesTransferred / taskSnapshot.totalByteCount)
Log.d("FirebaseUpload", "Upload is $progress% done")
}
}
}
class PrefsFragment : PreferenceFragmentCompat() {
class PrefsFragment : PreferenceFragmentCompat(){
private lateinit var tapManager: AppVersionTapManager
private var isServerSelectionVisible = false
private lateinit var serverPreference: Preference
private lateinit var currentServerPreference: Preference
lateinit var firebaseManager: FirebaseManager
private var topDevMode = false
lateinit var databaseRepository: DatabaseRepository
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
firebaseManager = FirebaseManager(requireContext())
firebaseManager = FirebaseManager(requireContext())
databaseRepository = (activity as DashboardActivity).databaseRepository
tapManager = AppVersionTapManager()
topDevMode = firebaseManager.getDevMode()
val sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
val currentServer = firebaseManager.getLastSelectedServer().serverName
// Language Preference
val languagePreference = ListPreference(requireContext()).apply {
key = "language_preference"
@@ -272,102 +140,52 @@ class PrefsFragment : PreferenceFragmentCompat() {
entryValues = arrayOf("en", "kn", "hi")
setDefaultValue("en")
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_translate_24)
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
val languageCode = newValue as String
updateLanguage(requireContext(), languageCode)
true
}
}
val servers = firebaseManager.getAvailableServers()
val serverNames = servers.map { it.serverName }.toTypedArray()
val serverSelectorPreference = CustomDialogPreference(requireContext()).apply {
key = "server_preference"
title = "Select the Server"
summary = "Current server: $currentServer"
setEntries(serverNames)
setEntryValues(serverNames)
setValue(currentServer)
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_cloud_sync_24)
setOnPreferenceChangeListener { newValue ->
val preferenceConfig = servers.find { it.serverName == newValue }
switchFirebaseServer(preferenceConfig!!)
true
}
}
// Add preferences to screen
preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(languagePreference)
val developerToggle = SwitchPreferenceCompat(requireContext()).apply {
title = "Developer Options"
summary = "Enable or disable developer options"
icon =
ContextCompat.getDrawable(requireContext(), R.drawable.baseline_developer_mode_24)
key = "developer_options" // Unique key for SharedPreferences
// Load toggle state from SharedPreferences
isChecked = firebaseManager.getDevMode()
setOnPreferenceChangeListener { _, newValue ->
val isEnabled = newValue as Boolean
firebaseManager.setDevModeOn(isEnabled)
if (!isEnabled) {
preferenceScreen.removePreference(this)
preferenceScreen.removePreference(serverSelectorPreference)
}
if (!firebaseManager.getDevMode() && currentServer != "prod"){
val prodConfig = servers.find { it.serverName == "prod" }
switchFirebaseServer(prodConfig!!)
}
true
}
}
val appVersionPreference = Preference(requireContext()).apply {
title = "App Version"
summary =
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + "->" + currentServer + "]"
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) +"->"+currentServer+"]"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_info_24)
setOnPreferenceClickListener {
tapManager.registerTap {
firebaseManager.setDevModeOn(true)
val devConfig = servers.find { it.serverName == "dev" }
if (firebaseManager.getDevMode() && currentServer != "dev") {
Toast.makeText(requireContext(), "Now you are a Developer", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Setting Up developer Environmnet", Toast.LENGTH_SHORT).show()
switchFirebaseServer(devConfig!!)
if ((sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN")) {
tapManager.registerTap {
if (!isServerSelectionVisible) {
showServerSelection()
}
}
} else {
if (preferenceScreen.findPreference<SwitchPreferenceCompat>("developer_options") == null) {
preferenceScreen.addPreference(developerToggle)
}
if (preferenceScreen.findPreference<ListPreference>("server_preference") == null) {
preferenceScreen.addPreference(serverSelectorPreference)
}
developerToggle.isChecked = true
updateServerPreference(currentServer)
}
true
}
}
}
preferenceScreen.addPreference(appVersionPreference)
if (firebaseManager.getDevMode()) {
developerToggle.isChecked = true // Ensure it's checked
preferenceScreen.addPreference(developerToggle)
preferenceScreen.addPreference(serverSelectorPreference)
}
currentServerPreference = Preference(requireContext()).apply {
key = "current_server_preference"
title = "Current Server"
summary = "No server selected"
isVisible = false
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_cloud_done_24)
setOnPreferenceClickListener {
// (activity as? DashboardActivity)?.sendData("hello test data")
// Toast.makeText(context, "data sent", Toast.LENGTH_SHORT).show() this was used to send the basic data as test data
true
}
}
preferenceScreen.addPreference(currentServerPreference)
setPreferenceScreen(preferenceScreen)
if (isLanguageChanged) {
@@ -376,23 +194,58 @@ class PrefsFragment : PreferenceFragmentCompat() {
}
private fun updateServerPreference(newServer: String) {
(findPreference<CustomDialogPreference>("server_preference"))?.let { pref ->
pref.setValue(newServer)
pref.summary = "Current server: $newServer"
private fun showServerSelection() {
val currentServer = firebaseManager.getLastSelectedServer().serverName
serverPreference = Preference(requireContext()).apply {
title = "Select Server"
summary = "Choose your server"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_cloud_sync_24)
setOnPreferenceClickListener {
showServerSelectionDialog()
true
}
}
preferenceScreen.addPreference(serverPreference)
currentServerPreference.isVisible = true
currentServerPreference.summary = "Current Server: $currentServer"
Toast.makeText(requireContext(), "Server selection now available", Toast.LENGTH_SHORT).show()
}
private fun showServerSelectionDialog() {
val servers = firebaseManager.getAvailableServers()
val serverNames = servers.map { it.serverName }.toTypedArray()
val builder = AlertDialog.Builder(requireContext())
builder.setTitle("Select Server")
.setItems(serverNames) { _, which ->
val selectedServer = servers[which]
switchFirebaseServer(selectedServer)
}
.setNegativeButton("Cancel", null)
.show()
}
private fun switchFirebaseServer(firebaseConfig: FirebaseConfig) {
firebaseManager.switchServer(firebaseConfig)
Toast.makeText(
requireContext(),
"Switched to ${firebaseConfig.serverName}, Please wait for few seconds",
Toast.LENGTH_SHORT
).show()
Toast.makeText(requireContext(), "Restart needed restarting the app", Toast.LENGTH_SHORT)
.show()
Toast.makeText(requireContext(), "Switched to ${firebaseConfig.serverName}, Please wait for few seconds", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Restart needed restarting the app", Toast.LENGTH_SHORT).show()
firebaseManager.restartApp()
currentServerPreference.summary = "Current Server: ${firebaseConfig.serverName}"
}
private fun switchCurrentServer(serverCode: String) {
Toast.makeText(requireContext(), "Switched to server: $serverCode", Toast.LENGTH_SHORT)
.show()
currentServerPreference.summary = "Current Server: $serverCode"
}
private fun updateLanguage(context: Context, languageCode: String) {
@@ -422,47 +275,3 @@ class PrefsFragment : PreferenceFragmentCompat() {
}
// CustomDialogPreference.kt
class CustomDialogPreference(context: Context) : Preference(context) {
private var entries: Array<String> = arrayOf()
private var entryValues: Array<String> = arrayOf()
private var currentValue: String = ""
private var onValueChangeListener: ((String) -> Boolean)? = null
fun setEntries(entries: Array<String>) {
this.entries = entries
}
fun setEntryValues(values: Array<String>) {
this.entryValues = values
}
fun setValue(value: String) {
currentValue = value
persistString(value)
}
fun setOnPreferenceChangeListener(listener: (String) -> Boolean) {
onValueChangeListener = listener
}
override fun onClick() {
val builder = MaterialAlertDialogBuilder(context)
builder.setTitle(title)
builder.setSingleChoiceItems(entries, entries.indexOf(currentValue)) { dialog, which ->
val newValue = entryValues[which]
if (onValueChangeListener?.invoke(newValue) == true) {
setValue(newValue)
dialog.dismiss()
}
}
builder.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
builder.show()
}
}

View File

@@ -19,6 +19,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.model.CalculationVariableForTest
@@ -35,7 +36,6 @@ import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.domain.SickleFindResultCaluculationWithMaxImpl
import com.example.hpostesting.domain.TestRightResultCalculation
import com.example.hpostesting.util.MyUtils
import com.example.hpostesting.util.NetworkMonitor
import com.google.firebase.storage.FirebaseStorage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
@@ -55,10 +55,10 @@ class TestRightViewModel @Inject constructor(
private val saveRawDataTest: SaveRawDataTest,
private val repository: DatabaseRepository,
private val userDao: UserDao,
networkMonitor: NetworkMonitor,
context: Context?
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
@@ -69,8 +69,9 @@ class TestRightViewModel @Inject constructor(
var testDetails = DataHolder.selectedTest
private var _networkStatusLiveData = networkMonitor.isConnected
val networkStatusLiveData = _networkStatusLiveData
private val _networkStatusLiveData = context?.let { NetworkStatusLiveData(it) }
val networkStatusLiveData: NetworkStatusLiveData?
get() = _networkStatusLiveData
val allUserData = userDao.getAll()
@@ -81,11 +82,6 @@ class TestRightViewModel @Inject constructor(
val calculationVariableList = ArrayList<CalculationVariableForTest>()
init {
networkMonitor.startMonitoring()
_networkStatusLiveData = networkMonitor.isConnected
}
fun mapDeviceConstants(string: String) {
if (string.isNotEmpty()) {
val listOfStrings = string.split(",")

View File

@@ -25,8 +25,11 @@ import androidx.lifecycle.viewModelScope
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.util.CsvWriter
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
@@ -43,12 +46,10 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.util.CsvWriter
import com.example.hpostesting.util.NetworkMonitor
import com.example.hpostesting.util.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
@@ -69,22 +70,20 @@ class TrueHemeViewModel @Inject constructor(
private val repository: Repository,
private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
networkMonitor: NetworkMonitor,
context: Context,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
val messages = MutableLiveData<String>()
private val sharedPreference = context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private val sharedPreference =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private val workManager = WorkManager.getInstance(context)
// init {
// startPeriodicCheckUpdate()
// }
init {
networkMonitor.startMonitoring()
}
// init {
// startPeriodicCheckUpdate()
// }
val loginResponse = MutableLiveData<Result<LoginResponse>>()
@@ -98,7 +97,7 @@ class TrueHemeViewModel @Inject constructor(
// Get the device ID of the device you want to retrieve data for (e.g., the first device in the list)
private val _networkStatusLiveData = networkMonitor.isConnected
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val allKitTestData = hemoCubeBufferDao.getAll()
val deviceData = MutableLiveData<DeviceData?>()
@@ -182,7 +181,7 @@ class TrueHemeViewModel @Inject constructor(
val logFile = logFileManager.createLogFile().let { file ->
val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file.name, it) }
requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) }
multipartFile?.let { partFile ->
repository.uploadLogs(partFile).let { result ->
uploadLogs.postValue(result)
@@ -194,35 +193,37 @@ class TrueHemeViewModel @Inject constructor(
fun uploadHemoCubeResultToDatabaseForBufferCheck(
isOnline: Boolean,
bufferCheckData: BufferCheckData,
) = viewModelScope.launch {
if (isOnline) {
try {
when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
) =
viewModelScope.launch {
if (isOnline) {
try {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
bufferCheckData.localFlag = true
hemoCubeBufferDao.insertAll(bufferCheckData)
}
else -> {}
else -> {}
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
} catch (e: Exception) {
Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
} else {
hemoCubeBufferDao.insertAll(bufferCheckData)
fireBaseUpload.postValue("Local")
}
} else {
hemoCubeBufferDao.insertAll(bufferCheckData)
fireBaseUpload.postValue("Local")
}
}
fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) {
viewModelScope.launch {
@@ -395,7 +396,8 @@ class TrueHemeViewModel @Inject constructor(
viewModelScope.launch {
try {
when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
when (val response =
repository.addTestToDatabaseforBufferCheck(bufferCheckData)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
@@ -413,9 +415,10 @@ class TrueHemeViewModel @Inject constructor(
}
}
private fun updateBufferLocalFlag(bufferId: String) = viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
private fun updateBufferLocalFlag(bufferId: String) =
viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true)
}
fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
@@ -452,12 +455,16 @@ class TrueHemeViewModel @Inject constructor(
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
)
val level: Int =
intent.getIntExtra(
BatteryManager.EXTRA_LEVEL,
-1
)
val scale: Int =
intent.getIntExtra(
BatteryManager.EXTRA_SCALE,
-1
)
level * 100 / scale.toFloat()
}
@@ -467,7 +474,8 @@ class TrueHemeViewModel @Inject constructor(
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
val temperature = intent.getIntExtra(
BatteryManager.EXTRA_TEMPERATURE, 0
BatteryManager.EXTRA_TEMPERATURE,
0
)
temperature.toFloat() / 10
}
@@ -476,11 +484,14 @@ class TrueHemeViewModel @Inject constructor(
}
fun getBatteryVoltage(context: Context): Float {
val batteryIntent = context.registerReceiver(
null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val batteryIntent =
context.registerReceiver(
null,
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
val voltage = batteryIntent?.getIntExtra(
BatteryManager.EXTRA_VOLTAGE, 0
BatteryManager.EXTRA_VOLTAGE,
0
) ?: 0
// milli-volts to volts
@@ -489,7 +500,8 @@ class TrueHemeViewModel @Inject constructor(
fun getBatteryCapacity(context: Context): Int {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batteryManager =
context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
@@ -498,7 +510,8 @@ class TrueHemeViewModel @Inject constructor(
fun getBatteryMaxCapacity(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val designCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val designCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
val currentCapacity =
batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
@@ -515,7 +528,8 @@ class TrueHemeViewModel @Inject constructor(
hemoCubeTestData.forEach { data ->
data.localFlag = true
hemoCubeDao.updateCSVFieldById(
data._id, true
data._id,
true
)
}
}

View File

@@ -32,20 +32,6 @@ import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.Constants.negativeBoderLineMetricCheck2mmStMax
import com.example.hpostesting.data.constant.Constants.negativeBoderLineMetricCheck2mmStMin
import com.example.hpostesting.data.constant.Constants.negativeBorderlineMaxSt2mm
import com.example.hpostesting.data.constant.Constants.negativeBorderlineMinSt2mm
import com.example.hpostesting.data.constant.Constants.normalMaxSt2mm
import com.example.hpostesting.data.constant.Constants.normalMinSt2mm
import com.example.hpostesting.data.constant.Constants.positiveBoderLineMetricCheck2mmStMax
import com.example.hpostesting.data.constant.Constants.positiveBoderLineMetricCheck2mmStMin
import com.example.hpostesting.data.constant.Constants.positiveForSickleCellMaxSt2mm
import com.example.hpostesting.data.constant.Constants.positiveForSickleCellMinSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellDiseaseMaxSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellDiseaseMinSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellTraitMaxSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellTraitMinSt2mm
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.TestStatus
import com.example.hpostesting.data.model.TestState
@@ -1210,20 +1196,6 @@ class TrueHemeTestFragment : Fragment() {
binding.btnSamplestart.isEnabled = true
return
}
}else if(cuvetteSizeSP == "2mmSt"){
inRange2mmLed1 = led1Average in min2mmLed1..max2mmLed1
inRange2mmLed2 = led2Average in min2mmLed2..max2mmLed2
if(!inRange2mmLed1 || !inRange2mmLed2){
trueHemeTestViewModel.messages.postValue("Absorbance out-of-Range - Repeat test with adequate blood volume and Incubation time")
this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code
binding.testing.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true
binding.btnSamplestart.isEnabled = true
return
}
}
}
}
@@ -1506,25 +1478,6 @@ class TrueHemeTestFragment : Fragment() {
return "Positive for Sickle Cell. Confirm with HPLC"
}
}
}else if(cuvetteSizeSP == "2mmSt"){
if (deviceRatioClass == "Negative Borderline") {
if (borderlineMetric < negativeBoderLineMetricCheck2mmStMin){//1.34
return "Sickle Cell Trait"
}else if(borderlineMetric > negativeBoderLineMetricCheck2mmStMax){
return "Normal"
}else if(borderlineMetric > negativeBoderLineMetricCheck2mmStMin && borderlineMetric < negativeBoderLineMetricCheck2mmStMax){
return "Negative borderline. Confirm with HPLC"
}
}
if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") {
if (borderlineMetric < positiveBoderLineMetricCheck2mmStMin){//1.34
return "Sickle Cell Disease"
}else if(borderlineMetric > positiveBoderLineMetricCheck2mmStMax){
return "Sickle Cell Trait"
}else if(borderlineMetric > positiveBoderLineMetricCheck2mmStMin && borderlineMetric < positiveBoderLineMetricCheck2mmStMax){
return "Positive for Sickle Cell. Confirm with HPLC"
}
}
}
}
} catch (e: Exception) {
@@ -1595,22 +1548,6 @@ class TrueHemeTestFragment : Fragment() {
if (ratio in sickleCellDiseaseMin2mm..sickleCellDiseaseMax2mm){
return "Sickle Cell Disease"
}
}else if(cuvetteSize == "2mmSt"){
if (ratio in normalMinSt2mm..normalMaxSt2mm) {
return "Normal"
}
if (ratio in negativeBorderlineMinSt2mm..negativeBorderlineMaxSt2mm){
return "Negative Borderline"
}
if (ratio in sickleCellTraitMinSt2mm..sickleCellTraitMaxSt2mm){
return "Sickle Cell Trait"
}
if (ratio in positiveForSickleCellMinSt2mm..positiveForSickleCellMaxSt2mm){//0.36
return "Positive for Sickle Cell. HPLC for Confirmation"
}
if (ratio in sickleCellDiseaseMinSt2mm..sickleCellDiseaseMaxSt2mm){
return "Sickle Cell Disease"
}
}
} else {

View File

@@ -27,6 +27,7 @@ import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.example.hpostesting.util.CsvWriter
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao
@@ -49,19 +50,14 @@ import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.util.NetworkMonitor
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Headers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.ResponseBody
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
@@ -76,7 +72,6 @@ class TrueHemeTestViewModel @Inject constructor(
private val repository: Repository,
private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
networkMonitor: NetworkMonitor,
context: Context,
) : ViewModel() {
private var testUpload: Boolean = false
@@ -92,9 +87,6 @@ class TrueHemeTestViewModel @Inject constructor(
// init {
// startPeriodicCheckUpdate()
// }
init {
networkMonitor.startMonitoring()
}
val loginResponse = MutableLiveData<Result<LoginResponse>>()
@@ -111,7 +103,7 @@ class TrueHemeTestViewModel @Inject constructor(
// Get the device ID of the device you want to retrieve data for (e.g., the first device in the list)
private val _networkStatusLiveData =networkMonitor.isConnected
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val allUserData = hemoCubeDao.getAll()
val allLocalData = hemoCubeDao.getAll()
val allPendingUserToUpload = hemoCubeDao.getPendingUser()
@@ -779,44 +771,7 @@ class TrueHemeTestViewModel @Inject constructor(
return maxCapacity
}
suspend fun createCSVNew(data: List<HemoCubeTestData>, context: Context): File? {
return withContext(Dispatchers.IO) {
try {
val timestamp = System.currentTimeMillis()
val fileName = "hemocube_data_$timestamp.csv"
// Create file in app's external files directory
val appFile = File(context.getExternalFilesDir(null), fileName)
// Ensure this file is used by localFileDataSource
val exportSuccess = localFileDataSource.exportDataToCSV(appFile.absolutePath, data)
if (exportSuccess) {
// Update database records
data.forEach { item ->
hemoCubeDao.updateCSVFieldById(
item._id,
true
)
}
// Verify file exists and has content
if (appFile.exists() && appFile.length() > 0) {
return@withContext appFile
} else {
Log.e("CSVCreation", "File creation verified failed: exists=${appFile.exists()}, size=${appFile.length()}")
return@withContext null
}
} else {
Log.e("CSVCreation", "exportDataToCSV returned false")
return@withContext null
}
} catch (e: Exception) {
Log.e("CSVCreation", "Error creating CSV", e)
return@withContext null
}
}
}
fun createCSV(hemoCubeTestData: List<HemoCubeTestData>, appContext: Context) =
viewModelScope.launch {
val fileName = "HPOS${getCurrentDate()}.csv"
@@ -842,5 +797,4 @@ class TrueHemeTestViewModel @Inject constructor(
hemoCubeDao.updateTest(testDetails!!)
}
}
}

View File

@@ -1,99 +0,0 @@
package com.example.hpostesting.util
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.net.HttpURLConnection
import java.net.URL
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NetworkMonitor @Inject constructor(
@ApplicationContext private val context: Context
) {
private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val _isConnected = MutableLiveData(false)
val isConnected: LiveData<Boolean> get() = _isConnected
private val networkScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
performPingCheck()
}
override fun onLost(network: Network) {
_isConnected.postValue(false)
}
override fun onCapabilitiesChanged(
network: Network, networkCapabilities: NetworkCapabilities
) {
// Recheck connectivity when capabilities change (e.g., network becomes validated)
performPingCheck()
}
}
fun startMonitoring() {
// Check initial connectivity status
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
val isInitiallyConnected = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
if (isInitiallyConnected) {
performPingCheck()
} else {
_isConnected.postValue(false)
}
val networkRequest =
NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
fun stopMonitoring() { // never needed to call
try {
connectivityManager.unregisterNetworkCallback(networkCallback)
} catch (_: IllegalArgumentException) {
// Ignore if callback was not registered
}
networkScope.cancel()
}
private fun performPingCheck() {
networkScope.launch {
try {
val url = URL("https://www.google.com")
val connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 2000
connection.readTimeout = 2000
connection.setRequestProperty("Connection", "close")
connection.connect()
// Consider any 2xx response as successful
val isReachable = connection.responseCode in 200..299
_isConnected.postValue(isReachable)
connection.disconnect()
} catch (e: Exception) {
_isConnected.postValue(false)
}
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.util
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
class NetworkStatusLiveData(context: Context) : LiveData<Boolean>() {
private val connectivityManager: ConnectivityManager =
context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
postValue(true)
}
override fun onLost(network: Network) {
postValue(false)
}
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onActive() {
super.onActive()
postValue(isNetworkAvailable())
registerNetworkCallback()
}
override fun onInactive() {
super.onInactive()
unregisterNetworkCallback()
}
private fun registerNetworkCallback() {
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.build()
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
private fun unregisterNetworkCallback() {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
@RequiresApi(Build.VERSION_CODES.M)
private fun isNetworkAvailable(): Boolean {
val network = connectivityManager.activeNetwork
val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
return networkCapabilities != null &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
}

View File

@@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M7,5h10v2h2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1c-1.1,0 -2,0.9 -2,2v4h2L7,5zM15.41,16.59L20,12l-4.59,-4.59L14,8.83 17.17,12 14,15.17l1.41,1.42zM10,15.17L6.83,12 10,8.83 8.59,7.41 4,12l4.59,4.59L10,15.17zM17,19L7,19v-2L5,17v4c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2v2z"/>
</vector>

View File

@@ -88,22 +88,12 @@
app:layout_constraintBottom_toBottomOf="@id/spinnerCuvette"
app:layout_constraintStart_toEndOf="@id/spinnerCuvette"
app:layout_constraintTop_toTopOf="@id/spinnerCuvette" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="Send Data To Server"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinnerCuvette"
/>
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/btn_download"
app:layout_constraintTop_toBottomOf="@+id/btn_add_size"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="10dp"/>

View File

@@ -0,0 +1,38 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- RadioGroup to select servers -->
<RadioGroup
android:id="@+id/radioGroupServers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical">
<!-- Radio Buttons for each server option -->
<RadioButton
android:id="@+id/radioButtonInternal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Internal" />
<RadioButton
android:id="@+id/radioButtonClinical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clinical" />
<RadioButton
android:id="@+id/radioButtonCustomer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Customer" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -16,12 +16,12 @@ package com.example.hpostesting
import android.content.Context
import android.content.SharedPreferences
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.example.hpostesting.util.NetworkStatusLiveData
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.presentation.autodac.AutoDacViewModel
import com.example.hpostesting.util.NetworkMonitor
import io.mockk.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,7 +43,7 @@ class AutoDacViewModelTest {
private val repository = mockk<Repository>()
private val context = mockk<Context>()
private val sharedPreferences = mockk<SharedPreferences>()
private val networkStatusLiveData = mockk<NetworkMonitor>()
private val networkStatusLiveData = mockk<NetworkStatusLiveData>()
@Before
fun setup() {
@@ -54,7 +54,7 @@ class AutoDacViewModelTest {
every { context.getSystemService(any()) } returns networkStatusLiveData
// Mocking the NetworkStatusLiveData
every { networkStatusLiveData.startMonitoring() } just Runs
every { networkStatusLiveData.observe(any(), any()) } just Runs
every { hemoCubeDao.getAll() } returns mockk()
// every { repository.addDiagnostics(any()) } returns Response.Success(Unit)