diff --git a/.idea/gradle.xml b/.idea/gradle.xml index ae388c2..cb865f6 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,8 +4,6 @@ diff --git a/app/build.gradle b/app/build.gradle index 0eca9d0..0a45e20 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,13 +14,13 @@ android { compileSdk 34 namespace 'in.sminnovations.hpostesting' - // prod - production, preprod - preproduction, quality - qc, + // prod - production, preprod - preproduction, quality - qc defaultConfig { applicationId "in.sminnovations.hpostesting" minSdk 21 targetSdk 34 - versionCode 39 - versionName "2.1.39" + versionCode 56 + versionName "2.1.56" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -55,12 +55,15 @@ android { } dependencies { + implementation "com.google.dagger:hilt-android:2.46" + kapt "com.google.dagger:hilt-android-compiler:2.46" 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' + implementation 'androidx.fragment:fragment-ktx:1.6.2' //firebase implementation platform('com.google.firebase:firebase-bom:32.1.0') @@ -75,8 +78,10 @@ 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") + implementation 'androidx.preference:preference-ktx:1.2.1' + implementation 'androidx.preference:preference-ktx:1.2.1' // Testing @@ -88,14 +93,14 @@ dependencies { androidTestImplementation 'org.mockito:mockito-android:3.12.4' androidTestImplementation 'org.mockito:mockito-inline:3.12.4' testImplementation "androidx.arch.core:core-testing:2.2.0" - testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1' 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' @@ -107,25 +112,27 @@ 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.0" + implementation "androidx.room:room-runtime:2.6.0" + kapt ("androidx.room:room-compiler:2.6.0") //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" implementation "com.squareup.retrofit2:converter-gson:2.9.0" + implementation "androidx.preference:preference-ktx:1.2.1" + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c2f6365..61c85a5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,8 +5,8 @@ - - @@ -32,6 +32,9 @@ android:supportsRtl="true" android:theme="@style/Theme.HPOSTesting" tools:targetApi="31"> + @@ -58,7 +61,8 @@ android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity" android:exported="false" android:label="@string/title_activity_dashboard" - android:theme="@style/Theme.HPOS.NoActionBar" /> + android:theme="@style/Theme.HPOS.NoActionBar" + tools:ignore="MissingClass" /> >> = mapOf>>( "HCV-000-3001" to listOf( listOf(1.313, -0.89), // LED1, 435nm @@ -91,10 +115,59 @@ object Constants { listOf(0.1964, 0.011565), // LED3, 555nm listOf(1.0, 0.0) // LED4 ), + "HCV-000-3003" to listOf( + listOf(0.723142, -0.09135), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.1964, 0.011565), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3004" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3005" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3006" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3007" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3008" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3009" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3010" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), ) const val INCUBATION_TIME_MIN = 0 const val INCUBATION_TIME_MAX = 1400 + const val BATTERY_LEVEL_MIN = 0 val BUFFER_INTENSITY_THRESHOLDS: Map>> = mapOf>>( "HCV-000-3001" to listOf( @@ -108,6 +181,54 @@ object Constants { listOf(24500, 26250), listOf(24500, 26250), listOf(24500, 26250), + ), + "HCV-000-3003" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3004" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3005" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3006" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3007" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3008" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3009" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3010" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), ) ) } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/constant/LanguageManager.kt b/app/src/main/java/com/example/hpostesting/data/constant/LanguageManager.kt new file mode 100644 index 0000000..85d6a7c --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/data/constant/LanguageManager.kt @@ -0,0 +1,30 @@ +package com.example.hpostesting.data.constant + +import android.content.Context +import android.content.SharedPreferences +import java.util.Locale + +object LanguageManager { + private const val LANGUAGE_PREF_KEY = "language_pref" + + fun setLocale(context: Context, languageCode: String) { + val locale = Locale(languageCode) + Locale.setDefault(locale) + + val resources = context.resources + val configuration = resources.configuration + configuration.setLocale(locale) + + context.createConfigurationContext(configuration) + } + + fun persistLanguagePreference(context: Context, languageCode: String) { + val prefs: SharedPreferences = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) + prefs.edit().putString(LANGUAGE_PREF_KEY, languageCode).apply() + } + + fun getSavedLanguage(context: Context): String { + val prefs: SharedPreferences = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) + return prefs.getString(LANGUAGE_PREF_KEY, "en") ?: "en" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt index 57e4b23..3ec47ec 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt @@ -8,11 +8,7 @@ import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.UserData -@Database( - entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], - version = 12, - exportSchema = false -) +@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 13, exportSchema = false) @TypeConverters(Converters::class) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao 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 f642605..5b22aee 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 @@ -11,12 +11,15 @@ data class HemoCubeTestData( var incubationTime: String = "", var bloodGroup: String = "", var birthYear: String = "", + var state: String = "", + var abhaId: String = "", var userImageURL: String = "", var location: UserData.Location? = null, var reportUploadTime: String? = "", var testType: String? = "HEMOCUBE", var testTime: String? = "", var testStatus: Boolean? = false, + var gender: String = "", var localFlag: Boolean = false, var deviceId: String? = "", var appVersion:String? = "", 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 a7ad7fd..a434558 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 @@ -9,10 +9,12 @@ data class UserData( @PrimaryKey var _id: String = "", var name: String = "", - var bloodGroup: String = "", var incubationTime: String = "", var birthYear: String = "", + var abhaId: String = "", + var bloodGroup: String = "", var userImageURL: String = "", + var gender: String ="", var location: Location? = null, var createdBy: String? = "", var reportUploadTime: String? = "", @@ -20,12 +22,14 @@ data class UserData( var testStatus: Boolean? = false, var mobileId: String = "", var deviceId: String = "", + var state: String = "", var deviceSerialNumber: String = "", var kitSerial: String = "", var csvPath: String = "", var reportPath: String = "", var result: TestRightResultType? = null, - var resultRatio: Double? = null + var resultRatio: Double? = null, + var prdClassification: String = "" ) { enum class Gender { MALE, @@ -45,7 +49,11 @@ fun UserData.toHemoCubeTestData() = HemoCubeTestData( birthYear = birthYear, userImageURL = userImageURL, testStatus = testStatus, + location = location, + gender = gender, + state = state, + abhaId = abhaId, bloodGroup = bloodGroup, - incubationTime = incubationTime, - location = location + prdClassification = prdClassification, + testTime = testTime ) diff --git a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt index 332d4cb..3c52ec8 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.content.Context import android.content.Intent import android.content.SharedPreferences @@ -10,8 +11,8 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants -import com.example.hpostesting.presentation.dashboard.DashboardActivity -import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity +import com.example.hpostesting.data.constant.LanguageManager + import com.example.hpostesting.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.testRight.TestRightActivity import com.google.android.material.snackbar.Snackbar @@ -33,7 +34,7 @@ class KitScanActivity : AppCompatActivity() { ScanContract() ) { result: ScanIntentResult -> if (result.contents.isNullOrEmpty()) { - Toast.makeText(this, "Cancelled: Unable to scan, Try Again!!", Toast.LENGTH_LONG).show() + Toast.makeText(this, R.string.cancelled_unable_scan, Toast.LENGTH_LONG).show() } else { Log.d(TAG, result.contents) processScannedData(result.contents) @@ -44,6 +45,12 @@ class KitScanActivity : AppCompatActivity() { binding.nameEditText.setText(contents) } + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -120,7 +127,7 @@ class KitScanActivity : AppCompatActivity() { } Toast.makeText( applicationContext, - "Kit number is updated, Please Select user before starting test", + R.string.kit_updated, Toast.LENGTH_SHORT ).show() @@ -138,9 +145,24 @@ class KitScanActivity : AppCompatActivity() { moveToNext() } } else { - Toast.makeText(this, "Invalid KIT Number", Toast.LENGTH_LONG).show() + Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() return@setOnClickListener } + if (serialNumber.isNotEmpty() && checkDataNotNull() && isSerialValid( + serialNumber + ) + ) { + DataHolder.kitSerial = binding.nameEditText.text.toString() + DataHolder.selectedTest?.kitSerial = binding.nameEditText.text.toString() + with(sharedPreference.edit()) { + putString(Constants.KIT_NUMBER, binding.nameEditText.text.toString()) + putInt(Constants.KIT_COUNT, 1) + apply() + } + moveToNext() + } else { + Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() + } } } @@ -195,7 +217,7 @@ class KitScanActivity : AppCompatActivity() { private fun checkDataNotNull(): Boolean { return if (DataHolder.selectedTest?._id == null) { Toast.makeText( - applicationContext, "Please Select patient before starting test", Toast.LENGTH_SHORT + applicationContext, R.string.select_patient, Toast.LENGTH_SHORT ).show() val i = Intent(applicationContext, DashboardActivity::class.java) diff --git a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt index dd5d0f6..91763ae 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.Manifest import android.content.* import android.content.pm.PackageManager @@ -9,8 +10,6 @@ import android.os.Bundle import android.util.Log import android.view.Menu import android.view.View -import android.view.ViewGroup -import android.widget.Button import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat @@ -18,9 +17,9 @@ import androidx.core.content.ContextCompat import androidx.core.view.get import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.test.TestType -import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.google.android.gms.location.* import com.google.android.material.snackbar.Snackbar import com.google.firebase.crashlytics.FirebaseCrashlytics @@ -46,6 +45,12 @@ class MainActivity : AppCompatActivity() { } } + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) @@ -109,6 +114,15 @@ class MainActivity : AppCompatActivity() { Constants.DEVICE_TYPE_HOMOCUBE } + device.productId == Constants.HEMO_CUBE_V2_PRODUCT_ID && device.vendorId == Constants.HEMO_CUBE_V2_VENDOR_ID -> { + binding.cvItem1.visibility = View.VISIBLE + binding.cvItem3.visibility = View.VISIBLE + binding.cvItem2.visibility = View.GONE + binding.cvItem4.visibility = View.GONE + DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HOMOCUBE) + Constants.DEVICE_TYPE_HOMOCUBE + } + device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> { Log.d( TAG, @@ -138,7 +152,7 @@ class MainActivity : AppCompatActivity() { else -> { Log.d(TAG, "Device NOT Connected") - Toast.makeText(this, "Device Not Connected", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.device_not, Toast.LENGTH_SHORT).show() DataHolder.usbConnected.value = false null } @@ -226,7 +240,7 @@ class MainActivity : AppCompatActivity() { ) != PackageManager.PERMISSION_GRANTED ) { // Handle location permission request if needed - Toast.makeText(this, "Please enable location services", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.enable_location, Toast.LENGTH_SHORT).show() requestCoarseLocationPermission() requestFineLocationPermission() return @@ -313,7 +327,7 @@ class MainActivity : AppCompatActivity() { requestFineLocationPermission() } else { // Coarse location permission denied - Toast.makeText(this, "Coarse location permission denied", Toast.LENGTH_SHORT) + Toast.makeText(this, R.string.coarse_location_denied, Toast.LENGTH_SHORT) .show() } } @@ -324,7 +338,7 @@ class MainActivity : AppCompatActivity() { getLocation() } else { // Fine location permission denied - Toast.makeText(this, "Fine location permission denied", Toast.LENGTH_SHORT) + Toast.makeText(this, R.string.location_denied, Toast.LENGTH_SHORT) .show() } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt index 3623888..c8e4a3a 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt @@ -1,6 +1,8 @@ package com.example.hpostesting.presentation +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.Manifest +import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.os.Build @@ -13,11 +15,9 @@ import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.example.hpostesting.data.DataHolder -import com.example.hpostesting.presentation.dashboard.DashboardActivity +import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.util.MyUtils -import com.google.firebase.firestore.FirebaseFirestoreSettings -import com.google.firebase.firestore.ktx.firestore -import com.google.firebase.ktx.Firebase +import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding class SplashActivity : AppCompatActivity() { @@ -34,6 +34,12 @@ class SplashActivity : AppCompatActivity() { private var allPermissionsGranted = false + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySplashBinding.inflate(layoutInflater) @@ -77,7 +83,7 @@ class SplashActivity : AppCompatActivity() { } else { Toast.makeText( this, - "You must grant permission to access all files to use the app", + R.string.permission_grant, Toast.LENGTH_SHORT ).show() finish() @@ -139,7 +145,7 @@ class SplashActivity : AppCompatActivity() { if (allGranted) { moveToLandingPage() } else { - Toast.makeText(this, "All permissions are required to use the app.", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.permission_required, Toast.LENGTH_SHORT).show() finish() } } 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 6acd933..2a77c87 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation.adapter +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -14,11 +15,13 @@ 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() { @@ -40,7 +43,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) } 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) @@ -61,7 +64,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) if (batLevel < 40) { Toast.makeText( view.context, - "Battery level is low than 40%, please charge the device to continue testing", + context?.getString(R.string.low_battery_warning), Toast.LENGTH_SHORT ).show() return@setOnClickListener @@ -70,7 +73,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) if (userList.testStatus!!) { Toast.makeText( view.context, - "Test has been already conducted for this user", + context?.getString(R.string.test_already_conducted), Toast.LENGTH_SHORT ).show() } else { @@ -78,13 +81,13 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) { Toast.makeText( view.context, - "Incubation has not completed 15 minutes", + context?.getString(R.string.incubation_not_completed), Toast.LENGTH_SHORT ).show() } else if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) { Toast.makeText( view.context, - "Incubation crossed 30 minutes, need to repeat the incubation", + context?.getString(R.string.incubation_crossed_30_minutes), Toast.LENGTH_SHORT ).show() } else { @@ -99,7 +102,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int) } else { Toast.makeText( view.context, - "Incubation not started for this user", + context?.getString(R.string.incubation_not_started), Toast.LENGTH_SHORT ).show() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt index 07ee06d..09d67bc 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt @@ -26,6 +26,7 @@ import android.widget.AutoCompleteTextView import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.getSystemService import androidx.fragment.app.FragmentActivity +import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.google.firebase.firestore.FirebaseFirestore @@ -70,10 +71,10 @@ class UserListAdapter( Glide.with(view).load(model.userImageURL).into(userImage) if (model.testStatus!!) { - teststatus.text = "Test concluded" + teststatus.text = view.context.getString(R.string.test_concluded) } else { - teststatus.text = "Test is Pending" + teststatus.text = view.context.getString(R.string.test_pending) } holder.binding.btnBlood.setOnClickListener { @@ -94,19 +95,19 @@ class UserListAdapter( val builder = AlertDialog.Builder(context) .setView(dialogView) - .setTitle("Add Blood Group") + .setTitle(R.string.blood_group) val etBloodGroup = dialogView.findViewById(R.id.et_blood_group) - builder.setPositiveButton("OK") { dialog, which -> + builder.setPositiveButton(R.string.ok) { dialog, which -> val bloodGroup = etBloodGroup.text.toString() - if (bloodGroup.equals("Select Blood Group") || bloodGroup.isNullOrBlank()) { - etBloodGroup.error = "Please enter your blood group" - Toast.makeText( - context, - "Please enter your blood group", - Toast.LENGTH_SHORT - ).show() + if (bloodGroup.equals("Select Blood Group") ||bloodGroup.equals("ರಕ್ತ ಗುಂಪು ಆಯ್ಕೆಮಾಡಿ") || bloodGroup.isNullOrBlank()) { + if (view != null) { + etBloodGroup.error =view.context.getString(R.string.blood_group_error) + } + if (view != null) { + Toast.makeText(context, view.context.getString(R.string.blood_group_toast), Toast.LENGTH_SHORT).show() + } } else { // Check if hemoCubeViewModel and testDetails are not null val db: FirebaseFirestore = FirebaseFirestore.getInstance() @@ -125,27 +126,33 @@ class UserListAdapter( ).format(Calendar.getInstance().time).toString() ) .addOnSuccessListener { - Toast.makeText( - context, - "Blood group updated successfully", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + Toast.makeText( + view.context, + context?.getString(R.string.blood_group_updated_successfully), + Toast.LENGTH_SHORT + ).show() + } btnBlood.visibility = View.GONE } .addOnFailureListener { e -> - Toast.makeText( - context, - "Failed to update blood group: ${e.message}", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + Toast.makeText( + view.context, + context?.getString(R.string.failed_to_update_blood_group), + Toast.LENGTH_SHORT + ).show() + } } } catch (e: IndexOutOfBoundsException) { // Handle the case where no documents are found for the specified ID - Toast.makeText( - context, - "No user data found for the specified ID", - Toast.LENGTH_SHORT - ).show() + if (view != null) { + Toast.makeText( + view.context, + context?.getString(R.string.no_user_data_found), + Toast.LENGTH_SHORT + ).show() + } } } @@ -160,7 +167,7 @@ class UserListAdapter( // Handle the selected blood group here } - builder.setNegativeButton("Cancel") { dialog, which -> + builder.setNegativeButton(R.string.cancel) { dialog, which -> dialog.dismiss() } @@ -190,10 +197,10 @@ class UserListAdapter( // } } userCard.setOnClickListener { - if (false) { + if (batLevel < Constants.BATTERY_LEVEL_MIN) { Toast.makeText( view.context, - "Battery level is low than 40%, please charge the device to continue testing", + context?.getString(R.string.low_battery_warning), Toast.LENGTH_SHORT ).show() return@setOnClickListener @@ -202,7 +209,7 @@ class UserListAdapter( if (model.testStatus!!) { Toast.makeText( view.context, - "Test has been already conducted for this user", + context?.getString(R.string.test_already_conducted), Toast.LENGTH_SHORT ).show() } else { @@ -210,13 +217,13 @@ class UserListAdapter( if (isBetween15And30Minutes(model.incubationTime) < -15000) { Toast.makeText( view.context, - "Incubation has not completed 15 minutes", + context?.getString(R.string.incubation_not_completed), Toast.LENGTH_SHORT ).show() } else if (isBetween15And30Minutes(model.incubationTime) > 300000) { Toast.makeText( view.context, - "Incubation crossed 30 minutes, need to repeat the incubation", + context?.getString(R.string.incubation_crossed_30_minutes), Toast.LENGTH_SHORT ).show() } else { @@ -227,7 +234,7 @@ class UserListAdapter( } else { Toast.makeText( view.context, - "Incubation not started for this user", + context?.getString(R.string.incubation_not_started), Toast.LENGTH_SHORT ).show() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt index 18d6a8b..62e555d 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt @@ -16,7 +16,6 @@ import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.presentation.UsbServiceListener -import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.ktx.Firebase @@ -84,7 +83,7 @@ class HemoCubeBufferCheckFragment : Fragment() { listenToHemoCube() getDeviceInfo() } else { - Toast.makeText(context, "Invalid KIT Number", Toast.LENGTH_LONG).show() + Toast.makeText(context, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() return@setOnClickListener } activity?.runOnUiThread { @@ -119,21 +118,21 @@ class HemoCubeBufferCheckFragment : Fragment() { hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, "")) } else { Toast.makeText( - requireContext(), "No internet connection available", Toast.LENGTH_SHORT + requireContext(), R.string.internt_not, Toast.LENGTH_SHORT ).show() } isOnline = isNetworkAvailable } hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> if (result == "Success") { - showToast("Kit result uploaded successfully") + showToast(R.string.kit_uploaded) } if (result == "Error") { showToast("Error uploading data, Kit result stored locally") startActivity(Intent(requireActivity(), DashboardActivity::class.java)) } if (result == "Local") { - showToast("Internet not available, Kit result stored locally") + showToast(R.string.kit_upload_failed) } binding.progressBar.visibility = View.GONE @@ -164,7 +163,7 @@ class HemoCubeBufferCheckFragment : Fragment() { } }) } catch (e: Exception) { - showToast("test is going on") + showToast(R.string.test_ongoing) Firebase.crashlytics.recordException(e) } } @@ -398,7 +397,7 @@ class HemoCubeBufferCheckFragment : Fragment() { return "INVALID" } } catch (e: Exception) { - showToast("error while performing classification") + showToast(R.string.error_classification) Firebase.crashlytics.recordException(e) return "ERROR" } @@ -425,10 +424,11 @@ class HemoCubeBufferCheckFragment : Fragment() { return "INVALID" } - private fun showToast(message: String) { - Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() + private fun showToast(messageResId: Int) { + Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show() } + private fun startBufferProcess() { activity?.runOnUiThread { binding.btnPlacebuffer.visibility = View.GONE diff --git a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt index 6375d39..2b27d63 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt @@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat import androidx.core.view.get import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.testRight.UsbService import com.hoho.android.usbserial.driver.UsbSerialDriver @@ -73,6 +74,12 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() { } } + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityHemocubeBinding.inflate(layoutInflater) @@ -92,7 +99,7 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() { } else { myMenu?.get(0)?.icon = ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24) - Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.device_disconnected, Toast.LENGTH_SHORT).show() } } } @@ -103,7 +110,7 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() { val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager) if (availableDrivers.isEmpty()) { - Toast.makeText(this, "No device found", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.no_device_found, Toast.LENGTH_SHORT).show() } else { mDriver = availableDrivers[0] mConnection = manager.openDevice(mDriver.device) 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..1117c9c 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 @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation.dashboard +import android.content.Context import android.os.Bundle import android.view.Menu import android.widget.Toast @@ -10,13 +11,11 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController +import com.example.hpostesting.data.constant.LanguageManager import com.google.android.material.navigation.NavigationView import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.google.firebase.crashlytics.ktx.crashlytics -//import com.google.firebase.appdistribution.FirebaseAppDistribution -//import com.google.firebase.appdistribution.FirebaseAppDistributionException import dagger.hilt.android.AndroidEntryPoint import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding @@ -27,6 +26,12 @@ class DashboardActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityDashboardBinding + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -59,7 +64,6 @@ class DashboardActivity : AppCompatActivity() { return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } - 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 aa7da3e..4ca2131 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 @@ -108,12 +108,12 @@ class HomeFragment : Fragment() { 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() } } @@ -203,14 +203,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() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt index d62d53b..5b89238 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/SlideshowFragment.kt @@ -1,49 +1,66 @@ package com.example.hpostesting.presentation.dashboard +import android.content.Context +import android.content.pm.PackageManager import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import com.example.hpostesting.presentation.dashboard.ui.slideshow.SlideshowViewModel -import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding +import android.widget.Toast +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import com.example.hpostesting.data.constant.LanguageManager +import `in`.sminnovations.hpostesting.R +private var isLanguageChanged = false -class SlideshowFragment : Fragment() { +class SlideshowFragment : PreferenceFragmentCompat() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext()) - private var _binding: FragmentSlideshowBinding? = null + val languagePreference = ListPreference(requireContext()) + languagePreference.key = "language_preference" + languagePreference.title = getString(R.string.app_language) + languagePreference.summary = getString(R.string.select_language) + languagePreference.entries = arrayOf("English", "Kannada", "Hindi") + languagePreference.entryValues = arrayOf("en", "kn", "hi") + languagePreference.setDefaultValue("en") - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! + languagePreference.onPreferenceChangeListener = + Preference.OnPreferenceChangeListener { _, newValue -> + val languageCode = newValue as String + updateLanguage(requireContext(), languageCode) + true + } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - val slideshowViewModel = - ViewModelProvider(this).get(SlideshowViewModel::class.java) + preferenceScreen.addPreference(languagePreference) + setPreferenceScreen(preferenceScreen) - _binding = FragmentSlideshowBinding.inflate(inflater, container, false) - val root: View = binding.root + // App Version Preference + val appVersionPreference = Preference(requireContext()) + appVersionPreference.title = "App Version" + appVersionPreference.summary = getAppVersion(requireContext()) - val pInfo = requireActivity().packageManager.getPackageInfo( - requireActivity().packageName, 0 - ) - val version = pInfo.versionName - binding.textSlideshow.text = version + preferenceScreen.addPreference(languagePreference) + preferenceScreen.addPreference(appVersionPreference) + setPreferenceScreen(preferenceScreen) -// val textView: TextView = binding.textSlideshow -// slideshowViewModel.text.observe(viewLifecycleOwner) { -// textView.text = it -// } - return root + if (isLanguageChanged) { + Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show() + } } - override fun onDestroyView() { - super.onDestroyView() - _binding = null + private fun updateLanguage(context: Context, languageCode: String) { + LanguageManager.persistLanguagePreference(context, languageCode) + LanguageManager.setLocale(context, languageCode) + requireActivity().recreate() // Recreate activity to apply language changes + isLanguageChanged = true + } + + private fun getAppVersion(context: Context): String { + return try { + val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) + pInfo.versionName + } catch (e: PackageManager.NameNotFoundException) { + "N/A" + } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt index 39fecbe..cb74fd0 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt @@ -47,10 +47,10 @@ class LoginFragment : Fragment() { performLogin(loginId, password) } else { if (loginId.isBlank()) { - binding.loginId.error = "Please enter a proper Login ID" + binding.loginId.error = R.string.enter_proper_login_id.toString() } if (password.isBlank()) { - binding.password.error = "Please enter a proper password" + binding.password.error = R.string.enter_proper_password.toString() } } } @@ -72,10 +72,10 @@ class LoginFragment : Fragment() { navigateToHomeFragment() return } else { - Toast.makeText(requireContext(), "Wrong Password", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show() } } - Toast.makeText(requireContext(), "Wrong UserID", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show() } private fun saveUserId(userId: String) { diff --git a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsActivity.kt index df5d356..25b41b4 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsActivity.kt @@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat import androidx.core.view.get import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.presentation.hemocube.HemoCubeFragment import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.testRight.UsbService @@ -77,6 +78,12 @@ class DiagnosticsActivity : AppCompatActivity() { } } + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityDiagnosticsBinding.inflate(layoutInflater) diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardActivity.kt new file mode 100644 index 0000000..6e82bf7 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardActivity.kt @@ -0,0 +1,47 @@ +package com.example.hpostesting.presentation.hemocube + +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.hardware.usb.UsbDevice +import android.hardware.usb.UsbDeviceConnection +import android.hardware.usb.UsbManager +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.os.IBinder +import android.view.Menu +import androidx.activity.viewModels +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.data.constant.LanguageManager +import com.example.hpostesting.presentation.testRight.UsbService +import com.hoho.android.usbserial.driver.UsbSerialDriver +import `in`.sminnovations.hpostesting.R +import `in`.sminnovations.hpostesting.databinding.ActivityDigitalCardBinding +import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding + +class DigitalCardActivity : AppCompatActivity() { + + private lateinit var binding: ActivityDigitalCardBinding + + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityDigitalCardBinding.inflate(layoutInflater) + setContentView(binding.root) + moveToNext() + } + + + private fun moveToNext() { + if (supportFragmentManager.isDestroyed) return + supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, DigitalCardFragment()) + .commit() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardFragment.kt new file mode 100644 index 0000000..f72c826 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/DigitalCardFragment.kt @@ -0,0 +1,83 @@ +package com.example.hpostesting.presentation.hemocube + +import android.annotation.SuppressLint +import android.content.Context +import android.content.SharedPreferences +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.activityViewModels +import com.example.hpostesting.data.DataHolder +import com.example.hpostesting.data.model.patient.toHemoCubeTestData +import `in`.sminnovations.hpostesting.R +import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding +import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +class DigitalCardFragment : Fragment() { + private lateinit var binding: FragmentDigitalCardBinding + private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() + private lateinit var sharedPreferences: SharedPreferences + private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, + ): View { + binding = FragmentDigitalCardBinding.inflate(inflater, container, false) + sharedPreferences = + requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initViews() + } + + @SuppressLint("SetTextI18n") + private fun initViews() { + activity?.runOnUiThread { + binding.progressBar.visibility = View.VISIBLE + } + Log.d("DigitalCardFragment", "Name: ${DataHolder.hemoCubeTestData?.name}") + Log.d("DigitalCardFragment", "DOB: ${testDetails?.birthYear}") + Log.d("DigitalCardFragment", "Gender: ${testDetails?.gender}") + Log.d("DigitalCardFragment", "State: ${testDetails?.state}") + Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}") + Log.d("DigitalCardFragment", "Blood Group: ${testDetails?.bloodGroup}") + Log.d("DigitalCardFragment", "Sickle-Cell: ${testDetails?.classificationResult}") +// Log.d("DigitalCardFragment", "Issue Date: $formattedDate") + activity?.runOnUiThread { + binding.progressBar.visibility = View.GONE + binding.name.text = "Name: ${DataHolder.hemoCubeTestData?.name}" + binding.dob.text = "DOB: ${testDetails?.birthYear}" + binding.gender.text = "Gender: ${testDetails?.gender}" + binding.State.text = "State: ${testDetails?.state}" + binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}" + binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}" + binding.sicklecell.text = "Sickle-Cell: ${DataHolder.hemoCubeTestData?.prdClassification.toString()}" + + } + // Update the UI with the fetched details + val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) + val originalDate: Date? = originalDateFormat.parse(SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time)) + +// Format the parsed date to "mm date, year" + val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()) + val formattedDate: String = originalDate?.let { desiredDateFormat.format(it) } ?: "N/A" + activity?.runOnUiThread { + binding.issueDate.text = "Issue Date: ${formattedDate}" + } + + } + + +} \ 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 096c72b..668f367 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 @@ -57,6 +57,7 @@ class HemoCubeFragment : Fragment() { private var validationError = false private var deviceHardwareId = "" private var allErrorMessages = "" + private var testStatusCode = 0.0 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, @@ -90,8 +91,8 @@ class HemoCubeFragment : Fragment() { binding.nameEditText.visibility = View.GONE binding.tvTitle.visibility = View.GONE binding.btnGo.visibility = View.GONE - binding.btnSubmit.isEnabled = false - binding.btnSubmit.isClickable = false +// binding.btnSubmit.isEnabled = false +// binding.btnSubmit.isClickable = false binding.btnPlacebuffer.visibility = View.GONE binding.tvName.text = "Name: ${testDetails?.name}\n ID: ${testDetails?._id}" @@ -121,24 +122,33 @@ class HemoCubeFragment : Fragment() { } + if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") { + activity?.runOnUiThread { + binding.tvDeviceMessages.visibility = View.VISIBLE + } + } } private fun observeViewModel() { hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> if (result == "Success") { - showToast("Test Results Uploaded Successfully") - val i = Intent( - requireContext().applicationContext, DashboardActivity::class.java - ) - startActivity(i) - (activity as HemocubeActivity).finish() + showToast(R.string.test_upload) + + activity?.runOnUiThread { + binding.btnSubmit.visibility = View.GONE + val i = Intent( + requireContext().applicationContext, DashboardActivity::class.java + ) + startActivity(i) + + } } if (result == "Local") { - showToast("Internet not available, test details stored locally") + showToast(R.string.internt_not_local) startActivity(Intent(requireActivity(), DashboardActivity::class.java)) } if (result == "Error") { - showToast("Error uploading data, test details stored locally") + showToast(R.string.error_local) startActivity(Intent(requireActivity(), DashboardActivity::class.java)) } @@ -167,6 +177,10 @@ class HemoCubeFragment : Fragment() { hemoCubeViewModel.messages.observe(viewLifecycleOwner) { binding.tvSubtitle4.text = it } + + hemoCubeViewModel.deviceMessages.observe(viewLifecycleOwner) { + binding.tvDeviceMessages.text = it + } } private fun checkAndStartProcess() { @@ -199,16 +213,16 @@ class HemoCubeFragment : Fragment() { false } } catch (e: Exception) { - showToast("error while getting existing buffer") + showToast(R.string.error_exist) false } } private fun showBufferAlertDialog() { val title = "WARNING" - val message = "Do you want to continue with existing buffer?" + val message = getString(R.string.do_exist) val negativeText = getString(R.string.no) - val positiveText = "Yes" + val positiveText = getString(R.string.yes) UIUtils.createAlertDialog(requireContext(), title, @@ -224,7 +238,7 @@ class HemoCubeFragment : Fragment() { activity?.runOnUiThread { binding.btnPlacebuffer.visibility = View.GONE binding.btnSamplestart.visibility = View.VISIBLE - binding.tvSubtitle4.text = "Place Sample" + binding.tvSubtitle4.text = getString(R.string.place_sample) } isUsingExistingBuffer = true } @@ -252,7 +266,7 @@ class HemoCubeFragment : Fragment() { } }) } catch (e: Exception) { - showToast("test is going on") + showToast(R.string.test_ongoing) Firebase.crashlytics.recordException(e) } } @@ -282,53 +296,71 @@ class HemoCubeFragment : Fragment() { } resultData += stringData + hemoCubeViewModel.deviceMessages.postValue(resultData) when { - stringData.contains("SN") -> { - val slData = stringData.split(" ") - if (slData.size > 1) { - val hardwareId = slData[1].trim() - deviceHardwareId = hardwareId + resultData.contains("SNE") && this.testStatusCode < Constants.TEST_STATUS_CODE_CONFIG_COMPLETED -> { + val pattern = Regex("HCV-\\d{3}-\\d{4}") + val matchResult = pattern.find(resultData) + val hardwareId = matchResult?.value + + if (hardwareId.toString().length == 12) { + deviceHardwareId += hardwareId with(sharedPreferences.edit()) { - putString(Constants.DEVICE_ID, hardwareId) + putString(Constants.DEVICE_ID, deviceHardwareId) apply() } + this.testStatusCode = Constants.TEST_STATUS_CODE_CONFIG_COMPLETED + } else { + hemoCubeViewModel.messages.postValue("Config error") } activity?.runOnUiThread { binding.btnPlacebuffer.visibility = View.VISIBLE } - hemoCubeViewModel.messages.postValue("Start") + hemoCubeViewModel.messages.postValue(getString(R.string.start)) } - stringData.contains("#BS") -> { - hemoCubeViewModel.messages.postValue("Buffer Started") + resultData.contains("#BS") && this.testStatusCode < Constants.TEST_STATUS_CODE_BUFFER_STARTED -> { + hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started)) + this.testStatusCode = Constants.TEST_STATUS_CODE_BUFFER_STARTED } - stringData.contains("#BC") -> { + resultData.contains("#BC") && this.testStatusCode < Constants.TEST_STATUS_CODE_BUFFER_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_BUFFER_COMPLETED activity?.runOnUiThread { - binding.tvSubtitle4.text = "Buffer Completed" + binding.tvSubtitle4.text = getString(R.string.buffer_completed) binding.btnSamplestart.visibility = View.VISIBLE } } - stringData.contains("#SS") -> { + resultData.contains("#SS") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_STARTED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_STARTED activity?.runOnUiThread { - binding.tvSubtitle4.text = "Sample Started" + binding.tvSubtitle4.text = getString(R.string.sample_started) binding.btnSamplestart.visibility = View.GONE } } - stringData.contains("#SC") -> { - hemoCubeViewModel.messages.postValue("Sample Completed \nGathering data") + resultData.contains("#SC") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED + hemoCubeViewModel.messages.postValue( + getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)) fetchResult() testingTrace.stop() } - resultData.contains("REND") -> { + resultData.contains("ovf") -> { hemoCubeViewModel.messages.postValue( - "Data collected \n" + - " Processing data" + getString(R.string.power_bank) ) + } + + resultData.contains("REND") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED + hemoCubeViewModel.messages.postValue( + getString(R.string.data_collected_processing_data) + ) + val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) var bufferIntensity = resultLines[1].split(' ')[1].trim() led1BufferForDevice = if (isUsingExistingBuffer) { @@ -391,7 +423,7 @@ class HemoCubeFragment : Fragment() { // If the test is ongoing, don't allow the back button action // You can optionally show a message to the user indicating why the back button is disabled // For example, show a Toast or Snackbar. - showToast("Test is ongoing. Cannot go back.") + showToast(R.string.test_go_noback) } else { // If the test is not ongoing, you can trigger the back action of the hosting activity activity?.onBackPressed() @@ -400,7 +432,7 @@ class HemoCubeFragment : Fragment() { private fun processResult() { try { - hemoCubeViewModel.messages.postValue("processing result") + hemoCubeViewModel.messages.postValue(getString(R.string.processing_result)) val deviceLog = resultData val pInfo = requireActivity().packageManager.getPackageInfo( @@ -408,36 +440,52 @@ class HemoCubeFragment : Fragment() { ) val version = pInfo.versionName - val led1Average = log10(led1BufferForDevice?.div(led1SampleForDevice!!) ?: 0.0) - val led2Average = log10(led2BufferForDevice?.div(led2SampleForDevice!!) ?: 0.0) - val led3Average = log10(led3BufferForDevice?.div(led3SampleForDevice!!) ?: 0.0) - val led4Average = log10(led4BufferForDevice?.div(led4SampleForDevice!!) ?: 0.0) + val led1Average = log10(led1BufferForDevice.div(led1SampleForDevice)) + val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice)) + val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice)) + val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice)) val deviceRatio = led3Average / led1Average - if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)?.get(0)!! - || led2BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(1)?.get(0)!! - || led3BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(2)?.get(0)!! - || led4BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(3)?.get(0)!! + if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) + ?.get(0)!! + || led2BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 1 + )?.get(0)!! + || led3BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 2 + )?.get(0)!! + || led4BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 3 + )?.get(0)!! ) { validationError = true allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)" activity?.runOnUiThread { - binding.errorMessage.text = "Error: Invalid Test. Improper buffer reading (low)" + "\n" + binding.errorMessage.text = getString(R.string.error_improper_buffer_low) binding.errorMessage.visibility = View.VISIBLE } } - if (led1BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)?.get(1)!! - || led2BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(1)?.get(1)!! - || led3BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(2)?.get(1)!! - || led4BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(3)?.get(1)!! + if (led1BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) + ?.get(1)!! + || led2BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 1 + )?.get(1)!! + || led3BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 2 + )?.get(1)!! + || led4BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 3 + )?.get(1)!! ) { validationError = true allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n" activity?.runOnUiThread { binding.errorMessage.text = - "Error: Invalid Test. Improper buffer reading (high)" + getString(R.string.error_improper_buffer_high) binding.errorMessage.visibility = View.VISIBLE + binding.btnSubmit.isEnabled = true + binding.btnSubmit.isClickable = true } } @@ -457,13 +505,13 @@ class HemoCubeFragment : Fragment() { constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(1) fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!! - _predictedDenovixRatio = fittedAbs3?.div(fittedAbs1!!)!! + _predictedDenovixRatio = fittedAbs3.div(fittedAbs1) - if (fittedAbs1!! <= fittedAbs2!!) { + if (fittedAbs1 <= fittedAbs2) { validationError = true allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n" activity?.runOnUiThread { - binding.errorMessage.text = "Error: Invalid Test. Problem with de-oxygenation" + binding.errorMessage.text = getString(R.string.error_invalid_test) binding.errorMessage.visibility = View.VISIBLE } } @@ -471,7 +519,7 @@ class HemoCubeFragment : Fragment() { if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) { validationError = true activity?.runOnUiThread { - binding.errorMessage.text = "Error: Negative Abs. Retake Blank Reading" + binding.errorMessage.text = getString(R.string.error_negative_abs) binding.errorMessage.visibility = View.VISIBLE } } @@ -515,10 +563,13 @@ class HemoCubeFragment : Fragment() { this.errorMessages = allErrorMessages this.resultData = deviceLog this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString() - this.batteryCapacity = hemoCubeViewModel.getBatteryCapacity(requireContext()).toString() - this.batteryMaxCapacity = hemoCubeViewModel.getBatteryMaxCapacity(requireContext()).toString() + this.batteryCapacity = + hemoCubeViewModel.getBatteryCapacity(requireContext()).toString() + this.batteryMaxCapacity = + hemoCubeViewModel.getBatteryMaxCapacity(requireContext()).toString() this.batteryTemperature = hemoCubeViewModel.getBatteryTemperature().toString() - this.batteryVoltage = hemoCubeViewModel.getBatteryVoltage(requireContext()).toString() + this.batteryVoltage = + hemoCubeViewModel.getBatteryVoltage(requireContext()).toString() } if (!isUsingExistingBuffer) { @@ -532,17 +583,17 @@ class HemoCubeFragment : Fragment() { } // if (!validationError) { - activity?.runOnUiThread { - binding.btnSubmit.visibility = View.VISIBLE - binding.btnSubmit.isEnabled = true - binding.btnSubmit.isClickable = true - binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) - } + activity?.runOnUiThread { + binding.btnSubmit.visibility = View.VISIBLE + binding.btnSubmit.isEnabled = true + binding.btnSubmit.isClickable = true + binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) + } // } } catch (e: Exception) { Toast.makeText( requireContext(), - "Error while processing device data", + R.string.error_processing_device_data, Toast.LENGTH_SHORT ).show() Firebase.crashlytics.recordException(e) @@ -554,28 +605,28 @@ class HemoCubeFragment : Fragment() { hemoCubeViewModel.messages.postValue("result classification") if (calculatedRatio != null) { if (calculatedRatio < 0.05) - return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume" + return getString(R.string.error_repeat_test_higher_volume) if (calculatedRatio in 0.05..0.155) - return "Normal" + return getString(R.string.normal) if (calculatedRatio in 0.155..0.175) - return "Negative Borderline. Repeat Test" + return getString(R.string.negative_borderline) if (calculatedRatio in 0.175..0.22) - return "Sickle Cell Trait" + return getString(R.string.sickle_cell_trait) if (calculatedRatio in 0.22..0.25) - return "Positive for Sickle Cell. HPLC for Confirmation" + return getString(R.string.positive_for_sickle_cell) if (calculatedRatio in 0.25..0.35) - return "Sickle Cell Disease" + return getString(R.string.sickle_cell_disease) if (calculatedRatio > 0.35) - return "Inconclusive. Repeat with test with lower volume of blood" + return getString(R.string.error_repeat_test_lower_volume) } else { - return "INVALID" + return getString(R.string.invalid) } } catch (e: Exception) { - showToast("error while performing classification") + showToast(R.string.error_classification) Firebase.crashlytics.recordException(e) - return "ERROR" + return getString(R.string.error) } - return "INVALID" + return getString(R.string.invalid) } private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String { @@ -583,28 +634,28 @@ class HemoCubeFragment : Fragment() { hemoCubeViewModel.messages.postValue("result classification") if (predictedDenovixRatio != null) { if (predictedDenovixRatio in 0.0..0.16) - return "Normal" + return getString(R.string.normal) if (predictedDenovixRatio in 0.16..0.165) - return "Negative Borderline" + return getString(R.string.negative_borderline) if (predictedDenovixRatio in 0.165..0.235) - return "Sickle Cell Trait" + return getString(R.string.sickle_cell_trait) if (predictedDenovixRatio in 0.235..0.24) - return "Positive Borderline" + return getString(R.string.positive_borderline) if (predictedDenovixRatio in 0.24..1.0) - return "Sickle Cell Disease" + return getString(R.string.sickle_cell_disease) } else { - return "INVALID" + return getString(R.string.invalid) } } catch (e: Exception) { - showToast("error while performing classification") + showToast(R.string.error_classification) Firebase.crashlytics.recordException(e) - return "ERROR" + return getString(R.string.error) } - return "INVALID" + return getString(R.string.invalid) } - private fun showToast(message: String) { - Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() + private fun showToast(messageResId: Int) { + Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show() } private fun startBufferProcess() { 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 b8e4d44..c6a9746 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 @@ -1,11 +1,13 @@ package com.example.hpostesting.presentation.hemocube +import android.app.Application import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.SharedPreferences import android.os.BatteryManager import android.util.Log +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -37,12 +39,12 @@ class HemoCubeViewModel @Inject constructor( ) : ViewModel() { var isServiceConnected = false val progressBar = MutableLiveData(false) - val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() - val messages = MutableLiveData() - private val sharedPreference: SharedPreferences = - context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() + val messages = MutableLiveData() + private val sharedPreference: SharedPreferences = + context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) - // Get the device ID of the device you want to retrieve data for (e.g., the first device in the list) + // Get the device ID of the device you want to retrieve data for (e.g., the first device in the list) private val _networkStatusLiveData = NetworkStatusLiveData(context) val allUserData = hemoCubeDao.getAll() @@ -63,23 +65,43 @@ class HemoCubeViewModel @Inject constructor( if (kitSerial != null) { testDetails?.kitSerial = kitSerial } - testDetails?.testStatus = testStatus - try { - 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") + fun uploadHemoCubeResultToDatabase( + isOnline: Boolean, + testStatus: Boolean, + kitSerial: String? + ) = + viewModelScope.launch { + if (kitSerial != null) { + testDetails?.kitSerial = kitSerial + } + testDetails?.testStatus = testStatus + + try { + 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}") } - } catch (e: Exception) { - Log.e("Testdb", "Upload failed: ${e.message}") } + + + fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) = + viewModelScope.launch { + addResultTestToDbforbuffercheck(bufferCheckData) + } + + fun getDeviceData(deviceId: String?) = viewModelScope.launch { + deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) }) } @@ -200,18 +222,75 @@ class HemoCubeViewModel @Inject constructor( userData.reportUploadTime = SimpleDateFormat( "yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).format(Calendar.getInstance().time) - when (repository.addTestToDatabase(userData)) { - is Response.Success -> { - fireBaseBulkUpload.postValue("Success") - updateLocalFlag(userData._id) - } + testDetails?.appVersion = DataHolder.hemoCubeTestData?.appVersion + testDetails?.deviceId = DataHolder.hemoCubeTestData?.deviceId + testDetails?.deviceSerialNumber = + sharedPreference.getString(Constants.USER_ID, "").toString() + testDetails?.kitSerial = sharedPreference.getString(Constants.KIT_NUMBER, "").toString() + testDetails?.led1Buffer = DataHolder.hemoCubeTestData?.led1Buffer + testDetails?.led2Buffer = DataHolder.hemoCubeTestData?.led2Buffer + testDetails?.led3Buffer = DataHolder.hemoCubeTestData?.led3Buffer + testDetails?.led4Buffer = DataHolder.hemoCubeTestData?.led4Buffer + testDetails?.led1Sample = DataHolder.hemoCubeTestData?.led1Sample + testDetails?.led2Sample = DataHolder.hemoCubeTestData?.led2Sample + testDetails?.led3Sample = DataHolder.hemoCubeTestData?.led3Sample + testDetails?.led4Sample = DataHolder.hemoCubeTestData?.led4Sample + testDetails?.led1Average = DataHolder.hemoCubeTestData?.led1Average + testDetails?.led2Average = DataHolder.hemoCubeTestData?.led2Average + testDetails?.led3Average = DataHolder.hemoCubeTestData?.led3Average + testDetails?.led4Average = DataHolder.hemoCubeTestData?.led4Average + testDetails?.abs1 = DataHolder.hemoCubeTestData?.abs1 + testDetails?.abs2 = DataHolder.hemoCubeTestData?.abs2 + testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3 + testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4 + testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio + testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio + testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio + testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients + testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! + testDetails?.prdClassification = + DataHolder.hemoCubeTestData?.prdClassification.toString() + testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString() + testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString() + testDetails?.batteryMaxCapacity = + DataHolder.hemoCubeTestData?.batteryMaxCapacity.toString() + testDetails?.batteryTemperature = + DataHolder.hemoCubeTestData?.batteryTemperature.toString() + testDetails?.batteryVoltage = DataHolder.hemoCubeTestData?.batteryVoltage.toString() + } - else -> { - fireBaseBulkUpload.postValue("Error") + private fun addResultTestToDb() { + viewModelScope.launch { + try { + testDetails!!.reportUploadTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + + when (val response = repository.addTestToDatabase(testDetails)) { + is Response.Success -> { + val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0) + with(sharedPreference.edit()) { + putInt(Constants.KIT_COUNT, kitCount.plus(1)) + apply() + } + Log.i("Testdb", "Data uploaded to Firestore successfully") + fireBaseUpload.postValue("Success") + testDetails.localFlag = true + hemoCubeDao.insertAll(testDetails) + } + + is Response.Error -> { + Log.e("Testdb", "Error uploading data to Firestore: $response") + fireBaseUpload.postValue("Error") + hemoCubeDao.insertAll(testDetails) + } + } + } catch (e: Exception) { + Log.e("Testdb", "Exception during data upload: ${e.message}") + fireBaseUpload.postValue("Error") } } } - } fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) { viewModelScope.launch { @@ -235,13 +314,16 @@ class HemoCubeViewModel @Inject constructor( hemoCubeDao.updateFieldById(id = userId, true) } - fun addUser(userData: HemoCubeTestData) = viewModelScope.launch { - hemoCubeDao.insertAll(userData) - } + private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) { + viewModelScope.launch { + try { - fun deleteById(userId: String) = viewModelScope.launch { - hemoCubeDao.deleteById(id = userId) - } + when (val response = + repository.addTestToDatabaseforBufferCheck(bufferCheckData)) { + is Response.Success -> { + Log.i("Testdb", "Data uploaded to Firestore successfully") + fireBaseUpload.postValue("Success") + } private fun updateBufferLocalFlag(bufferId: String) = viewModelScope.launch { hemoCubeBufferDao.updateFieldById(id = bufferId, true) @@ -255,8 +337,16 @@ class HemoCubeViewModel @Inject constructor( level * 100 / scale.toFloat() } - return batteryPct - } + fun bulkAddResultTestToDb(userData: HemoCubeTestData) { + viewModelScope.launch { + userData.reportUploadTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + when (repository.addTestToDatabase(userData)) { + is Response.Success -> { + fireBaseBulkUpload.postValue("Success") + updateLocalFlag(userData._id) + } fun getBatteryTemperature(): Float? { val batteryTemp: Float? = batteryStatus?.let { intent -> @@ -264,7 +354,66 @@ class HemoCubeViewModel @Inject constructor( temperature.toFloat() / 10 } - return batteryTemp + private fun updateLocalFlag(userId: String) = viewModelScope.launch { + hemoCubeDao.updateFieldById(id = userId, true) + } + + fun addUser(userData: HemoCubeTestData) = viewModelScope.launch { + hemoCubeDao.insertAll(userData) + } + + fun deleteById(userId: String) = viewModelScope.launch { + hemoCubeDao.deleteById(id = userId) + } + + fun getBatteryLevel(): Float? { + val batteryPct: Float? = batteryStatus?.let { intent -> + val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) + val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) + level * 100 / scale.toFloat() + } + + return batteryPct + } + + fun getBatteryTemperature(): Float? { + val batteryTemp: Float? = batteryStatus?.let { intent -> + val temperature = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0 + temperature.toFloat() / 10 + } + + return batteryTemp + } + + fun getBatteryVoltage(context: Context): Float { + val batteryIntent = + context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + val voltage = batteryIntent?.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) ?: 0 + + // milli-volts to volts + return voltage.toFloat() / 1000 + } + + fun getBatteryCapacity(context: Context): Int { + val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + val currentCapacity = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) + + return currentCapacity + } + + fun getBatteryMaxCapacity(context: Context): Float { + val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + val designCapacity = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + val currentCapacity = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) + + // Calculate the estimated maximum battery capacity in mAh + val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100 + + return maxCapacity + } } fun getBatteryVoltage(context: Context): Float { diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt index fcc4110..ca197fe 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt @@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat import androidx.core.view.get import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.presentation.testRight.UsbService import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialProber @@ -72,6 +73,12 @@ open class HemocubeActivity : AppCompatActivity() { viewModel.isServiceConnected = false } } + override fun attachBaseContext(newBase: Context?) { + val languageCode = LanguageManager.getSavedLanguage(newBase!!) + LanguageManager.setLocale(newBase, languageCode) + super.attachBaseContext(newBase) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) 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..f6bed53 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 @@ -1,5 +1,6 @@ package com.example.hpostesting.presentation.testRight +import com.example.hpostesting.presentation.dashboard.DashboardActivity import android.content.Context import android.content.Intent import android.content.SharedPreferences @@ -14,7 +15,6 @@ import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.model.test.TestRightResultType import com.example.hpostesting.data.model.test.TestType -import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.util.MyUtils.calculateAgeFromYOB import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.ktx.firestore 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..baf2b05 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 diff --git a/app/src/main/res/drawable/indianoil.jpg b/app/src/main/res/drawable/indianoil.jpg new file mode 100644 index 0000000..3f6e528 Binary files /dev/null and b/app/src/main/res/drawable/indianoil.jpg differ diff --git a/app/src/main/res/drawable/karnataka.png b/app/src/main/res/drawable/karnataka.png new file mode 100644 index 0000000..4d12e96 Binary files /dev/null and b/app/src/main/res/drawable/karnataka.png differ diff --git a/app/src/main/res/drawable/person.xml b/app/src/main/res/drawable/person.xml new file mode 100644 index 0000000..98730cd --- /dev/null +++ b/app/src/main/res/drawable/person.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/user.png b/app/src/main/res/drawable/user.png new file mode 100644 index 0000000..68711d0 Binary files /dev/null and b/app/src/main/res/drawable/user.png differ diff --git a/app/src/main/res/layout/activity_digital_card.xml b/app/src/main/res/layout/activity_digital_card.xml new file mode 100644 index 0000000..3e8cf38 --- /dev/null +++ b/app/src/main/res/layout/activity_digital_card.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_hemocube.xml b/app/src/main/res/layout/activity_hemocube.xml index a91259a..2d0b501 100644 --- a/app/src/main/res/layout/activity_hemocube.xml +++ b/app/src/main/res/layout/activity_hemocube.xml @@ -1,10 +1,8 @@ - - + app:layout_constraintTop_toTopOf="parent" /> - - - - - - \ No newline at end of file + + diff --git a/app/src/main/res/layout/content_dashboard.xml b/app/src/main/res/layout/content_dashboard.xml index 02c00de..27f66f1 100644 --- a/app/src/main/res/layout/content_dashboard.xml +++ b/app/src/main/res/layout/content_dashboard.xml @@ -18,4 +18,6 @@ app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/dashboard_navigation" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_digital_card.xml b/app/src/main/res/layout/fragment_digital_card.xml new file mode 100644 index 0000000..7259d46 --- /dev/null +++ b/app/src/main/res/layout/fragment_digital_card.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +