Compare commits

..

12 Commits

31 changed files with 675 additions and 575 deletions

View File

@@ -65,12 +65,14 @@
<activity
android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar"/>
<activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false"
android:noHistory="true"
android:screenOrientation="portrait"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
@@ -114,7 +116,7 @@
<service
android:name="com.example.hpostesting.presentation.testRight.UsbService"
android:name="com.example.hpostesting.util.UsbService"
android:enabled="true"
android:exported="false" />

View File

@@ -55,6 +55,7 @@ object Constants {
const val USER_ID = "usernameId"
const val QUICK_CAPTURE_SOLUTION = "SOLUTION"
const val QUICK_CAPTURE_FOR_ADMIN = "ADMIN"
const val QUICK_CAPTURE_CONCENTRATION = "CONCENTRATION"
const val QUICK_CAPTURE_VOLUME = "VOLUME"
const val QUICK_CAPTURE_READING_PER_SAMPLE = "READING_PER_SAMPLE"

View File

@@ -15,4 +15,5 @@ enum class HemoCubeCommands(val command: String) {
SECOND_GAIN_COMMAND("U\r"),
THIRD_GAIN_COMMAND("V\r"),
FORTH_GAIN_COMMAND("W\r"),
CHECK_CUVETTE_COMMAND("L\r"),
}

View File

@@ -10,8 +10,12 @@ enum class TestStatus(val code: Double) {
FIRST_EMPTY_AIR_READING_PRINT_COMPLETED(4.4),
EPROM_ADC_RETRIEVAL_STARTED(4.5),
EPROM_ADC_RETRIEVAL_COMPLETED(4.6),
BUFFER_STARTED(4.7),
BUFFER_COMPLETED(5.0),
CUVETTE_ABSENT(4.7),
CUVETTE_PRESENT(4.8),
CUVETTE_ABSENTS(7.7),
CUVETTE_PRESENTS(7.8),
BUFFER_STARTED(4.9),
BUFFER_COMPLETED(5.1),
BUFFER_PRINT_STARTED(6.0),
BUFFER_PRINT_COMPLETED(7.0),
SAMPLE_STARTED(8.0),

View File

@@ -13,12 +13,6 @@ interface HemoCubeDao {
@Query("SELECT * from hemo_cube_test_table")
fun getAll(): LiveData<List<HemoCubeTestData>>
@Query("SELECT * from hemo_cube_test_table WHERE molbioFlag=false")
fun getMolbioPending(): List<HemoCubeTestData>
@Query("SELECT * from hemo_cube_test_table WHERE localFlag=false")
fun getFirebasePending():List<HemoCubeTestData>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(hemoCubeTestData: HemoCubeTestData)

View File

@@ -10,7 +10,7 @@ import com.example.hpostesting.data.model.patient.UserData
@Database(
entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class],
version = 29,
version = 30,
exportSchema = false
)
@TypeConverters(Converters::class)

View File

@@ -11,4 +11,6 @@ interface LocalFileDataSource {
fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData>,
): Boolean
fun backUpDataToCSV(fileName: String, dataList: List<HemoCubeTestData>)
}

View File

@@ -153,6 +153,127 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
}
}
override fun backUpDataToCSV(fileName: String, dataList: List<HemoCubeTestData>) {
try {
val filePath = File(getExternalStorageDirectory(), fileName)
val writer = FileWriter(filePath)
val csvWriter = CSVWriter(writer)
// Write CSV header
val header = arrayOf(
"_id",
"name",
"incubationTime",
"bloodGroup",
"birthYear", // Include other fields from the data class
"state",
"abhaId",
"userImageURL",
"location",
"reportUploadTime",
"testType",
"testTime",
"testStatus",
"gender",
"localFlag", // Add more fields as necessary
"deviceId",
"appVersion",
"deviceSerialNumber",
"deviceType",
"kitSerial",
"resultData",
"led1Buffer",
"led2Buffer",
"led3Buffer",
"led4Buffer",
"led1Sample",
"led2Sample",
"led3Sample",
"led4Sample",
"led1Average",
"led2Average",
"led3Average",
"led4Average",
"abs1",
"abs2",
"abs3",
"abs4",
"deviceRatio",
"calculatedRatio",
"predictedDenovixRatio",
"coefficients",
"classificationResult",
"prdClassification",
"errorMessages",
"batteryLevel",
"batteryCapacity",
"batteryMaxCapacity",
"batteryTemperature",
"batteryVoltage"
)
csvWriter.writeNext(header)
// Filter and write data rows where testStatus is true
val filteredDataList = dataList.filter { it.testStatus == true }
for (data in filteredDataList) {
val row = arrayOf(
data._id,
data.name,
data.incubationTime,
data.bloodGroup,
data.birthYear, // Include other fields similarly
data.state,
data.abhaId,
data.userImageURL,
data.location?.toString(),
data.reportUploadTime ?: "",
data.testType ?: "",
data.testTime ?: "",
data.testStatus?.toString() ?: "",
data.gender,
data.localFlag.toString(),
data.deviceId ?: "",
data.appVersion ?: "",
data.deviceSerialNumber,
data.deviceType,
data.kitSerial,
data.resultData,
data.led1Buffer?.toString() ?: "",
data.led2Buffer?.toString() ?: "",
data.led3Buffer?.toString() ?: "",
data.led4Buffer?.toString() ?: "",
data.led1Sample?.toString() ?: "",
data.led2Sample?.toString() ?: "",
data.led3Sample?.toString() ?: "",
data.led4Sample?.toString() ?: "",
data.led1Average?.toString() ?: "",
data.led2Average?.toString() ?: "",
data.led3Average?.toString() ?: "",
data.led4Average?.toString() ?: "",
data.abs1?.toString() ?: "",
data.abs2?.toString() ?: "",
data.abs3?.toString() ?: "",
data.abs4?.toString() ?: "",
data.deviceRatio?.toString() ?: "",
data.calculatedRatio?.toString() ?: "",
data.predictedDenovixRatio?.toString() ?: "",
data.coefficients ?: "",
data.classificationResult,
data.prdClassification,
data.errorMessages,
data.batteryLevel,
data.batteryCapacity,
data.batteryMaxCapacity,
data.batteryTemperature,
data.batteryVoltage
)
csvWriter.writeNext(row)
}
writer.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun getExternalStorageDirectory(): File {
val folder = File(Environment.getExternalStorageDirectory(), "HposFolder")

View File

@@ -90,6 +90,7 @@ data class HemoCubeTestData(
var quickCapture: Boolean = false,
var solution: String? = "",
var concentration: String? = "",
var filter: String? = "",
var volume: String? = "",
var isCSVCreated: Boolean = false,
)

View File

@@ -1,42 +0,0 @@
package com.example.hpostesting.encryption
import android.util.Base64
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
object Encryption {
private const val AES_MODE = "AES/CBC/PKCS5Padding"
private const val KEY_SPEC_ALGORITHM = "PBKDF2WithHmacSHA1"
private const val SALT = "Bigtec"
private const val ITERATION_COUNT = 10000
private const val KEY_LENGTH = 256
private val FIXED_IV = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
fun encrypt(textToEncrypt: String, password: String): String {
val salt = SALT.toByteArray()
val factory = SecretKeyFactory.getInstance(KEY_SPEC_ALGORITHM)
val spec = PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH)
val tmp = factory.generateSecret(spec)
val key = SecretKeySpec(tmp.encoded, "AES")
val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(FIXED_IV))
val encryptedBytes = cipher.doFinal(textToEncrypt.toByteArray(Charsets.UTF_8))
return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
}
fun decrypt(encryptedText: String, password: String): String {
val salt = SALT.toByteArray()
val encryptedBytes = Base64.decode(encryptedText, Base64.NO_WRAP)
val factory = SecretKeyFactory.getInstance(KEY_SPEC_ALGORITHM)
val spec = PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH)
val tmp = factory.generateSecret(spec)
val key = SecretKeySpec(tmp.encoded, "AES")
val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.DECRYPT_MODE, key, IvParameterSpec(FIXED_IV))
val decryptedBytes = cipher.doFinal(encryptedBytes)
return String(decryptedBytes, Charsets.UTF_8)
}
}

View File

@@ -44,7 +44,6 @@ class AssuranceControlsFragment : Fragment() {
private fun initViews() {
// binding.btnSubmit.visibility = View.GONE
val solutionSpinner: Spinner = binding.spinnerSolutions
val solutionOptions = arrayOf("Select solution", "Tartrazine", "Acid Red")
val solutionAdapter =
@@ -123,6 +122,27 @@ class AssuranceControlsFragment : Fragment() {
}
}
val adminspinner: Spinner = binding.spinnerAdmin
val adminOptions = arrayOf("Select options", "Sickle-Cert-Buffer", "1 Abs Holo Filter", "0.25 Abs Holo Filter", "Air Blank")
val adminAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, adminOptions)
adminAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
adminspinner.adapter =adminAdapter
adminspinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
val selectedValue: String = adminOptions[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
// load saved values
val savedSolution =
sharedPreferences.getString(Constants.QUICK_CAPTURE_SOLUTION, "").toString()
@@ -139,18 +159,30 @@ class AssuranceControlsFragment : Fragment() {
val volumePosition = getPositionOfValue(savedVolume, volumeOptions.toList())
volumeSpinner.setSelection(volumePosition)
val foradmin =
sharedPreferences.getString(Constants.QUICK_CAPTURE_FOR_ADMIN, "").toString()
val adminPosition = getPositionOfValue(foradmin, adminOptions.toList())
adminspinner.setSelection(adminPosition)
binding.btnSubmit.setOnClickListener {
val selectedSolution = binding.spinnerSolutions.selectedItem.toString()
val selectedConcentration = binding.spinnerConcentration.selectedItem.toString()
val selectedadminOption = binding.spinnerAdmin.selectedItem.toString()
// Check if any of the selections are default values
if (selectedSolution == "Select solution") {
Toast.makeText(requireContext(), "Please select a solution", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
}
// if (selectedSolution == "Select solution") {
// Toast.makeText(requireContext(), "Please select a solution", Toast.LENGTH_LONG).show()
// return@setOnClickListener // Prevent further execution
// }
//
// if (selectedConcentration == "Select concentration") {
// Toast.makeText(requireContext(), "Please select a concentration", Toast.LENGTH_LONG).show()
// return@setOnClickListener // Prevent further execution
// }
if (selectedConcentration == "Select concentration") {
Toast.makeText(requireContext(), "Please select a concentration", Toast.LENGTH_LONG).show()
if (selectedadminOption == "Select options") {
Toast.makeText(requireContext(), "Please select a option", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
}
DataHolder.hemoCubeTestData!!.quickCapture = true
@@ -162,7 +194,14 @@ class AssuranceControlsFragment : Fragment() {
DataHolder.hemoCubeTestData!!._id = currentUnixTime.toString() + "SMI"
DataHolder.hemoCubeTestData!!.solution = binding.spinnerSolutions.selectedItem.toString()
DataHolder.hemoCubeTestData!!.concentration = binding.spinnerConcentration.selectedItem.toString()
DataHolder.hemoCubeTestData!!.name = "${DataHolder.hemoCubeTestData!!.solution} ${DataHolder.hemoCubeTestData!!.concentration} ${DataHolder.hemoCubeTestData!!.volume}"
DataHolder.hemoCubeTestData!!.filter = binding.spinnerAdmin.selectedItem.toString()
if(binding.spinnerAdmin.selectedItem.toString().equals("Select options")){
Toast.makeText(requireContext(), "Please select a option", Toast.LENGTH_LONG).show()
}else {
DataHolder.hemoCubeTestData!!.name = DataHolder.hemoCubeTestData!!.filter.toString()
}
DataHolder.selectedTest = UserData()
DataHolder.selectedTest?._id = DataHolder.hemoCubeTestData!!._id
@@ -175,6 +214,7 @@ class AssuranceControlsFragment : Fragment() {
DataHolder.hemoCubeTestData!!.concentration
)
putString(Constants.QUICK_CAPTURE_VOLUME, DataHolder.hemoCubeTestData!!.volume)
putString(Constants.QUICK_CAPTURE_FOR_ADMIN, DataHolder.hemoCubeTestData!!.filter)
apply()
}

View File

@@ -23,7 +23,7 @@ import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -24,7 +24,7 @@ import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -23,7 +23,7 @@ import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -15,8 +15,6 @@ import android.net.Uri
import android.os.BatteryManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Base64
import android.util.Log
import android.view.LayoutInflater
@@ -30,7 +28,6 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.Result
import com.example.hpostesting.presentation.utils.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.login.LoginRequest
@@ -42,7 +39,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.encryption.Encryption
import com.example.hpostesting.presentation.utils.DeviceCommunicationHandler
import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
@@ -59,7 +56,6 @@ import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import kotlinx.coroutines.tasks.await
import okhttp3.ResponseBody
import org.json.JSONObject
import java.io.BufferedOutputStream
@@ -125,6 +121,8 @@ class HomeFragment : Fragment() {
userData.forEach {
if (it.testStatus == false) {
userList.add(it)
}else if(it.testStatus == true){
userList.removeAll(userData)
}
}
val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager
@@ -154,71 +152,65 @@ class HomeFragment : Fragment() {
}
// Now re-subscribe to allUserData
/* hemoCubeViewModel.allLocalData.observe(viewLifecycleOwner) { originalUserDataList ->
hemoCubeViewModel.allLocalData.observe(viewLifecycleOwner) { originalUserDataList ->
Log.d("LOCAL_DB OBSERVE", "OBSERVE CALLED")
Log.d("LOCAL_DB OBSERVE", "OBSERVE CALLED")
val resultList = MolbioV2ResultRequest(mutableListOf())
originalUserDataList.forEach { userData ->
Log.d(
": USER DATA",
originalUserDataList.count().toString() + " : " + userData._id
)
var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
// Upload results after processing all userData to avoid duplicates and ensure all modifications are done
if(accessToken.isNotEmpty()) {
if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) {
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
val bufferIntensityThreshold =
Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString()
?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult
?: "defaultStatus", // Handle possible nulls
thresholds = bufferIntensityThreshold,
interpretation = userData.classificationResult
?: "defaultInterpretation", // Handle possible nulls
testId = userData._id,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted
)
)
}
}
}
Log.d("USER DATA LIST SIZE", resultList.results?.count().toString())
val resultList = MolbioV2ResultRequest(mutableListOf())
originalUserDataList.forEach { userData ->
Log.d(": USER DATA", originalUserDataList.count().toString() + " : " + userData._id)
var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
// Upload results after processing all userData to avoid duplicates and ensure all modifications are done
if(accessToken.isNotEmpty()) {
resultList.results?.forEach { result ->
val userData = result.rawData
Log.d("UserData", userData.toString())
if (userData != null) {
if (!userData.localFlag) {
hemoCubeViewModel.bulkAddResultTestToDb(userData)
if (!userData.localFlag && userData.testStatus == true) {
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
}
}
}
resultList.results?.forEach { result ->
result.rawData?.let { sanitizeDoubleValues(it) }
}
if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION && userData.testStatus == true) {
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
val bufferIntensityThreshold =
Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString()
?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult ?: "defaultStatus", // Handle possible nulls
thresholds = bufferIntensityThreshold,
interpretation = userData.classificationResult ?: "defaultInterpretation", // Handle possible nulls
testId = userData._id,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted
)
)
}
}
}
// Then, check if there are any results to upload.
if (resultList.results?.isNotEmpty() == true) {
hemoCubeViewModel.uploadResult(resultList)
Log.d("resultcount1", "Uploading sanitized results")
}
Log.d("USER DATA LIST SIZE", resultList.results?.count().toString())
}*/
hemoCubeViewModel.sendDataToMolbio()
hemoCubeViewModel.sendDataToFirebase()
resultList.results?.forEach { result ->
val userData = result.rawData
Log.d("UserData", userData.toString())
}
resultList.results?.forEach { result ->
result.rawData?.let { sanitizeDoubleValues(it) }
}
// Then, check if there are any results to upload.
if (resultList.results?.isNotEmpty() == true) {
hemoCubeViewModel.uploadResult(resultList)
Log.d("resultcount1", "Uploading sanitized results")
}
}
} else {
binding.internetAvailableCL.visibility = View.GONE
@@ -249,27 +241,28 @@ class HomeFragment : Fragment() {
binding.uploadData.setOnClickListener {
// showUploadDialog(requireContext())
}
// hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
//
// val btnSaveLocalVisibility =
// if (userData.any { it.testStatus == true }) View.GONE else View.GONE
//
// binding.downloadCSV.visibility = btnSaveLocalVisibility
//
// binding.downloadCSV.setOnClickListener {
// if (btnSaveLocalVisibility == View.VISIBLE) {
// // Execute the action when the button is visible (testStatus is true for at least one user)
// showDownloadDialog(requireContext())
// } else {
// // Handle the case when the button is not visible
// Toast.makeText(
// requireContext(),
// "No test details stored locally",
// Toast.LENGTH_SHORT
// ).show()
// }
// }
// }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE
binding.downloadCSV.visibility = btnSaveLocalVisibility
binding.downloadCSV.setOnClickListener {
if (btnSaveLocalVisibility == View.VISIBLE) {
// Execute the action when the button is visible (testStatus is true for at least one user)
showDownloadDialog(requireContext())
} else {
// Handle the case when the button is not visible
Toast.makeText(
requireContext(),
"No test details stored locally",
Toast.LENGTH_SHORT
).show()
}
}
}else{
binding.downloadCSV.visibility = View.GONE
}
}
binding.btnNewKit.setOnClickListener {
@@ -279,7 +272,7 @@ class HomeFragment : Fragment() {
apply()
}
startActivity(Intent(requireContext(), KitScanActivity::class.java))
requireActivity().finish()
// requireActivity().finish()
}
@@ -290,7 +283,7 @@ class HomeFragment : Fragment() {
apply()
}
startActivity(Intent(requireContext(), KitScanActivity::class.java))
requireActivity().finish()
// requireActivity().finish()
}
binding.btnQuickCapture.setOnClickListener {
DataHolder.hemoCubeTestData = HemoCubeTestData()
@@ -313,52 +306,26 @@ class HomeFragment : Fragment() {
var password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
var userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").toString()
if(userID.isNotEmpty() && password.isNotEmpty()) {
Log.d("istoken",isTokenAvailable.toString())
if (!isTokenAvailable) {
Log.d("istoken1",isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(userID, password))
isTokenAvailable = true
val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val file = File(target, "credentials.txt") //this file contains userID and password to communicate with API.
if (userID.isNotEmpty() && password.isNotEmpty()) {
Log.d("istoken", isTokenAvailable.toString())
if (!isTokenAvailable) {
Log.d("istoken1", isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(userID, password))
isTokenAvailable = true
} else if (isTokenAvailable) {
Log.d("istoken7", isTokenAvailable.toString())
isTokenAvailable = true
hemoCubeViewModel.startPeriodicCheckUpdate()
hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
} else {
if (isTokenExpired(accessToken)) {
Log.d("istoken8", isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(userID, password))
}
}
}else if(isTokenAvailable){
Log.d("istoken7",isTokenAvailable.toString())
isTokenAvailable = true
hemoCubeViewModel.startPeriodicCheckUpdate()
hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
}else{
if(isTokenExpired(accessToken)) {
Log.d("istoken8",isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(userID, password))
}
}
} else if (userID == "deviceIDAPI" && password == "devicePasswordAPI" && deviceId.isNotEmpty()) {
fetchDeviceCredentials()
} else if (file.exists()) {
val encryptedString = file.readText()
val encryptionKey =
Settings.Secure.getString(context?.contentResolver, Settings.Secure.ANDROID_ID)
val decryptedMessage: String = Encryption.decrypt(encryptedString, encryptionKey)
val credentials = decryptedMessage.split("\n")
userID = credentials[0]
password = credentials[1]
Toast.makeText(context, "DECRYPTED: $credentials", Toast.LENGTH_SHORT).show()
if (!isTokenAvailable) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
isTokenAvailable = true
} else if (isTokenAvailable) {
isTokenAvailable = true
hemoCubeViewModel.startPeriodicCheckUpdate()
hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
} else {
if (isTokenExpired(accessToken)) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
}
}
} else {
Toast.makeText(
requireContext(),
@@ -373,7 +340,7 @@ class HomeFragment : Fragment() {
updateTokens(response)
response.data.data?.accessToken
isTokenAvailable = true
Log.d("istoken2", isTokenAvailable.toString())
Log.d("istoken2",isTokenAvailable.toString())
}
is Result.Error -> {
@@ -399,7 +366,7 @@ class HomeFragment : Fragment() {
when (it) {
is Result.Success -> {
Log.d("success,", "uploded")
Log.d("success,","uploded")
it.data.data?.forEach { id ->
id.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
@@ -407,11 +374,7 @@ class HomeFragment : Fragment() {
)
}
}
Toast.makeText(
activity,
"Molbio Result is successfully uploaded",
Toast.LENGTH_LONG
)
Toast.makeText(activity, "Molbio Result is successfully uploaded", Toast.LENGTH_LONG)
.show()
}
@@ -462,29 +425,25 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.checkUpdate.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
val updatedversion = response.data.data?.version.toString()
val updatedversion = response.data.data?.version.toString()
val currentversion =
context?.let { ctx ->
val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
val versionName = packageInfo.versionName
val versionCode: Long =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// From Android P (API level 28), versionCode is deprecated and you should use longVersionCode instead.
packageInfo.longVersionCode
} else {
// For older Android versions, use versionCode (cast it to Long for consistency).
packageInfo.versionCode.toLong()
}
val versionCode: Long = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// From Android P (API level 28), versionCode is deprecated and you should use longVersionCode instead.
packageInfo.longVersionCode
} else {
// For older Android versions, use versionCode (cast it to Long for consistency).
packageInfo.versionCode.toLong()
}
// Use versionName and versionCode as needed
Log.d(
"AppInfo",
"Version Name: $versionName, Version Code: $versionCode"
)
Log.d("AppInfo", "Version Name: $versionName, Version Code: $versionCode")
}
Log.d("versionnow", currentversion.toString())
Log.d("versionnow", updatedversion.toString())
if (updatedversion > currentversion.toString()) {
Log.d("versionnow",currentversion.toString())
Log.d("versionnow",updatedversion.toString())
if(updatedversion > currentversion.toString()){
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
Toast.makeText(
activity,
@@ -492,7 +451,7 @@ class HomeFragment : Fragment() {
Toast.LENGTH_LONG
)
.show()
} else {
}else{
Toast.makeText(
activity,
"App is Up to date",
@@ -528,19 +487,14 @@ class HomeFragment : Fragment() {
val downloadDirectory = "NATS"
val fileName = "nats_certificate.zip"
val unzipDirectoryPath =
requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
// Check if the directory with extracted files exists.
val directory = File(unzipDirectoryPath)
if (directory.exists() && directory.isDirectory) {
// Assuming if the directory exists, the certificate has been downloaded and extracted.
// You can add more specific checks here, e.g., checking for specific files within the directory.
Toast.makeText(
requireContext(),
"NATS certificate already downloaded and extracted.",
Toast.LENGTH_SHORT
).show()
Toast.makeText(requireContext(), "NATS certificate already downloaded and extracted.", Toast.LENGTH_SHORT).show()
return@observe
}
val file = downloadFile(url, requireContext(), fileName, downloadDirectory)
@@ -572,7 +526,7 @@ class HomeFragment : Fragment() {
private fun isTokenExpired(token: String): Boolean {
if (token.isNotEmpty()) {
if(token.isNotEmpty()) {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
val jsonPayload = JSONObject(decodedPayload)
@@ -581,7 +535,7 @@ class HomeFragment : Fragment() {
val currentTimeSeconds = System.currentTimeMillis() / 1000
return exp <= currentTimeSeconds
} else {
}else{
return false
}
}
@@ -596,7 +550,7 @@ class HomeFragment : Fragment() {
apply()
}
isTokenAvailable = true
Log.d("istoken3", isTokenAvailable.toString())
Log.d("istoken3",isTokenAvailable.toString())
}
private fun createLoginRequestData(userID: String, password: String): LoginRequest {
@@ -739,9 +693,9 @@ class HomeFragment : Fragment() {
putString(Constants.NATS_TOKEN, natsToken)
apply()
}
if (!isTokenAvailable) {
if (!isTokenAvailable ) {
Log.d("istoken0", isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(username, password))
hemoCubeViewModel.login(createLoginRequestData(username, password))
}
} ?: Log.e("fetchDeviceCredentials", "Failed to parse device data.")
@@ -925,11 +879,15 @@ class HomeFragment : Fragment() {
}
private fun checkUnprocessedCSVData() {
// hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
// val downloadDataVisibility =
// if (userDataList.any { !it.isCSVCreated && it.testStatus == true }) View.GONE else View.GONE
// binding.downloadCSV.visibility = downloadDataVisibility
// }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
val downloadDataVisibility =
if (userDataList.any { !it.isCSVCreated && it.testStatus == true }) View.VISIBLE else View.GONE
binding.downloadCSV.visibility = downloadDataVisibility
}else{
binding.downloadCSV.visibility = View.GONE
}
}
}
private fun sanitizeDoubleValues(hemoCubeTestData: HemoCubeTestData): HemoCubeTestData {
@@ -946,6 +904,7 @@ class HomeFragment : Fragment() {
}
private fun showUploadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.upload_db_registration_title)
@@ -963,22 +922,22 @@ class HomeFragment : Fragment() {
dialog.show()
}
// private fun showDownloadDialog(context: Context) {
// val builder = AlertDialog.Builder(context)
// builder.setTitle(R.string.download_db_registration_title)
// builder.setMessage(R.string.download_db_registration_message)
//
// builder.setPositiveButton(R.string.downloadcsv) { dialog, _ ->
// downloadLocalDBData(dialog)
// }
//
// builder.setNegativeButton(R.string.cancel) { dialog, _ ->
// dialog.dismiss()
// }
//
// val dialog = builder.create()
// dialog.show()
// }
private fun showDownloadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.download_db_registration_title)
builder.setMessage(R.string.download_db_registration_message)
builder.setPositiveButton(R.string.downloadcsv) { dialog, _ ->
downloadLocalDBData(dialog)
}
builder.setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
private fun uploadLocalDBData(dialog: DialogInterface) {
// viewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
@@ -1040,27 +999,25 @@ class HomeFragment : Fragment() {
}
}
// private fun downloadLocalDBData(dialog: DialogInterface) {
// hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
// val downloadList = mutableListOf<HemoCubeTestData>()
//
// userDataList.forEach { userData ->
// if (!userData.isCSVCreated) {
// downloadList.add(userData) // Add the userData to downloadList
// }
// }
//
// if (downloadList.isNotEmpty()) {
// // Call ViewModel function to create CSV with filtered data
// hemoCubeViewModel.createCSV(downloadList, requireContext())
// Toast.makeText(requireContext(), "Done", Toast.LENGTH_SHORT).show()
// } else {
// Toast.makeText(requireContext(), "Failed", Toast.LENGTH_SHORT).show()
// }
//
// dialog.dismiss()
// }
// }
private fun downloadLocalDBData(dialog: DialogInterface) {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val downloadList = mutableListOf<HemoCubeTestData>()
userDataList.forEach { userData ->
if (!userData.isCSVCreated) {
downloadList.add(userData) // Add the userData to downloadList
}
}
if (downloadList.isNotEmpty()) {
// Call ViewModel function to create CSV with filtered data
hemoCubeViewModel.createCSV(downloadList, requireContext())
Toast.makeText(requireContext(), "Done", Toast.LENGTH_SHORT).show()
}
dialog.dismiss()
}
}
private fun deleteIncompleteRegistrations(userDataList: List<UserData>) {
userDataList.forEach { userData ->
@@ -1096,22 +1053,22 @@ class HomeFragment : Fragment() {
}
}
private fun showDownloadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.download_db_registration_title)
builder.setMessage(R.string.download_db_registration_message)
builder.setPositiveButton(R.string.downloadcsv) { dialog, _ ->
// private fun showDownloadDialog(context: Context) {
// val builder = AlertDialog.Builder(context)
// builder.setTitle(R.string.download_db_registration_title)
// builder.setMessage(R.string.download_db_registration_message)
//
// builder.setPositiveButton(R.string.downloadcsv) { dialog, _ ->
// downloadLocalDBData(dialog)
}
builder.setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.dismiss()
}
val dialog = builder.create()
dialog.show()
}
// }
//
// builder.setNegativeButton(R.string.cancel) { dialog, _ ->
// dialog.dismiss()
// }
//
// val dialog = builder.create()
// dialog.show()
// }
// private fun downloadLocalDBData(dialog: DialogInterface) {
// var csvDownloaded = false
@@ -1158,7 +1115,7 @@ class HomeFragment : Fragment() {
// }
private fun getDeviceId() {
Log.d("HomeFragmentUSb", "getDeviceId")
Log.d("HomeFragmentUSb","getDeviceId")
val handler = activity as? DeviceCommunicationHandler
handler?.sendAndListenToDevice(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
@@ -1166,10 +1123,9 @@ class HomeFragment : Fragment() {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val receivedData = String(it, Charset.forName("UTF-8"))
Log.d("HomeFragment", "USB data" + receivedData)
Log.d("HomeFragment","USB data"+receivedData)
// Assuming the device ID is the full content of the received data. Adjust if needed.
deviceId =
extractDeviceId(receivedData) // Implement this method based on your data format.
deviceId = extractDeviceId(receivedData) // Implement this method based on your data format.
if (deviceId.isNotEmpty()) {
// Store the deviceId in SharedPreferences
with(sharedPreference.edit()) {
@@ -1186,7 +1142,7 @@ class HomeFragment : Fragment() {
override fun onUsbError(e: Exception?) {
// Handle USB communication error
Log.d("HomeFragment", "USB read error" + e.toString())
Log.d("HomeFragment","USB read error"+e.toString())
}
})
@@ -1198,103 +1154,94 @@ class HomeFragment : Fragment() {
val matchResult = regex.find(receivedData)
return matchResult?.groups?.get(1)?.value ?: ""
}
@SuppressLint("SuspiciousIndentation")
private fun checkForUpdate() {
try {
val db = Firebase.firestore
//val deviceId = deviceId
//val deviceId = deviceId
val deviceRef = db.collection("deviceUpdate").document(Constants.DOCUMENT_ID_FOR_UPDATE)
deviceRef.get().addOnSuccessListener { documentSnapshot ->
if (documentSnapshot.exists()) {
if (documentSnapshot.exists()) {
val deviceData =
documentSnapshot.toObject(DeviceData::class.java)
val deviceData =
documentSnapshot.toObject(DeviceData::class.java)
// deviceData?.let { data ->
// deviceData?.let { data ->
val deviceVersion = deviceData!!.deviceVersion
val deviceUpdateAvailableGlobal = deviceData.deviceUpdateAvailable
val updatePathGlobal = deviceData.updatePath
val deviceVersion = deviceData!!.deviceVersion
val deviceUpdateAvailableGlobal= deviceData.deviceUpdateAvailable
val updatePathGlobal= deviceData.updatePath
db.collection("devices").whereEqualTo("deviceId", deviceId).get()
.addOnSuccessListener { documentSnapshotNew ->
if (documentSnapshotNew.documents.isNotEmpty()) {
documentSnapshotNew.documents.forEach {
val documentIn = it.toObject(DeviceData::class.java)
db.collection("devices").whereEqualTo("deviceId", deviceId).get().addOnSuccessListener { documentSnapshotNew ->
if (documentSnapshotNew.documents.isNotEmpty()) {
documentSnapshotNew.documents.forEach{
val documentIn = it.toObject(DeviceData::class.java)
val globalUpdateIgnore = documentIn!!.globalUpdateIgnore
val deviceUpdateAvailable = documentIn.deviceUpdateAvailable
val globalUpdateDone = documentIn.globalUpdateDone
val updatePath = documentIn.updatePath
if (globalUpdateIgnore) {
if (deviceUpdateAvailable) {
val update = db.collection("devices").document(it.id)
.update("deviceUpdateAvailable", false)
update.addOnSuccessListener {
Log.d(
"HomeFragmentUpdate",
"Device local update done"
)
val globalUpdateIgnore = documentIn!!.globalUpdateIgnore
val deviceUpdateAvailable = documentIn.deviceUpdateAvailable
val globalUpdateDone = documentIn.globalUpdateDone
val updatePath = documentIn.updatePath
if(globalUpdateIgnore){
if(deviceUpdateAvailable){
val update = db.collection("devices").document(it.id).update("deviceUpdateAvailable",false)
update.addOnSuccessListener {
Log.d("HomeFragmentUpdate","Device local update done")
initiateUpdate(updatePath)
}.addOnFailureListener {
Log.e("fetchDeviceUpdate", "update fail.")
}
} else {
Log.d(
"HomeFragmentUpdate",
"Device update not available"
)
}
} else {
if (deviceUpdateAvailableGlobal) {
if (!globalUpdateDone) {
val update =
db.collection("devices").document(it.id)
.update("globalUpdateDone", true)
update.addOnSuccessListener {
Log.d(
"HomeFragmentUpdate",
"Device global update done"
)
initiateUpdate(updatePath)
}.addOnFailureListener{
Log.e("fetchDeviceUpdate", "update fail.")
}
}else{
Log.d("HomeFragmentUpdate","Device update not available")
}
}else{
if(deviceUpdateAvailableGlobal) {
if (!globalUpdateDone) {
val update =
db.collection("devices").document(it.id)
.update("globalUpdateDone", true)
update.addOnSuccessListener {
Log.d(
"HomeFragmentUpdate",
"Device global update done"
)
initiateUpdate(updatePathGlobal)
}.addOnFailureListener {
Log.e(
"fetchDeviceUpdate",
"update fail."
)
initiateUpdate(updatePathGlobal)
}.addOnFailureListener {
Log.e(
"fetchDeviceUpdate",
"update fail."
)
}
}
}
}
}
} else {
Log.e("fetchDeviceUpdate", "Document does not exist.")
}
}.addOnFailureListener { exception ->
Log.e("fetchDeviceUpdate", "Error fetching device data", exception)
}
} else {
Log.e("fetchDeviceUpdate", "Document does not exist.")
}
}.addOnFailureListener { exception ->
Log.e("fetchDeviceUpdate", "Error fetching device data", exception)
}
// Toast.makeText(requireActivity()," true -version."+deviceVersion+"updatePath.."+updatePath,Toast.LENGTH_LONG).show()
// Toast.makeText(requireActivity()," true -version."+deviceVersion+"updatePath.."+updatePath,Toast.LENGTH_LONG).show()
// Log for debugging
Log.d(
"fetchDeviceCredentials",
"deviceVersion: $deviceVersion, Password: $deviceUpdateAvailableGlobal, updatePath: $updatePathGlobal"
)
// Log for debugging
Log.d(
"fetchDeviceCredentials",
"deviceVersion: $deviceVersion, Password: $deviceUpdateAvailableGlobal, updatePath: $updatePathGlobal"
)
// ?: Log.e("fetchDeviceUpdate", "Failed to parse device data.")
} else {
Log.e("fetchDeviceUpdate", "Document does not exist.")
} else {
Log.e("fetchDeviceUpdate", "Document does not exist.")
}
}
}
.addOnFailureListener { exception ->
Log.e("fetchDeviceUpdate", "Error fetching device data", exception)
}
@@ -1316,8 +1263,7 @@ class HomeFragment : Fragment() {
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setDestinationInExternalFilesDir(requireActivity(), "Updates", "update.apk")
val downloadManager =
requireActivity().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadManager = requireActivity().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadId = downloadManager.enqueue(request)
// Register a BroadcastReceiver to receive the download complete event
@@ -1327,15 +1273,12 @@ class HomeFragment : Fragment() {
requireActivity().registerReceiver(downloadReceiver, filter, RECEIVER_EXPORTED)
}
}
private fun extractApkUrl(responseBody: ResponseBody): String {
return responseBody.string()
}
private fun isValidHttpUrl(url: String): Boolean {
return url.startsWith("http://") || url.startsWith("https://")
}
private val downloadReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
@@ -1349,11 +1292,8 @@ class HomeFragment : Fragment() {
val file = File(requireActivity().getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
val pInfo = requireActivity().baseContext.packageManager.getPackageInfo(
requireActivity().baseContext.packageName,
0
)
Log.d("HomeFragmentShowInfo", pInfo.packageName.toString())
val pInfo = requireActivity().baseContext.packageManager.getPackageInfo(requireActivity().baseContext.packageName, 0)
Log.d("HomeFragmentShowInfo",pInfo.packageName.toString())
val uri: Uri = FileProvider.getUriForFile(
requireActivity(),
"${pInfo.packageName}.fileprovider",
@@ -1376,7 +1316,7 @@ class HomeFragment : Fragment() {
}
override fun onDestroy() {
if (isRegistered) {
if(isRegistered) {
try {
requireActivity().unregisterReceiver(downloadReceiver)
} catch (e: Exception) {

View File

@@ -27,7 +27,7 @@ import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.utils.DeviceCommunicationHandler
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -26,7 +26,7 @@ import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.utils.DeviceCommunicationHandler
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -4,8 +4,6 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@@ -19,15 +17,11 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.encryption.Encryption
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
import java.io.File
import java.io.FileOutputStream
class DeviceProvisionFragment : Fragment() {
private var resultData: String = ""
@@ -128,10 +122,6 @@ class DeviceProvisionFragment : Fragment() {
deviceUpdateAvailable = false
)
)
encryptAndSaveToFile(
response.data.data?.credentials?.username.toString(),
response.data.data?.credentials?.password.toString()
)
// viewModel.addDeviceId(DeviceData(deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()))
Log.e("idpass", response.toString())
Log.e("idpass", response.data.data?.credentials?.username.toString())
@@ -231,25 +221,4 @@ class DeviceProvisionFragment : Fragment() {
}
}
}
private fun encryptAndSaveToFile(username: String, password: String) {
val messageToEncrypt = "$username\n$password"
val encryptionKey =
Settings.Secure.getString(context?.contentResolver, Settings.Secure.ANDROID_ID)
val encryptedString = Encryption.encrypt(messageToEncrypt, encryptionKey)
Log.d("DEVICE ID/encryptionKey", encryptionKey)
val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val file = File(target, "credentials.txt")
if (!file.exists()) {
file.createNewFile()
}
file.writeText(encryptedString)
Log.d("Encrypted Message", encryptedString)
}
}
}

View File

@@ -23,7 +23,7 @@ import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -35,7 +36,9 @@ import kotlin.math.log10
@Suppress("MemberVisibilityCanBePrivate")
class HemoCubeFragment : Fragment() {
private var checkCuvette = false
private var checkCuvetteSam = false
private var sampleClick = false
private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
@@ -111,33 +114,63 @@ class HemoCubeFragment : Fragment() {
binding.nameEditText.visibility = View.GONE
binding.tvTitle.visibility = View.GONE
binding.btnGo.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE
// binding.btnPlacebuffer.visibility = View.GONE
binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}"
binding.tvSubtitle4.text = "Config"
binding.btnSamplestart.setOnClickListener {
activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE
// binding.tvSubtitle4.text = "Sample Started"
if (isBufferValueAvailable() || !Constants.BLANK_EVERY_TEST) {
binding.btnPlacebuffer.apply {
setBackgroundColor(Color.GREEN) // Set button background color to green
text = "Fresh Buffer" // Change button text to "Buffer Exists"
}
}else if(!isBufferValueAvailable() || Constants.BLANK_EVERY_TEST){
binding.btnPlacebuffer.apply {
setBackgroundColor(Color.RED) // Set button background color to green
text = "No Buffer" // Change button text to "Buffer Exists"
}
startSampleProcess()
it.visibility = View.GONE
}
binding.btnPlacebuffer.setOnClickListener {
if (isBufferValueAvailable() || !Constants.BLANK_EVERY_TEST) {
showBufferAlertDialog()
} else {
binding.btnSamplestart.setOnClickListener {
sampleClick = true
if(checkCuvetteSam){
activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE
// binding.tvSubtitle4.text = "Buffer Started"
// binding.tvSubtitle4.text = "Sample Started"
}
checkAndStartProcess()
it.visibility = View.GONE
startSampleProcess()
// it.visibility = View.GONE
}else{
checkCuvettePresence()
}
}
binding.btnRetryCheckCuvette.setOnClickListener {
checkCuvettePresence()
}
binding.btnPlacebuffer.setOnClickListener {
if(checkCuvette){
startBufferProcess()
// if (isBufferValueAvailable() || !Constants.BLANK_EVERY_TEST) {
//// showBufferAlertDialog()
// } else {
activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE
// binding.tvSubtitle4.text = "Buffer Started"
}
// checkAndStartProcess()
// it.visibility = View.GONE
// }
}else{
checkCuvettePresence()
}
}
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
activity?.runOnUiThread {
@@ -261,9 +294,9 @@ class HemoCubeFragment : Fragment() {
currentResultData = ""
}
private fun checkAndStartProcess() {
startBufferProcess()
}
// private fun checkAndStartProcess() {
// startBufferProcess()
// }
private fun isBufferValueAvailable(): Boolean {
return try {
@@ -314,7 +347,7 @@ class HemoCubeFragment : Fragment() {
override fun onClickPositiveButton() {
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE
// binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
binding.tvSubtitle4.text = getString(R.string.place_sample)
}
@@ -391,7 +424,7 @@ class HemoCubeFragment : Fragment() {
resultData += stringData
currentResultData += stringData
hemoCubeViewModel.deviceMessages.postValue(currentResultData)
Log.e("testStatus",this.testStatusCode.toString())
when {
resultData.contains("SNE") && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> {
processV2HardwareId(resultData)
@@ -418,20 +451,51 @@ class HemoCubeFragment : Fragment() {
(resultData.contains("#RC") && this.testStatusCode < TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code) -> {
this.testStatusCode = TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code
hemoCubeViewModel.messages.postValue("EPROM ADC Loaded")
showStartBufferButton()
//checkCuvettePresence()
}
resultData.contains("#CIN") && sampleClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTS.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present))
this.testStatusCode = TestStatus.CUVETTE_PRESENTS.code
activity?.runOnUiThread {
checkCuvetteSam = true
binding.btnRetryCheckCuvette.visibility = View.GONE
}
}
resultData.contains("#AIN") && sampleClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTS.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_absent))
this.testStatusCode = TestStatus.CUVETTE_ABSENTS.code
showRetryButtonForCuvette()
}
resultData.contains("#CIN") && this.testStatusCode < TestStatus.CUVETTE_PRESENT.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present))
this.testStatusCode = TestStatus.CUVETTE_PRESENT.code
activity?.runOnUiThread {
checkCuvette = true
binding.btnRetryCheckCuvette.visibility = View.GONE
}
}
resultData.contains("#AIN") && this.testStatusCode <= TestStatus.CUVETTE_ABSENT.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_absent))
this.testStatusCode = TestStatus.CUVETTE_ABSENT.code
showRetryButtonForCuvette()
}
resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started))
this.testStatusCode = TestStatus.BUFFER_STARTED.code
}
resultData.contains("#BC") && this.testStatusCode < TestStatus.BUFFER_COMPLETED.code -> {
this.testStatusCode = TestStatus.BUFFER_COMPLETED.code
activity?.runOnUiThread {
resultData = ""
// resultData.replace("#AIN","#BAIN",false)
Log.d("resultDataBC",resultData)
binding.tvSubtitle4.text = getString(R.string.buffer_completed)
binding.btnSamplestart.visibility = View.VISIBLE
// binding.btnSamplestart.visibility = View.VISIBLE
binding.btnPlacebuffer.visibility = View.GONE
}
this.testStatusCode = TestStatus.BUFFER_COMPLETED.code
}
(resultData.contains("#SS") || resultData.contains("#SS1")) && this.testStatusCode < TestStatus.SAMPLE_STARTED.code -> {
@@ -439,11 +503,15 @@ class HemoCubeFragment : Fragment() {
activity?.runOnUiThread {
binding.tvSubtitle4.text = getString(R.string.sample_started)
binding.btnSamplestart.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE
}
}
(resultData.contains("#SC") || resultData.contains("#SC1")) && this.testStatusCode < TestStatus.SAMPLE_COMPLETED.code -> {
this.testStatusCode = TestStatus.SAMPLE_COMPLETED.code
activity?.runOnUiThread {
binding.btnSamplestart.visibility = View.GONE
}
hemoCubeViewModel.messages.postValue(
getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)
)
@@ -600,6 +668,13 @@ class HemoCubeFragment : Fragment() {
}
}
private fun showRetryButtonForCuvette() {
activity?.runOnUiThread {
// binding.btnPlacebuffer.visibility = View.GONE
binding.btnRetryCheckCuvette.visibility = View.VISIBLE
}
}
fun finishReading() {
repeatReadingCount += 1
isTestOngoing = false
@@ -686,9 +761,20 @@ class HemoCubeFragment : Fragment() {
fun showStartBufferButton() {
activity?.runOnUiThread {
binding.btnRetryCheckCuvette.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
// hemoCubeViewModel.messages.postValue(getString(R.string.start))
}
fun showStartSampleButton() {
activity?.runOnUiThread {
binding.btnRetryCheckCuvette.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
}
// hemoCubeViewModel.messages.postValue(getString(R.string.start))
}
fun extractV1HardwareId(input: String): String? {
@@ -1138,13 +1224,29 @@ class HemoCubeFragment : Fragment() {
Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show()
}
private fun startBufferProcess() {
hemoCubeViewModel.progressBar.postValue(true)
private fun checkCuvettePresence() {
Toast.makeText(requireContext(),"Please wait...",Toast.LENGTH_LONG).show()
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE
binding.btnRetryCheckCuvette.visibility = View.GONE
}
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.CHECK_CUVETTE_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun startBufferProcess() {
hemoCubeViewModel.progressBar.postValue(true)
// activity?.runOnUiThread {
// binding.btnPlacebuffer.visibility = View.GONE
// }
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_BUFFER_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
@@ -1156,16 +1258,17 @@ class HemoCubeFragment : Fragment() {
}
private fun startSampleProcess() {
hemoCubeViewModel.progressBar.postValue(true)
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_SAMPLE,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.START_SAMPLE,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
private fun sendFirstGainCommand() {

View File

@@ -38,7 +38,6 @@ import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
@@ -113,7 +112,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.kitSerial = kitSerial
}
testDetails?.testStatus = testStatus
// localFileDataSource.backUpDataToCSV("",testDetails)
try {
if (isOnline) {
parseData()
@@ -153,89 +152,6 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun sendDataToMolbio() = viewModelScope.launch(Dispatchers.IO) {
Log.d("molbio","getting in sendMolbio")
val resultList = MolbioV2ResultRequest(mutableListOf())
val pendingData = hemoCubeDao.getMolbioPending()
Log.d("molbio","pending size"+pendingData.size)
pendingData.forEach{
userData ->
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
val bufferIntensityThreshold =
Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString()
?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult
?: "defaultStatus", // Handle possible nulls
thresholds = bufferIntensityThreshold,
interpretation = userData.classificationResult
?: "defaultInterpretation", // Handle possible nulls
testId = userData._id,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted
)
)
}
resultList.results?.forEach { result ->
result.rawData?.let { sanitizeDoubleValues(it) }
}
if (resultList.results?.isNotEmpty() == true) {
uploadMoblioBulkResults(resultList)
}
}
fun uploadMoblioBulkResults(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch {
Log.d("molbio","upload called")
repository.uploadResults(molbioV2ResultRequest).let {
when (it) {
is Result.Success -> {
it.data.data?.forEach { id ->
id.rawData?.let { it1 ->
updateMolbioFlag(
it1._id
)
}
}
}
is Result.Error -> {
Log.d("result","result upload error")
}
else -> {
Log.d("result","result upload else")
}
}
}
}
fun sendDataToFirebase() = viewModelScope.launch ( Dispatchers.IO ) {
val pendingData = hemoCubeDao.getFirebasePending()
pendingData.forEach{
userData ->
if (userData != null) {
if (!userData.localFlag) {
bulkAddResultTestToDb(userData)
}
}
}
}
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
checkUpdate.postValue(Result.Loading())
repository.checkUpdate(checkUpdateRequest).let {
@@ -398,6 +314,8 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.solution = DataHolder.hemoCubeTestData?.solution
testDetails?.concentration = DataHolder.hemoCubeTestData?.concentration
testDetails?.volume = DataHolder.hemoCubeTestData?.volume
testDetails?.filter = DataHolder.hemoCubeTestData?.filter
}
private fun addResultTestToDb() {
@@ -643,7 +561,7 @@ class HemoCubeViewModel @Inject constructor(
val fileName = "HPOS${getCurrentDate()}.csv"
if (localFileDataSource.exportDataToCSV(fileName, hemoCubeTestData)) {
hemoCubeTestData.forEach { data ->
data.localFlag = true
// data.localFlag = true
hemoCubeDao.updateCSVFieldById(
data._id,
true

View File

@@ -25,7 +25,7 @@ import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -24,7 +24,7 @@ import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -25,7 +25,7 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.UsbService
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint

View File

@@ -1,4 +1,4 @@
package com.example.hpostesting.presentation.testRight
package com.example.hpostesting.util
import android.app.Service
import android.content.Intent

View File

@@ -39,6 +39,7 @@
<Spinner
android:id="@+id/spinner_solutions"
android:layout_width="0dp"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:background="@drawable/spinner_border"
@@ -50,6 +51,7 @@
<Spinner
android:id="@+id/spinner_concentration"
android:layout_width="0dp"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:background="@drawable/spinner_border"
@@ -59,6 +61,20 @@
app:layout_constraintTop_toBottomOf="@id/spinner_solutions" />
<Spinner
android:id="@+id/spinner_admin"
android:layout_width="0dp"
android:visibility="visible"
android:layout_height="wrap_content"
android:layout_marginTop="52dp"
android:background="@drawable/spinner_border"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinner_concentration" />
<Spinner
android:id="@+id/spinner_volume"
android:layout_width="0dp"
@@ -71,6 +87,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinner_concentration" />
<Button
android:id="@+id/btn_submit"
android:layout_width="match_parent"

View File

@@ -147,51 +147,67 @@
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/et_abha_id"
app:layout_constraintTop_toTopOf="@id/et_abha_id" />
<Button
android:visibility="gone"
android:id="@+id/btn_samplestart"
<LinearLayout
android:id="@+id/ll_btns"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/Start_Sample"
android:textColor="@color/white"
app:cornerRadius="16dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_placebuffer" />
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4">
<Button
android:id="@+id/btn_placebuffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:visibility="visible"
android:clickable="false"
android:text="@string/place_buffer"
android:textColor="@color/white"
app:cornerRadius="16dp"
/>
<Button
android:id="@+id/btn_samplestart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="5dp"
android:clickable="false"
android:text="@string/Start_Sample"
android:textColor="@color/white"
app:cornerRadius="16dp"
/>
<Button
android:id="@+id/btn_placebuffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/place_buffer"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button
android:id="@+id/btn_retry_check_cuvette"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/retry"
android:textColor="@color/white"
app:cornerRadius="16dp"
/>
<Button
android:id="@+id/btn_submit"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/submit"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<Button
android:id="@+id/btn_submit"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="@string/submit"
android:textColor="@color/white"
app:cornerRadius="16dp"
/>
</LinearLayout>
<TextView
android:id="@+id/error_message"
@@ -206,7 +222,7 @@
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
app:layout_constraintTop_toBottomOf="@id/ll_btns" />
<TextView
android:id="@+id/tv_device_messages"
@@ -217,9 +233,9 @@
android:text="no device message"
android:textColor="@color/black"
android:textSize="11sp"
android:visibility="gone"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/error_message" />
app:layout_constraintTop_toBottomOf="@id/ll_btns" />
<Button
android:visibility="gone"

View File

@@ -272,4 +272,8 @@
<string name="downloadcsv">सीएसवी डाउनलोड करें</string>
<string name="action_activity">Activities</string>
<string name="check_cuvette">Checking cuvette presence</string>
<string name="cuvette_present">Cuvette present</string>
<string name="cuvette_absent">Cuvette absent</string>
<string name="retry">Retry</string>
</resources>

View File

@@ -271,6 +271,10 @@
<string name="ok">ಸರಿ</string>
<string name="downloadcsv">CSV ಡೌನ್ಲೋಡ್ ಮಾಡಿ</string>
<string name="action_activity">Activities</string>
<string name="check_cuvette">Checking cuvette presence</string>
<string name="cuvette_present">Cuvette present</string>
<string name="cuvette_absent">Cuvette absent</string>
<string name="retry">Retry</string>
<!-- Add translations for other strings -->
</resources>

View File

@@ -118,7 +118,7 @@
<string name="Firefox">Firefox</string>
<string name="Files">Files</string>
<string name="deviceinfo">Device Information</string>
<string name="place_buffer">Start</string>
<string name="place_buffer">Start Buffer</string>
<string name="Start_Sample">Start Sample</string>
<string name="new_kit">New Kit</string>
<string name="new_buffer">New Buffer</string>
@@ -274,4 +274,8 @@
<string name="app_language">App Language</string>
<string name="ok">OK</string>
<string name="action_activity">Activities</string>
<string name="check_cuvette">Checking cuvette presence</string>
<string name="cuvette_present">Cuvette present , you can start the test</string>
<string name="cuvette_absent">Cuvette is absent , please place the cuvette and retry again</string>
<string name="retry">Retry again</string>
</resources>