Compare commits

..

2 Commits

23 changed files with 440 additions and 334 deletions

View File

@@ -20,14 +20,9 @@ android {
applicationId "in.sminnovations.hpostesting.server"
minSdk 30
targetSdk 34
versionCode 138
versionName "2.1.133"
versionCode 134
versionName "2.1.132"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ''
}
}
}
@@ -59,12 +54,6 @@ android {
packagingOptions {
exclude 'mockito-extensions/org.mockito.plugins.MockMaker'
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.22.1'
}
}
// testOptions {
// unitTests {
// includeAndroidResources = true

View File

@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "in.sminnovations.hpostesting.dev",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 127,
"versionName": "2.1.127",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 21
}

View File

@@ -24,12 +24,13 @@
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission
android:name="android.permission.ACCOUNT_MANAGER"
<uses-permission android:name="android.permission.ACCOUNT_MANAGER"
tools:ignore="ProtectedPermissions" />
<application
android:name="com.example.hpostesting.HPOSTestingApplication"
android:allowBackup="true"
@@ -45,7 +46,7 @@
<activity
android:name="com.example.hpostesting.presentation.main_base.UpdateValuesActivity"
android:exported="false"
android:screenOrientation="portrait" />
android:screenOrientation="portrait"/>
<service
android:name="com.example.hpostesting.util.MyAuthenticatorService"
@@ -218,4 +219,5 @@
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

@@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.18.1)
project("native-server")
# Create the shared library from server.cpp
add_library(
native-server
SHARED
server.cpp
)
# Find Android logging library
find_library(
log-lib
log
)
# Link logging library to our native lib
target_link_libraries(
native-server
${log-lib}
)

View File

@@ -1,53 +0,0 @@
#include <jni.h>
#include <string>
#include <unordered_map>
std::vector<std::pair<int, std::pair<std::string, std::unordered_map<std::string, std::string>>>> firebaseDataOrdered = {
{0, {"dev", {{"apiKey", "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"}, {"appId", "1:650071678820:android:a53292637abb7c0d6c6471"}, {"projectId", "hpos-af3cc"}, {"storageBucket", "hpos-af3cc.appspot.com"}}}},
{1, {"qc-qa", {{"apiKey", "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs"}, {"appId", "1:1004619739289:android:3dbcefb10ea99654e5c808"}, {"projectId", "hpos-qa"}, {"storageBucket", "hpos-qa.appspot.com"}}}},
{2, {"prod", {{"apiKey", "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs"}, {"appId", "1:1012719870714:android:d8d7c962d96f4097de5f43"}, {"projectId", "hpos-prod"}, {"storageBucket", "hpos-prod.appspot.com"}}}},
{3, {"pre prod", {{"apiKey", "AIzaSyDYySi27LioZGNisP1NfnNU5inJX_0FT38"}, {"appId", "1:121176529204:android:e6841fdac57bdc95bbed61"}, {"projectId", "hpos-preprod"}, {"storageBucket", "hpos-preprod.appspot.com"}}}},
{4, {"SMI R&D", {{"apiKey", "AIzaSyAVxpilbB804iRCCpMBDjjmdZhQguctGHM"}, {"appId", "1:327771387914:android:a3b4ed2e42ea6e38dc87f3"}, {"projectId", "hposrandd"}, {"storageBucket", "hposrandd.firebasestorage.app"}}}},
{5, {"molbio", {{"apiKey", "molbio"}, {"appId", "molbio"}, {"projectId", "molbio"}, {"storageBucket", "molbio"}}}}
};
extern "C"
JNIEXPORT jobject JNICALL
Java_com_example_hpostesting_firebase_FirebaseManager_getFirebaseDataMap(JNIEnv *env,jobject thiz) {
jclass mapClass = env->FindClass("java/util/LinkedHashMap"); // ✅ preserves insertion order
jmethodID init = env->GetMethodID(mapClass, "<init>", "()V");
jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
jobject outerMap = env->NewObject(mapClass, init);
for (const auto &entry : firebaseDataOrdered) {
int order = entry.first;
const std::string &outerKeyStr = entry.second.first;
const auto &innerMapData = entry.second.second;
jobject innerMap = env->NewObject(mapClass, init);
// "int" field for order
jstring intKey = env->NewStringUTF("int");
jstring intValue = env->NewStringUTF(std::to_string(order).c_str());
env->CallObjectMethod(innerMap, put, intKey, intValue);
env->DeleteLocalRef(intKey);
env->DeleteLocalRef(intValue);
// actual firebase config keys
for (const auto &innerPair : innerMapData) {
jstring key = env->NewStringUTF(innerPair.first.c_str());
jstring value = env->NewStringUTF(innerPair.second.c_str());
env->CallObjectMethod(innerMap, put, key, value);
env->DeleteLocalRef(key);
env->DeleteLocalRef(value);
}
jstring outerKey = env->NewStringUTF(outerKeyStr.c_str());
env->CallObjectMethod(outerMap, put, outerKey, innerMap);
env->DeleteLocalRef(outerKey);
env->DeleteLocalRef(innerMap);
}
return outerMap;
}

View File

@@ -15,6 +15,7 @@ package com.example.hpostesting
import android.app.Application
import com.example.hpostesting.firebase.FirebaseManager
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.FirebaseFirestoreSettings
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
@@ -22,16 +23,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import javax.inject.Inject
@HiltAndroidApp
class HPOSTestingApplication : Application() {
companion object {
init {
System.loadLibrary("native-server")
}
}
@Inject
lateinit var firebaseManager: FirebaseManager
override fun onCreate() {
@@ -46,5 +39,4 @@ class HPOSTestingApplication : Application() {
val firestore = firebaseManager.getCurrentFirestore()
firestore.firestoreSettings = firestoreSettings
}
}

View File

@@ -28,8 +28,8 @@ object Constants {
const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
var MOLBIO_INTEGRATION = true
var FIREBASE_INTEGRATION = false
const val MOLBIO_INTEGRATION = false
const val FIREBASE_INTEGRATION = true
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI"
@@ -44,9 +44,10 @@ object Constants {
const val DELAY_BETWEEN_COMMANDS: Long = 1000
const val TEST_RIGHT_TOTAL_PIXEL = 3694
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 34
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM = 9
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM_RANDD= 129
const val MAXIMUM_TEST_ALLOWED_SINGLE_TEST = 0
const val RANGE_IN_RESULT_CALCULATIONS = 10
@@ -1586,6 +1587,7 @@ object Constants {
//Trueheme for 10mm
//Before changing below values review before
//classification borderline metric
const val TEST_FOR_10MM = "SMI/SC-2-D10/"
const val positiveBoderLineMetricCheck10mmMin = 1.3
const val positiveBoderLineMetricCheck10mmMax = 1.66
const val negativeBoderLineMetricCheck10mmMin = 2.0
@@ -1603,6 +1605,7 @@ object Constants {
const val sickleCellDiseaseMax10mm = 0.7
//Trueheme for 2mm
//classification borderline metric
const val TEST_FOR_2MM = "SMI/SC/"
const val positiveBoderLineMetricCheck2mmMin = 0.8
const val positiveBoderLineMetricCheck2mmMax = 1.1
const val negativeBoderLineMetricCheck2mmMin = 1.5
@@ -1619,6 +1622,25 @@ object Constants {
const val sickleCellDiseaseMin2mm = 0.45
const val sickleCellDiseaseMax2mm = 0.7
//Trueheme for 10mm Single Test
//classification borderline metric
const val singleTest = "SMI/SC-ST/"
const val positiveBoderLineMetricCheck2mmStMin = 1.3
const val positiveBoderLineMetricCheck2mmStMax = 1.66
const val negativeBoderLineMetricCheck2mmStMin = 2.0
const val negativeBoderLineMetricCheck2mmStMax = 2.4
//classification device ratio
const val normalMinSt2mm = 0.07
const val normalMaxSt2mm = 0.23
const val negativeBorderlineMinSt2mm = 0.23
const val negativeBorderlineMaxSt2mm = 0.27
const val sickleCellTraitMinSt2mm = 0.27
const val sickleCellTraitMaxSt2mm = 0.31
const val positiveForSickleCellMinSt2mm = 0.31
const val positiveForSickleCellMaxSt2mm = 0.39
const val sickleCellDiseaseMinSt2mm = 0.39
const val sickleCellDiseaseMaxSt2mm = 0.7
const val min2mmLed1 = 0.34
const val max2mmLed1 = 1.48
const val min2mmLed2 = 0.04

View File

@@ -38,15 +38,16 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
}
override fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData>,
filePath: String, dataList: List<HemoCubeTestData>,
): Boolean {
try {
val formattedFileName = fileName.replace(
Regex("[^a-zA-Z0-9.-]"),
"_"
) // Replace special characters with underscores
val filePath = File(getExternalStorageDirectory(), formattedFileName)
val writer = FileWriter(filePath)
// Create the file directly from the provided path
val file = File(filePath)
// Ensure parent directory exists
file.parentFile?.mkdirs()
val writer = FileWriter(file)
val csvWriter = CSVWriter(writer)
// Write CSV header
val header = arrayOf(
@@ -103,8 +104,8 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
csvWriter.writeNext(header)
// Filter and write data rows where testStatus is true
val filteredDataList = dataList.filter { it.testStatus == true }
for (data in filteredDataList) {
// val filteredDataList = dataList.filter { it.testStatus == true }
for (data in dataList) {
val row = arrayOf(
data._id,
data.name,
@@ -226,8 +227,8 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
csvWriter.writeNext(header)
// Filter and write data rows where testStatus is true
val filteredDataList = dataList.filter { it.testStatus == true }
for (data in filteredDataList) {
//val filteredDataList = dataList.filter { it.testStatus == true }
for (data in dataList) {
val row = arrayOf(
data._id,
data.name,

View File

@@ -243,10 +243,9 @@ object AppModule {
@Provides
@Singleton
fun provideNetworkMonitor(
@ApplicationContext context: Context
): NetworkMonitor {
return NetworkMonitor(context).apply { startMonitoring() }
fun provideNetworkMonitor(@ApplicationContext context: Context): NetworkMonitor {
return NetworkMonitor(context)
}
}

View File

@@ -14,9 +14,7 @@ package com.example.hpostesting.firebase
import android.content.Context
import android.content.Intent
import android.os.Process
import android.util.Log
import androidx.core.content.edit
import com.example.hpostesting.data.constant.Constants
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.firestore.FirebaseFirestore
@@ -29,53 +27,20 @@ import kotlinx.coroutines.launch
import javax.inject.Inject
class FirebaseManager @Inject constructor(private val context: Context) {
private var defaultServers = mutableListOf<FirebaseConfig>()
external fun getFirebaseDataMap(): Map<String, Map<String, String>>
private val map: Map<String, Map<String, String>> = getFirebaseDataMap()
companion object {
init {
System.loadLibrary("native-server") //use NDK ro secure somethings
}
}
private val sharedPreferencesServerConfig = context.getSharedPreferences("FirebaseConfigPrefs", Context.MODE_PRIVATE)
private val sharedPreferencesDev = context.getSharedPreferences("DevMode",Context.MODE_PRIVATE)
private var currentFirestore: FirebaseFirestore = FirebaseFirestore.getInstance()
private var currentStorage: FirebaseStorage = FirebaseStorage.getInstance()
private var updateStatus = false
private fun Map<String, String>.toFirebaseConfig(server: String): FirebaseConfig? {
val apiKey = this["apiKey"] ?: return null
val appId = this["appId"] ?: return null
val projectId = this["projectId"] ?: return null
val storageBucket = this["storageBucket"] ?: return null
return FirebaseConfig(
serverName = server,
projectId = projectId,
appId = appId,
apiKey = apiKey,
storageBucket = storageBucket
)
}
fun populate() {
defaultServers.clear()
map.forEach { (server, config) ->
config.toFirebaseConfig(server)?.let {
defaultServers.add(it)
} ?: Log.w("Firebase", "Skipping $server due to missing keys")
}
}
var updateStatus = false
private val defaultServers = listOf(
// i have it in different place look down
firebaseConfigProd, firebaseConfigDev , firebaseConfigQaQc, firebaseConfigPreProd
)
init {
populate()
val lastSelectedServer = getLastSelectedServer()
switchServer(lastSelectedServer)
}
@@ -96,17 +61,11 @@ class FirebaseManager @Inject constructor(private val context: Context) {
fun getCurrentStorage(): FirebaseStorage = currentStorage
fun switchServer(firebaseConfig: FirebaseConfig) {
if (firebaseConfig.serverName =="molbio" ||firebaseConfig.apiKey == "molbio"){
saveSelectedServer(firebaseConfig)
makeMolbioAsBackEnd()
}else {
makeSMIBackEnd()
saveSelectedServer(firebaseConfig)
val firebaseApp = getOrInitializeFirebaseApp(firebaseConfig)
currentFirestore = FirebaseFirestore.getInstance(firebaseApp)
currentStorage = FirebaseStorage.getInstance(firebaseApp)
updateStatus = true
}
saveSelectedServer(firebaseConfig)
val firebaseApp = getOrInitializeFirebaseApp(firebaseConfig)
currentFirestore = FirebaseFirestore.getInstance(firebaseApp)
currentStorage = FirebaseStorage.getInstance(firebaseApp)
updateStatus = true
}
@@ -114,6 +73,7 @@ class FirebaseManager @Inject constructor(private val context: Context) {
val existingApp = FirebaseApp.getApps(context).find { it.name == firebaseConfig.serverName }
return if (existingApp != null) {
existingApp
} else {
@@ -165,16 +125,6 @@ class FirebaseManager @Inject constructor(private val context: Context) {
fun getAvailableServers(): List<FirebaseConfig> {
return defaultServers
}
private fun makeMolbioAsBackEnd(){
Constants.FIREBASE_INTEGRATION = false
Constants.MOLBIO_INTEGRATION = true
restartApp()
}
private fun makeSMIBackEnd(){
Constants.FIREBASE_INTEGRATION = true
Constants.MOLBIO_INTEGRATION = false
}
}
fun restartApp(context: Context) {
@@ -191,51 +141,34 @@ fun delayedRestart(context: Context) {
}
}
//
//
//private val firebaseConfigDev = FirebaseConfig(
// serverName = "dev",
// apiKey = "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I",
// appId = "1:650071678820:android:a53292637abb7c0d6c6471",
// projectId = "hpos-af3cc",
// storageBucket = "hpos-af3cc.appspot.com"
//)
//private val firebaseConfigQaQc = FirebaseConfig(
// serverName = "qc-qa",
// apiKey = "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs",
// appId = "1:1004619739289:android:3dbcefb10ea99654e5c808",
// projectId = "hpos-qa",
// storageBucket = "hpos-qa.appspot.com"
//)
//
//private val firebaseConfigProd = FirebaseConfig(
// serverName = "prod",
// apiKey = "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs",
// appId = "1:1012719870714:android:d8d7c962d96f4097de5f43",
// projectId = "hpos-prod",
// storageBucket = "hpos-prod.appspot.com"
//)
//
//private val firebaseConfigPreProd = FirebaseConfig(
// serverName = "pre prod",
// apiKey = "AIzaSyDYySi27LioZGNisP1NfnNU5inJX_0FT38",
// appId = "1:121176529204:android:e6841fdac57bdc95bbed61",
// projectId = "hpos-preprod",
// storageBucket = "hpos-preprod.appspot.com"
//)
//
//private val firebaseConfigSmiRandD= FirebaseConfig(
// serverName = "SMI R&D",
// apiKey = "AIzaSyAVxpilbB804iRCCpMBDjjmdZhQguctGHM",
// appId = "1:327771387914:android:a3b4ed2e42ea6e38dc87f3",
// projectId = "hposrandd",
// storageBucket = "hposrandd.firebasestorage.app"
//)
//
//private val configMolbio = FirebaseConfig(
// serverName = "molbio",
// apiKey = "molbio",
// appId = "molbio",
// projectId = "molbio",
// storageBucket = "molbio"
//)
private val firebaseConfigDev = FirebaseConfig(
serverName = "dev",
apiKey = "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I",
appId = "1:650071678820:android:a53292637abb7c0d6c6471",
projectId = "hpos-af3cc",
storageBucket = "hpos-af3cc.appspot.com"
)
private val firebaseConfigQaQc = FirebaseConfig(
serverName = "qc-qa",
apiKey = "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs",
appId = "1:1004619739289:android:3dbcefb10ea99654e5c808",
projectId = "hpos-qa",
storageBucket = "hpos-qa.appspot.com"
)
private val firebaseConfigProd = FirebaseConfig(
serverName = "prod",
apiKey = "AIzaSyA_O0oZGzy3Kiw9fiLQ3OFPME-xQJP88vs",
appId = "1:1012719870714:android:d8d7c962d96f4097de5f43",
projectId = "hpos-prod",
storageBucket = "hpos-prod.appspot.com"
)
private val firebaseConfigPreProd = FirebaseConfig(
serverName = "pre prod",
apiKey = "AIzaSyDYySi27LioZGNisP1NfnNU5inJX_0FT38",
appId = "1:121176529204:android:e6841fdac57bdc95bbed61",
projectId = "hpos-preprod",
storageBucket = "hpos-preprod.appspot.com"
)

View File

@@ -22,12 +22,13 @@ import android.util.Log
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContentProviderCompat.requireContext
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.Constants.TEST_FOR_10MM
import com.example.hpostesting.data.constant.Constants.TEST_FOR_2MM
import com.example.hpostesting.data.constant.Constants.singleTest
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.main_base.DashboardActivity
import com.example.hpostesting.presentation.hb_test.HBTestActivity
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestActivity
@@ -54,7 +55,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
private var fromWhere = "Home"
private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding
private lateinit var firebaseManager: FirebaseManager
private var maxTest = 9
private lateinit var sharedPreference: SharedPreferences
var sdkHandler: SDKHandler? = null
@@ -73,21 +74,28 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
}
private fun processScannedData(contents: String) {//edited auto selection of cuvette size
if (contents.contains("SMI/SC/")) {
if(contents.contains(TEST_FOR_2MM)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
} else if (contents.contains("SMI/SC-2-D10/")) {
}else if(contents.contains(TEST_FOR_10MM)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
} else {
}else if(contents.contains(singleTest)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mmSt")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm for single test", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(contents)
}else{
Toast.makeText(this, R.string.invalid_kit, Toast.LENGTH_LONG).show()
}
}
@@ -129,42 +137,32 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
firebaseManager = FirebaseManager(this)
val currentServer = firebaseManager.getLastSelectedServer().serverName
binding = ActivityKitScanBinding.inflate(layoutInflater)
sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
binding.toolbar.title = "Kit Serial Number"
fromWhere = intent.getStringExtra("fromWhere").toString()
val maxTest = if (currentServer == "SMI R&D"){
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM_RANDD
Log.d(TAG, "onCreate RandD mode")
}else {
if (sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm") {
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
} else {
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM
}
if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm"){
maxTest = Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
}else if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "10mm"){
maxTest = Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM
} else if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mmSt").toString() == "10mmSt"){
maxTest = Constants.MAXIMUM_TEST_ALLOWED_SINGLE_TEST
}
val time = timeDifference(sharedPreference.getString(Constants.KIT_TIME, "").toString())
val kitNum = sharedPreference.getString(Constants.KIT_NUMBER, "").toString()
// Toast.makeText(this@KitScanActivity,"Test MAx time"+ time+"-Test count-"+kitNum,Toast.LENGTH_SHORT).show()
// Toast.makeText(this@KitScanActivity,"Test MAx time"+ time+"-Test count-"+kitNum,Toast.LENGTH_SHORT).show()
// if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
// moveToNext()
// }else{
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
moveToNext()
} else {
}else{
if (DataHolder.sampleReadCounter <= maxTest && kitNum != "" && time < Constants.MAX_KIT_TIME) {
moveToNext()
} else {
Toast.makeText(
this@KitScanActivity,
"Limit Reached, Use New KIT for testing",
Toast.LENGTH_SHORT
).show()
Toast.makeText(this@KitScanActivity, "Limit Reached, Use New KIT for testing", Toast.LENGTH_SHORT).show()
DataHolder.sampleReadCounter = 0
DataHolder.kitSerial = ""
@@ -226,19 +224,27 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
if (serialNumber.contains("SMI/SC/")) {
if(serialNumber.contains(TEST_FOR_2MM)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "2mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show()
} else if (serialNumber.contains("SMI/SC-2-D10/")) {
}else if(serialNumber.contains(TEST_FOR_10MM)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mm")
apply()
}
Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show()
}else if(serialNumber.contains(singleTest)){
with(sharedPreference.edit()) {
putString(Constants.CUVETTE_SIZE, "10mmSt")
apply()
}
Toast.makeText(this, "Selected cuvette size: 2mm for single test", Toast.LENGTH_SHORT).show()
binding.nameEditText.setText(serialNumber)
}
val kitTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
@@ -315,8 +321,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
if (mScannerInfoList.isNotEmpty()) {
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
} else {
Toast.makeText(this, "Scanner Is not available In this device", Toast.LENGTH_LONG)
.show()
Toast.makeText(this,"Scanner Is not available In this device", Toast.LENGTH_LONG).show()
}
}
@@ -354,7 +359,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
runOnUiThread {
val editableResult: Editable = Editable.Factory.getInstance().newEditable(result)
processScannedData(result)
// binding.nameEditText.text = editableResult
// binding.nameEditText.text = editableResult
}
}
@@ -366,30 +371,33 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
// }
private fun isSerialValid(s: String): Boolean {
if (s.contains("SMI/SC/")) {
if (s.length != 17) {
binding.nameEditText.error =
"Invalid Kit Serial Number, correct example SMI/SC/000/00/000"
if (s.contains(TEST_FOR_2MM)) {
if(s.length != 17){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC/000/00/000"
return false
}
} else if (s.contains("SMI/SC-2-D10/")) {
if (s.length != 27) {
binding.nameEditText.error =
"Invalid Kit Serial Number, correct example SMI/SC-2-D10/000000/000/000"
}else if(s.contains(TEST_FOR_10MM)){
if(s.length != 27){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC-2-D10/000000/000/000"
return false
}
} else {
}else if(s.contains(singleTest)){
if(s.length != 27){
binding.nameEditText.error = "Invalid Kit Serial Number, correct example SMI/SC-ST/000000/000/000"
return false
}
}else{
return false
}
return true
}
private fun moveToNext() {
if (fromWhere == "Main") {
if (DataHolder.selectedTestType == TestType.HB_EST) {
if(fromWhere == "Main"){
if(DataHolder.selectedTestType == TestType.HB_EST){
val i = Intent(applicationContext, HBTestActivity::class.java)
startActivity(i)
} else {
}else{
DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) {
Constants.DEVICE_TYPE_HEMOCUBE -> {
@@ -442,7 +450,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
true
}
}
private fun timeDifference(createdAt: String): Long {
val currentTime = Calendar.getInstance().time
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())

View File

@@ -14,7 +14,6 @@
package com.example.hpostesting.presentation
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -34,7 +33,6 @@ import com.example.hpostesting.util.MyUtils
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
@SuppressLint("CustomSplashScreen")
class SplashActivity : AppCompatActivity() {
private lateinit var binding: ActivitySplashBinding

View File

@@ -1,21 +1,16 @@
package com.example.hpostesting.presentation.main_base
import com.example.hpostesting.data.constant.Constants.FIREBASE_INTEGRATION
import com.example.hpostesting.data.constant.Constants.MOLBIO_INTEGRATION
class AppVersionTapManager {
private var tapCount = 0
private val maxTapCount = 5
val shouldEnable = FIREBASE_INTEGRATION && !MOLBIO_INTEGRATION
val notEnable = MOLBIO_INTEGRATION && !FIREBASE_INTEGRATION
fun registerTap(onMaxTapsReached: () -> Unit) {
tapCount++
if (tapCount >= maxTapCount && shouldEnable) {
onMaxTapsReached()
reset()
}
if (tapCount >= maxTapCount) {
onMaxTapsReached()
reset()
}
}
private fun reset() {
tapCount = 0

View File

@@ -89,7 +89,6 @@ class PanelFragment : Fragment() {
binding.btnDeviceInfo.visibility = View.VISIBLE
binding.btnResetPassword.visibility = View.VISIBLE
binding.btnUpdateValues.visibility = View.VISIBLE
binding.btnRnd.visibility = View.GONE
}else{
binding.btnResetPassword.visibility = View.GONE
binding.btnDeviceProvision.visibility = View.GONE
@@ -103,7 +102,6 @@ class PanelFragment : Fragment() {
binding.btnSubmit.visibility = View.GONE
binding.btnDeviceInfo.visibility = View.VISIBLE
binding.btnUpdateValues.visibility = View.GONE
binding.btnRnd.visibility = View.GONE
}
binding.btnResetPassword.setOnClickListener{
@@ -144,7 +142,6 @@ class PanelFragment : Fragment() {
startActivity(intent)
}
binding.btnFiles.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "file/*"

View File

@@ -14,38 +14,58 @@
package com.example.hpostesting.presentation.main_base
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import androidx.preference.SwitchPreferenceCompat
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseConfig
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.trueheme_test.TrueHemeTestViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage
import com.google.firebase.storage.ktx.storageMetadata
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
private var isLanguageChanged = false
class SlideshowFragment : Fragment() {
private var selectedItem = "10mm"
private val values = arrayOf("10mm", "2mm")
private val values = arrayOf("10mm", "2mm", "10mmSt")
private lateinit var binding: FragmentSlideshowBinding
private val trueHemeTestViewModel: TrueHemeTestViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView(
@@ -58,7 +78,9 @@ class SlideshowFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.btnDownload.setOnClickListener {
sendData()
}
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, ""))
selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString()
binding.btnGo.setOnClickListener {
@@ -80,8 +102,10 @@ class SlideshowFragment : Fragment() {
val pos: Int
if (selectedItem == "10mm") {
pos = 0
} else {
} else if (selectedItem == "2mm"){
pos = 1
} else {
pos = 2
}
binding.spinnerCuvette.adapter = adapter
@@ -113,6 +137,111 @@ class SlideshowFragment : Fragment() {
childFragmentManager.beginTransaction().replace(binding.container.id, PrefsFragment())
.commit()
}
private fun sendData() {
//This data will saved in firebase storage check in HPOS-Prod
val dialog = AlertDialog.Builder(requireContext())
.setTitle("Downloading")
.setMessage("Please wait...")
.setCancelable(false)
.create()
dialog.show()
downloadLocalDBData(dialog)
}
private fun downloadLocalDBData(dialog: DialogInterface) {
var csvDownloaded = false
trueHemeTestViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
if (!csvDownloaded) {
val downloadList = mutableListOf<HemoCubeTestData>()
userDataList.forEach { userData ->
Log.d("DownloadDebug", "userData: $userData, isCSVCreated: ${userData.isCSVCreated}")
downloadList.add(userData)
}
if (downloadList.isNotEmpty()) {
// Set flag to prevent multiple executions due to observer
csvDownloaded = true
// Launch coroutine to handle CSV creation and upload
lifecycleScope.launch {
try {
// Call suspend function to create CSV and wait for result
val csvFile = trueHemeTestViewModel.createCSVNew(downloadList, requireContext())
if (csvFile != null && csvFile.exists() && csvFile.length() > 0) {
uploadToFirebaseStorage(csvFile)
Toast.makeText(
requireContext(),
"CSV file created successfully at ${csvFile.absolutePath}",
Toast.LENGTH_LONG
).show()
} else {
csvDownloaded = false // Reset flag if failed
Toast.makeText(
requireContext(),
"CSV file creation failed, please try again",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
csvDownloaded = false // Reset flag if exception
e.printStackTrace()
Toast.makeText(
requireContext(),
"Error creating CSV file: ${e.message}",
Toast.LENGTH_SHORT
).show()
} finally {
dialog.dismiss()
}
}
} else {
Toast.makeText(requireContext(), "No data to download", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
}
}
}
private fun uploadToFirebaseStorage(file: File) {
// Get Firebase Storage reference
val storage = Firebase.storage
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val storageRef = storage.reference.child("!!!csv_files/hemocube_data_$timestamp.csv")
// Create file metadata
val metadata = storageMetadata {
contentType = "text/csv"
}
// Upload file
val uploadTask = storageRef.putFile(Uri.fromFile(file), metadata)
uploadTask
.addOnSuccessListener {
Toast.makeText(
requireContext(),
"CSV file uploaded to Firebase successfully",
Toast.LENGTH_SHORT
).show()
}
.addOnFailureListener { exception ->
Log.e("FirebaseUpload", "Upload failed", exception)
Toast.makeText(
requireContext(),
"Failed to upload CSV to Firebase",
Toast.LENGTH_SHORT
).show()
}
.addOnProgressListener { taskSnapshot ->
val progress = (100.0 * taskSnapshot.bytesTransferred / taskSnapshot.totalByteCount)
Log.d("FirebaseUpload", "Upload is $progress% done")
}
}
}
class PrefsFragment : PreferenceFragmentCompat() {
@@ -200,6 +329,7 @@ class PrefsFragment : PreferenceFragmentCompat() {
}
}
val appVersionPreference = Preference(requireContext()).apply {
title = "App Version"
summary =
@@ -210,10 +340,11 @@ class PrefsFragment : PreferenceFragmentCompat() {
tapManager.registerTap {
firebaseManager.setDevModeOn(true)
val devConfig = servers.find { it.serverName == "dev" }
if (firebaseManager.getDevMode() && currentServer != "dev") {
Toast.makeText(requireContext(), "Now you are a Developer", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Setting Up developer Environmnet", Toast.LENGTH_SHORT).show()
switchFirebaseServer(devConfig!!)
}
if (preferenceScreen.findPreference<SwitchPreferenceCompat>("developer_options") == null) {

View File

@@ -593,7 +593,7 @@ class TrueHemeFragment : Fragment() {
binding.btnSubmit.visibility = View.VISIBLE
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd"))
binding.ivCheck.visibility = View.VISIBLE
}
} else {
@@ -736,7 +736,7 @@ class TrueHemeFragment : Fragment() {
}
}
private fun processResult(){
private fun processResult() {
try {
hemoCubeViewModel.messages.postValue(getString(R.string.processing_result))
val deviceLog = resultData

View File

@@ -32,6 +32,20 @@ import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.Constants.negativeBoderLineMetricCheck2mmStMax
import com.example.hpostesting.data.constant.Constants.negativeBoderLineMetricCheck2mmStMin
import com.example.hpostesting.data.constant.Constants.negativeBorderlineMaxSt2mm
import com.example.hpostesting.data.constant.Constants.negativeBorderlineMinSt2mm
import com.example.hpostesting.data.constant.Constants.normalMaxSt2mm
import com.example.hpostesting.data.constant.Constants.normalMinSt2mm
import com.example.hpostesting.data.constant.Constants.positiveBoderLineMetricCheck2mmStMax
import com.example.hpostesting.data.constant.Constants.positiveBoderLineMetricCheck2mmStMin
import com.example.hpostesting.data.constant.Constants.positiveForSickleCellMaxSt2mm
import com.example.hpostesting.data.constant.Constants.positiveForSickleCellMinSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellDiseaseMaxSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellDiseaseMinSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellTraitMaxSt2mm
import com.example.hpostesting.data.constant.Constants.sickleCellTraitMinSt2mm
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.TestStatus
import com.example.hpostesting.data.model.TestState
@@ -1196,6 +1210,20 @@ class TrueHemeTestFragment : Fragment() {
binding.btnSamplestart.isEnabled = true
return
}
}else if(cuvetteSizeSP == "2mmSt"){
inRange2mmLed1 = led1Average in min2mmLed1..max2mmLed1
inRange2mmLed2 = led2Average in min2mmLed2..max2mmLed2
if(!inRange2mmLed1 || !inRange2mmLed2){
trueHemeTestViewModel.messages.postValue("Absorbance out-of-Range - Repeat test with adequate blood volume and Incubation time")
this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code
binding.testing.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true
binding.btnSamplestart.isEnabled = true
return
}
}
}
}
@@ -1478,6 +1506,25 @@ class TrueHemeTestFragment : Fragment() {
return "Positive for Sickle Cell. Confirm with HPLC"
}
}
}else if(cuvetteSizeSP == "2mmSt"){
if (deviceRatioClass == "Negative Borderline") {
if (borderlineMetric < negativeBoderLineMetricCheck2mmStMin){//1.34
return "Sickle Cell Trait"
}else if(borderlineMetric > negativeBoderLineMetricCheck2mmStMax){
return "Normal"
}else if(borderlineMetric > negativeBoderLineMetricCheck2mmStMin && borderlineMetric < negativeBoderLineMetricCheck2mmStMax){
return "Negative borderline. Confirm with HPLC"
}
}
if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") {
if (borderlineMetric < positiveBoderLineMetricCheck2mmStMin){//1.34
return "Sickle Cell Disease"
}else if(borderlineMetric > positiveBoderLineMetricCheck2mmStMax){
return "Sickle Cell Trait"
}else if(borderlineMetric > positiveBoderLineMetricCheck2mmStMin && borderlineMetric < positiveBoderLineMetricCheck2mmStMax){
return "Positive for Sickle Cell. Confirm with HPLC"
}
}
}
}
} catch (e: Exception) {
@@ -1548,6 +1595,22 @@ class TrueHemeTestFragment : Fragment() {
if (ratio in sickleCellDiseaseMin2mm..sickleCellDiseaseMax2mm){
return "Sickle Cell Disease"
}
}else if(cuvetteSize == "2mmSt"){
if (ratio in normalMinSt2mm..normalMaxSt2mm) {
return "Normal"
}
if (ratio in negativeBorderlineMinSt2mm..negativeBorderlineMaxSt2mm){
return "Negative Borderline"
}
if (ratio in sickleCellTraitMinSt2mm..sickleCellTraitMaxSt2mm){
return "Sickle Cell Trait"
}
if (ratio in positiveForSickleCellMinSt2mm..positiveForSickleCellMaxSt2mm){//0.36
return "Positive for Sickle Cell. HPLC for Confirmation"
}
if (ratio in sickleCellDiseaseMinSt2mm..sickleCellDiseaseMaxSt2mm){
return "Sickle Cell Disease"
}
}
} else {

View File

@@ -53,11 +53,15 @@ import com.example.hpostesting.util.NetworkMonitor
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Headers
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.ResponseBody
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
@@ -775,7 +779,44 @@ class TrueHemeTestViewModel @Inject constructor(
return maxCapacity
}
suspend fun createCSVNew(data: List<HemoCubeTestData>, context: Context): File? {
return withContext(Dispatchers.IO) {
try {
val timestamp = System.currentTimeMillis()
val fileName = "hemocube_data_$timestamp.csv"
// Create file in app's external files directory
val appFile = File(context.getExternalFilesDir(null), fileName)
// Ensure this file is used by localFileDataSource
val exportSuccess = localFileDataSource.exportDataToCSV(appFile.absolutePath, data)
if (exportSuccess) {
// Update database records
data.forEach { item ->
hemoCubeDao.updateCSVFieldById(
item._id,
true
)
}
// Verify file exists and has content
if (appFile.exists() && appFile.length() > 0) {
return@withContext appFile
} else {
Log.e("CSVCreation", "File creation verified failed: exists=${appFile.exists()}, size=${appFile.length()}")
return@withContext null
}
} else {
Log.e("CSVCreation", "exportDataToCSV returned false")
return@withContext null
}
} catch (e: Exception) {
Log.e("CSVCreation", "Error creating CSV", e)
return@withContext null
}
}
}
fun createCSV(hemoCubeTestData: List<HemoCubeTestData>, appContext: Context) =
viewModelScope.launch {
val fileName = "HPOS${getCurrentDate()}.csv"

View File

@@ -1,6 +1,5 @@
package com.example.hpostesting.util
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
@@ -13,8 +12,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.net.HttpURLConnection
import java.net.URL
@@ -26,7 +23,7 @@ import javax.inject.Singleton
class NetworkMonitor @Inject constructor(
@ApplicationContext private val context: Context
) {
private var isMonitoringStarted = false
private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
@@ -52,10 +49,7 @@ class NetworkMonitor @Inject constructor(
}
}
@SuppressLint("NewApi")
fun startMonitoring() {
if (isMonitoringStarted) return // Already started, do nothing.
isMonitoringStarted = true
// Check initial connectivity status
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
@@ -72,8 +66,6 @@ class NetworkMonitor @Inject constructor(
.build()
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
// Start periodic checks:
startPeriodicPingCheck()
}
fun stopMonitoring() { // never needed to call
@@ -104,14 +96,4 @@ class NetworkMonitor @Inject constructor(
}
}
}
private fun startPeriodicPingCheck(intervalMillis: Long = 1 * 60_000L) {
networkScope.launch {
while (isActive) {
performPingCheck()
delay(intervalMillis)
}
}
}
}

View File

@@ -55,21 +55,7 @@
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<Button
android:id="@+id/btn_rnd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="R and D"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<Button
<Button
android:id="@+id/btn_diagnostics"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -81,7 +67,7 @@
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_rnd" />
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_auto_dac"
@@ -167,7 +153,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_deviceProvision" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_update_values"
android:layout_width="match_parent"
@@ -175,13 +160,12 @@
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:text="Update valueLs"
android:text="Update values"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_reset_password" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_firefox"
android:layout_width="match_parent"

View File

@@ -88,12 +88,22 @@
app:layout_constraintBottom_toBottomOf="@id/spinnerCuvette"
app:layout_constraintStart_toEndOf="@id/spinnerCuvette"
app:layout_constraintTop_toTopOf="@id/spinnerCuvette" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="Send Data To Server"
android:textColor="@color/white"
app:cornerRadius="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spinnerCuvette"
/>
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/btn_add_size"
app:layout_constraintTop_toBottomOf="@+id/btn_download"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="10dp"/>

View File

@@ -25,7 +25,6 @@
<item>ka</item>
<!-- Use language codes (e.g., en, kn) as values -->
</string-array>
<string-array name="district">
<item>Mysuru</item>
<item>Kodagu</item>

View File

@@ -25,3 +25,4 @@ plugins {
task clean(type: Delete) {
delete rootProject.buildDir
}