From a068ae492c48ceb099662ce9c45278e5f069275f Mon Sep 17 00:00:00 2001 From: Mariya Date: Mon, 6 Nov 2023 12:36:50 +0530 Subject: [PATCH 01/22] unitest is pending --- app/build.gradle | 7 +- .../data/model/test/ViewModelModule.kt | 29 +++++++ .../data/repository/DatabaseRepository.kt | 4 + .../hpostesting/data/repository/Repository.kt | 1 + .../presentation/dashboard/HomeFragment.kt | 2 +- .../presentation/hemocube/HemoCubeFragment.kt | 2 +- .../testRight/TestRightActivity.kt | 2 +- .../testRight/TestRightExpReference.kt | 2 +- .../testRight/TestRightExpSample.kt | 2 +- .../testRight/TestRightResults.kt | 2 +- .../testRight/TestRightViewModel.kt | 80 ++++++++++--------- .../hpostesting/HemocubeViewModelTest.kt | 60 ++++++++++++++ .../hpostesting/TestRightViewModelTest.kt | 45 +++++++++-- build.gradle | 4 +- 14 files changed, 188 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt create mode 100644 app/src/test/java/com/example/hpostesting/HemocubeViewModelTest.kt diff --git a/app/build.gradle b/app/build.gradle index 55ec74c..9195a22 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -71,15 +71,16 @@ dependencies { implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' implementation 'com.google.android.things:androidthings:1.0' - implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta10' - implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta10") + implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11' + implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta11") // Testing testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - + testImplementation 'org.mockito:mockito-core:3.12.0' + testImplementation "androidx.arch.core:core-testing:2.2.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" implementation 'com.opencsv:opencsv:4.6' 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 a7a2d8f..8bb712d 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 @@ -138,4 +138,8 @@ class DatabaseRepository : Repository { // 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/Repository.kt b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt index 3419ceb..7a4cc10 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 @@ -1,5 +1,6 @@ package com.example.hpostesting.data.repository interface Repository { + 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/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 1a6995f..33beb7d 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 @@ -40,7 +40,7 @@ import java.util.Locale class HomeFragment : Fragment() { private var _binding: FragmentHomeBinding? = null private val binding get() = _binding!! - private val viewModel: TestRightViewModel by activityViewModels() + 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 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 ee592d9..75769de 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 @@ -309,7 +309,7 @@ class HemoCubeFragment : Fragment() { } } - private fun handleValidResult(validString: String, fullReadOutput: String) { + fun handleValidResult(validString: String, fullReadOutput: String) { try { val result = validString.split(" ") val deviceLog = resultData diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt index 2a75ac8..9ff7cea 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt @@ -32,7 +32,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityTestRightBinding class TestRightActivity : AppCompatActivity() { private lateinit var binding: ActivityTestRightBinding - private val viewModel by viewModels() + private val viewModel by viewModels>() private var myMenu: Menu? = null private lateinit var mDriver: UsbSerialDriver diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt index a9d0536..92bbe6b 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt @@ -25,7 +25,7 @@ import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpReferenceB @AndroidEntryPoint class TestRightExpReference : Fragment() { private lateinit var binding: FragmentTestRightExpReferenceBinding - private val viewModel: TestRightViewModel by activityViewModels() + private val viewModel: TestRightViewModel by activityViewModels() private val TAG = "TestRightExpReference" override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt index 33f79ce..369fb33 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt @@ -27,7 +27,7 @@ import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpSampleBind class TestRightExpSample : Fragment() { private lateinit var binding: FragmentTestRightExpSampleBinding - private val viewModel: TestRightViewModel by activityViewModels() + private val viewModel: TestRightViewModel by activityViewModels() private val TAG = "TestRightExpSample" 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 a225428..9bb27e8 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 @@ -32,7 +32,7 @@ import kotlinx.coroutines.withContext class TestRightResults : Fragment() { private lateinit var binding: FragmentTestRightResultsBinding - private val viewModel: TestRightViewModel by activityViewModels() + private val viewModel: TestRightViewModel by activityViewModels() private lateinit var sharedPreference: SharedPreferences override fun onCreateView( 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 636f8b3..b6b5266 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 @@ -2,7 +2,6 @@ package com.example.hpostesting.presentation.testRight import android.content.Context import android.net.Uri -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -27,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 @@ -39,14 +39,16 @@ import kotlin.math.log10 import kotlin.math.pow @HiltViewModel +@ViewModelScoped class TestRightViewModel @Inject constructor( private val saveRawData: SaveRawData, private val saveRawDataTest: SaveRawDataTest, private val repository: DatabaseRepository, private val userDao: UserDao, - context: Context + context: Context? ) : ViewModel() { + var isServiceConnected = false val progressBar = MutableLiveData(false) @@ -55,10 +57,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() @@ -440,7 +442,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") } @@ -449,43 +451,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 @@ -520,7 +524,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/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 72ec827..e99c834 100644 --- a/app/src/test/java/com/example/hpostesting/TestRightViewModelTest.kt +++ b/app/src/test/java/com/example/hpostesting/TestRightViewModelTest.kt @@ -1,17 +1,49 @@ 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 { - private val viewModel = TestRightViewModel() + + @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 @@ -63,8 +95,11 @@ class TestRightViewModelTest { viewModel.mapDeviceConstants(data.inputRead) viewModel.mapPixelNumberToWavelength() viewModel.mapIntensityValues(TestDataGenerator().getInputReferenceMapIntensityValues(), true) - viewModel.mapIntensityValues(TestDataGenerator().getInputSampleMapIntensityValues(), false) - viewModel.patientDetails = PatientData("Surya", 2, "Male", TestRightResultType.UNDEFINED) + val mapIntensityValues = viewModel.mapIntensityValues( + TestDataGenerator().getInputSampleMapIntensityValues(), + false + ) + viewModel.testDetails = UserData("Surya", "2", "Male") viewModel.mapWavelengthToAbsorbance() val wavelengthList = TestDataGenerator().getOutputMapPixelNumberToWavelength() diff --git a/build.gradle b/build.gradle index a4b7f88..1bd6789 100644 --- a/build.gradle +++ b/build.gradle @@ -4,8 +4,8 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:8.0.2' - classpath 'com.google.gms:google-services:4.3.15' - classpath 'com.google.firebase:firebase-appdistribution-gradle:4.0.0' + classpath 'com.google.gms:google-services:4.4.0' + classpath 'com.google.firebase:firebase-appdistribution-gradle:4.0.1' } repositories { mavenCentral() From 825a5730609f4c6cb667d9be649283bfd669ada1 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 1 Dec 2023 12:19:02 +0530 Subject: [PATCH 02/22] Error resolved --- .../hpostesting/presentation/dashboard/HomeFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 33beb7d..19baf33 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 @@ -40,7 +40,7 @@ import java.util.Locale class HomeFragment : Fragment() { private var _binding: FragmentHomeBinding? = null private val binding get() = _binding!! - private val viewModel: TestRightViewModel by activityViewModels() + 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 @@ -74,7 +74,7 @@ class HomeFragment : Fragment() { hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> deleteHemoCubeIncompleteRegistrations(userData) } - viewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected -> + viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected -> if (isConnected) { binding.internetAvailableCL.visibility = View.VISIBLE binding.internetNotAvailableCL.visibility = View.GONE From f39bce5786927c40df828c2d9531e678ccf56eac Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:11:21 +0530 Subject: [PATCH 03/22] TestRight related issues fixed --- .../hpostesting/presentation/testRight/TestRightActivity.kt | 2 +- .../presentation/testRight/TestRightExpReference.kt | 2 +- .../hpostesting/presentation/testRight/TestRightExpSample.kt | 2 +- .../hpostesting/presentation/testRight/TestRightResults.kt | 4 ++-- .../hpostesting/presentation/testRight/TestRightViewModel.kt | 1 - 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt index 9ff7cea..2a75ac8 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightActivity.kt @@ -32,7 +32,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityTestRightBinding class TestRightActivity : AppCompatActivity() { private lateinit var binding: ActivityTestRightBinding - private val viewModel by viewModels>() + private val viewModel by viewModels() private var myMenu: Menu? = null private lateinit var mDriver: UsbSerialDriver diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt index 92bbe6b..a9d0536 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpReference.kt @@ -25,7 +25,7 @@ import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpReferenceB @AndroidEntryPoint class TestRightExpReference : Fragment() { private lateinit var binding: FragmentTestRightExpReferenceBinding - private val viewModel: TestRightViewModel by activityViewModels() + private val viewModel: TestRightViewModel by activityViewModels() private val TAG = "TestRightExpReference" override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt index 369fb33..33f79ce 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightExpSample.kt @@ -27,7 +27,7 @@ import `in`.sminnovations.hpostesting.databinding.FragmentTestRightExpSampleBind class TestRightExpSample : Fragment() { private lateinit var binding: FragmentTestRightExpSampleBinding - private val viewModel: TestRightViewModel by activityViewModels() + private val viewModel: TestRightViewModel by activityViewModels() private val TAG = "TestRightExpSample" 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 9bb27e8..ea0b909 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 @@ -32,7 +32,7 @@ import kotlinx.coroutines.withContext class TestRightResults : Fragment() { private lateinit var binding: FragmentTestRightResultsBinding - private val viewModel: TestRightViewModel by activityViewModels() + private val viewModel: TestRightViewModel by activityViewModels() private lateinit var sharedPreference: SharedPreferences override fun onCreateView( @@ -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 b6b5266..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 @@ -39,7 +39,6 @@ import kotlin.math.log10 import kotlin.math.pow @HiltViewModel -@ViewModelScoped class TestRightViewModel @Inject constructor( private val saveRawData: SaveRawData, private val saveRawDataTest: SaveRawDataTest, From 1a7e618fa563e2c7be27426351df4e35e8e6547b Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:25:23 +0530 Subject: [PATCH 04/22] offline adapter added --- .../adapter/OfflineUserListAdapter.kt | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt 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 new file mode 100644 index 0000000..afa492b --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt @@ -0,0 +1,147 @@ +package com.example.hpostesting.presentation.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.Resources +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.navigation.findNavController +import androidx.recyclerview.widget.AsyncListDiffer +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.model.patient.HemoCubeTestData +import com.example.hpostesting.data.model.patient.UserData +import `in`.sminnovations.hpostesting.R +import `in`.sminnovations.hpostesting.databinding.OfflineUserListViewBinding +import org.apache.commons.collections4.MapUtils.getString +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + + +class OfflineUserListAdapter(private val view: View, private val batLevel: Int) : + RecyclerView.Adapter() { + + inner class OfflineUserListViewHolder(val binding: OfflineUserListViewBinding) : + RecyclerView.ViewHolder(binding.root) { + + } + + private val differCallback = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: HemoCubeTestData, newItem: HemoCubeTestData + ): Boolean { + return oldItem._id == newItem._id + } + + override fun areContentsTheSame( + oldItem: HemoCubeTestData, newItem: HemoCubeTestData + ): Boolean { + return oldItem == newItem + } + } + + val differ = AsyncListDiffer(this, differCallback) + private val context: Context? = null + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OfflineUserListViewHolder { + return OfflineUserListViewHolder( + OfflineUserListViewBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + } + + override fun getItemCount(): Int { + return differ.currentList.size + } + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) { + val userList = differ.currentList[position] + holder.binding.apply { + userID.text = "User ID: ${userList._id}" + bloodGroup.text = "Blood group: ${userList.bloodGroup}" + time.text = "Time: ${isBetween15And30Minutes(userList.incubationTime)} \n Started at: ${ + SimpleDateFormat("HH:mm:ss").format( + SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).parse(userList.incubationTime)!! + ) + }" + + if (userList.testStatus!!) { + teststatus.text = view.context.getString(R.string.test_concluded) + + } else { + teststatus.text = view.context.getString(R.string.test_pending) + } + + userCard.setOnClickListener { + if (batLevel < 40) { + showWarningToast(R.string.low_battery_warning) + } else { + if (userList.testStatus != null) { + if (userList.testStatus!!) { + showWarningToast(R.string.test_already_conducted) + } else { + if (userList.incubationTime != "") { + val incubationTimeDiff = isBetween15And30Minutes(userList.incubationTime) + if (incubationTimeDiff < 15) { + showWarningToast(R.string.incubation_not_completed) + } else if (incubationTimeDiff > 30) { + showWarningToast(R.string.incubation_crossed_30_minutes) + } else { + DataHolder.selectedTest = UserData( + _id = userList._id, + bloodGroup = userList.bloodGroup, + incubationTime = userList.incubationTime + ) + view.findNavController() + .navigate(R.id.action_nav_home_to_mainActivity) + } + } else { + showWarningToast(R.string.incubation_not_started) + } + } + } + } + } + + } + } + + private fun isBetween15And30Minutes(createdAt: String): Long { + val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) + val createdAtDate: Date = formatter.parse(createdAt)!! + + val currentTime = Calendar.getInstance().time + + val diffMillis = currentTime.time - createdAtDate.time + + return diffMillis / (60 * 1000) + } + + + private fun showWarningToast(resId: Int) { + val contextToUse = view.context ?: return + + val message = try { + contextToUse.getString(resId) + } catch (e: Resources.NotFoundException) { + "Resource not found for ID: $resId" + } + + Toast.makeText( + contextToUse, + message, + Toast.LENGTH_SHORT + ).show() + } + + + + +} \ No newline at end of file From 08fa6b84eb5fb78e69ec97d6bafaf05ab0ed4b52 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:29:22 +0530 Subject: [PATCH 05/22] offline adapter added --- .../main/res/layout/offline_userlist_view.xml | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 app/src/main/res/layout/offline_userlist_view.xml diff --git a/app/src/main/res/layout/offline_userlist_view.xml b/app/src/main/res/layout/offline_userlist_view.xml new file mode 100644 index 0000000..9d60f04 --- /dev/null +++ b/app/src/main/res/layout/offline_userlist_view.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file From 58d3281b1846491016f668a78a0a9d9b745b1912 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:33:22 +0530 Subject: [PATCH 06/22] offline adapter added --- .../hpostesting/data/model/patient/HemoCubeTestData.kt | 2 ++ .../hpostesting/presentation/hemocube/HemoCubeViewModel.kt | 4 ++++ .../{offline_userlist_view.xml => offline_user_list_view.xml} | 0 3 files changed, 6 insertions(+) rename app/src/main/res/layout/{offline_userlist_view.xml => offline_user_list_view.xml} (100%) 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 5599862..8bbf84b 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 @@ -9,6 +9,8 @@ data class HemoCubeTestData( var _id: String = "", var name: String = "", var birthYear: String = "", + var bloodGroup: String = "", + var incubationTime: String = "", var userImageURL: String = "", var location: UserData.Location? = null, var reportUploadTime: String? = "", 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 73d05fc..7fc86b6 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 @@ -183,6 +183,10 @@ class HemoCubeViewModel @Inject constructor( hemoCubeDao.updateFieldById(id = userId, true) } + fun addUser(userData: HemoCubeTestData) = viewModelScope.launch { + hemoCubeDao.insertAll(userData) + } + fun deleteById(userId: String) = viewModelScope.launch { hemoCubeDao.deleteById(id = userId) } diff --git a/app/src/main/res/layout/offline_userlist_view.xml b/app/src/main/res/layout/offline_user_list_view.xml similarity index 100% rename from app/src/main/res/layout/offline_userlist_view.xml rename to app/src/main/res/layout/offline_user_list_view.xml From c5993e3e876916a3be393bc97918ce4091b3119a Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:42:23 +0530 Subject: [PATCH 07/22] offline adapter added --- .../hpostesting/data/constant/Constants.kt | 7 ++ .../data/model/patient/UserData.kt | 2 + .../presentation/dashboard/HomeFragment.kt | 93 +++++++++++++------ .../presentation/hemocube/HemoCubeFragment.kt | 28 +++++- app/src/main/res/values/strings.xml | 25 +++-- 5 files changed, 115 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt index b79ea1a..e677416 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt @@ -70,4 +70,11 @@ object Constants { const val BUFFER_VALUE_1 = "BufferValue1" const val BUFFER_VALUE_2 = "BufferValue2" const val DEVICE_ID = "DEVICE_ID" + + val COEFFICIENTS: Map>> = mapOf( + "HC-V1-001" to listOf( + listOf(1.5,0.0), + listOf(0.0,0.0) + ) + ) } \ No newline at end of file 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 1b6c95d..ee6f2ad 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 @@ -11,6 +11,7 @@ data class UserData( var name: String = "", var incubationTime: String = "", var birthYear: String = "", + var bloodGroup: String = "", var userImageURL: String = "", var location: Location? = null, var createdBy: String? = "", @@ -41,6 +42,7 @@ data class UserData( fun UserData.toHemoCubeTestData() = HemoCubeTestData( _id = _id, name = name, + bloodGroup = bloodGroup, birthYear = birthYear, userImageURL = userImageURL, testStatus = testStatus, 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 19baf33..a3ff49b 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 @@ -73,30 +73,43 @@ class HomeFragment : Fragment() { } hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> deleteHemoCubeIncompleteRegistrations(userData) + if (userData.isNotEmpty()) { + val userList = mutableListOf() + userData.forEach { + if (it.testStatus == false) { + userList.add(it) + } + } + val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager + val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + adapter = OfflineUserListAdapter(binding.root, batLevel) + adapter.differ.submitList(userList) + binding.rvOrderOffline.adapter = adapter + } } viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected -> - 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() - } +// 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( requireContext(), - "Test Results Uploaded Successfully", + R.string.test_upload, Toast.LENGTH_SHORT ).show() } if (result == "Error") { - Toast.makeText(requireContext(), "Test Results Upload Failed", Toast.LENGTH_SHORT) + Toast.makeText(requireContext(), R.string.test_upload_failed, Toast.LENGTH_SHORT) .show() } } @@ -120,10 +133,19 @@ class HomeFragment : Fragment() { private fun setUserId() { binding.btnSubmit.setOnClickListener { val userId = binding.userId.text.toString() - if (userId.length >= 18) { - val userData = UserData(_id = userId) - DataHolder.selectedTest = userData - findNavController().navigate(R.id.action_nav_home_to_mainActivity) + val bloodGroup = binding.etBloodGroup.text + + if (userId.length >= 18 && !bloodGroup.equals("Select Blood Group") || !bloodGroup.isNullOrBlank()) { + hemoCubeViewModel.addUser( + HemoCubeTestData( + _id = userId, bloodGroup = bloodGroup.toString(), incubationTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time).toString() + ) + ) +// val userData = UserData(_id = userId) +// DataHolder.selectedTest = userData +// findNavController().navigate(R.id.action_nav_home_to_mainActivity) } else { val errorMessage = getString(R.string.user_id_error_message) Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show() @@ -155,10 +177,12 @@ class HomeFragment : Fragment() { val bm = requireContext().getSystemService(BATTERY_SERVICE) as BatteryManager val batLevel: Int = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) - rvAdapter = view?.let { - UserListAdapter(requireContext(), hemoCubeViewModel, recyclerViewOptions, - it, batLevel, requireActivity()) - }!! + rvAdapter = view?.let { + UserListAdapter( + requireContext(), hemoCubeViewModel, recyclerViewOptions, + it, batLevel, requireActivity() + ) + }!! binding.rvOrder.adapter = rvAdapter rvAdapter.startListening() @@ -176,14 +200,14 @@ class HomeFragment : Fragment() { private fun logoutUser(context: Context) { val builder = AlertDialog.Builder(context) - builder.setTitle("Log Out") - builder.setMessage("Do you want to LogOut the Application?") - builder.setPositiveButton("Yes") { dialog, _ -> + builder.setTitle(R.string.log_out) + builder.setMessage(R.string.do_log_out) + builder.setPositiveButton(R.string.yes) { dialog, _ -> saveUserId("") findNavController().navigate(R.id.action_nav_home_to_loginFragment) dialog.dismiss() } - builder.setNegativeButton("No") { dialog, _ -> + builder.setNegativeButton(R.string.no) { dialog, _ -> dialog.dismiss() } @@ -206,8 +230,9 @@ class HomeFragment : Fragment() { val partition = dateFormat.format(currentDate) val searchTerm = partition + search val searchField = field + "Search" - val query = Firebase.firestore.collection("patientData").orderBy(searchField).startAt(searchTerm) - .endAt(searchTerm + "\uf8ff") + val query = + Firebase.firestore.collection("patientData").orderBy(searchField).startAt(searchTerm) + .endAt(searchTerm + "\uf8ff") query.get().addOnSuccessListener { userSearchTrace.stop() } @@ -218,7 +243,14 @@ class HomeFragment : Fragment() { batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) rvAdapter = view?.let { - UserListAdapter(requireContext(), hemoCubeViewModel, recyclerViewOptions, it, batLevel, requireActivity()) + UserListAdapter( + requireContext(), + hemoCubeViewModel, + recyclerViewOptions, + it, + batLevel, + requireActivity() + ) }!! binding.rvOrder.adapter = rvAdapter rvAdapter.startListening() @@ -272,7 +304,8 @@ class HomeFragment : Fragment() { } hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> - val uploadDataVisibility = if (userDataList.any { !it.localFlag }) View.VISIBLE else View.GONE + val uploadDataVisibility = + if (userDataList.any { !it.localFlag && it.testStatus == true}) View.VISIBLE else View.GONE binding.uploadData.visibility = uploadDataVisibility } } @@ -331,7 +364,7 @@ class HomeFragment : Fragment() { private fun deleteHemoCubeIncompleteRegistrations(userDataList: List) { userDataList.forEach { userData -> - if (userData.testTime?.isEmpty() == true) { + if (userData._id.isEmpty()) { hemoCubeViewModel.deleteById(userData._id) } } 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 75769de..ce29492 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 @@ -39,6 +39,7 @@ class HemoCubeFragment : Fragment() { private var currentDeviceData: DeviceData? = null private var resultData: String = "" private var isUsingExistingBuffer = false + private var loginId: String = "" private var isTestOngoing = false private var startListening = MutableLiveData(false) val testingTrace = Firebase.performance.newTrace("testing_trace") @@ -98,7 +99,8 @@ class HemoCubeFragment : Fragment() { (activity as HemocubeActivity).finish() } if (result == "Local") { - showToast("Internet not available, test details stored locally") + showToast("test details stored locally") +// showToast("Internet not available, test details stored locally") startActivity(Intent(requireActivity(), DashboardActivity::class.java)) } if (result == "Error") { @@ -345,6 +347,10 @@ class HemoCubeFragment : Fragment() { val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0) val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0) val deviceRatio = led1Average / led2Average + val coefficientsList = Constants.COEFFICIENTS[loginId] + val coefficient1 = coefficientsList?.get(0)?.get(0) + val coefficient2 = coefficientsList?.get(0)?.get(1) + val coefficientsString = "$coefficient1,$coefficient2" // if (led1BufferForDevice!! > 20000 && led1BufferForDevice < 24000 && led2BufferForDevice!! > 20000 && led2BufferForDevice < 24000) { // if (led1Sample!! < led1BufferForDevice && led1Sample < 24000 && led2Sample!! < led2BufferForDevice && led2Sample < 24000) { // if (deviceRatio < 0.08) { @@ -373,7 +379,8 @@ class HemoCubeFragment : Fragment() { this.led2Average = led2Average this.deviceRatio = deviceRatio this.calculatedRatio = calculateRatio(deviceRatio) - this.coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString() +// this.coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString() + this.coefficients = coefficientsString this.classificationResult = findResult(calculatedRatio) hemoCubeViewModel.messages.postValue(this.classificationResult) this.resultData = deviceLog @@ -475,8 +482,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 } @@ -508,4 +515,17 @@ class HemoCubeFragment : Fragment() { return true return false } + + + + + + + + + + + + + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f75c24f..d88440b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -190,10 +190,23 @@ Upload Cancel Upload done successfully - Test Completed - Select Blood Group - All registered user are tested successfully - Incubate - Check Buffer - + Battery level is low than 40%, please charge the device to continue testing + Test has been already conducted for this user + Incubation has not completed 15 minutes + Incubation crossed 30 minutes, need to repeat the incubation + Incubation not started for this user + Test concluded + Test is Pending + Please enter your blood group + Please enter your blood group + Blood group updated successfully + Failed to update blood group: %1$s + No user data found for the specified ID + Device is Disconnected + No device found + Invalid KIT Number + Internet is Not Available + Internet not available, test details stored locally + Error uploading data, test details stored locally + error while getting existing buffer \ No newline at end of file From 1486848fcc5e630559b71e6b63c310674e7c5d49 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:44:49 +0530 Subject: [PATCH 08/22] offline adapter added --- .../example/hpostesting/presentation/dashboard/HomeFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 a3ff49b..c3a75e5 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 @@ -20,6 +20,7 @@ import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.presentation.KitScanActivity +import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter import com.example.hpostesting.presentation.adapter.UserListAdapter import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.testRight.TestRightViewModel @@ -44,7 +45,7 @@ class HomeFragment : Fragment() { 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 lateinit var adapter: OfflineUserListAdapter private lateinit var sharedPreference: SharedPreferences override fun onCreateView( From 9b2fec81f578b1a0ed32086d113de48767c45229 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:46:11 +0530 Subject: [PATCH 09/22] offline adapter added --- app/src/main/res/layout/fragment_home.xml | 38 +++++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 9aa32ec..87f4636 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -22,7 +22,7 @@ android:id="@+id/internetNotAvailableCL" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="gone" + android:visibility="visible" android:padding="24dp"> + + + + + + app:layout_constraintTop_toBottomOf="@+id/til_blood_group" /> + + @@ -74,7 +106,7 @@ android:id="@+id/internetAvailableCL" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="visible" + android:visibility="gone" android:padding="24dp"> Date: Fri, 8 Dec 2023 23:47:23 +0530 Subject: [PATCH 10/22] offline adapter added --- app/src/main/res/values/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d88440b..4ee8fe7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -209,4 +209,6 @@ Internet not available, test details stored locally Error uploading data, test details stored locally error while getting existing buffer + Select Blood Group + All registered user are tested successfully \ No newline at end of file From 32461f03bbeee7d44a5ccc3130122775da5fab24 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:50:28 +0530 Subject: [PATCH 11/22] OFFLINE FEATURE ADDED --- .../presentation/dashboard/HomeFragment.kt | 1 + app/src/main/res/values/strings.xml | 71 ++++++++++++++++--- 2 files changed, 61 insertions(+), 11 deletions(-) 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 c3a75e5..9b41ee5 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 @@ -34,6 +34,7 @@ import dagger.hilt.android.AndroidEntryPoint import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding import java.text.SimpleDateFormat +import java.util.Calendar import java.util.Date import java.util.Locale diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ee8fe7..ec5b9d3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -67,7 +67,6 @@ Step 1 : Place the cuvette containing blood sample mixed with kit solution. Step 2 : Press the button below to start the device reading values. - Login ID Password Login @@ -80,7 +79,6 @@ Age can\'t be empty Gender can\'t be empty Age should be valid - Year of birth can\'t be empty Invalid Year of Birth Mobile Number can\'t be empty @@ -113,7 +111,7 @@ Sickle Find Submit Device Diagnostics - Start Buffer + Start Start Sample New Kit New Buffer @@ -121,7 +119,7 @@ \*Result to be confirmed with laboratory test \*Result to be confirmed with laboratory test as age of the patient is less than 5 years Positive Borderline - Negative Borderline + Negative Borderline, Repeat Test Is Patient under any medication or treatment? Is Patient undergoing any blood transfusion? Scan Aadhaar\nCard @@ -147,7 +145,6 @@ sminnovations.in Navigation header Settings - Home Show Result Gallery @@ -158,6 +155,8 @@ Is Patient Married? (Yes/No) Category Blood Group + Add Blood Group + Digital Counselling Card Patient Medical Records Patient Address Details District @@ -183,13 +182,18 @@ User List User ID Aadhar ID - Internet not available, please enter the user ID manually - User ID should be 18 digits - Upload DB Registration - Do you want to upload the local DB Registration to the cloud? + Please enter the user ID and blood group manually + User ID should be 18 digits and please select the blood group + Upload DB Tests + Do you want to upload the local DB tests to the cloud? Upload Cancel Upload done successfully + Test Completed + Select Blood Group + All registered user are tested successfully + Incubate + Check Buffer Battery level is low than 40%, please charge the device to continue testing Test has been already conducted for this user Incubation has not completed 15 minutes @@ -209,6 +213,51 @@ Internet not available, test details stored locally Error uploading data, test details stored locally error while getting existing buffer - Select Blood Group - All registered user are tested successfully + Do you want to continue with existing buffer? + Kit result uploaded successfully + Kit result uploading failed, note it down manually + test is going on + test is going on, can\'t go back + error while performing classification + Test Results Uploaded Successfully + Test Results Upload Failed + LOG OUT + Do you want to LogOut the Application? + Cancelled: Unable to scan, Try Again!! + Kit number is updated, Please Select user before starting test + Please Select patient before starting test + Please enable location services + Fine location permission denied + Coarse location permission denied + You must grant permission to access all files to use the app + All permissions are required to use the app. + Device Not Connected. + Please enter a proper Login ID + Please enter a proper password + Wrong Password + Wrong UserID + Invalid Test. Problem with de-oxygenation + Error: Negative Abs. Retake Blank Reading + Error: Invalid Test. Improper buffer reading (high) + Error: Invalid Test. Improper buffer reading (low) + error while processing device data + Inconclusive. Repeat with test with lower volume of blood + Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume + Positive for Sickle Cell. HPLC for Confirmation + Something is wrong with the device, please disconnect and reconnect the device and test the user again + processing result + Data collected, Processing data + Sample Completed + Gathering data + Sample Started + Buffer Completed + Buffer Started + Start + Place Sample + Invalid + Error + Language updated successfully + Select your preferred language + App Language + OK \ No newline at end of file From 1d9cf3096a6f5f2a8008b852c2d349a54b73dea9 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:51:53 +0530 Subject: [PATCH 12/22] OFFLINE FEATURE ADDED --- .../presentation/hemocube/HemoCubeViewModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 7fc86b6..868e255 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 @@ -54,17 +54,17 @@ class HemoCubeViewModel @Inject constructor( testDetails?.testStatus = testStatus try { - if (isOnline) { - parseData() - addResultTestToDb() - } else { +// if (isOnline) { +// parseData() +// addResultTestToDb() +// } else { parseData() testDetails?.testTime = SimpleDateFormat( "yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).format(Calendar.getInstance().time) hemoCubeDao.insertAll(testDetails!!) fireBaseUpload.postValue("Local") - } +// } } catch (e: Exception) { Log.e("Testdb", "Upload failed: ${e.message}") } From 865844af9bbbe15cce3e1eac114d6646bbc5e860 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 8 Dec 2023 23:53:36 +0530 Subject: [PATCH 13/22] OFFLINE FEATURE ADDED- DB VERSION CHANGE --- .../main/java/com/example/hpostesting/data/dao/MyDataBase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ac14230..12a5bc4 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 @@ -11,7 +11,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.google.android.datatransport.runtime.dagger.Provides import javax.inject.Singleton -@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 3, exportSchema = false) +@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 4, exportSchema = false) @TypeConverters(Converters::class) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao From 976f6f07e8699cca3fc5d4ad37d7fd3e5646128c Mon Sep 17 00:00:00 2001 From: Mariya Date: Sat, 9 Dec 2023 00:03:32 +0530 Subject: [PATCH 14/22] OFFLINE FEATURE ADDED- DB VERSION CHANGE --- .../presentation/hemocube/HemoCubeFragment.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 ce29492..eb271c5 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 @@ -321,13 +321,13 @@ class HemoCubeFragment : Fragment() { putString(Constants.DEVICE_ID, deviceSerialNo) apply() } - val loginId = sharedPreferences.getString(Constants.USER_ID, "").toString() - if (checkDeviceIdMismatch(deviceSerialNo, loginId)) { - activity?.runOnUiThread { - binding.errorMessage.text = "Warning: Login Id is different" - binding.errorMessage.visibility = View.VISIBLE - } - } + loginId = sharedPreferences.getString(Constants.USER_ID, "").toString() +// if (checkDeviceIdMismatch(deviceSerialNo, loginId)) { +// activity?.runOnUiThread { +// binding.errorMessage.text = "Warning: Login Id is different" +// binding.errorMessage.visibility = View.VISIBLE +// } +// } val led1BufferForDevice = if (isUsingExistingBuffer) { sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull() } else { From 53bf35ac383a1e0bcc67fc0e8def37b39174340f Mon Sep 17 00:00:00 2001 From: Mariya Date: Tue, 12 Dec 2023 12:18:42 +0530 Subject: [PATCH 15/22] OFFLINE FEATURE ADDED- with csv file data downloading format added --- app/src/debug/res/drawable/downloads.xml | 5 ++ .../com/example/hpostesting/data/CsvWriter.kt | 50 +++++++++++++++++++ .../adapter/OfflineUserListAdapter.kt | 2 +- .../dashboard/DashboardActivity.kt | 6 ++- .../presentation/dashboard/HomeFragment.kt | 24 ++++++++- .../dashboard/ui/home/HomeViewModel.kt | 13 ----- .../presentation/hemocube/HemoCubeFragment.kt | 3 ++ .../hemocube/HemoCubeViewModel.kt | 39 +++++++++++++++ app/src/main/res/layout/fragment_home.xml | 10 ++++ .../res/layout/offline_user_list_view.xml | 4 +- 10 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 app/src/debug/res/drawable/downloads.xml create mode 100644 app/src/main/java/com/example/hpostesting/data/CsvWriter.kt delete mode 100644 app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/home/HomeViewModel.kt diff --git a/app/src/debug/res/drawable/downloads.xml b/app/src/debug/res/drawable/downloads.xml new file mode 100644 index 0000000..772735f --- /dev/null +++ b/app/src/debug/res/drawable/downloads.xml @@ -0,0 +1,5 @@ + + + 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/presentation/adapter/OfflineUserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt index afa492b..dbeaf5e 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 @@ -97,7 +97,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) DataHolder.selectedTest = UserData( _id = userList._id, bloodGroup = userList.bloodGroup, - incubationTime = userList.incubationTime + incubationTime = userList.incubationTime, ) view.findNavController() .navigate(R.id.action_nav_home_to_mainActivity) 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 02b1df6..9eb8374 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 @@ -3,6 +3,7 @@ package com.example.hpostesting.presentation.dashboard import android.os.Bundle import android.view.Menu import android.widget.Toast +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.drawerlayout.widget.DrawerLayout import androidx.navigation.findNavController @@ -10,6 +11,7 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController +import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.google.android.material.navigation.NavigationView import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistributionException @@ -26,7 +28,7 @@ class DashboardActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityDashboardBinding - + private val viewModel: HemoCubeViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -60,6 +62,8 @@ class DashboardActivity : AppCompatActivity() { } + + 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 9b41ee5..ac87e7b 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 @@ -47,7 +47,7 @@ class HomeFragment : Fragment() { private lateinit var rvAdapter: UserListAdapter 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? @@ -121,6 +121,10 @@ class HomeFragment : Fragment() { binding.uploadData.setOnClickListener { showUploadDialog(requireContext()) } + + binding.btnSaveLocal.setOnClickListener { + downloadCsv() + } binding.btnNewKit.setOnClickListener { with(sharedPreference.edit()) { putString(Constants.KIT_NUMBER, "") @@ -376,4 +380,22 @@ 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() + } + } + } + + + } \ 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 eb271c5..a698df9 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 @@ -373,6 +373,9 @@ class HemoCubeFragment : Fragment() { led1Buffer = led1BufferForDevice led2Buffer = led2BufferForDevice appVersion = version + this.name = testDetails?.name.toString() + this.birthYear = testDetails?.birthYear.toString() + this.userImageURL = testDetails?.userImageURL.toString() this.led1Sample = led1Sample this.led2Sample = led2Sample this.led1Average = led1Average 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 868e255..5f2318a 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 @@ -7,6 +7,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.example.hpostesting.data.CsvWriter import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.constant.Constants @@ -102,6 +103,9 @@ class HemoCubeViewModel @Inject constructor( testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients + testDetails?.name = DataHolder.hemoCubeTestData?.name.toString() + testDetails?.birthYear = DataHolder.hemoCubeTestData?.birthYear.toString() + testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString() testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! } @@ -187,6 +191,41 @@ class HemoCubeViewModel @Inject constructor( hemoCubeDao.insertAll(userData) } + + 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 + } + + fun deleteById(userId: String) = viewModelScope.launch { hemoCubeDao.deleteById(id = userId) } diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 87f4636..c56295c 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -100,6 +100,16 @@ app:layout_constraintTop_toBottomOf="@+id/btn_submit" tools:listitem="@layout/offline_user_list_view" /> + + + + tools:text="Name: Mariya" /> + tools:text="UserID: Mariya" /> Date: Thu, 14 Dec 2023 21:05:59 +0530 Subject: [PATCH 16/22] added dialog box --- .../hpostesting/data/dao/HemoCubeDao.kt | 3 + .../data/model/patient/HemoCubeTestData.kt | 6 +- .../data/model/patient/UserData.kt | 6 + .../data/repository/LocalFileRepository.kt | 108 ++++++++++++++++++ .../presentation/dashboard/HomeFragment.kt | 46 +++++++- .../hemocube/HemoCubeViewModel.kt | 16 +++ 6 files changed, 183 insertions(+), 2 deletions(-) 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 c7cb63d..89d4306 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 @@ -23,4 +23,7 @@ interface HemoCubeDao { @Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id") suspend fun updateFieldById(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/model/patient/HemoCubeTestData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt index 8bbf84b..2cc6dab 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 @@ -9,6 +9,9 @@ data class HemoCubeTestData( var _id: String = "", var name: String = "", var birthYear: String = "", + var gender: String = "", + var abhaId: String = "", + var state: String = "", var bloodGroup: String = "", var incubationTime: String = "", var userImageURL: String = "", @@ -33,5 +36,6 @@ data class HemoCubeTestData( var deviceRatio: Double? = null, var calculatedRatio: Double? = null, var coefficients: String? = "", - var classificationResult: String = "" + var classificationResult: 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 ee6f2ad..36ac6fa 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,7 +10,10 @@ 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 = "", var userImageURL: String = "", var location: Location? = null, @@ -44,6 +47,9 @@ fun UserData.toHemoCubeTestData() = HemoCubeTestData( 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/repository/LocalFileRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/LocalFileRepository.kt index 6290bf0..054d84f 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,106 @@ class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) fun saveTextToDisk(filepath: String, contents: String) = localFileDataSource.saveTextToDisk(filepath, contents) + + + 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/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index ac87e7b..1edc549 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 @@ -123,7 +123,7 @@ class HomeFragment : Fragment() { } binding.btnSaveLocal.setOnClickListener { - downloadCsv() + context?.let { it1 -> showDownloadDialog(context = it1) } } binding.btnNewKit.setOnClickListener { with(sharedPreference.edit()) { @@ -397,5 +397,49 @@ 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, _ -> + downloadLocalDBData(dialog) + } + + builder.setNegativeButton(R.string.cancel) { dialog, _ -> + dialog.dismiss() + } + + val dialog = builder.create() + dialog.show() + } + + + + + private fun downloadLocalDBData(dialog: DialogInterface) { + hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> + val downloadList = mutableListOf() + + 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(), "CSV file downloaded successfully", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(requireContext(), "CSV file downloaing failed", Toast.LENGTH_SHORT).show() + } + + dialog.dismiss() + } + } + + + } \ No newline at end of file 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 5f2318a..5f4d77e 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 @@ -12,6 +12,7 @@ import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.constant.Constants 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.patient.BufferCheckData import com.example.hpostesting.data.model.patient.DeviceData @@ -29,6 +30,7 @@ import javax.inject.Inject class HemoCubeViewModel @Inject constructor( private val hemoCubeDao: HemoCubeDao, private val repository: DatabaseRepository, + private val localFileDataSource: LocalFileDataSource, context: Context, ) : ViewModel() { var isServiceConnected = false @@ -229,4 +231,18 @@ class HemoCubeViewModel @Inject constructor( fun deleteById(userId: String) = viewModelScope.launch { hemoCubeDao.deleteById(id = userId) } + + 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 + ) + } + } + } } \ No newline at end of file From a00bd6e99e8bb2f91f33b9b8a3cb76c8655d1708 Mon Sep 17 00:00:00 2001 From: Mariya Date: Thu, 14 Dec 2023 21:11:36 +0530 Subject: [PATCH 17/22] added changes related to save local data in csv file format --- .../hpostesting/presentation/dashboard/HomeFragment.kt | 2 +- .../presentation/hemocube/HemoCubeViewModel.kt | 9 ++++++++- app/src/main/res/values/strings.xml | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) 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 1edc549..8dcf4dd 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 @@ -123,7 +123,7 @@ class HomeFragment : Fragment() { } binding.btnSaveLocal.setOnClickListener { - context?.let { it1 -> showDownloadDialog(context = it1) } + showDownloadDialog(requireContext()) } binding.btnNewKit.setOnClickListener { with(sharedPreference.edit()) { 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 5f4d77e..3c99e63 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 @@ -19,10 +19,12 @@ import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.repository.DatabaseRepository +import com.example.hpostesting.data.repository.LocalFileRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Calendar +import java.util.Date import java.util.Locale import javax.inject.Inject @@ -30,7 +32,7 @@ import javax.inject.Inject class HemoCubeViewModel @Inject constructor( private val hemoCubeDao: HemoCubeDao, private val repository: DatabaseRepository, - private val localFileDataSource: LocalFileDataSource, + private val localFileDataSource: LocalFileRepository, context: Context, ) : ViewModel() { var isServiceConnected = false @@ -227,6 +229,11 @@ class HemoCubeViewModel @Inject constructor( 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 deleteById(userId: String) = viewModelScope.launch { hemoCubeDao.deleteById(id = userId) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec5b9d3..6f9bd9f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -188,6 +188,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 From 180ecf4b7311a22b06c302dcb277d2634616a313 Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 15 Dec 2023 13:07:22 +0530 Subject: [PATCH 18/22] fixed issues related to save local data in csv file format --- .../data/datasource/LocalFileDataSource.kt | 106 ++++++++++++++++++ .../data/repository/LocalFileRepository.kt | 99 ---------------- .../hpostesting/domain/di/AppModule.kt | 17 ++- .../hemocube/HemoCubeViewModel.kt | 2 +- 4 files changed, 121 insertions(+), 103 deletions(-) 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/repository/LocalFileRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/LocalFileRepository.kt index 054d84f..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 @@ -16,104 +16,5 @@ class LocalFileRepository(private val localFileDataSource: LocalFileDataSource) localFileDataSource.saveTextToDisk(filepath, contents) - 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/domain/di/AppModule.kt b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt index e0252b6..acbcc3f 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 @@ -9,6 +9,7 @@ import com.example.hpostesting.data.dao.UserDao import com.example.hpostesting.data.datasource.LocalFileDataSource import com.example.hpostesting.data.repository.DatabaseRepository import com.example.hpostesting.data.repository.LocalFileRepository +import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.domain.SaveRawData import com.example.hpostesting.domain.SaveRawDataTest import dagger.Module @@ -27,9 +28,7 @@ object AppModule { fun provideMyDatabase(@ApplicationContext context: Context): MyDatabase { return Room.databaseBuilder( context, MyDatabase::class.java, "my_database" - ) - .fallbackToDestructiveMigration() - .build() + ).fallbackToDestructiveMigration().build() } @Provides @@ -69,4 +68,16 @@ object AppModule { fun provideDatabaseRepository(): DatabaseRepository { return DatabaseRepository() } + + @Provides + @Singleton + fun provideRepository(): Repository { + return DatabaseRepository() + } + + @Provides + @Singleton + fun provideLocalFileDataSource(): LocalFileDataSource { + return LocalFileDataSource() + } } \ No newline at end of file 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 3c99e63..939e357 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 @@ -32,7 +32,7 @@ import javax.inject.Inject class HemoCubeViewModel @Inject constructor( private val hemoCubeDao: HemoCubeDao, private val repository: DatabaseRepository, - private val localFileDataSource: LocalFileRepository, + private val localFileDataSource: LocalFileDataSource, context: Context, ) : ViewModel() { var isServiceConnected = false From 9093caa9df6dd1d5a7f981c7d6ec2844e426522d Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 15 Dec 2023 16:23:28 +0530 Subject: [PATCH 19/22] gradle issues fixed --- app/build.gradle | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9195a22..7a26f17 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,7 +54,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2' @@ -79,17 +79,16 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - testImplementation 'org.mockito:mockito-core:3.12.0' + testImplementation 'org.mockito:mockito-core:3.12.4' testImplementation "androidx.arch.core:core-testing:2.2.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" - implementation 'com.opencsv:opencsv:4.6' implementation 'com.github.mik3y:usb-serial-for-android:3.5.1' - implementation "androidx.fragment:fragment-ktx:1.6.1" + implementation "androidx.fragment:fragment-ktx:1.6.2" // CSV read, write - implementation 'com.opencsv:opencsv:4.6' + implementation 'com.opencsv:opencsv:5.5' // Barcode scanner implementation 'com.journeyapps:zxing-android-embedded:4.3.0' @@ -98,22 +97,22 @@ dependencies { implementation 'com.google.android.gms:play-services-code-scanner:16.1.0' //Room - implementation "androidx.room:room-ktx:2.6.0-rc01" - implementation "androidx.room:room-runtime:2.6.0-rc01" - kapt ("androidx.room:room-compiler:2.6.0-rc01") + implementation "androidx.room:room-ktx:2.6.1" + implementation "androidx.room:room-runtime:2.6.1" + kapt ("androidx.room:room-compiler:2.6.1") //image implementation 'com.github.bumptech.glide:glide:4.13.2' annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2' // Navigation Component - implementation "androidx.navigation:navigation-fragment-ktx:2.7.3" - implementation "androidx.navigation:navigation-ui-ktx:2.7.3" + implementation "androidx.navigation:navigation-fragment-ktx:2.7.5" + implementation "androidx.navigation:navigation-ui-ktx:2.7.5" //Dagger - Hilt implementation "com.google.dagger:hilt-android:2.46" kapt "com.google.dagger:hilt-android-compiler:2.46" - kapt "androidx.hilt:hilt-compiler:1.0.0" + kapt "androidx.hilt:hilt-compiler:1.1.0" // Retrofit + GSON implementation "com.squareup.retrofit2:retrofit:2.9.0" From d25a1bb08a329b4e06985638f43a4de7fa14809f Mon Sep 17 00:00:00 2001 From: Mariya Date: Fri, 15 Dec 2023 16:43:27 +0530 Subject: [PATCH 20/22] color of download button changed, and try catch block added for download function of csv --- app/src/debug/res/drawable/downloads.xml | 6 +++--- .../presentation/dashboard/HomeFragment.kt | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/app/src/debug/res/drawable/downloads.xml b/app/src/debug/res/drawable/downloads.xml index 772735f..37f8230 100644 --- a/app/src/debug/res/drawable/downloads.xml +++ b/app/src/debug/res/drawable/downloads.xml @@ -1,5 +1,5 @@ - - - + + \ No newline at end of file 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 8dcf4dd..1cc2059 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 @@ -419,6 +419,7 @@ class HomeFragment : Fragment() { private fun downloadLocalDBData(dialog: DialogInterface) { hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> + try { val downloadList = mutableListOf() userDataList.forEach { userData -> @@ -427,15 +428,19 @@ class HomeFragment : Fragment() { } } - if (downloadList.isNotEmpty()) { - // Call ViewModel function to create CSV with filtered data - hemoCubeViewModel.createCSV(downloadList, requireContext()) - Toast.makeText(requireContext(), "CSV file downloaded successfully", Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(requireContext(), "CSV file downloaing failed", Toast.LENGTH_SHORT).show() + if (downloadList.isNotEmpty()) { + // Call ViewModel function to create CSV with filtered data + hemoCubeViewModel.createCSV(downloadList, requireContext()) + 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() } - - dialog.dismiss() } } From 762cbcbe44665d0496c20dc92b0d103ef7e42160 Mon Sep 17 00:00:00 2001 From: Mariya Date: Tue, 19 Dec 2023 15:11:09 +0530 Subject: [PATCH 21/22] changes related to csv added --- .../presentation/dashboard/HomeFragment.kt | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) 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 1cc2059..c8fe39d 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 @@ -418,22 +418,33 @@ class HomeFragment : Fragment() { private fun downloadLocalDBData(dialog: DialogInterface) { + var csvDownloaded = false hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> try { - val downloadList = mutableListOf() + if (!csvDownloaded) { - 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(), "CSV file downloaded successfully", Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(requireContext(), "No data to download", Toast.LENGTH_SHORT).show() + val downloadList = mutableListOf() + + 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()) + 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() From 8e675408337b3db4dc34bec474ad11b534ea7873 Mon Sep 17 00:00:00 2001 From: Mariya Date: Tue, 19 Dec 2023 17:12:11 +0530 Subject: [PATCH 22/22] Fixed issued related to csv file downloading --- .../hpostesting/data/dao/MyDataBase.kt | 2 +- .../presentation/dashboard/HomeFragment.kt | 61 ++++++++++++++----- .../hemocube/HemoCubeViewModel.kt | 1 + app/src/main/res/layout/fragment_home.xml | 1 + 4 files changed, 48 insertions(+), 17 deletions(-) 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 12a5bc4..339d58d 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 @@ -11,7 +11,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.google.android.datatransport.runtime.dagger.Provides import javax.inject.Singleton -@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 4, exportSchema = false) +@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 5, exportSchema = false) @TypeConverters(Converters::class) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao 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 c8fe39d..b41dd7f 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 @@ -87,6 +87,7 @@ class HomeFragment : Fragment() { adapter = OfflineUserListAdapter(binding.root, batLevel) adapter.differ.submitList(userList) binding.rvOrderOffline.adapter = adapter + } } viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected -> @@ -118,12 +119,31 @@ class HomeFragment : Fragment() { binding.btnLogout.setOnClickListener { logoutUser(requireContext()) } + + binding.uploadData.setOnClickListener { showUploadDialog(requireContext()) } + hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> - binding.btnSaveLocal.setOnClickListener { - showDownloadDialog(requireContext()) + 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()) { @@ -311,7 +331,9 @@ class HomeFragment : Fragment() { hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> val uploadDataVisibility = - if (userDataList.any { !it.localFlag && it.testStatus == true}) View.VISIBLE else View.GONE + if (userDataList.any { + !it.localFlag && it.testStatus == true}) + View.VISIBLE else View.GONE binding.uploadData.visibility = uploadDataVisibility } } @@ -427,25 +449,32 @@ class HomeFragment : Fragment() { 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() + 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() 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 939e357..9c2a2cb 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 @@ -107,6 +107,7 @@ class HemoCubeViewModel @Inject constructor( testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio 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() diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index c56295c..e62ff1f 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -107,6 +107,7 @@ 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" />