Merge remote-tracking branch 'origin/Local-storing-data' into dev

This commit is contained in:
Pritimay Sarkar
2024-01-16 12:03:24 +05:30
25 changed files with 657 additions and 66 deletions

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="@color/primary"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/primary" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

View File

@@ -0,0 +1,50 @@
package com.example.hpostesting.data
import android.content.Context
import android.os.Environment
import java.io.File
import java.io.FileWriter
import java.io.IOException
class CsvWriter(private val context: Context) {
fun writeCsv(fileName: String, data: List<Array<String>>): Boolean {
try {
val filePath = File(getExternalStorageDirectory(), fileName)
val writer = FileWriter(filePath)
// Write header row
val header = arrayOf(
"ID",
"Blood Group",
"Birth Year",
"Classification Result",
"Test Time",
"User Image URL",
"Name"
)
writer.write(header.joinToString(",") + "\n")
// Write data rows
for (line in data) {
writer.write(line.joinToString(",") + "\n")
}
writer.close()
return true
} catch (e: IOException) {
e.printStackTrace()
return false
}
}
private fun getExternalStorageDirectory(): File {
val folder = File(Environment.getExternalStorageDirectory(), "HposFolder")
if (!folder.exists()) {
folder.mkdirs()
}
return folder
}
}

View File

@@ -26,4 +26,7 @@ interface HemoCubeDao {
@Query("UPDATE hemo_cube_test_table SET molbioFlag = :newValue WHERE _id = :id") @Query("UPDATE hemo_cube_test_table SET molbioFlag = :newValue WHERE _id = :id")
suspend fun updateMolbioFlag(id: String, newValue: Boolean) suspend fun updateMolbioFlag(id: String, newValue: Boolean)
@Query("UPDATE hemo_cube_test_table SET isCSVCreated = :newValue WHERE _id = :id")
suspend fun updateCSVFieldById(id: String, newValue: Boolean)
} }

View File

@@ -8,7 +8,7 @@ import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], version = 21, exportSchema = false) @Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], version = 22, exportSchema = false)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() { abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao abstract fun userDao(): UserDao

View File

@@ -1,8 +1,11 @@
package com.example.hpostesting.data.datasource package com.example.hpostesting.data.datasource
import android.os.Environment
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter import com.opencsv.CSVWriter
import java.io.File import java.io.File
import java.io.FileWriter import java.io.FileWriter
import java.io.IOException
class LocalFileDataSource { class LocalFileDataSource {
@@ -20,4 +23,107 @@ class LocalFileDataSource {
writer.close() writer.close()
} }
fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData>
): Boolean {
try {
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(
"_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",
"led1Sample",
"led2Sample",
"led1Average",
"led2Average",
"deviceRatio",
"calculatedRatio",
"coefficients",
"classificationResult",
"errorMessages",
"batteryLevel"
)
csvWriter.writeNext(header)
// Write data rows
for (data in dataList) {
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.led1Sample?.toString() ?: "",
data.led2Sample?.toString() ?: "",
data.led1Average?.toString() ?: "",
data.led2Average?.toString() ?: "",
data.deviceRatio?.toString() ?: "",
data.calculatedRatio?.toString() ?: "",
data.coefficients ?: "",
data.classificationResult
)
csvWriter.writeNext(row)
}
writer.close()
return true
} catch (e: IOException) {
e.printStackTrace()
return false
}
}
private fun getExternalStorageDirectory(): File {
val folder = File(Environment.getExternalStorageDirectory(), "HposFolder")
if (!folder.exists()) {
folder.mkdirs()
}
return folder
}
} }

View File

@@ -81,4 +81,5 @@ data class HemoCubeTestData(
var solution: String? = "", var solution: String? = "",
var concentration: String? = "", var concentration: String? = "",
var volume: String? = "", var volume: String? = "",
var isCSVCreated: Boolean = false
) )

View File

@@ -10,6 +10,8 @@ data class UserData(
var _id: String = "", var _id: String = "",
var name: String = "", var name: String = "",
var incubationTime: String = "", var incubationTime: String = "",
var gender: String = "",
var state: String = "",
var birthYear: String = "", var birthYear: String = "",
var abhaId: String = "", var abhaId: String = "",
var bloodGroup: String = "", var bloodGroup: String = "",
@@ -46,7 +48,11 @@ data class UserData(
fun UserData.toHemoCubeTestData() = HemoCubeTestData( fun UserData.toHemoCubeTestData() = HemoCubeTestData(
_id = _id, _id = _id,
name = name, name = name,
bloodGroup = bloodGroup,
birthYear = birthYear, birthYear = birthYear,
gender = gender,
state = state,
abhaId = abhaId,
userImageURL = userImageURL, userImageURL = userImageURL,
testStatus = testStatus, testStatus = testStatus,
location = location, location = location,

View File

@@ -0,0 +1,29 @@
package com.example.hpostesting.di
import android.content.Context
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.qualifiers.ApplicationContext
@Module
@InstallIn(ViewModelComponent::class)
object ViewModelModule {
@Provides
fun provideTestRightViewModel(
saveRawData: SaveRawData,
saveRawDataTest: SaveRawDataTest,
databaseRepository: DatabaseRepository,
userDao: UserDao,
context: Context
): TestRightViewModel {
return TestRightViewModel(saveRawData, saveRawDataTest, databaseRepository, userDao, context)
}
}

View File

@@ -202,4 +202,8 @@ class DatabaseRepository @Inject constructor(
// Find the DeviceData object with the specified deviceId // Find the DeviceData object with the specified deviceId
return allDeviceDataList.find { it.deviceId == deviceId } return allDeviceDataList.find { it.deviceId == deviceId }
} }
override fun <UserData> addTestToDatabase(testDetails: UserData): Any {
TODO("Not yet implemented")
}
} }

View File

@@ -1,6 +1,12 @@
package com.example.hpostesting.data.repository package com.example.hpostesting.data.repository
import android.os.Environment
import com.example.hpostesting.data.datasource.LocalFileDataSource import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) { class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) {
fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) = fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) =
@@ -8,4 +14,7 @@ class LocalFileRepository(private val localFileDataSource: LocalFileDataSource)
fun saveTextToDisk(filepath: String, contents: String) = fun saveTextToDisk(filepath: String, contents: String) =
localFileDataSource.saveTextToDisk(filepath, contents) localFileDataSource.saveTextToDisk(filepath, contents)
} }

View File

@@ -19,4 +19,6 @@ interface Repository {
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean>
suspend fun getDeviceDataById(deviceId: String): DeviceData? suspend fun getDeviceDataById(deviceId: String): DeviceData?
abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any
// suspend fun addToDatabase(data: PatientDetails)
} }

View File

@@ -170,4 +170,10 @@ object AppModule {
@Provides @Provides
@Singleton @Singleton
fun provideLogFileManager(context: Context): LogFileManager = LogFileManager(context) fun provideLogFileManager(context: Context): LogFileManager = LogFileManager(context)
@Provides
@Singleton
fun provideLocalFileDataSource(): LocalFileDataSource {
return LocalFileDataSource()
}
} }

View File

@@ -1,6 +1,8 @@
package com.example.hpostesting.presentation.adapter package com.example.hpostesting.presentation.adapter
import android.content.Context import android.content.Context
import android.annotation.SuppressLint
import android.content.res.Resources
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup

View File

@@ -22,11 +22,11 @@ import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.NatsManager import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.android.material.progressindicator.LinearProgressIndicator import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.play.core.appupdate.AppUpdateManager import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.appdistribution.FirebaseAppDistributionException
@@ -205,6 +205,8 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()

View File

@@ -53,11 +53,9 @@ class HomeFragment : Fragment() {
private val viewModel: TestRightViewModel by activityViewModels() private val viewModel: TestRightViewModel by activityViewModels()
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var rvAdapter: UserListAdapter private lateinit var rvAdapter: UserListAdapter
private var batLevel: Int = private var batLevel: Int = 0 // Initialize with a default value, or obtain the actual battery level
0 // Initialize with a default value, or obtain the actual battery level
private lateinit var adapter: OfflineUserListAdapter private lateinit var adapter: OfflineUserListAdapter
private val homeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
@@ -105,7 +103,7 @@ class HomeFragment : Fragment() {
binding.rvOrderOffline.adapter = adapter binding.rvOrderOffline.adapter = adapter
} }
} }
viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected -> viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) { if (isConnected) {
binding.internetAvailableCL.visibility = View.VISIBLE binding.internetAvailableCL.visibility = View.VISIBLE
@@ -120,6 +118,19 @@ class HomeFragment : Fragment() {
setUserId() setUserId()
} }
} }
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected ->
// if (isConnected) {
// binding.internetAvailableCL.visibility = View.VISIBLE
// binding.internetNotAvailableCL.visibility = View.GONE
// loadUserData()
// setSearch()
// checkForLocalDBData()
// } else {
binding.internetAvailableCL.visibility = View.GONE
binding.internetNotAvailableCL.visibility = View.VISIBLE
setUserId()
// }
}
hemoCubeViewModel.fireBaseBulkUpload.observe(viewLifecycleOwner) { result -> hemoCubeViewModel.fireBaseBulkUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") { if (result == "Success") {
Toast.makeText( Toast.makeText(
@@ -134,9 +145,32 @@ class HomeFragment : Fragment() {
binding.btnLogout.setOnClickListener { binding.btnLogout.setOnClickListener {
logoutUser(requireContext()) logoutUser(requireContext())
} }
binding.uploadData.setOnClickListener { binding.uploadData.setOnClickListener {
showUploadDialog(requireContext()) showUploadDialog(requireContext())
} }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE
binding.btnSaveLocal.visibility = btnSaveLocalVisibility
binding.btnSaveLocal.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()
}
}
}
binding.btnNewKit.setOnClickListener { binding.btnNewKit.setOnClickListener {
with(sharedPreference.edit()) { with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "") putString(Constants.KIT_NUMBER, "")
@@ -568,4 +602,82 @@ class HomeFragment : Fragment() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
} }
private fun downloadCsv() {
context?.let { context ->
val success = homeViewModel.getLocalUserDataForCsv(context)
if (success) {
// Provide feedback to the user if needed
Toast.makeText(context, "CSV file downloaded successfully", Toast.LENGTH_SHORT).show()
} else {
// Handle the case where CSV file generation failed
Toast.makeText(context, "Failed to download CSV file", Toast.LENGTH_SHORT).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 downloadLocalDBData(dialog: DialogInterface) {
var csvDownloaded = false
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
try {
if (!csvDownloaded) {
val downloadList = mutableListOf<HemoCubeTestData>()
userDataList.forEach { userData ->
if(userData.testStatus == true) {
// 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())
csvDownloaded = true
Toast.makeText(
requireContext(),
"CSV file downloaded successfully",
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
requireContext(),
"No data to download",
Toast.LENGTH_SHORT
)
.show()
}
}
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(requireContext(), "Error downloading CSV file", Toast.LENGTH_SHORT).show()
} finally {
dialog.dismiss()
}
}
}
} }

View File

@@ -1,13 +0,0 @@
package com.example.hpostesting.presentation.dashboard.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class HomeViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is home Fragment"
}
val text: LiveData<String> = _text
}

View File

@@ -43,6 +43,7 @@ class HemoCubeFragment : Fragment() {
private var resultData: String = "" private var resultData: String = ""
private var currentResultData: String = "" private var currentResultData: String = ""
private var isUsingExistingBuffer = false private var isUsingExistingBuffer = false
private var loginId: String = ""
private var isTestOngoing = false private var isTestOngoing = false
private var startListening = MutableLiveData<Boolean>(false) private var startListening = MutableLiveData<Boolean>(false)
private val testingTrace = Firebase.performance.newTrace("testing_trace") private val testingTrace = Firebase.performance.newTrace("testing_trace")
@@ -1026,8 +1027,8 @@ class HemoCubeFragment : Fragment() {
} }
private fun calculateRatio(ratio: Double): Double { private fun calculateRatio(ratio: Double): Double {
val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0 val coefficient1: Double = (Constants.COEFFICIENTS[loginId]?.get(0)?.get(0)) as Double
val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 0.0 val coefficient2: Double = (Constants.COEFFICIENTS[loginId]?.get(1)?.get(0)) as Double
return coefficient1 * ratio + coefficient2 return coefficient1 * ratio + coefficient2
} }
} }

View File

@@ -13,12 +13,14 @@ import androidx.lifecycle.viewModelScope
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import com.example.hpostesting.data.CsvWriter
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.datasource.LocalFileDataSource
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.log.UploadLogsResponse import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
@@ -37,6 +39,7 @@ import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.domain.CheckUpdateWorker import com.example.hpostesting.domain.CheckUpdateWorker
import com.example.hpostesting.domain.LogFileManager import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.data.repository.LocalFileRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@@ -45,6 +48,7 @@ import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.ResponseBody import okhttp3.ResponseBody
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
@@ -56,6 +60,7 @@ class HemoCubeViewModel @Inject constructor(
private val repository: Repository, private val repository: Repository,
private val databaseRepository: DatabaseRepository, private val databaseRepository: DatabaseRepository,
private val logFileManager: LogFileManager, private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource,
context: Context, context: Context,
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
@@ -271,6 +276,10 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio
testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString()
testDetails?.name = DataHolder.hemoCubeTestData?.name.toString()
testDetails?.birthYear = DataHolder.hemoCubeTestData?.birthYear.toString()
testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString()
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString() testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
testDetails?.deviceRatioClass = DataHolder.hemoCubeTestData?.deviceRatioClass.toString() testDetails?.deviceRatioClass = DataHolder.hemoCubeTestData?.deviceRatioClass.toString()
@@ -403,6 +412,59 @@ class HemoCubeViewModel @Inject constructor(
hemoCubeBufferDao.updateFieldById(id = bufferId, true) hemoCubeBufferDao.updateFieldById(id = bufferId, true)
} }
fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
// Observe the LiveData to get the actual data when available
localUserDataLiveData.observeForever { localUserData ->
localUserData?.let {
val csvData = mutableListOf<Array<String>>()
it.forEach { userData ->
csvData.add(
arrayOf(
userData._id,
userData.name,
userData.bloodGroup,
userData.birthYear,
userData.classificationResult,
userData.testTime.toString(),
userData.userImageURL
)
)
}
val csvWriter = CsvWriter(context)
csvWriter.writeCsv("userData.csv", csvData)
// Remove the observer to avoid leaks
localUserDataLiveData.removeObserver {}
}
}
return true // Assuming success, you might want to modify this based on your actual logic
}
private fun getCurrentDate(): String {
val dateFormat = SimpleDateFormat("dd-MM-yy", Locale.getDefault())
val currentDate = Date()
return dateFormat.format(currentDate)
}
fun createCSV(hemoCubeTestData: List<HemoCubeTestData>, appContext: Context) =
viewModelScope.launch {
val fileName = "HPOS${getCurrentDate()}.csv"
if (localFileDataSource.exportDataToCSV(fileName, hemoCubeTestData)) {
hemoCubeTestData.forEach { data ->
data.localFlag = true
hemoCubeDao.updateCSVFieldById(
data._id,
true
)
}
}
}
fun getBatteryLevel(): Float? { fun getBatteryLevel(): Float? {
val batteryPct: Float? = batteryStatus?.let { intent -> val batteryPct: Float? = batteryStatus?.let { intent ->

View File

@@ -135,7 +135,7 @@ class TestRightResults : Fragment() {
} }
} }
} }
viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable -> viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isNetworkAvailable ->
val deviceStaticId = sharedPreference.getString(Constants.USER_ID, "") val deviceStaticId = sharedPreference.getString(Constants.USER_ID, "")
if (isNetworkAvailable) { if (isNetworkAvailable) {
viewModel.uploadResultToDatabase(requireContext(), true, deviceStaticId!!) viewModel.uploadResultToDatabase(requireContext(), true, deviceStaticId!!)

View File

@@ -26,6 +26,7 @@ import com.example.hpostesting.domain.TestRightResultCalculation
import com.example.hpostesting.util.MyUtils import com.example.hpostesting.util.MyUtils
import com.google.firebase.storage.FirebaseStorage import com.google.firebase.storage.FirebaseStorage
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import java.io.File import java.io.File
@@ -43,9 +44,10 @@ class TestRightViewModel @Inject constructor(
private val saveRawDataTest: SaveRawDataTest, private val saveRawDataTest: SaveRawDataTest,
private val repository: DatabaseRepository, private val repository: DatabaseRepository,
private val userDao: UserDao, private val userDao: UserDao,
context: Context context: Context?
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
@@ -54,10 +56,10 @@ class TestRightViewModel @Inject constructor(
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
val testDetails = DataHolder.selectedTest var testDetails = DataHolder.selectedTest
private val _networkStatusLiveData = NetworkStatusLiveData(context) private val _networkStatusLiveData = context?.let { NetworkStatusLiveData(it) }
val networkStatusLiveData: LiveData<Boolean> val networkStatusLiveData: NetworkStatusLiveData?
get() = _networkStatusLiveData get() = _networkStatusLiveData
val allUserData = userDao.getAll() val allUserData = userDao.getAll()
@@ -439,7 +441,7 @@ class TestRightViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(testDetails)) { when (repository.addTestToDatabase(testDetails)) {
is Response.Success -> { is Response.Success<*> -> {
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
} }
@@ -448,43 +450,45 @@ class TestRightViewModel @Inject constructor(
} }
} }
fun uploadResultToDatabase(context: Context, isOnline: Boolean,deviceSerialNumber: String) = viewModelScope.launch { fun uploadResultToDatabase(context: Context, isOnline: Boolean, deviceSerialNumber: String) =
val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName() viewModelScope.launch {
val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName() val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName()
testDetails?.csvPath = csvFilePath val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName()
testDetails?.reportPath = logTxtFilePath testDetails?.csvPath = csvFilePath
testDetails?.deviceSerialNumber = deviceSerialNumber testDetails?.reportPath = logTxtFilePath
if (isOnline) { testDetails?.deviceSerialNumber = deviceSerialNumber
val storageRef = FirebaseStorage.getInstance().reference if (isOnline) {
val storageTestDetailsRef = storageRef.child("${testDetails?._id}/") val storageRef = FirebaseStorage.getInstance().reference
val storageTestDetailsRef = storageRef.child("${testDetails?._id}/")
try { try {
val csvFileUri = Uri.fromFile(File(csvFilePath)) val csvFileUri = Uri.fromFile(File(csvFilePath))
val logTxtFileUri = Uri.fromFile(File(logTxtFilePath)) val logTxtFileUri = Uri.fromFile(File(logTxtFilePath))
val csvUploadTask = val csvUploadTask =
storageTestDetailsRef.child(csvFileUri.lastPathSegment!!).putFile(csvFileUri) storageTestDetailsRef.child(csvFileUri.lastPathSegment!!)
.await() .putFile(csvFileUri)
val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!) .await()
.putFile(logTxtFileUri).await() val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!)
.putFile(logTxtFileUri).await()
val csvUri = csvUploadTask.storage.downloadUrl.await().toString() val csvUri = csvUploadTask.storage.downloadUrl.await().toString()
val logUri = logUploadTask.storage.downloadUrl.await().toString() val logUri = logUploadTask.storage.downloadUrl.await().toString()
val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber } val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber }
testDetails?.csvPath = csvUri testDetails?.csvPath = csvUri
testDetails?.reportPath = logUri testDetails?.reportPath = logUri
addResultTestToDb() addResultTestToDb()
} catch (exception: Exception) { } catch (exception: Exception) {
// Handle the exception appropriately (e.g., log the error, display an error message) // Handle the exception appropriately (e.g., log the error, display an error message)
}
} else {
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
userDao.insertAll(testDetails!!)
} }
} else {
testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
userDao.insertAll(testDetails!!)
} }
}
fun bulkUploadResultToDatabase(userData: UserData) = viewModelScope.launch { fun bulkUploadResultToDatabase(userData: UserData) = viewModelScope.launch {
val storageRef = FirebaseStorage.getInstance().reference val storageRef = FirebaseStorage.getInstance().reference
@@ -519,7 +523,7 @@ class TestRightViewModel @Inject constructor(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) { when (repository.addTestToDatabase(userData)) {
is Response.Success -> { is Response.Success<*> -> {
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
} }

View File

@@ -100,6 +100,17 @@
app:layout_constraintTop_toBottomOf="@+id/btn_submit" app:layout_constraintTop_toBottomOf="@+id/btn_submit"
tools:listitem="@layout/offline_user_list_view" /> tools:listitem="@layout/offline_user_list_view" />
<ImageView
android:id="@+id/btnSaveLocal"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="10dp"
android:src="@drawable/downloads"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/rv_order_offline"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout

View File

@@ -47,7 +47,21 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/userID" app:layout_constraintTop_toBottomOf="@id/userID"
tools:text="UserID: MohamedKaif" /> tools:text="UserID: Mariya" />
<TextView
android:id="@+id/teststatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/title1_1"
android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
android:gravity="start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bloodGroup"
tools:text="Test Status: Completed"/>
<TextView <TextView
android:id="@+id/time" android:id="@+id/time"
@@ -61,9 +75,8 @@
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bloodGroup" app:layout_constraintTop_toBottomOf="@id/teststatus"
tools:text="Test Status: Completed" /> tools:text="startedAt: yyyy-MM-dd HH:mm:ss" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View File

@@ -193,6 +193,10 @@
<string name="upload_db_registration_message">Do you want to upload the local DB tests to the cloud?</string> <string name="upload_db_registration_message">Do you want to upload the local DB tests to the cloud?</string>
<string name="upload">Upload</string> <string name="upload">Upload</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="downloadcsv">Download CSV</string>
<string name="download_db_registration_title">Download DB Tests</string>
<string name="download_db_registration_message">Do you want to download the local DB tests in CSV format?</string>
<string name="upload_success_message">Upload done successfully</string> <string name="upload_success_message">Upload done successfully</string>
<string name="test_completed">Test Completed</string> <string name="test_completed">Test Completed</string>
<string name="select_blood_group">Select Blood Group</string> <string name="select_blood_group">Select Blood Group</string>

View File

@@ -0,0 +1,60 @@
package com.example.hpostesting
import android.content.SharedPreferences
import android.view.View
import com.example.hpostesting.presentation.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
class HemocubeViewModelTest {
@Mock
private lateinit var mockSharedPreferences: SharedPreferences
@Mock
private lateinit var mockActivity: HemocubeActivity // Replace with your actual Activity class
@Mock
private lateinit var mockBinding: FragmentHemoCubeReferenceBinding // Replace with your actual Binding class
private lateinit var hemoCubeFragment: HemoCubeFragment
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
hemoCubeFragment = HemoCubeFragment()
}
@Test
fun `handleValidResult with valid input`() {
// Arrange
val validString = "valid string"
val fullReadOutput = "full read output"
`when`(mockSharedPreferences.getString(anyString(), anyString())).thenReturn("dummy_value")
`when`(mockActivity.runOnUiThread(any())).thenAnswer {
val runnable = it.getArgument(0, Runnable::class.java)
runnable.run()
}
// Act
hemoCubeFragment.handleValidResult(validString, fullReadOutput)
// Assert
// Add appropriate assertions based on the behavior you expect
verify(mockSharedPreferences).edit()
verify(mockBinding).btnSubmit.visibility = View.VISIBLE
verify(mockBinding).btnSubmit.isEnabled = true
// Add more verifications as needed
}
// Add more test cases for different scenarios if needed
}

View File

@@ -1,19 +1,85 @@
package com.example.hpostesting package com.example.hpostesting
import android.content.Context
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.PatientData import com.example.hpostesting.data.dao.UserDao
import com.example.hpostesting.data.model.test.TestRightResultType import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.presentation.testRight.TestRightViewModel import com.example.hpostesting.presentation.testRight.TestRightViewModel
import junit.framework.Assert.assertEquals import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import java.math.RoundingMode import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
class TestRightViewModelTest { class TestRightViewModelTest {
<<<<<<< HEAD
// private val viewModel = TestRightViewModel() // private val viewModel = TestRightViewModel()
// private val data = InputData() // private val data = InputData()
// //
=======
@Mock
lateinit var mockContext: Context
@Mock
lateinit var mockRepository: DatabaseRepository
@Mock
lateinit var mockSaveRawData: SaveRawData
@Mock
lateinit var mockSaveRawDataTest: SaveRawDataTest
@Mock
lateinit var mockUserDao: UserDao
lateinit var viewModel: TestRightViewModel<Any?>
@Before
fun setUp() {
// Initialize mocks
MockitoAnnotations.initMocks(this)
// Create the ViewModel with mock dependencies
viewModel = TestRightViewModel(mockSaveRawData,mockSaveRawDataTest,mockRepository,mockUserDao,mockContext)
}
private val data = InputData()
@Test
fun test_mapDeviceConstants() {
viewModel.mapDeviceConstants(data.inputRead)
assertEquals("0", DataHolder.deviceConstant!!.a)
assertEquals("1.69989422e-06", DataHolder.deviceConstant!!.b)
assertEquals("1.60642711e-01", DataHolder.deviceConstant!!.c)
assertEquals("3.85754470e+02", DataHolder.deviceConstant!!.d)
}
@Test
fun test_mapPixelNumberToWavelength() {
viewModel.mapDeviceConstants(data.inputRead)
viewModel.mapPixelNumberToWavelength()
val outputList = TestDataGenerator().getOutputMapPixelNumberToWavelength()
assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, DataHolder.wavelengthToPixelArray.size)
assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, outputList.size)
val df = DecimalFormat("#.###")
df.roundingMode = RoundingMode.FLOOR
for (i in 0 until Constants.TEST_RIGHT_TOTAL_PIXEL){
assertEquals(df.format(outputList[i]), df.format(DataHolder.wavelengthToPixelArray[i]))
}
}
>>>>>>> origin/Local-storing-data
// @Test // @Test
// fun test_mapDeviceConstants() { // fun test_mapDeviceConstants() {
// viewModel.mapDeviceConstants(data.inputRead) // viewModel.mapDeviceConstants(data.inputRead)
@@ -96,6 +162,52 @@ class TestRightViewModelTest {
// println(each[0].toString() + " -> " + each[1]) // println(each[0].toString() + " -> " + each[1])
// } // }
// } // }
<<<<<<< HEAD
=======
@Test
fun test_mapWavelengthToAbsorbance() {
viewModel.mapDeviceConstants(data.inputRead)
viewModel.mapPixelNumberToWavelength()
viewModel.mapIntensityValues(TestDataGenerator().getInputReferenceMapIntensityValues(), true)
val mapIntensityValues = viewModel.mapIntensityValues(
TestDataGenerator().getInputSampleMapIntensityValues(),
false
)
viewModel.testDetails = UserData("Surya", "2", "Male")
viewModel.mapWavelengthToAbsorbance()
val wavelengthList = TestDataGenerator().getOutputMapPixelNumberToWavelength()
val absorbanceList = TestDataGenerator().getOutputMapWavelengthToAbsorbance()
val df = DecimalFormat("#.###")
df.roundingMode = RoundingMode.FLOOR
assertEquals(Constants.TEST_RIGHT_TOTAL_PIXEL, viewModel.wavelengthToAbsorbance.size)
for (i in 0 until Constants.TEST_RIGHT_TOTAL_PIXEL){
assertEquals(df.format(wavelengthList[i]), df.format(viewModel.wavelengthToAbsorbance[i][0]))
assertEquals(df.format(absorbanceList[i]), df.format(viewModel.wavelengthToAbsorbance[i][1]))
}
}
@Test
fun testRightViewModel_calculateDataForCSV() {
viewModel.mapDeviceConstants(data.inputRead)
viewModel.mapPixelNumberToWavelength()
viewModel.mapIntensityValues(data.printForReference, true)
viewModel.mapIntensityValues(data.printForSample, false)
// viewModel.patientDetails = PatientData("Surya", 2, "Male", null)
// viewModel.calculateResults()
viewModel.mapWavelengthToAbsorbance()
for (each in viewModel.wavelengthToAbsorbance){
println(each[0].toString() + " -> " + each[1])
}
}
>>>>>>> origin/Local-storing-data
} }