diff --git a/app/src/debug/res/drawable/downloads.xml b/app/src/debug/res/drawable/downloads.xml new file mode 100644 index 0000000..37f8230 --- /dev/null +++ b/app/src/debug/res/drawable/downloads.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/CsvWriter.kt b/app/src/main/java/com/example/hpostesting/data/CsvWriter.kt new file mode 100644 index 0000000..c7f3c4e --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/data/CsvWriter.kt @@ -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>): 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 + } +} diff --git a/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt b/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt index 7ebe1d6..189d4ef 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt @@ -26,4 +26,7 @@ interface HemoCubeDao { @Query("UPDATE hemo_cube_test_table SET molbioFlag = :newValue WHERE _id = :id") 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) } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt index b380365..c31736d 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt @@ -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.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) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao diff --git a/app/src/main/java/com/example/hpostesting/data/datasource/LocalFileDataSource.kt b/app/src/main/java/com/example/hpostesting/data/datasource/LocalFileDataSource.kt index 39ccd8c..cdc1f38 100644 --- a/app/src/main/java/com/example/hpostesting/data/datasource/LocalFileDataSource.kt +++ b/app/src/main/java/com/example/hpostesting/data/datasource/LocalFileDataSource.kt @@ -1,8 +1,11 @@ package com.example.hpostesting.data.datasource +import android.os.Environment +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 LocalFileDataSource { @@ -20,4 +23,107 @@ class LocalFileDataSource { writer.close() } + + fun exportDataToCSV( + fileName: String, dataList: List + ): 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 + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt index 52c7a5f..f55caf9 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt @@ -81,4 +81,5 @@ data class HemoCubeTestData( var solution: String? = "", var concentration: String? = "", var volume: String? = "", + var isCSVCreated: Boolean = false ) diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/UserData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/UserData.kt index a434558..1cadeb6 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/patient/UserData.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/patient/UserData.kt @@ -10,6 +10,8 @@ data class UserData( var _id: String = "", var name: String = "", var incubationTime: String = "", + var gender: String = "", + var state: String = "", var birthYear: String = "", var abhaId: String = "", var bloodGroup: String = "", @@ -46,7 +48,11 @@ data class UserData( fun UserData.toHemoCubeTestData() = HemoCubeTestData( _id = _id, name = name, + bloodGroup = bloodGroup, birthYear = birthYear, + gender = gender, + state = state, + abhaId = abhaId, userImageURL = userImageURL, testStatus = testStatus, location = location, diff --git a/app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt b/app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt new file mode 100644 index 0000000..7250b18 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt @@ -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) + } +} diff --git a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt index 710ae5f..40a7074 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt @@ -202,4 +202,8 @@ class DatabaseRepository @Inject constructor( // Find the DeviceData object with the specified deviceId return allDeviceDataList.find { it.deviceId == deviceId } } + + override fun addTestToDatabase(testDetails: UserData): Any { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/repository/LocalFileRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/LocalFileRepository.kt index 6290bf0..2a8553f 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/LocalFileRepository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/LocalFileRepository.kt @@ -1,6 +1,12 @@ package com.example.hpostesting.data.repository +import android.os.Environment 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) { fun saveCsvToDisk(filepath: String, contents: ArrayList>) = @@ -8,4 +14,7 @@ class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) fun saveTextToDisk(filepath: String, contents: String) = localFileDataSource.saveTextToDisk(filepath, contents) + + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt index f809295..3c60abf 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt @@ -19,4 +19,6 @@ interface Repository { suspend fun uploadFileToStorage(patientID: String, filePath: String): Response suspend fun getDeviceDataById(deviceId: String): DeviceData? + abstract fun addTestToDatabase(testDetails: UserData): Any +// suspend fun addToDatabase(data: PatientDetails) } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt index bb0b369..ca277e2 100644 --- a/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt +++ b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt @@ -170,4 +170,10 @@ object AppModule { @Provides @Singleton fun provideLogFileManager(context: Context): LogFileManager = LogFileManager(context) + + @Provides + @Singleton + fun provideLocalFileDataSource(): LocalFileDataSource { + return LocalFileDataSource() + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt index f1481a5..4031909 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt @@ -1,6 +1,8 @@ package com.example.hpostesting.presentation.adapter import android.content.Context +import android.annotation.SuppressLint +import android.content.res.Resources import android.view.LayoutInflater import android.view.View import android.view.ViewGroup diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt index 6591f33..331bd23 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt @@ -22,11 +22,11 @@ import androidx.navigation.ui.setupWithNavController import com.example.hpostesting.data.Result import com.example.hpostesting.data.constant.LanguageManager 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.progressindicator.LinearProgressIndicator import com.google.android.play.core.appupdate.AppUpdateManager 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.FirebaseAppDistributionException @@ -205,6 +205,8 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { } + + override fun onResume() { super.onResume() diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index a2fd65e..0210a51 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -53,11 +53,9 @@ class HomeFragment : Fragment() { private val viewModel: TestRightViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private lateinit var rvAdapter: UserListAdapter - private var batLevel: Int = - 0 // Initialize with a default value, or obtain the actual battery level + private var batLevel: Int = 0 // Initialize with a default value, or obtain the actual battery level private lateinit var adapter: OfflineUserListAdapter - - + private val homeViewModel: HemoCubeViewModel by activityViewModels() private lateinit var sharedPreference: SharedPreferences override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -105,7 +103,7 @@ class HomeFragment : Fragment() { binding.rvOrderOffline.adapter = adapter } } - viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected -> + viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected -> if (isConnected) { binding.internetAvailableCL.visibility = View.VISIBLE @@ -120,6 +118,19 @@ class HomeFragment : Fragment() { 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 -> if (result == "Success") { Toast.makeText( @@ -134,9 +145,32 @@ class HomeFragment : Fragment() { binding.btnLogout.setOnClickListener { logoutUser(requireContext()) } + + binding.uploadData.setOnClickListener { 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 { with(sharedPreference.edit()) { putString(Constants.KIT_NUMBER, "") @@ -568,4 +602,82 @@ class HomeFragment : Fragment() { super.onDestroyView() _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() + + 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() + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/home/HomeViewModel.kt deleted file mode 100644 index 4b02588..0000000 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/home/HomeViewModel.kt +++ /dev/null @@ -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().apply { - value = "This is home Fragment" - } - val text: LiveData = _text -} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 0769fb2..53a442f 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -43,6 +43,7 @@ class HemoCubeFragment : Fragment() { private var resultData: String = "" private var currentResultData: String = "" private var isUsingExistingBuffer = false + private var loginId: String = "" private var isTestOngoing = false private var startListening = MutableLiveData(false) private val testingTrace = Firebase.performance.newTrace("testing_trace") @@ -1026,8 +1027,8 @@ class HemoCubeFragment : Fragment() { } private fun calculateRatio(ratio: Double): Double { - val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0 - val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 0.0 + val coefficient1: Double = (Constants.COEFFICIENTS[loginId]?.get(0)?.get(0)) as Double + val coefficient2: Double = (Constants.COEFFICIENTS[loginId]?.get(1)?.get(0)) as Double return coefficient1 * ratio + coefficient2 } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index 2e89400..e674147 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -13,12 +13,14 @@ import androidx.lifecycle.viewModelScope import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager +import com.example.hpostesting.data.CsvWriter import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.Result import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.dao.HemoCubeBufferDao import com.example.hpostesting.data.dao.HemoCubeDao +import com.example.hpostesting.data.datasource.LocalFileDataSource import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.log.UploadLogsResponse 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.domain.CheckUpdateWorker import com.example.hpostesting.domain.LogFileManager +import com.example.hpostesting.data.repository.LocalFileRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -45,6 +48,7 @@ import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.ResponseBody import java.text.SimpleDateFormat import java.util.Calendar +import java.util.Date import java.util.Locale import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -56,6 +60,7 @@ class HemoCubeViewModel @Inject constructor( private val repository: Repository, private val databaseRepository: DatabaseRepository, private val logFileManager: LogFileManager, + private val localFileDataSource: LocalFileDataSource, context: Context, ) : ViewModel() { var isServiceConnected = false @@ -271,6 +276,10 @@ class HemoCubeViewModel @Inject constructor( testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio 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?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString() testDetails?.deviceRatioClass = DataHolder.hemoCubeTestData?.deviceRatioClass.toString() @@ -403,6 +412,59 @@ class HemoCubeViewModel @Inject constructor( hemoCubeBufferDao.updateFieldById(id = bufferId, true) } + + fun getLocalUserDataForCsv(context: Context): Boolean { + val localUserDataLiveData: LiveData> = hemoCubeDao.getAll() + + // Observe the LiveData to get the actual data when available + localUserDataLiveData.observeForever { localUserData -> + localUserData?.let { + val csvData = mutableListOf>() + + 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, 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? { val batteryPct: Float? = batteryStatus?.let { intent -> diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt index fdb8e9a..c841e16 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightResults.kt @@ -135,7 +135,7 @@ class TestRightResults : Fragment() { } } } - viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable -> + viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isNetworkAvailable -> val deviceStaticId = sharedPreference.getString(Constants.USER_ID, "") if (isNetworkAvailable) { viewModel.uploadResultToDatabase(requireContext(), true, deviceStaticId!!) diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt index baf2b05..19af4da 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt @@ -26,6 +26,7 @@ import com.example.hpostesting.domain.TestRightResultCalculation import com.example.hpostesting.util.MyUtils import com.google.firebase.storage.FirebaseStorage import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.scopes.ViewModelScoped import kotlinx.coroutines.launch import kotlinx.coroutines.tasks.await import java.io.File @@ -43,9 +44,10 @@ class TestRightViewModel @Inject constructor( private val saveRawDataTest: SaveRawDataTest, private val repository: DatabaseRepository, private val userDao: UserDao, - context: Context + context: Context? ) : ViewModel() { + var isServiceConnected = false val progressBar = MutableLiveData(false) @@ -54,10 +56,10 @@ class TestRightViewModel @Inject constructor( val fireBaseUpload = MutableLiveData() - val testDetails = DataHolder.selectedTest + var testDetails = DataHolder.selectedTest - private val _networkStatusLiveData = NetworkStatusLiveData(context) - val networkStatusLiveData: LiveData + private val _networkStatusLiveData = context?.let { NetworkStatusLiveData(it) } + val networkStatusLiveData: NetworkStatusLiveData? get() = _networkStatusLiveData val allUserData = userDao.getAll() @@ -439,7 +441,7 @@ class TestRightViewModel @Inject constructor( "yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).format(Calendar.getInstance().time) when (repository.addTestToDatabase(testDetails)) { - is Response.Success -> { + is Response.Success<*> -> { fireBaseUpload.postValue("Success") } @@ -448,43 +450,45 @@ class TestRightViewModel @Inject constructor( } } - fun uploadResultToDatabase(context: Context, isOnline: Boolean,deviceSerialNumber: String) = viewModelScope.launch { - val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName() - val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName() - testDetails?.csvPath = csvFilePath - testDetails?.reportPath = logTxtFilePath - testDetails?.deviceSerialNumber = deviceSerialNumber - if (isOnline) { - val storageRef = FirebaseStorage.getInstance().reference - val storageTestDetailsRef = storageRef.child("${testDetails?._id}/") + fun uploadResultToDatabase(context: Context, isOnline: Boolean, deviceSerialNumber: String) = + viewModelScope.launch { + val csvFilePath = MyUtils.getAppFolderPath(context) + getCSVFileName() + val logTxtFilePath = MyUtils.getAppFolderPath(context) + getLogFileName() + testDetails?.csvPath = csvFilePath + testDetails?.reportPath = logTxtFilePath + testDetails?.deviceSerialNumber = deviceSerialNumber + if (isOnline) { + val storageRef = FirebaseStorage.getInstance().reference + val storageTestDetailsRef = storageRef.child("${testDetails?._id}/") - try { - val csvFileUri = Uri.fromFile(File(csvFilePath)) - val logTxtFileUri = Uri.fromFile(File(logTxtFilePath)) + try { + val csvFileUri = Uri.fromFile(File(csvFilePath)) + val logTxtFileUri = Uri.fromFile(File(logTxtFilePath)) - val csvUploadTask = - storageTestDetailsRef.child(csvFileUri.lastPathSegment!!).putFile(csvFileUri) - .await() - val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!) - .putFile(logTxtFileUri).await() + val csvUploadTask = + storageTestDetailsRef.child(csvFileUri.lastPathSegment!!) + .putFile(csvFileUri) + .await() + val logUploadTask = storageTestDetailsRef.child(logTxtFileUri.lastPathSegment!!) + .putFile(logTxtFileUri).await() - val csvUri = csvUploadTask.storage.downloadUrl.await().toString() - val logUri = logUploadTask.storage.downloadUrl.await().toString() - val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber } - testDetails?.csvPath = csvUri - testDetails?.reportPath = logUri + val csvUri = csvUploadTask.storage.downloadUrl.await().toString() + val logUri = logUploadTask.storage.downloadUrl.await().toString() + val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber } + testDetails?.csvPath = csvUri + testDetails?.reportPath = logUri - addResultTestToDb() - } catch (exception: Exception) { - // Handle the exception appropriately (e.g., log the error, display an error message) + addResultTestToDb() + } catch (exception: Exception) { + // 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 { val storageRef = FirebaseStorage.getInstance().reference @@ -519,7 +523,7 @@ class TestRightViewModel @Inject constructor( "yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).format(Calendar.getInstance().time) when (repository.addTestToDatabase(userData)) { - is Response.Success -> { + is Response.Success<*> -> { fireBaseUpload.postValue("Success") } diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 34910da..21e268f 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -100,6 +100,17 @@ app:layout_constraintTop_toBottomOf="@+id/btn_submit" tools:listitem="@layout/offline_user_list_view" /> + + + + tools:text="UserID: Mariya" /> + - + app:layout_constraintTop_toBottomOf="@id/teststatus" + tools:text="startedAt: yyyy-MM-dd HH:mm:ss" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d8672c6..9e5ded7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -193,6 +193,10 @@ Do you want to upload the local DB tests to the cloud? Upload Cancel + + Download CSV + Download DB Tests + Do you want to download the local DB tests in CSV format? Upload done successfully Test Completed Select Blood Group diff --git a/app/src/test/java/com/example/hpostesting/HemocubeViewModelTest.kt b/app/src/test/java/com/example/hpostesting/HemocubeViewModelTest.kt new file mode 100644 index 0000000..1a3d2e2 --- /dev/null +++ b/app/src/test/java/com/example/hpostesting/HemocubeViewModelTest.kt @@ -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 +} \ No newline at end of file diff --git a/app/src/test/java/com/example/hpostesting/TestRightViewModelTest.kt b/app/src/test/java/com/example/hpostesting/TestRightViewModelTest.kt index 2be9212..5a95677 100644 --- a/app/src/test/java/com/example/hpostesting/TestRightViewModelTest.kt +++ b/app/src/test/java/com/example/hpostesting/TestRightViewModelTest.kt @@ -1,19 +1,85 @@ package com.example.hpostesting +import android.content.Context import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants -import com.example.hpostesting.data.model.PatientData -import com.example.hpostesting.data.model.test.TestRightResultType +import com.example.hpostesting.data.dao.UserDao +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 junit.framework.Assert.assertEquals +import org.junit.Before import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations import java.math.RoundingMode import java.text.DecimalFormat class TestRightViewModelTest { +<<<<<<< HEAD // private val viewModel = TestRightViewModel() // 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 + + @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 // fun test_mapDeviceConstants() { // viewModel.mapDeviceConstants(data.inputRead) @@ -96,6 +162,52 @@ class TestRightViewModelTest { // 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 } \ No newline at end of file