Compare commits

...

29 Commits

Author SHA1 Message Date
chandrashekhar reddy
a72bd3d59e app version 130.2, default remote config values updated 2025-01-13 16:49:21 +05:30
chandrashekhar reddy
54be3a1037 app version 130.1, without borderline classification and buffer limit 2024-12-31 15:10:53 +05:30
chandrashekhar reddy
69055b5498 app version 130, without borderline classification 2024-12-30 12:00:39 +05:30
chandrashekhar reddy
7dde6bf976 app version 130, without borderline classification 2024-12-30 11:42:04 +05:30
chandrashekhar reddy
ee0f1d748a Merge remote-tracking branch 'origin/dev-server-2.1.130' into dev-server-2.1.130 2024-12-30 11:36:57 +05:30
chandrashekhar reddy
d32e7b6cbb app version 130, without borderline classification 2024-12-30 11:36:08 +05:30
Chandrashekhar Reddy
d306d0b9fa Update .gitlab-ci.yml file 2024-10-16 09:23:33 +00:00
chandrashekhar reddy
8e074e01c9 rename of the branch 2024-10-15 15:56:03 +05:30
chandrashekhar reddy
6b0c81213e rename of the branch 2024-10-15 15:04:39 +05:30
sathwikcs
51480393da optimised the unnecessary code in json
added sever info in home fragment
removed basic data test
2024-10-09 16:55:44 +05:30
chandrashekhar reddy
d9221a3bb6 Submit button check in HemoCubeFragment 2024-10-09 15:06:05 +05:30
sathwikcs
569155d193 Server switching is implemented
pipeline fixed
version 2.1.128
2024-10-08 17:19:38 +05:30
sathwikcs
ad029e4cce Server switching is implemented
version 2.1.128
2024-10-08 17:03:32 +05:30
sathwikcs
31654be3bb Server switching is implemented
version 2.1.128
2024-10-08 16:53:44 +05:30
sathwikcs
738375afc5 Server switching is implemented
version 2.1.128
2024-10-08 16:44:43 +05:30
chandrashekhar reddy
e77b4d9a23 Changes in 127, added HBTest screen option 2024-09-17 12:47:53 +05:30
chandrashekhar reddy
cf429b4fc3 Changes in 127, added HBTest screen option 2024-09-11 17:11:53 +05:30
chandrashekhar reddy
30df9732a7 127 version with all updates, credential.txt file location changed, Ui updated. 2024-09-10 11:43:48 +05:30
chandrashekhar reddy
a1ce200ad8 127 version with all updates, credential.txt file location changed, Ui updated. 2024-09-10 11:37:00 +05:30
chandrashekhar reddy
2512556e8a 127 version, pipeline fixed 2024-08-24 11:24:16 +05:30
chandrashekhar reddy
4c1429f3cb 127 version, updated the normal threshold 2024-08-22 18:59:25 +05:30
chandrashekhar reddy
d0f33582df 127 version, updated the normal threshold 2024-08-22 18:57:23 +05:30
chandrashekhar reddy
6be6a65e95 127 version, refresh buffer separated, added buffer flag, added remote config to manage threshold, remove cards direct test can be performed 2024-08-09 12:02:13 +05:30
chandrashekhar reddy
b32c5e29d0 127 version, refresh buffer separated, added buffer flag, added remote config to manage threshold 2024-08-03 22:33:34 +05:30
chandrashekhar reddy
453af33baa 125 version, net kit button issue resolved 2024-07-25 12:49:54 +05:30
chandrashekhar reddy
dd345a1b31 new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 20:29:39 +05:30
chandrashekhar reddy
ba52efc670 new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 15:15:58 +05:30
chandrashekhar reddy
eb60025add new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 15:07:42 +05:30
chandrashekhar reddy
5e1283873d new 125 version, changes in HemoCubeFragment Ip address in home, led1Average at line 1004 change if condition, in home download csv for all. 2024-07-15 14:44:19 +05:30
62 changed files with 2653 additions and 410 deletions

View File

@@ -1,63 +1,31 @@
# This file is a template, and might need editing before it works on your project.
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml
# Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny
# If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template.
image: eclipse-temurin:17-jdk-jammy image: eclipse-temurin:17-jdk-jammy
variables: variables:
# ANDROID_COMPILE_SDK is the version of Android you're compiling with.
# It should match compileSdkVersion.
ANDROID_COMPILE_SDK: "34" ANDROID_COMPILE_SDK: "34"
# ANDROID_BUILD_TOOLS is the version of the Android build tools you are using.
# It should match buildToolsVersion.
ANDROID_BUILD_TOOLS: "33.0.2" ANDROID_BUILD_TOOLS: "33.0.2"
# It's what version of the command line tools we're going to download from the official site.
# Official Site-> https://developer.android.com/studio/index.html
# There, look down below at the cli tools only, sdk tools package is of format:
# commandlinetools-os_type-ANDROID_SDK_TOOLS_latest.zip
# when the script was last modified for latest compileSdkVersion, it was which is written down below
ANDROID_SDK_TOOLS: "9477386" ANDROID_SDK_TOOLS: "9477386"
# Packages installation before running script # Keystore credentials stored as GitLab CI/CD variables
KEYSTORE_PASSWORD: $KS_PASSWORD
KEY_ALIAS: $KS_ALIAS
KEY_PASSWORD: $KS_KEY_PASSWORD
before_script: before_script:
- apt-get --quiet update --yes - apt-get --quiet update --yes
- apt-get --quiet install --yes wget unzip - apt-get --quiet install --yes wget unzip
# Setup path as android_home for moving/exporting the downloaded sdk into it
- export ANDROID_HOME="${PWD}/android-sdk-root" - export ANDROID_HOME="${PWD}/android-sdk-root"
# Create a new directory at specified location
- install -d $ANDROID_HOME - install -d $ANDROID_HOME
# Here we are installing androidSDK tools from official source,
# (the key thing here is the url from where you are downloading these sdk tool for command line, so please do note this url pattern there and here as well)
# after that unzipping those tools and
# then running a series of SDK manager commands to install necessary android SDK packages that'll allow the app to build
- wget --no-verbose --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip - wget --no-verbose --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip
- unzip -q -d "$ANDROID_HOME/cmdline-tools" "$ANDROID_HOME/cmdline-tools.zip" - unzip -q -d "$ANDROID_HOME/cmdline-tools" "$ANDROID_HOME/cmdline-tools.zip"
- mv -T "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools" - mv -T "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools"
- export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin - export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin
# Nothing fancy here, just checking sdkManager version
- sdkmanager --version - sdkmanager --version
# use yes to accept all licenses
- yes | sdkmanager --licenses > /dev/null || true - yes | sdkmanager --licenses > /dev/null || true
- sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" - sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"
- sdkmanager "platform-tools" - sdkmanager "platform-tools"
- sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" - sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}"
# Not necessary, but just for surity
- chmod +x ./gradlew - chmod +x ./gradlew
# Basic android and gradle stuff
# Check linting
lintDebug: lintDebug:
interruptible: true interruptible: true
stage: build stage: build
@@ -69,7 +37,6 @@ lintDebug:
expose_as: "lint-report" expose_as: "lint-report"
when: always when: always
# Make Project
assembleDebug: assembleDebug:
interruptible: true interruptible: true
stage: build stage: build
@@ -79,7 +46,67 @@ assembleDebug:
paths: paths:
- app/build/outputs/ - app/build/outputs/
# Run all tests, if any fails, interrupt the pipeline(fail it) # Job for building signed release APK for tags containing "release" on any branch
assembleRelease:
stage: build
script:
- |
if [[ "$CI_COMMIT_TAG" =~ release ]]; then
echo "Decoding keystore file from Base64"
# Debug: Print the first few characters of BASE64_KEYSTORE
echo "First 20 characters of BASE64_KEYSTORE: ${BASE64_KEYSTORE:0:20}..."
# Check if BASE64_KEYSTORE is a file path
if [[ "$BASE64_KEYSTORE" == /* ]] && [[ -f "$BASE64_KEYSTORE" ]]; then
echo "BASE64_KEYSTORE appears to be a file path. Reading content..."
BASE64_CONTENT=$(cat "$BASE64_KEYSTORE")
else
echo "BASE64_KEYSTORE is not a file path. Using as-is."
BASE64_CONTENT="$BASE64_KEYSTORE"
fi
# Remove any potential whitespace or newline characters
CLEANED_KEYSTORE=$(echo "$BASE64_CONTENT" | tr -d '[:space:]')
# Attempt to decode and save to a file
if echo "$CLEANED_KEYSTORE" | base64 -d > "$CI_PROJECT_DIR/app/keystore.jks" 2>/tmp/base64_error; then
echo "Keystore file decoded successfully"
else
echo "Error decoding keystore file:"
cat /tmp/base64_error
echo "First 20 characters of cleaned content: ${CLEANED_KEYSTORE:0:20}..."
exit 1
fi
# Check if the keystore file was created and has content
if [ -s "$CI_PROJECT_DIR/app/keystore.jks" ]; then
echo "Keystore file created successfully"
# Print file size for verification
ls -l "$CI_PROJECT_DIR/app/keystore.jks"
else
echo "Error: Keystore file is empty or not created"
exit 1
fi
echo "Building signed release APK"
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file="$CI_PROJECT_DIR/app/keystore.jks" \
-Pandroid.injected.signing.store.password="$KEYSTORE_PASSWORD" \
-Pandroid.injected.signing.key.alias="$KEY_ALIAS" \
-Pandroid.injected.signing.key.password="$KEY_PASSWORD"
else
echo "Tag '$CI_COMMIT_TAG' does not contain 'release'. Skipping release build."
fi
artifacts:
paths:
- app/build/outputs/
expire_in: never
rules:
- if: $CI_COMMIT_TAG =~ /release/
when: always
- when: never
debugTests: debugTests:
needs: [lintDebug, assembleDebug] needs: [lintDebug, assembleDebug]
interruptible: true interruptible: true

View File

@@ -2,3 +2,4 @@
### Release key ### Release key
key0: prime24 key0: prime24

View File

@@ -15,13 +15,13 @@ android {
namespace 'in.sminnovations.hpostesting' namespace 'in.sminnovations.hpostesting'
// dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production // dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production
// server -> for server switching for internal test
defaultConfig { defaultConfig {
applicationId "in.sminnovations.hpostesting.iocl" applicationId "in.sminnovations.hpostesting.server"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 125 versionCode 132
versionName "2.1.125" versionName "2.1.130.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -76,6 +76,7 @@ dependencies {
implementation platform('com.google.firebase:firebase-bom:32.1.0') implementation platform('com.google.firebase:firebase-bom:32.1.0')
implementation("com.google.firebase:firebase-perf-ktx") implementation("com.google.firebase:firebase-perf-ktx")
implementation("com.google.firebase:firebase-crashlytics-ktx") implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-config-ktx")
implementation("com.google.firebase:firebase-analytics-ktx") implementation("com.google.firebase:firebase-analytics-ktx")
implementation 'com.google.firebase:firebase-firestore-ktx' implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-auth-ktx' implementation 'com.google.firebase:firebase-auth-ktx'
@@ -89,7 +90,6 @@ dependencies {
implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta12") implementation("com.google.firebase:firebase-appdistribution-api-ktx:16.0.0-beta12")
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'com.google.android.play:core:1.10.3'
implementation 'io.nats:jnats:2.11.4' implementation 'io.nats:jnats:2.11.4'
@@ -121,10 +121,9 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
implementation 'com.opencsv:opencsv:5.9' implementation 'com.opencsv:opencsv:5.9'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1' implementation 'com.github.mik3y:usb-serial-for-android:3.8.0'
implementation "androidx.fragment:fragment-ktx:1.6.2" implementation "androidx.fragment:fragment-ktx:1.6.2"
// CSV read, write // CSV read, write
implementation 'com.opencsv:opencsv:5.9' implementation 'com.opencsv:opencsv:5.9'
@@ -164,7 +163,7 @@ dependencies {
implementation("androidx.work:work-runtime-ktx:2.9.0") implementation("androidx.work:work-runtime-ktx:2.9.0")
// implementation("io.nats:jnats:2.11.2") // implementation("io.nats:jnats:2.11.2")
implementation 'com.google.android.play:core:1.10.3' // implementation 'com.google.android.play:core:1.10.3'
implementation fileTree(dir: 'libs', include: ['*.aar']) implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation 'io.nats:jnats:2.11.4' implementation 'io.nats:jnats:2.11.4'

View File

@@ -1,64 +1,36 @@
{ {
"project_info": { "project_info": {
"project_number": "243503501547", "project_number": "650071678820",
"project_id": "iocl-iisc-hpos", "project_id": "hpos-af3cc",
"storage_bucket": "iocl-iisc-hpos.appspot.com" "storage_bucket": "hpos-af3cc.appspot.com"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:243503501547:android:f17de652a3524d047feeae", "mobilesdk_app_id": "1:650071678820:android:f6fd45e2f6a63aef6c6471",
"android_client_info": { "android_client_info": {
"package_name": "com.iocl_iisc.hposqc" "package_name": "in.sminnovations.hpostesting.server"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyBPxgcDkZfZMr8cFrkMWkVf1a-MstzWC1k" "current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [] "other_platform_oauth_client": [
}
}
},
{ {
"client_info": { "client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"mobilesdk_app_id": "1:243503501547:android:e1bb0f338c8448dd7feeae", "client_type": 3
"android_client_info": {
"package_name": "in.sminnovations.hposregistration.iocl"
} }
}, ]
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBPxgcDkZfZMr8cFrkMWkVf1a-MstzWC1k"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:243503501547:android:18b8b33b2dc3776d7feeae",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.iocl"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBPxgcDkZfZMr8cFrkMWkVf1a-MstzWC1k"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
} }
} }
} }

View File

@@ -4,17 +4,34 @@
"type": "APK", "type": "APK",
"kind": "Directory" "kind": "Directory"
}, },
"applicationId": "in.sminnovations.hpostesting.iocl", "applicationId": "in.sminnovations.hpostesting.dev",
"variantName": "release", "variantName": "release",
"elements": [ "elements": [
{ {
"type": "SINGLE", "type": "SINGLE",
"filters": [], "filters": [],
"attributes": [], "attributes": [],
"versionCode": 125, "versionCode": 127,
"versionName": "2.1.125", "versionName": "2.1.127",
"outputFile": "app-release.apk" "outputFile": "app-release.apk"
} }
], ],
"elementType": "File" "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

@@ -25,6 +25,12 @@
<uses-permission android:name="android.permission.USB_PERMISSION" /> <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"
tools:ignore="ProtectedPermissions" />
<application <application
android:name="com.example.hpostesting.HPOSTestingApplication" android:name="com.example.hpostesting.HPOSTestingApplication"
android:allowBackup="true" android:allowBackup="true"
@@ -74,13 +80,17 @@
android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity" android:name="com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.hb_test.HBTestActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity" android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.jig.JigActivity" android:name="com.example.hpostesting.presentation.jig.JigActivity"
android:exported="false" android:exported="true"
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity" android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity"
@@ -124,7 +134,7 @@
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity" android:name="com.example.hpostesting.presentation.dashboard.DashboardActivity"
android:exported="false" android:exported="true"
android:label="@string/title_activity_dashboard" android:label="@string/title_activity_dashboard"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"
@@ -166,7 +176,7 @@
</activity> </activity>
<activity <activity
android:name="com.example.hpostesting.presentation.testRight.TestRightActivity" android:name="com.example.hpostesting.presentation.testRight.TestRightActivity"
android:exported="false" android:exported="true"
android:noHistory="true" android:noHistory="true"
android:parentActivityName="com.example.hpostesting.presentation.MainActivity" android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"

View File

@@ -14,25 +14,29 @@
package com.example.hpostesting package com.example.hpostesting
import android.app.Application import android.app.Application
import com.example.hpostesting.firebase.FirebaseManager
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.FirebaseFirestoreSettings import com.google.firebase.firestore.FirebaseFirestoreSettings
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import javax.inject.Inject
@HiltAndroidApp @HiltAndroidApp
class HPOSTestingApplication : Application() { class HPOSTestingApplication : Application() {
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) @Inject
lateinit var firebaseManager: FirebaseManager
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
// You can now use firebaseManager here after Hilt injects it
val firestoreSettings = FirebaseFirestoreSettings.Builder() val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(true) // Enable offline persistence if needed .setPersistenceEnabled(true) // Enable offline persistence if needed
.build() .build()
val firestore = FirebaseFirestore.getInstance() val firestore = firebaseManager.getCurrentFirestore()
firestore.firestoreSettings = firestoreSettings firestore.firestoreSettings = firestoreSettings
} }
} }

View File

@@ -16,7 +16,7 @@ package com.example.hpostesting.data.constant
object Constants { object Constants {
const val CENTER_NAME ="" const val CENTER_NAME =""
const val DISTRICT ="" const val DISTRICT =""
const val FLAGS_ENABLED = false//testing flag disable then pass buffer and sample checks const val BUFFER_FLAGS_ENABLED = true//testing flag disable then pass buffer and sample checks
const val ABS_FLAGS_ENABLED = false const val ABS_FLAGS_ENABLED = false
const val IP_ADDRESS="ip_address" const val IP_ADDRESS="ip_address"
const val QUICK_CAPTURE="quick_capture" const val QUICK_CAPTURE="quick_capture"
@@ -28,7 +28,8 @@ object Constants {
const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb" const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb"
const val ABHA_APP_PACKAGE = "in.ndhm.phr" const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val MOLBIO_INTEGRATION = true const val MOLBIO_INTEGRATION = false
const val FIREBASE_INTEGRATION = true
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in" const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69" const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI" const val DEVICE_ID_API = "deviceIDAPI"
@@ -44,8 +45,8 @@ object Constants {
const val TEST_RIGHT_TOTAL_PIXEL = 3694 const val TEST_RIGHT_TOTAL_PIXEL = 3694
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 35 const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 34
const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM = 10 const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE10MM = 9
const val RANGE_IN_RESULT_CALCULATIONS = 10 const val RANGE_IN_RESULT_CALCULATIONS = 10
@@ -107,6 +108,7 @@ object Constants {
const val DEVICE_ID = "DEVICE_ID" const val DEVICE_ID = "DEVICE_ID"
const val LABNAME = "LAB_NAME" const val LABNAME = "LAB_NAME"
const val CUVETTE_SIZE = "CUVETTE_SIZE" const val CUVETTE_SIZE = "CUVETTE_SIZE"
const val LAST_UPDATED = "LAST_UPDATED"
const val IS_TOKEN_AVAILABLE = "IS_TOKEN_AVAILABLE" const val IS_TOKEN_AVAILABLE = "IS_TOKEN_AVAILABLE"
const val BUFFER_LED_LOWER_BOUND = 21000 const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 23500 const val BUFFER_LED_UPPER_BOUND = 23500
@@ -1587,15 +1589,15 @@ object Constants {
const val positiveBoderLine10mm2 = 1.66 const val positiveBoderLine10mm2 = 1.66
const val negativeBoderLine10mm1 = 2.0 const val negativeBoderLine10mm1 = 2.0
const val negativeBoderLine10mm2 = 2.4 const val negativeBoderLine10mm2 = 2.4
const val normalMin10mm = 0.1 const val normalMin10mm = 0.07
const val normalMax10mm = 0.23 const val normalMax10mm = 0.23
const val negativeBorderlineMin10mm = 0.23 const val negativeBorderlineMin10mm = 0.23
const val negativeBorderlineMax10mm = 0.25 const val negativeBorderlineMax10mm = 0.27
const val sickleCellTraitMin10mm = 0.25 const val sickleCellTraitMin10mm = 0.27
const val sickleCellTraitMax10mm = 0.31 const val sickleCellTraitMax10mm = 0.31
const val positiveForSickleCellMin10mm = 0.31 const val positiveForSickleCellMin10mm = 0.31
const val positiveForSickleCellMax10mm = 0.43 const val positiveForSickleCellMax10mm = 0.39
const val sickleCellDiseaseMin10mm = 0.43 const val sickleCellDiseaseMin10mm = 0.39
const val sickleCellDiseaseMax10mm = 0.7 const val sickleCellDiseaseMax10mm = 0.7
//Hemocube for 2mm //Hemocube for 2mm
const val positiveBoderLine2mm1 = 0.8 const val positiveBoderLine2mm1 = 0.8
@@ -1622,6 +1624,11 @@ object Constants {
const val min10mmLed2 = 0.05 const val min10mmLed2 = 0.05
const val max10mmLed2 = 0.41 const val max10mmLed2 = 0.41
const val bufferMinLed1 = 21000.00
const val bufferMaxLed1 = 23000.00
const val bufferMinLed2 = 17000.00
const val bufferMaxLed2 = 19000.00
// val STATICID = listOf( // val STATICID = listOf(
// "FACTORY", // "FACTORY",

View File

@@ -21,6 +21,7 @@ import com.example.hpostesting.data.model.test.TestType
object DataHolder { object DataHolder {
var sampleId: String = "sampleId"
var selectedTestType: TestType = TestType.SICKLECERT var selectedTestType: TestType = TestType.SICKLECERT
val usbConnected = MutableLiveData(true) val usbConnected = MutableLiveData(true)
var mobileUniqueId: String? = null var mobileUniqueId: String? = null
@@ -37,12 +38,14 @@ object DataHolder {
val intensityReferenceArray = ArrayList<Double>() val intensityReferenceArray = ArrayList<Double>()
var selectedTest: UserData? = null var selectedTest: UserData? = null
var hemoCubeTestData: HemoCubeTestData? = null var hemoCubeTestData: HemoCubeTestData? = null
var bloodGroup: String = "Unknown"
var age = "0"
var kitSerial: String = "" var kitSerial: String = ""
var centerName: String = "" var centerName: String = ""
var district: String = "" var district: String = ""
var quickCapture:Boolean = false var quickCapture:Boolean = false
var location: UserData.Location? = null var location: UserData.Location? = null
var ipAddress: String ="" var ipAddress: String ="0.0"
var testExp: Boolean = true var testExp: Boolean = true
var hemocubeResult: Double? = null var hemocubeResult: Double? = null
} }

View File

@@ -26,13 +26,17 @@ enum class TestStatus(val code: Double) {
TEMPERATURE_CHECK(4.7), TEMPERATURE_CHECK(4.7),
CUVETTE_ABSENT(4.8), CUVETTE_ABSENT(4.8),
CUVETTE_PRESENT(4.9), CUVETTE_PRESENT(4.9),
CUVETTE_ABSENTR(5.1),
CUVETTE_PRESENTR(5.2),
CUVETTE_ABSENTS(7.7), CUVETTE_ABSENTS(7.7),
CUVETTE_PRESENTS(7.8), CUVETTE_PRESENTS(7.8),
BUFFER_STARTED(5.1), BUFFER_STARTED(5.4),
BUFFER_COMPLETED(5.2), BUFFER_COMPLETED(5.5),
BUFFER_PRINT_STARTED(6.0), BUFFER_PRINT_STARTED(6.0),
BUFFER_PRINT_COMPLETED(7.0), BUFFER_PRINT_COMPLETED(7.0),
SAMPLE_STARTED(8.0), SAMPLE_STARTED(8.0),
CUVETTE_ABSENTT(30.2),
CUVETTE_PRESENTT(30.1),
SAMPLE_COMPLETED(9.0), SAMPLE_COMPLETED(9.0),
SAMPLE_PRINT_STARTED(10.0), SAMPLE_PRINT_STARTED(10.0),
SAMPLE_PRINT_COMPLETED(11.0), SAMPLE_PRINT_COMPLETED(11.0),

View File

@@ -40,7 +40,8 @@ interface HemoCubeDao {
@Query("DELETE FROM hemo_cube_test_table WHERE _id = :id") @Query("DELETE FROM hemo_cube_test_table WHERE _id = :id")
suspend fun deleteById(id: String) suspend fun deleteById(id: String)
@Query("DELETE FROM hemo_cube_test_table WHERE testStatus = 0")
suspend fun deleteByStatus()
@Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id") @Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id")
suspend fun updateFieldById(id: String, newValue: Boolean) suspend fun updateFieldById(id: String, newValue: Boolean)

View File

@@ -23,7 +23,7 @@ import com.example.hpostesting.data.model.patient.UserData
@Database( @Database(
entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class],
version = 35, version = 38,
exportSchema = false exportSchema = false
) )
@TypeConverters(Converters::class) @TypeConverters(Converters::class)

View File

@@ -54,7 +54,7 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
"name", "name",
"incubationTime", "incubationTime",
"bloodGroup", "bloodGroup",
"birthYear", // Include other fields from the data class "age", // Include other fields from the data class
"state", "state",
"abhaId", "abhaId",
"userImageURL", "userImageURL",
@@ -110,7 +110,7 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
data.name, data.name,
data.incubationTime, data.incubationTime,
data.bloodGroup, data.bloodGroup,
data.birthYear, // Include other fields similarly data.age, // Include other fields similarly
data.state, data.state,
data.abhaId, data.abhaId,
data.userImageURL, data.userImageURL,
@@ -177,7 +177,7 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
"name", "name",
"incubationTime", "incubationTime",
"bloodGroup", "bloodGroup",
"birthYear", // Include other fields from the data class "age", // Include other fields from the data class
"state", "state",
"abhaId", "abhaId",
"userImageURL", "userImageURL",
@@ -233,7 +233,7 @@ class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
data.name, data.name,
data.incubationTime, data.incubationTime,
data.bloodGroup, data.bloodGroup,
data.birthYear, // Include other fields similarly data.age, // Include other fields similarly
data.state, data.state,
data.abhaId, data.abhaId,
data.userImageURL, data.userImageURL,

View File

@@ -24,7 +24,7 @@ data class HemoCubeTestData(
var name: String = "", var name: String = "",
var incubationTime: String = "", var incubationTime: String = "",
var bloodGroup: String = "", var bloodGroup: String = "",
var birthYear: String = "", var age: String = "",
var state: String = "", var state: String = "",
var abhaId: String = "", var abhaId: String = "",
var userImageURL: String = "", var userImageURL: String = "",
@@ -110,5 +110,6 @@ data class HemoCubeTestData(
var cuvetteSize: String? = "", var cuvetteSize: String? = "",
var district: String? = "", var district: String? = "",
var centerName: String? = "", var centerName: String? = "",
var ipAddress:String?= "" var ipAddress:String?= "",
var configUpdatedRecent:String?= ""
) )

View File

@@ -24,7 +24,7 @@ data class UserData(
var name: String = "", var name: String = "",
var incubationTime: String = "", var incubationTime: String = "",
var gender: String = "", var gender: String = "",
var birthYear: String = "", var age: String = "",
var abhaId: String = "", var abhaId: String = "",
var bloodGroup: String = "", var bloodGroup: String = "",
var userImageURL: String = "", var userImageURL: String = "",
@@ -63,7 +63,7 @@ fun UserData.toHemoCubeTestData() = HemoCubeTestData(
sampleid = sampleid, sampleid = sampleid,
bloodGroup = bloodGroup, bloodGroup = bloodGroup,
incubationTime = incubationTime, incubationTime = incubationTime,
birthYear = birthYear, age = age,
gender = gender, gender = gender,
state = state, state = state,
abhaId = abhaId, abhaId = abhaId,

View File

@@ -15,5 +15,6 @@ package com.example.hpostesting.data.model.test
enum class TestType { enum class TestType {
SICKLECERT, SICKLECERT,
SICKLEFIND SICKLEFIND,
HB_EST
} }

View File

@@ -14,6 +14,9 @@
package com.example.hpostesting.data.repository package com.example.hpostesting.data.repository
import android.net.Uri import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.hpostesting.util.Result import com.example.hpostesting.util.Result
import com.example.hpostesting.data.api.MolbioAuthApi import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi import com.example.hpostesting.data.api.MolbioResultApi
@@ -37,17 +40,18 @@ import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.CheckUpdateResponse
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.firebase.FirebaseManager
import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage import com.google.firebase.storage.FirebaseStorage
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.ResponseBody import okhttp3.ResponseBody
import java.io.File import java.io.File
import java.net.ConnectException import java.net.ConnectException
import java.net.SocketTimeoutException import java.net.SocketTimeoutException
import java.time.LocalTime
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
@@ -55,11 +59,30 @@ class NetworkException(message: String, cause: Throwable) : Exception(message, c
class DatabaseRepository @Inject constructor( class DatabaseRepository @Inject constructor(
@Named("Auth") private val molbioAuthApi: MolbioAuthApi, @Named("Auth") private val molbioAuthApi: MolbioAuthApi,
private val molbioResultApi: MolbioResultApi, private val molbioResultApi: MolbioResultApi,
private val firebaseManager: FirebaseManager,
) : Repository { ) : Repository {
private val db: FirebaseFirestore = Firebase.firestore private val localdb: FirebaseFirestore
private val storage = Firebase.storage get() = firebaseManager.getCurrentFirestore()
private val localStg: FirebaseStorage
get() = firebaseManager.getCurrentStorage()
// // Example function to add data to Firestore , like the basic data as test data
// @RequiresApi(Build.VERSION_CODES.O)
// fun addtodb(data: String) {
// val date = LocalTime.now()
// localdb.collection("BasicData")
// .add(mapOf("data $date" to data))
// .addOnSuccessListener {
// Log.d("UPLOAD", "Data uploaded successfully ${localdb.app.name}")
// }
// .addOnFailureListener { exception ->
// Log.d("UPLOAD", "Failed to upload data: ${exception.message} ${localdb.app.name}")
// }
// }
private suspend fun <T : Any> safeApiCall(apiCall: suspend () -> T): Result<T> { private suspend fun <T : Any> safeApiCall(apiCall: suspend () -> T): Result<T> {
return try { return try {
val response = apiCall.invoke() val response = apiCall.invoke()
@@ -108,13 +131,13 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> { override suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try { return try {
val userdata = val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await() localdb.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) { if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach { userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true) localdb.collection("patientData").document(it.id).update("testStatus", true)
} }
} }
db.collection("testData").add(data).await() localdb.collection("testData").add(data).await()
Response.Success(data._id) Response.Success(data._id)
} catch (e: Exception) { } catch (e: Exception) {
Response.Error(e) Response.Error(e)
@@ -122,15 +145,10 @@ class DatabaseRepository @Inject constructor(
} }
override suspend fun addQcTestToDatabase(data: HemoCubeTestData?): Response<String> { override suspend fun addQcTestToDatabase(data: HemoCubeTestData?): Response<String> {
return try { return try {
val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await() localdb.collection("qcData").add(data!!).await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("qcData").add(data).await()
Response.Success(data._id) Response.Success(data._id)
} catch (e: Exception) { } catch (e: Exception) {
Response.Error(e) Response.Error(e)
} }
@@ -142,7 +160,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> { override suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> {
return try { return try {
db.collection("buffers").add(data!!).await() localdb.collection("buffers").add(data!!).await()
Response.Success(data.kitno) Response.Success(data.kitno)
} catch (e: Exception) { } catch (e: Exception) {
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
@@ -152,7 +170,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> { override suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> {
return try { return try {
db.collection("diagnostics").add(data!!).await() localdb.collection("diagnostics").add(data!!).await()
Response.Success(data.deviceId) Response.Success(data.deviceId)
} catch (e: Exception) { } catch (e: Exception) {
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
@@ -163,7 +181,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestJigData(data: JigData?): Response<String> { override suspend fun addTestJigData(data: JigData?): Response<String> {
return try { return try {
db.collection("jigs").add(data!!).await() localdb.collection("jigs").add(data!!).await()
Response.Success(data.deviceId) Response.Success(data.deviceId)
} catch (e: Exception) { } catch (e: Exception) {
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
@@ -177,7 +195,7 @@ class DatabaseRepository @Inject constructor(
try { try {
val file = Uri.fromFile(File(filePath)) val file = Uri.fromFile(File(filePath))
val riversRef = storage.reference.child("$patientID/${file.lastPathSegment}") val riversRef = localStg.reference.child("$patientID/${file.lastPathSegment}")
riversRef.putFile(file).await() riversRef.putFile(file).await()
return Response.Success(true) return Response.Success(true)
} catch (e: Exception) { } catch (e: Exception) {
@@ -188,7 +206,7 @@ class DatabaseRepository @Inject constructor(
suspend fun addToPendingQueue(pendingUploads: PendingUploads): Response<Boolean> { suspend fun addToPendingQueue(pendingUploads: PendingUploads): Response<Boolean> {
return try { return try {
db.collection("pendingUploads").document(pendingUploads.pendingId).set(pendingUploads) localdb.collection("pendingUploads").document(pendingUploads.pendingId).set(pendingUploads)
.await() .await()
Response.Success(true) Response.Success(true)
@@ -201,7 +219,7 @@ class DatabaseRepository @Inject constructor(
suspend fun getAllFromPendingQueue(): List<PendingUploads> { suspend fun getAllFromPendingQueue(): List<PendingUploads> {
val pendingList = mutableListOf<PendingUploads>() val pendingList = mutableListOf<PendingUploads>()
return try { return try {
val querySnapshot = db.collection("pendingUploads").orderBy("timeAdded").get().await() val querySnapshot = localdb.collection("pendingUploads").orderBy("timeAdded").get().await()
for (doc in querySnapshot.documents) { for (doc in querySnapshot.documents) {
val pendingFile = doc.toObject(PendingUploads::class.java) val pendingFile = doc.toObject(PendingUploads::class.java)
@@ -219,7 +237,7 @@ class DatabaseRepository @Inject constructor(
suspend fun removeFromPendingQueue(fileName: String): Response<Boolean> { suspend fun removeFromPendingQueue(fileName: String): Response<Boolean> {
return try { return try {
db.collection("pendingUploads").document(fileName).delete().await() localdb.collection("pendingUploads").document(fileName).delete().await()
Response.Success(true) Response.Success(true)
} catch (e: Exception) { } catch (e: Exception) {
@@ -229,11 +247,11 @@ class DatabaseRepository @Inject constructor(
} }
suspend fun getDeviceData(): List<DeviceData> { suspend fun getDeviceData(): List<DeviceData> {
return db.collection("devices").get().await().toObjects(DeviceData::class.java) return localdb.collection("devices").get().await().toObjects(DeviceData::class.java)
} }
override suspend fun getDeviceDataById(deviceId: String): DeviceData? { override suspend fun getDeviceDataById(deviceId: String): DeviceData? {
val querySnapshot = db.collection("devices").get().await() val querySnapshot = localdb.collection("devices").get().await()
val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java) val allDeviceDataList = querySnapshot.toObjects(DeviceData::class.java)
// Find the DeviceData object with the specified deviceId // Find the DeviceData object with the specified deviceId
@@ -242,7 +260,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun getDeviceResponse(data: DeviceData?): Response<String> { override suspend fun getDeviceResponse(data: DeviceData?): Response<String> {
return try { return try {
db.collection("devices").add(data!!).await() localdb.collection("devices").add(data!!).await()
Response.Success(data.deviceProvisionResponse) Response.Success(data.deviceProvisionResponse)
} catch (e: Exception) { } catch (e: Exception) {
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
@@ -252,7 +270,7 @@ class DatabaseRepository @Inject constructor(
override suspend fun uploadDeviceId(data: DeviceData): Response<String>? { override suspend fun uploadDeviceId(data: DeviceData): Response<String>? {
return try { return try {
db.collection("devices").add(data!!).await() localdb.collection("devices").add(data!!).await()
Response.Success(data.deviceId) Response.Success(data.deviceId)
} catch (e: Exception) { } catch (e: Exception) {
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)
@@ -267,13 +285,13 @@ class DatabaseRepository @Inject constructor(
override suspend fun addTestToDatabasefornew(data: HemoCubeTestData?): Response<String> { override suspend fun addTestToDatabasefornew(data: HemoCubeTestData?): Response<String> {
return try { return try {
val userdata = val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await() localdb.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) { if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach { userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true) localdb.collection("patientData").document(it.id).update("testStatus", true)
} }
} }
db.collection("testData").add(data).await() localdb.collection("testData").add(data).await()
Response.Success(data._id) Response.Success(data._id)
} catch (e: Exception) { } catch (e: Exception) {
Firebase.crashlytics.recordException(e) Firebase.crashlytics.recordException(e)

View File

@@ -21,7 +21,6 @@ import androidx.room.Room
import com.example.hpostesting.data.api.MolbioAuthApi import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.util.PropertyProvider
import com.example.hpostesting.data.dao.HemoCubeBufferDao import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.dao.MyDatabase import com.example.hpostesting.data.dao.MyDatabase
@@ -36,9 +35,13 @@ import com.example.hpostesting.domain.LogFileManager
import com.example.hpostesting.domain.LogFileManagerImpl import com.example.hpostesting.domain.LogFileManagerImpl
import com.example.hpostesting.domain.SaveRawData import com.example.hpostesting.domain.SaveRawData
import com.example.hpostesting.domain.SaveRawDataTest import com.example.hpostesting.domain.SaveRawDataTest
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.utils.UsbServiceListener import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.example.hpostesting.presentation.utils.UsbServiceListenerImpl import com.example.hpostesting.presentation.utils.UsbServiceListenerImpl
import com.example.hpostesting.util.PropertyProvider
import com.example.hpostesting.util.PropertyProviderImpl import com.example.hpostesting.util.PropertyProviderImpl
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.storage.FirebaseStorage
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@@ -107,22 +110,52 @@ object AppModule {
return SaveRawDataTest(repository) return SaveRawDataTest(repository)
} }
@Provides
@Singleton
fun provideFirebaseFirestore(): FirebaseFirestore {
return FirebaseFirestore.getInstance()
}
@Provides
@Singleton
fun provideFirebaseStorage(): FirebaseStorage {
return FirebaseStorage.getInstance()
}
@Provides
@Singleton
fun provideFirebaseManager(
@ApplicationContext context: Context,
): FirebaseManager {
return FirebaseManager(context)
}
@Provides @Provides
@Singleton @Singleton
fun provideDatabaseRepository( fun provideDatabaseRepository(
firebaseManager: FirebaseManager,
@Named("Auth") molbioAuthApi: MolbioAuthApi, @Named("Auth") molbioAuthApi: MolbioAuthApi,
molbioResultApi: MolbioResultApi molbioResultApi: MolbioResultApi
): DatabaseRepository { ): DatabaseRepository {
return DatabaseRepository(molbioAuthApi = molbioAuthApi, molbioResultApi = molbioResultApi) return DatabaseRepository(
firebaseManager = firebaseManager,
molbioAuthApi = molbioAuthApi,
molbioResultApi = molbioResultApi
)
} }
@Provides @Provides
@Singleton @Singleton
fun provideRepository( fun provideRepository(
firebaseManager: FirebaseManager,
@Named("Auth") molbioAuthApi: MolbioAuthApi, @Named("Auth") molbioAuthApi: MolbioAuthApi,
molbioResultApi: MolbioResultApi molbioResultApi: MolbioResultApi
): Repository { ): Repository {
return DatabaseRepository(molbioAuthApi, molbioResultApi) return DatabaseRepository(
firebaseManager = firebaseManager,
molbioAuthApi = molbioAuthApi,
molbioResultApi = molbioResultApi
)
} }
@Provides @Provides
@@ -206,4 +239,9 @@ object AppModule {
fun provideUsbServiceListener(context: Context): UsbServiceListener { fun provideUsbServiceListener(context: Context): UsbServiceListener {
return UsbServiceListenerImpl(context) return UsbServiceListenerImpl(context)
} }
} }

View File

@@ -0,0 +1,153 @@
package com.example.hpostesting.firebase
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
import android.content.Context
import android.content.Intent
import android.os.Process
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.storage.FirebaseStorage
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
class FirebaseManager @Inject constructor(private val context: Context) {
private val sharedPreferences =
context.getSharedPreferences("FirebaseConfigPrefs", Context.MODE_PRIVATE)
private var currentFirestore: FirebaseFirestore = FirebaseFirestore.getInstance()
private var currentStorage: FirebaseStorage = FirebaseStorage.getInstance()
var updateStatus = false
private val defaultServers = listOf(
// i have it in different place look down
firebaseConfig1, firebaseConfig2, firebaseConfig3,
)
init {
val lastSelectedServer = getLastSelectedServer()
switchServer(lastSelectedServer)
}
fun getCurrentFirestore(): FirebaseFirestore = currentFirestore
fun getCurrentStorage(): FirebaseStorage = currentStorage
fun switchServer(firebaseConfig: FirebaseConfig) {
saveSelectedServer(firebaseConfig)
val firebaseApp = getOrInitializeFirebaseApp(firebaseConfig)
currentFirestore = FirebaseFirestore.getInstance(firebaseApp)
currentStorage = FirebaseStorage.getInstance(firebaseApp)
updateStatus = true
}
private fun getOrInitializeFirebaseApp(firebaseConfig: FirebaseConfig): FirebaseApp {
val existingApp = FirebaseApp.getApps(context).find { it.name == firebaseConfig.serverName }
return if (existingApp != null) {
existingApp
} else {
val options = FirebaseOptions.Builder().setProjectId(firebaseConfig.projectId)
.setApplicationId(firebaseConfig.appId).setApiKey(firebaseConfig.apiKey)
.setStorageBucket(firebaseConfig.storageBucket).build()
FirebaseApp.initializeApp(context, options, firebaseConfig.serverName)
}
}
private fun saveSelectedServer(firebaseConfig: FirebaseConfig) {
with(sharedPreferences.edit()) {
putString("selectedServerName", firebaseConfig.serverName)
putString("projectId", firebaseConfig.projectId)
putString("appId", firebaseConfig.appId)
putString("apiKey", firebaseConfig.apiKey)
putString("storageBucket", firebaseConfig.storageBucket)
apply()
}
}
fun restartApp() {
if (updateStatus) {
updateStatus = false
delayedRestart(context)
}
}
fun getLastSelectedServer(): FirebaseConfig {
val selectedServerName =
sharedPreferences.getString("selectedServerName", defaultServers.first().serverName)
val projectId = sharedPreferences.getString("projectId", defaultServers.first().projectId)
val appId = sharedPreferences.getString("appId", defaultServers.first().appId)
val apiKey = sharedPreferences.getString("apiKey", defaultServers.first().apiKey)
val storageBucket =
sharedPreferences.getString("storageBucket", defaultServers.first().storageBucket)
return FirebaseConfig(
serverName = selectedServerName ?: defaultServers.first().serverName,
projectId = projectId ?: defaultServers.first().projectId,
appId = appId ?: defaultServers.first().appId,
apiKey = apiKey ?: defaultServers.first().apiKey,
storageBucket = storageBucket ?: defaultServers.first().storageBucket
)
}
fun getAvailableServers(): List<FirebaseConfig> {
return defaultServers
}
}
fun restartApp(context: Context) {
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
Process.killProcess(Process.myPid())
}
@OptIn(DelicateCoroutinesApi::class)
fun delayedRestart(context: Context) {
GlobalScope.launch(Dispatchers.Main) {
delay(5000L)
restartApp(context)
}
}
private val firebaseConfig1 = FirebaseConfig(
serverName = "dev",
apiKey = "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I",
appId = "1:650071678820:android:a53292637abb7c0d6c6471",
projectId = "hpos-af3cc",
storageBucket = "hpos-af3cc.appspot.com"
)
private val firebaseConfig2 = FirebaseConfig(
serverName = "qc-qa",
apiKey = "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs",
appId = "1:1004619739289:android:3dbcefb10ea99654e5c808",
projectId = "hpos-qa",
storageBucket = "hpos-qa.appspot.com"
)
private val firebaseConfig3 = FirebaseConfig(
serverName = "prod",
apiKey = "AIzaSyDYySi27LioZGNisP1NfnNU5inJX_0FT38",
appId = "1:121176529204:android:a7bc0842f61e5095bbed61",
projectId = "hpos-preprod",
storageBucket = "hpos-preprod.appspot.com"
)

View File

@@ -0,0 +1,21 @@
package com.example.hpostesting.firebase
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
data class FirebaseConfig(
val serverName: String,
val apiKey: String,
val appId: String,
val projectId: String,
val storageBucket: String
)

View File

@@ -26,7 +26,9 @@ import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.data.constant.DataHolder import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.presentation.hb_test.HBTestActivity
import com.example.hpostesting.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity import com.example.hpostesting.presentation.testRight.TestRightActivity
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@@ -51,7 +53,7 @@ import java.util.Locale
import kotlin.math.max import kotlin.math.max
class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate { class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
private var fromWhere = "Home"
private val TAG = "KitScanActivity" private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding private lateinit var binding: ActivityKitScanBinding
@@ -134,6 +136,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root) setContentView(binding.root)
binding.toolbar.title = "Kit Serial Number" binding.toolbar.title = "Kit Serial Number"
fromWhere = intent.getStringExtra("fromWhere").toString()
val maxTest = if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm"){ val maxTest = if(sharedPreference.getString(Constants.CUVETTE_SIZE, "10mm").toString() == "2mm"){
Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE
}else{ }else{
@@ -142,7 +145,9 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
val time = timeDifference(sharedPreference.getString(Constants.KIT_TIME, "").toString()) val time = timeDifference(sharedPreference.getString(Constants.KIT_TIME, "").toString())
val kitNum = sharedPreference.getString(Constants.KIT_NUMBER, "").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 (DataHolder.sampleReadCounter <= maxTest && kitNum != "" && time < Constants.MAX_KIT_TIME) { if (DataHolder.sampleReadCounter <= maxTest && kitNum != "" && time < Constants.MAX_KIT_TIME) {
moveToNext() moveToNext()
} else { } else {
@@ -157,6 +162,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
apply() apply()
} }
} }
}
// if (checkHemoCubeKitData()) { // if (checkHemoCubeKitData()) {
// DataHolder.selectedTest!!.kitSerial = // DataHolder.selectedTest!!.kitSerial =
@@ -363,7 +369,11 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
} }
private fun moveToNext() { private fun moveToNext() {
if(fromWhere == "Main"){
if(DataHolder.selectedTestType == TestType.HB_EST){
val i = Intent(applicationContext, HBTestActivity::class.java)
startActivity(i)
}else{
DataHolder.deviceType.observe(this) { deviceType -> DataHolder.deviceType.observe(this) { deviceType ->
when (deviceType) { when (deviceType) {
Constants.DEVICE_TYPE_HEMOCUBE -> { Constants.DEVICE_TYPE_HEMOCUBE -> {
@@ -383,6 +393,8 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
} }
} }
} }
}
}
private fun startScanningNow() { private fun startScanningNow() {
val options = ScanOptions() val options = ScanOptions()

View File

@@ -18,6 +18,7 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import android.location.Location import android.location.Location
@@ -30,10 +31,9 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.get import androidx.core.view.get
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants 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.constant.LanguageManager
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestType import com.example.hpostesting.data.model.test.TestType
import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.FusedLocationProviderClient
@@ -48,12 +48,12 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding import `in`.sminnovations.hpostesting.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
private var myMenu: Menu? = null private var myMenu: Menu? = null
private val TAG = "MainActivity" private val TAG = "MainActivity"
private lateinit var fusedLocationClient: FusedLocationProviderClient private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback private lateinit var locationCallback: LocationCallback
private lateinit var sharedPreference: SharedPreferences
private val usbReceiver = object : BroadcastReceiver() { private val usbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) { override fun onReceive(context: Context?, intent: Intent) {
@@ -73,14 +73,21 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
sharedPreference = getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
binding.myToolbar.title = "Test Type" binding.myToolbar.title = "Test Type"
setSupportActionBar(binding.myToolbar) setSupportActionBar(binding.myToolbar)
if ((sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN")) {
binding.cvItem3.visibility = View.VISIBLE
}else{
binding.cvItem3.visibility = View.GONE
}
setupListeners() setupListeners()
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
getLocation() getLocation()
locationCallback = object : LocationCallback() { locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) { override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let { location -> locationResult.lastLocation?.let { location ->
@@ -92,7 +99,6 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
val usbFilter = IntentFilter().apply { val usbFilter = IntentFilter().apply {
addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
@@ -111,12 +117,13 @@ class MainActivity : AppCompatActivity() {
} }
} }
if (DataHolder.selectedTest == null) { // if (DataHolder.selectedTest == null) {
startActivity(Intent(this, DashboardActivity::class.java)) // startActivity(Intent(this, DashboardActivity::class.java))
finish() // finish()
} // }
} }
private fun checkAndUpdateUsbConnection() { private fun checkAndUpdateUsbConnection() {
val availableDrivers = UsbSerialProber.getDefaultProber() val availableDrivers = UsbSerialProber.getDefaultProber()
.findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager) .findAllDrivers(getSystemService(Context.USB_SERVICE) as UsbManager)
@@ -220,6 +227,7 @@ class MainActivity : AppCompatActivity() {
binding.cvItem1.setOnClickListener { binding.cvItem1.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLECERT DataHolder.selectedTestType = TestType.SICKLECERT
val i = Intent(applicationContext, KitScanActivity::class.java) val i = Intent(applicationContext, KitScanActivity::class.java)
i.putExtra("fromWhere","Main")
startActivity(i) startActivity(i)
finish() finish()
} }
@@ -227,6 +235,14 @@ class MainActivity : AppCompatActivity() {
binding.cvItem2.setOnClickListener { binding.cvItem2.setOnClickListener {
DataHolder.selectedTestType = TestType.SICKLEFIND DataHolder.selectedTestType = TestType.SICKLEFIND
val i = Intent(applicationContext, KitScanActivity::class.java) val i = Intent(applicationContext, KitScanActivity::class.java)
i.putExtra("fromWhere","Main")
startActivity(i)
finish()
}
binding.cvItem3.setOnClickListener {
DataHolder.selectedTestType = TestType.HB_EST
val i = Intent(applicationContext, KitScanActivity::class.java)
i.putExtra("fromWhere","Main")
startActivity(i) startActivity(i)
finish() finish()
} }

View File

@@ -14,25 +14,21 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.os.BatteryManager import android.os.BatteryManager
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.testRight.TestRightViewModel
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentActivitiesBinding import `in`.sminnovations.hpostesting.databinding.FragmentActivitiesBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class ActivitiesFragment : Fragment() { class ActivitiesFragment : Fragment() {
private lateinit var binding: FragmentActivitiesBinding private lateinit var binding: FragmentActivitiesBinding
@@ -53,6 +49,12 @@ class ActivitiesFragment : Fragment() {
hemoCubeViewModel.allPendingUserToUpload.observe(viewLifecycleOwner) { userData -> hemoCubeViewModel.allPendingUserToUpload.observe(viewLifecycleOwner) { userData ->
if (userData.isNotEmpty()) { if (userData.isNotEmpty()) {
userData.forEach { user ->
if((isBetween15And30Minutes(user.incubationTime) > 30 || isBetween15And30Minutes(user.incubationTime) < 0 ) && user.testStatus == false){
hemoCubeViewModel.deleteByStatus()
}
}
binding.rvOrderOffline.visibility = View.VISIBLE binding.rvOrderOffline.visibility = View.VISIBLE
binding.noDataText.visibility = View.GONE binding.noDataText.visibility = View.GONE
val bm = val bm =
@@ -68,5 +70,16 @@ class ActivitiesFragment : Fragment() {
} }
} }
} }
private fun isBetween15And30Minutes(createdAt: String): Long {
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val createdAtDate: Date = formatter.parse(createdAt)!!
val currentTime = Calendar.getInstance().time
val diffMillis = currentTime.time - createdAtDate.time
return diffMillis / (60 * 1000)
}
} }

View File

@@ -0,0 +1,18 @@
package com.example.hpostesting.presentation.dashboard
class AppVersionTapManager {
private var tapCount = 0
private val maxTapCount = 5
fun registerTap(onMaxTapsReached: () -> Unit) {
tapCount++
if (tapCount >= maxTapCount) {
onMaxTapsReached()
reset()
}
}
private fun reset() {
tapCount = 0
}
}

View File

@@ -33,25 +33,26 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.util.Result
import com.example.hpostesting.data.constant.Constants 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.constant.LanguageManager
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.utils.NatsManager import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.jig.JigActivity import com.example.hpostesting.presentation.jig.JigActivity
import com.example.hpostesting.presentation.utils.NatsManager
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.ktx.Firebase
import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.BuildConfig import `in`.sminnovations.hpostesting.BuildConfig
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import java.io.File import java.io.File
import java.security.MessageDigest import java.security.MessageDigest
import javax.inject.Inject
interface NatsMessageCallback { interface NatsMessageCallback {
fun onMessageReceived(topic: String, message: String) fun onMessageReceived(topic: String, message: String)
@@ -64,7 +65,9 @@ open interface IDataCollector: NatsMessageCallback {
@AndroidEntryPoint @AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector { class DashboardActivity : AppCompatActivity(), IDataCollector {
@Inject
lateinit var databaseRepository: DatabaseRepository
private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
val TAG = "DashboardActivity" val TAG = "DashboardActivity"
private var isRegistered = false private var isRegistered = false
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
@@ -72,6 +75,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
lateinit var sharedPreferences: SharedPreferences lateinit var sharedPreferences: SharedPreferences
var responses: String = "" var responses: String = ""
lateinit var nats: NatsManager lateinit var nats: NatsManager
private var downloadId: Long = 0 private var downloadId: Long = 0
// TODO: Remove hemocube viewmodel // TODO: Remove hemocube viewmodel
private val hemocubeViewModel: HemoCubeViewModel by viewModels() private val hemocubeViewModel: HemoCubeViewModel by viewModels()
@@ -82,6 +86,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
super.attachBaseContext(newBase) super.attachBaseContext(newBase)
} }
override fun onMessageReceived(topic: String, message: String) { override fun onMessageReceived(topic: String, message: String) {
// Handle incoming messages from NATS // Handle incoming messages from NATS
@@ -91,12 +96,15 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
@SuppressLint("SetWorldReadable") @SuppressLint("SetWorldReadable")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val firebaseManager = FirebaseManager(this)
binding = ActivityDashboardBinding.inflate(layoutInflater) binding = ActivityDashboardBinding.inflate(layoutInflater)
sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar) setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this) nats = NatsManager(this)
val currentServer = firebaseManager.getLastSelectedServer().serverName
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
nats.connect() nats.connect()
} }
@@ -105,7 +113,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
Log.d("DashboardActivity", "Saved Kit Serial: $savedKitSerial") Log.d("DashboardActivity", "Saved Kit Serial: $savedKitSerial")
// Toast.makeText(this, "Saved Kit Serial: $savedKitSerial", Toast.LENGTH_SHORT).show() // Toast.makeText(this, "Saved Kit Serial: $savedKitSerial", Toast.LENGTH_SHORT).show()
val versionName = getAppVersion(this@DashboardActivity) + " [ " + getAppEnvironment(this@DashboardActivity) + " ]" val versionName = getAppVersion(this@DashboardActivity) + " [ " + getAppEnvironment(this@DashboardActivity) +"->"+currentServer+"]"
binding.appBarDashboard.versionName.text = versionName binding.appBarDashboard.versionName.text = versionName
@@ -114,6 +122,90 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
nats.sub("server.hpos.${deviceId}.ping") nats.sub("server.hpos.${deviceId}.ping")
nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG") nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 3600
}
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
remoteConfig.fetchAndActivate()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val normalMin2mm = remoteConfig.getDouble("normalMin2mm")
val normalMax2mm = remoteConfig.getDouble("normalMax2mm")
val negativeBorderlineMin2mm = remoteConfig.getDouble("negativeBorderlineMin2mm")
val negativeBorderlineMax2mm = remoteConfig.getDouble("negativeBorderlineMax2mm")
val positiveForSickleCellMin2mm = remoteConfig.getDouble("positiveForSickleCellMin2mm")
val positiveForSickleCellMax2mm = remoteConfig.getDouble("positiveForSickleCellMax2mm")
val sickleCellTraitMin2mm = remoteConfig.getDouble("sickleCellTraitMin2mm")
val sickleCellTraitMax2mm = remoteConfig.getDouble("sickleCellTraitMax2mm")
val sickleCellDiseaseMin2mm = remoteConfig.getDouble("sickleCellDiseaseMin2mm")
val sickleCellDiseaseMax2mm = remoteConfig.getDouble("sickleCellDiseaseMax2mm")
val positiveBoderLine2mm1 = remoteConfig.getDouble("positiveBoderLine2mm1")
val positiveBoderLine2mm2 = remoteConfig.getDouble("positiveBoderLine2mm2")
val negativeBoderLine2mm1 = remoteConfig.getDouble("negativeBoderLine2mm1")
val negativeBoderLine2mm2 = remoteConfig.getDouble("negativeBoderLine2mm2")
val normalMin10mm = remoteConfig.getDouble("normalMin10mm")
val normalMax10mm = remoteConfig.getDouble("normalMax10mm")
val negativeBorderlineMin10mm = remoteConfig.getDouble("negativeBorderlineMin10mm")
val negativeBorderlineMax10mm = remoteConfig.getDouble("negativeBorderlineMax10mm")
val positiveForSickleCellMin10mm = remoteConfig.getDouble("positiveForSickleCellMin10mm")
val positiveForSickleCellMax10mm = remoteConfig.getDouble("positiveForSickleCellMax10mm")
val sickleCellTraitMin10mm = remoteConfig.getDouble("sickleCellTraitMin10mm")
val sickleCellTraitMax10mm = remoteConfig.getDouble("sickleCellTraitMax10mm")
val sickleCellDiseaseMin10mm = remoteConfig.getDouble("sickleCellDiseaseMin10mm")
val sickleCellDiseaseMax10mm = remoteConfig.getDouble("sickleCellDiseaseMax10mm")
val positiveBoderLine10mm1 = remoteConfig.getDouble("positiveBoderLine10mm1")
val positiveBoderLine10mm2 = remoteConfig.getDouble("positiveBoderLine10mm2")
val negativeBoderLine10mm1 = remoteConfig.getDouble("negativeBoderLine10mm1")
val negativeBoderLine10mm2 = remoteConfig.getDouble("negativeBoderLine10mm2")
val bufferMinLed1 = remoteConfig.getDouble("bufferMinLed1")
val bufferMaxLed1 = remoteConfig.getDouble("bufferMaxLed1")
val bufferMinLed2 = remoteConfig.getDouble("bufferMinLed2")
val bufferMaxLed2 = remoteConfig.getDouble("bufferMaxLed2")
with(sharedPreferences.edit()) {
putString("bufferMinLed1", bufferMinLed1.toString())
putString("bufferMaxLed1", bufferMaxLed1.toString())
putString("bufferMinLed2", bufferMinLed2.toString())
putString("bufferMaxLed2", bufferMaxLed2.toString())//buffer
putString("normalMin2mm", normalMin2mm.toString())//2mm
putString("normalMax2mm", normalMax2mm.toString())
putString("negativeBorderlineMin2mm", negativeBorderlineMin2mm.toString())
putString("negativeBorderlineMax2mm", negativeBorderlineMax2mm.toString())
putString("positiveForSickleCellMin2mm", positiveForSickleCellMin2mm.toString())
putString("positiveForSickleCellMax2mm", positiveForSickleCellMax2mm.toString())
putString("sickleCellTraitMin2mm", sickleCellTraitMin2mm.toString())
putString("sickleCellTraitMax2mm", sickleCellTraitMax2mm.toString())
putString("sickleCellDiseaseMin2mm", sickleCellDiseaseMin2mm.toString())
putString("sickleCellDiseaseMax2mm", sickleCellDiseaseMax2mm.toString())
putString("positiveBoderLine2mm1", positiveBoderLine2mm1.toString())
putString("positiveBoderLine2mm2", positiveBoderLine2mm2.toString())
putString("negativeBoderLine2mm1", negativeBoderLine2mm1.toString())
putString("negativeBoderLine2mm2", negativeBoderLine2mm2.toString())//2mm
putString("normalMin10mm", normalMin10mm.toString())//10mm
putString("normalMax10mm", normalMax10mm.toString())
putString("negativeBorderlineMin10mm", negativeBorderlineMin10mm.toString())
putString("negativeBorderlineMax10mm", negativeBorderlineMax10mm.toString())
putString("positiveForSickleCellMin10mm", positiveForSickleCellMin10mm.toString())
putString("positiveForSickleCellMax10mm", positiveForSickleCellMax10mm.toString())
putString("sickleCellTraitMin10mm", sickleCellTraitMin10mm.toString())
putString("sickleCellTraitMax10mm", sickleCellTraitMax10mm.toString())
putString("sickleCellDiseaseMin10mm", sickleCellDiseaseMin10mm.toString())
putString("sickleCellDiseaseMax10mm", sickleCellDiseaseMax10mm.toString())
putString("positiveBoderLine10mm1", positiveBoderLine10mm1.toString())
putString("positiveBoderLine10mm2", positiveBoderLine10mm2.toString())
putString("negativeBoderLine10mm1", negativeBoderLine10mm1.toString())
putString("negativeBoderLine10mm2", negativeBoderLine10mm2.toString())//10mm
apply()
}
Log.d(TAG, "Config params updated")
} else {
Log.d(TAG, "Config params Fetch failed")
}
}
hemocubeViewModel.deviceUpdate.observe(this) { hemocubeViewModel.deviceUpdate.observe(this) {
Log.d("DashboardLogs",it.toString()) Log.d("DashboardLogs",it.toString())
@@ -127,8 +219,8 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
input.copyTo(output) input.copyTo(output)
} }
} }
} }
hemocubeViewModel.deviceUpdateheader.observe(this){ hemocubeViewModel.deviceUpdateheader.observe(this){
val apkFile = File(getExternalFilesDir("Downloads"), "update.apk") val apkFile = File(getExternalFilesDir("Downloads"), "update.apk")
val expectedChecksum = it.get("Checksum") // Provide your expected checksum here val expectedChecksum = it.get("Checksum") // Provide your expected checksum here
@@ -163,6 +255,12 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
// fun sendData(data:String){ this was used to send the basic data for server validation
// databaseRepository.addtodb(data)
// Toast.makeText(this, "data uploaded", Toast.LENGTH_SHORT).show()
// }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present. // Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.dashboard, menu) menuInflater.inflate(R.menu.dashboard, menu)
@@ -288,6 +386,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
return try { return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) { } catch (e: PackageManager.NameNotFoundException) {
"N/A" "N/A"
} }

View File

@@ -24,11 +24,14 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri import android.net.Uri
import android.os.BatteryManager import android.os.BatteryManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.provider.ContactsContract.Data
import android.provider.Settings import android.provider.Settings
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
@@ -41,6 +44,8 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder import com.example.hpostesting.data.constant.DataHolder
@@ -71,10 +76,9 @@ import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.ResponseBody import okhttp3.ResponseBody
import org.json.JSONObject import org.json.JSONObject
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
@@ -88,7 +92,6 @@ import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.Scanner
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
import kotlin.properties.Delegates import kotlin.properties.Delegates
@@ -138,6 +141,7 @@ class HomeFragment : Fragment() {
viewModel.allUserData.observe(viewLifecycleOwner) { userData -> viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteIncompleteRegistrations(userData) deleteIncompleteRegistrations(userData)
} }
// getLocationIP()
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteHemoCubeIncompleteRegistrations(userData) deleteHemoCubeIncompleteRegistrations(userData)
if (userData.isNotEmpty()) { if (userData.isNotEmpty()) {
@@ -174,6 +178,7 @@ class HomeFragment : Fragment() {
Toast.makeText( Toast.makeText(
requireContext(), R.string.test_upload, Toast.LENGTH_SHORT requireContext(), R.string.test_upload, Toast.LENGTH_SHORT
).show() ).show()
hemoCubeViewModel.fireBaseBulkUpload.postValue("Done")
} }
if (result == "Error") { if (result == "Error") {
Toast.makeText(requireContext(), R.string.test_upload_failed, Toast.LENGTH_SHORT) Toast.makeText(requireContext(), R.string.test_upload_failed, Toast.LENGTH_SHORT)
@@ -192,7 +197,11 @@ class HomeFragment : Fragment() {
//// showUploadDialog(requireContext()) //// showUploadDialog(requireContext())
// } // }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") { // if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") {
//
// }else{
// binding.downloadCSV.visibility = View.GONE
// }
val btnSaveLocalVisibility = val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE
binding.downloadCSV.visibility = btnSaveLocalVisibility binding.downloadCSV.visibility = btnSaveLocalVisibility
@@ -209,9 +218,6 @@ class HomeFragment : Fragment() {
).show() ).show()
} }
} }
}else{
binding.downloadCSV.visibility = View.GONE
}
} }
@@ -232,7 +238,10 @@ class HomeFragment : Fragment() {
// putInt(Constants.KIT_COUNT, 0) // putInt(Constants.KIT_COUNT, 0)
// apply() // apply()
// } // }
startActivity(Intent(requireContext(), KitScanActivity::class.java)) DataHolder.selectedTest = null
val intent = Intent(requireContext(), KitScanActivity::class.java)
intent.putExtra("fromWhere","Home")
startActivity(intent)
// requireActivity().finish() // requireActivity().finish()
} }
binding.btnQuickCapture.setOnClickListener { binding.btnQuickCapture.setOnClickListener {
@@ -256,10 +265,43 @@ class HomeFragment : Fragment() {
checkNetworkStatus() checkNetworkStatus()
} }
// private fun getLocationIP() {
// try {
// if (isInternetAvailable(requireContext())) {
// getPublicIpAddr { ipAddress ->
// if (ipAddress != "fail") {
// DataHolder.ipAddress = ipAddress
// with(sharedPreference.edit()) {
// putString(Constants.IP_ADDRESS, ipAddress)
// apply()
// }
// } else {
// Log.e("Home", "Failed to get public IP address")
// }
// }
// } else {
// Log.e("Home", "Internet is not available")
// }
// } catch (e: UnknownHostException) {
// Log.e("Home", "UnknownHostException: Unable to resolve host. Network might be unavailable or DNS server is not reachable", e)
// } catch (e: Exception) {
// Log.e("Home", "Network Problem", e)
// }
// }
@RequiresApi(Build.VERSION_CODES.P) @RequiresApi(Build.VERSION_CODES.P)
private fun checkNetworkStatus() { private fun checkNetworkStatus() {
hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected -> hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected ->
// Toast.makeText(requireContext(),"connected"+isConnected+wasConnected, Toast.LENGTH_SHORT).show() // Toast.makeText(requireContext(),"connected"+isConnected+wasConnected, Toast.LENGTH_SHORT).show()
if(isConnected){
binding.tvTitleNoInternet.text = "Please enter the user id and select blood group to start the test."
binding.internetIcon.setImageDrawable(AppCompatResources.getDrawable(requireContext(),R.drawable.internet))
binding.internetNotAvailableCL.visibility = View.VISIBLE
}else{
binding.internetIcon.setImageDrawable(AppCompatResources.getDrawable(requireContext(),R.drawable.off))
binding.tvTitleNoInternet.text = getString(R.string.internet_not_available_please_enter_the_user_id_manually)
binding.internetNotAvailableCL.visibility = View.VISIBLE
}
if (isConnected != wasConnected) { if (isConnected != wasConnected) {
if (isConnected) { if (isConnected) {
binding.tvTitleNoInternet.text = "Please enter the user id and select blood group to start the test." binding.tvTitleNoInternet.text = "Please enter the user id and select blood group to start the test."
@@ -341,7 +383,9 @@ class HomeFragment : Fragment() {
if(Constants.MOLBIO_INTEGRATION){ if(Constants.MOLBIO_INTEGRATION){
hemoCubeViewModel.sendDataToMolbio() hemoCubeViewModel.sendDataToMolbio()
} }
if(Constants.FIREBASE_INTEGRATION) {
hemoCubeViewModel.sendDataToFirebase() hemoCubeViewModel.sendDataToFirebase()
}
} else { } else {
binding.tvTitleNoInternet.text = getString(R.string.internet_not_available_please_enter_the_user_id_manually) binding.tvTitleNoInternet.text = getString(R.string.internet_not_available_please_enter_the_user_id_manually)
@@ -372,7 +416,8 @@ class HomeFragment : Fragment() {
var userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString() var userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").toString() deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").toString()
val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) // val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val target = File(requireContext().getExternalFilesDir(null), "HPOSDocuments")
val file = File(target, "credentials.txt") //this file contains userID and password to communicate with API. val file = File(target, "credentials.txt") //this file contains userID and password to communicate with API.
if (userID.isNotEmpty() && password.isNotEmpty()) { if (userID.isNotEmpty() && password.isNotEmpty()) {
@@ -672,9 +717,10 @@ class HomeFragment : Fragment() {
requireActivity().packageName, 0 requireActivity().packageName, 0
) )
val version = pInfo.versionName val version = pInfo.versionName
var labname = sharedPreference.getString(Constants.LABNAME,"") val labname = sharedPreference.getString(Constants.CENTER_NAME,"")
val ip = sharedPreference.getString(Constants.IP_ADDRESS,"")
return LoginRequest( return LoginRequest(
location = DataHolder.ipAddress, password = password, serialNumber = userID, username = userID, version = version, lab = labname location = ip, password = password, serialNumber = userID, username = userID, version = version, lab = labname
) )
} }
private fun createCheckUpdateRequestData(): CheckUpdateRequest { private fun createCheckUpdateRequestData(): CheckUpdateRequest {
@@ -753,17 +799,72 @@ class HomeFragment : Fragment() {
private fun setUserId() { private fun setUserId() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString() val userId = binding.userId.text.toString()
val bloodGroup = binding.etBloodGroup.text DataHolder.sampleId = userId
if (userId.length >= 10 && !bloodGroup.equals("Select Blood Group") || !bloodGroup.isNullOrBlank()) { val age = binding.age.text.toString()
DataHolder.age = age
val bloodGroup = binding.etBloodGroup.text.toString()
DataHolder.bloodGroup = bloodGroup
// if (userId.length >= 5 && bloodGroup != "Select Blood Group") {
// DataHolder.selectedTest = UserData(
// _id = userId,
// bloodGroup = bloodGroup,
// incubationTime = SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time).toString()
// )
// findNavController().navigate(R.id.action_nav_home_to_mainActivity)
if (userId.length >= 5 && bloodGroup.isNotEmpty() && age.isNotEmpty()) {
lifecycleScope.launch {
// Add user first, ensuring it's done before fetching the user
withContext(Dispatchers.IO) {
hemoCubeViewModel.addUser( hemoCubeViewModel.addUser(
HemoCubeTestData( HemoCubeTestData(
_id = userId, _id = userId,
bloodGroup = bloodGroup.toString(), age = age,
bloodGroup = bloodGroup,
incubationTime = SimpleDateFormat( incubationTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString() ).format(Calendar.getInstance().time).toString()
) )
) )
}
// Now fetch the user after the addUser operation is complete
val user = withContext(Dispatchers.IO) {
hemoCubeViewModel.hemoCubeDao.getUserByID(userId)
}
user?.let {
DataHolder.selectedTest = UserData(
sampleid = it.sampleid,
_id = it._id,
age = it.age,
bloodGroup = it.bloodGroup,
incubationTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
)
findNavController().navigate(R.id.action_nav_home_to_mainActivity)
} ?: run {
Log.e("Error", "User not found")
}
}
// hemoCubeViewModel.addUser(
// HemoCubeTestData(
// _id = userId,
// bloodGroup = bloodGroup.toString(),
// incubationTime = SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time).toString()
// )
// )
Toast.makeText(requireContext(), "Successfully added- $userId", Toast.LENGTH_SHORT).show()
binding.userId.setText("")
binding.age.setText("")
binding.etBloodGroup.setText("")
// val userData = UserData(_id = userId) // val userData = UserData(_id = userId)
// DataHolder.selectedTest = userData // DataHolder.selectedTest = userData
// findNavController().navigate(R.id.action_nav_home_to_mainActivity) // findNavController().navigate(R.id.action_nav_home_to_mainActivity)
@@ -1509,34 +1610,64 @@ class HomeFragment : Fragment() {
super.onDestroy() super.onDestroy()
} }
@OptIn(DelicateCoroutinesApi::class)
private fun getPublicIpAddr(callback: (String) -> Unit) { private fun getPublicIpAddr(callback: (String) -> Unit) {
lifecycleScope.launch(Dispatchers.IO) {
try { try {
GlobalScope.launch(Dispatchers.IO) {
val url = URL("https://api.ipify.org") val url = URL("https://api.ipify.org")
val conn = url.openConnection() as HttpURLConnection val conn = url.openConnection() as HttpURLConnection
try { try {
conn.connect() conn.connect()
if (conn.responseCode == HttpURLConnection.HTTP_OK) { if (conn.responseCode == HttpURLConnection.HTTP_OK) {
val scanner = Scanner(conn.inputStream) val inputStream = conn.inputStream
scanner.useDelimiter("\\A") val ipAddress = inputStream.bufferedReader().use { it.readText() }
if (scanner.hasNext()) { inputStream.close()
val ipAddress = scanner.next() withContext(Dispatchers.Main) {
Log.d("ipaddress",DataHolder.ipAddress)
callback(ipAddress) callback(ipAddress)
}
} else { } else {
withContext(Dispatchers.Main) {
callback("fail") callback("fail")
} }
} }
} finally { } finally {
conn.disconnect() conn.disconnect()
} }
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e("home",e.toString()) Log.e("getPublicIpAddr", e.toString())
withContext(Dispatchers.Main) {
callback("fail") callback("fail")
} }
} }
}
}
// @OptIn(DelicateCoroutinesApi::class)
// private fun getPublicIpAddr(callback: (String) -> Unit) {
// try {
// GlobalScope.launch(Dispatchers.IO) {
// val url = URL("https://api.ipify.org")
// val conn = url.openConnection() as HttpURLConnection
// try {
// conn.connect()
// if (conn.responseCode == HttpURLConnection.HTTP_OK) {
// val scanner = Scanner(conn.inputStream)
// scanner.useDelimiter("\\A")
// if (scanner.hasNext()) {
// val ipAddress = scanner.next()
// Log.d("ipaddress",DataHolder.ipAddress)
// callback(ipAddress)
// }else{
// callback("fail")
// }
// }
// } finally {
// conn.disconnect()
// }
// }
// }catch (e: Exception){
// Log.e("home",e.toString())
// callback("fail")
// }
// }
private fun callLogin(userID: String, password: String) { private fun callLogin(userID: String, password: String) {
if(DataHolder.ipAddress == "0.0"){ if(DataHolder.ipAddress == "0.0"){
@@ -1568,7 +1699,24 @@ class HomeFragment : Fragment() {
return diffMillis / (60 * 1000) // Convert milliseconds to minutes return diffMillis / (60 * 1000) // Convert milliseconds to minutes
} }
private fun isInternetAvailable(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork ?: return false
val activeNetwork = connectivityManager.getNetworkCapabilities(network) ?: return false
return when {
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
@Suppress("DEPRECATION")
val networkInfo = connectivityManager.activeNetworkInfo ?: return false
@Suppress("DEPRECATION")
return networkInfo.isConnected
}
}
} }

View File

@@ -13,6 +13,7 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -23,7 +24,7 @@ import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
@@ -31,10 +32,10 @@ import androidx.preference.PreferenceFragmentCompat
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.data.model.TestState import com.example.hpostesting.data.repository.DatabaseRepository
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.firebase.FirebaseConfig
import com.example.hpostesting.firebase.FirebaseManager
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding import `in`.sminnovations.hpostesting.databinding.FragmentSlideshowBinding
private var isLanguageChanged = false private var isLanguageChanged = false
@@ -44,12 +45,12 @@ class SlideshowFragment : Fragment(){
private val values = arrayOf("10mm", "2mm") private val values = arrayOf("10mm", "2mm")
private lateinit var binding: FragmentSlideshowBinding private lateinit var binding: FragmentSlideshowBinding
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View { ): View {
binding = FragmentSlideshowBinding.inflate(inflater, container, false) binding = FragmentSlideshowBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root return binding.root
} }
@@ -59,22 +60,20 @@ class SlideshowFragment : Fragment(){
binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, "")) binding.nameEditText.setText(sharedPreferences.getString(Constants.LABNAME, ""))
selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString() selectedItem = sharedPreferences.getString(Constants.CUVETTE_SIZE, "10mm").toString()
val time = sharedPreferences.getString(Constants.LAST_UPDATED, "NA").toString()
binding.lastUpdated.text = "Last updated config: $time"
binding.btnGo.setOnClickListener { binding.btnGo.setOnClickListener {
var labname = binding.nameEditText.text.toString() var labname = binding.nameEditText.text.toString()
DataHolder.hemoCubeTestData?.apply { DataHolder.hemoCubeTestData?.apply {
this.labName = labname this.labName = labname
} }
with(sharedPreferences.edit()) { with(sharedPreferences.edit()) {
putString(Constants.LABNAME, labname) putString(Constants.LABNAME, labname)
apply() apply()
} }
Toast.makeText( Toast.makeText(
requireContext(), requireContext(), "Lab Name is Added successfully.", Toast.LENGTH_SHORT
"Lab Name is Added successfully.",
Toast.LENGTH_SHORT
).show() ).show()
} }
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, values) val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, values)
@@ -87,8 +86,11 @@ class SlideshowFragment : Fragment(){
} }
binding.spinnerCuvette.adapter = adapter binding.spinnerCuvette.adapter = adapter
binding.spinnerCuvette.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { binding.spinnerCuvette.onItemSelectedListener =
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?, view: View?, position: Int, id: Long
) {
// Handle item selection here // Handle item selection here
selectedItem = values[position] selectedItem = values[position]
} }
@@ -103,54 +105,158 @@ class SlideshowFragment : Fragment(){
putString(Constants.CUVETTE_SIZE, selectedItem) putString(Constants.CUVETTE_SIZE, selectedItem)
apply() apply()
} }
Toast.makeText(requireContext(), "Selected cuvette size: $selectedItem", Toast.LENGTH_SHORT).show() Toast.makeText(
requireContext(), "Selected cuvette size: $selectedItem", Toast.LENGTH_SHORT
).show()
} }
childFragmentManager.beginTransaction().replace(binding.container.id,PrefsFragment()).commit() childFragmentManager.beginTransaction().replace(binding.container.id, PrefsFragment())
.commit()
} }
} }
class PrefsFragment : PreferenceFragmentCompat(){ class PrefsFragment : PreferenceFragmentCompat(){
private lateinit var tapManager: AppVersionTapManager
private var isServerSelectionVisible = false
private lateinit var serverPreference: Preference
private lateinit var currentServerPreference: Preference
lateinit var firebaseManager: FirebaseManager
lateinit var databaseRepository: DatabaseRepository
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
firebaseManager = FirebaseManager(requireContext())
databaseRepository = (activity as DashboardActivity).databaseRepository
tapManager = AppVersionTapManager()
val sharedPreference =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext()) val preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
val currentServer = firebaseManager.getLastSelectedServer().serverName
val languagePreference = ListPreference(requireContext()) // Language Preference
languagePreference.key = "language_preference" val languagePreference = ListPreference(requireContext()).apply {
languagePreference.title = getString(R.string.app_language) key = "language_preference"
languagePreference.summary = getString(R.string.select_language) title = getString(R.string.app_language)
languagePreference.entries = arrayOf("English", "Kannada", "Hindi") summary = getString(R.string.select_language)
languagePreference.entryValues = arrayOf("en", "kn", "hi") entries = arrayOf("English", "Kannada", "Hindi")
languagePreference.setDefaultValue("en") entryValues = arrayOf("en", "kn", "hi")
setDefaultValue("en")
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_translate_24)
languagePreference.onPreferenceChangeListener = onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
Preference.OnPreferenceChangeListener { _, newValue ->
val languageCode = newValue as String val languageCode = newValue as String
updateLanguage(requireContext(), languageCode) updateLanguage(requireContext(), languageCode)
true true
} }
}
preferenceScreen.addPreference(languagePreference) preferenceScreen.addPreference(languagePreference)
setPreferenceScreen(preferenceScreen)
// App Version Preference val appVersionPreference = Preference(requireContext()).apply {
val appVersionPreference = Preference(requireContext()) title = "App Version"
appVersionPreference.title = "App Version" summary =
appVersionPreference.summary = getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) +"->"+currentServer+"]"
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]" icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_info_24)
preferenceScreen.addPreference(languagePreference) setOnPreferenceClickListener {
if ((sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN")) {
tapManager.registerTap {
if (!isServerSelectionVisible) {
showServerSelection()
}
}
} else {
}
true
}
}
preferenceScreen.addPreference(appVersionPreference) preferenceScreen.addPreference(appVersionPreference)
currentServerPreference = Preference(requireContext()).apply {
key = "current_server_preference"
title = "Current Server"
summary = "No server selected"
isVisible = false
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_cloud_done_24)
setOnPreferenceClickListener {
// (activity as? DashboardActivity)?.sendData("hello test data")
// Toast.makeText(context, "data sent", Toast.LENGTH_SHORT).show() this was used to send the basic data as test data
true
}
}
preferenceScreen.addPreference(currentServerPreference)
setPreferenceScreen(preferenceScreen) setPreferenceScreen(preferenceScreen)
if (isLanguageChanged) { if (isLanguageChanged) {
Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), R.string.language_update, Toast.LENGTH_SHORT).show()
} }
}
private fun showServerSelection() {
val currentServer = firebaseManager.getLastSelectedServer().serverName
serverPreference = Preference(requireContext()).apply {
title = "Select Server"
summary = "Choose your server"
icon = ContextCompat.getDrawable(requireContext(), R.drawable.baseline_cloud_sync_24)
setOnPreferenceClickListener {
showServerSelectionDialog()
true
}
}
preferenceScreen.addPreference(serverPreference)
currentServerPreference.isVisible = true
currentServerPreference.summary = "Current Server: $currentServer"
Toast.makeText(requireContext(), "Server selection now available", Toast.LENGTH_SHORT).show()
}
private fun showServerSelectionDialog() {
val servers = firebaseManager.getAvailableServers()
val serverNames = servers.map { it.serverName }.toTypedArray()
val builder = AlertDialog.Builder(requireContext())
builder.setTitle("Select Server")
.setItems(serverNames) { _, which ->
val selectedServer = servers[which]
switchFirebaseServer(selectedServer)
}
.setNegativeButton("Cancel", null)
.show()
}
private fun switchFirebaseServer(firebaseConfig: FirebaseConfig) {
firebaseManager.switchServer(firebaseConfig)
Toast.makeText(requireContext(), "Switched to ${firebaseConfig.serverName}, Please wait for few seconds", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Restart needed restarting the app", Toast.LENGTH_SHORT).show()
firebaseManager.restartApp()
currentServerPreference.summary = "Current Server: ${firebaseConfig.serverName}"
} }
private fun switchCurrentServer(serverCode: String) {
Toast.makeText(requireContext(), "Switched to server: $serverCode", Toast.LENGTH_SHORT)
.show()
currentServerPreference.summary = "Current Server: $serverCode"
}
private fun updateLanguage(context: Context, languageCode: String) { private fun updateLanguage(context: Context, languageCode: String) {
LanguageManager.persistLanguagePreference(context, languageCode) LanguageManager.persistLanguagePreference(context, languageCode)
LanguageManager.setLocale(context, languageCode) LanguageManager.setLocale(context, languageCode)
requireActivity().recreate() // Recreate activity to apply language changes requireActivity().recreate()
isLanguageChanged = true isLanguageChanged = true
} }
private fun getAppVersion(context: Context): String { private fun getAppVersion(context: Context): String {
return try { return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
@@ -169,3 +275,5 @@ class PrefsFragment: PreferenceFragmentCompat(){
} }
} }
} }

View File

@@ -30,6 +30,7 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@@ -75,21 +76,35 @@ class LoginFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
init() init()
if(isInternetAvailable()){
getPublicIpAddr { ipAddress ->
DataHolder.ipAddress = ipAddress
}
Log.d("ipaddress",DataHolder.ipAddress)
}
// if(isInternetAvailable()){
// getPublicIpAddr { ipAddress ->
// DataHolder.ipAddress = ipAddress
// }
// Log.d("ipaddress",DataHolder.ipAddress)
// }
setupAutoCompleteTextView()
//checkLocation() //checkLocation()
} }
override fun onResume() {
super.onResume()
setupAutoCompleteTextView()
}
private fun setupAutoCompleteTextView() {
val districts = resources.getStringArray(R.array.district)
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, districts)
binding.etDistrict.setAdapter(adapter)
// Only set the default text if it's empty to avoid resetting user selection
if (binding.etDistrict.text.isEmpty()) {
binding.etDistrict.setText("Other", false)
}
}
private fun init() { private fun init() {
if (isUserLoggedIn()) { if (isUserLoggedIn()) {
navigateToHomeFragment() navigateToHomeFragment()
return return
} }
binding.btnLogin.setOnClickListener { binding.btnLogin.setOnClickListener {
// Toast.makeText(requireContext(), "$latitude/$longitude",Toast.LENGTH_SHORT).show() // Toast.makeText(requireContext(), "$latitude/$longitude",Toast.LENGTH_SHORT).show()
val loginId = binding.loginId.text.toString().trim() val loginId = binding.loginId.text.toString().trim()

View File

@@ -248,11 +248,15 @@ class DeviceProvisionFragment : Fragment() {
private fun encryptAndSaveToFile(username: String, password: String) { private fun encryptAndSaveToFile(username: String, password: String) {
val messageToEncrypt = "$username\n$password" val messageToEncrypt = "$username\n$password"
val encryptionKey = val encryptionKey = Settings.Secure.getString(requireContext().contentResolver, Settings.Secure.ANDROID_ID)
Settings.Secure.getString(context?.contentResolver, Settings.Secure.ANDROID_ID)
val encryptedString = Encryption.encrypt(messageToEncrypt, encryptionKey) val encryptedString = Encryption.encrypt(messageToEncrypt, encryptionKey)
Log.d("DEVICE ID/encryptionKey", encryptionKey) Log.d("DEVICE ID/encryptionKey", encryptionKey)
val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val target = File(requireContext().getExternalFilesDir(null), "HPOSDocuments")
if (!target.exists()) {
target.mkdirs() // Create the directory if it doesn't exist
}
// val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val file = File(target, "credentials.txt") val file = File(target, "credentials.txt")
if (!file.exists()) { if (!file.exists()) {

View File

@@ -0,0 +1,207 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hb_test
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
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.repository.DatabaseRepository
import com.example.hpostesting.firebase.FirebaseManager
import com.example.hpostesting.util.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHbTestBinding
import javax.inject.Inject
@AndroidEntryPoint
class HBTestActivity : AppCompatActivity() {
@Inject
lateinit var databaseRepository: DatabaseRepository
private lateinit var binding: ActivityHbTestBinding
val viewModel: HBTestViewModel by viewModels()
private var myMenu: Menu? = null
private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService
private val TAG = "HemoCube"
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
connectUsb(true)
DataHolder.usbConnected.postValue(true)
}
} else {
onErrorReported("permission denied for device")
DataHolder.usbConnected.postValue(true)
}
}
}
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder
mService = binder.getService()
viewModel.isServiceConnected = true
mConnection.let { mService.connect(mDriver, mConnection!!) }
moveToNext()
}
override fun onServiceDisconnected(arg0: ComponentName) {
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)
val firebaseManager = FirebaseManager(this)
val lastSelectedServer = firebaseManager.getLastSelectedServer()
// switchFirebaseServer(lastSelectedServer)
Log.d("CURRENT SERVR......","server : ${lastSelectedServer.serverName}")
binding = ActivityHbTestBinding.inflate(layoutInflater)
setContentView(binding.root)
// setSupportActionBar(binding.myToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener()
connectUsb(false)
}
// private fun switchFirebaseServer(config: FirebaseConfig) {
// val (newFirestore, newStorage) = firebaseManager.switchFirestoreServer(config)
// databaseRepository.switchServer(newFirestore, newStorage)
//// Toast.makeText(this, "server switched", Toast.LENGTH_SHORT).show()// Update repository with new Firestore and Storage
// }
private fun setupListener() {
DataHolder.usbConnected.observe(this) {
Log.d("USB OBSERVE", "HemoCube called -> $it")
if (it) {
myMenu?.get(0)?.icon =
ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
} 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()
}
}
}
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
if (availableDrivers.isEmpty()) {
onErrorReported("No Device is Connected")
} else {
mDriver = availableDrivers[0]
mConnection = manager.openDevice(mDriver.device)
if (mConnection == null) {
requestUserPermission(manager, mDriver.device)
} else {
setupService()
}
}
}
fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed()
}
private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgHbTest.id, HBTestFragment())
.commit()
}
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu)
return true
}
override fun onDestroy() {
super.onDestroy()
if (viewModel.isServiceConnected) {
mService.disconnect()
unbindService(connection)
viewModel.isServiceConnected = false
}
}
}

View File

@@ -0,0 +1,399 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hb_test
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.presentation.utils.UsbServiceListener
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentAutoDacBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHbTestBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import kotlin.math.log10
class HBTestFragment : Fragment() {
private var isUsingExistingBuffer = false
private var led1Average = 0.0
private var led3Average = 0.0
private var led2Average = 0.0
private var led4Average = 0.0
private var led1SampleForDevice = 0.0
private var led2SampleForDevice = 0.0
private var led3SampleForDevice = 0.0
private var led4SampleForDevice = 0.0
private var led1BufferForDevice = 0.0
private var led2BufferForDevice = 0.0
private var led3BufferForDevice = 0.0
private var led4BufferForDevice = 0.0
private var x = 0.0
private var deviceId = ""
private var hbEst = 0.0
private var testStatusCode = 0.0
private var testDetails: HemoCubeTestData = HemoCubeTestData()
private lateinit var binding: FragmentHbTestBinding
private val hBTestViewModel: HBTestViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
// private val messages = MutableLiveData<String>()
private var startListening = MutableLiveData(false)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = FragmentHbTestBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
}
private fun initViews() {
binding.btnSubmit.visibility = View.GONE
listenToHemoCube()
getDeviceId()
binding.tvSubtitle4.movementMethod = ScrollingMovementMethod()
binding.btnSubmit.setOnClickListener {
hBTestViewModel.messages.postValue(resultData)
binding.btnSubmit.visibility = View.GONE
testDetails.localFlag = false
testDetails.testStatus = true
testDetails.deviceId = deviceId
testDetails._id = DataHolder.sampleId
testDetails.kitSerial = DataHolder.kitSerial
testDetails.classificationResult = "HB: $hbEst"
testDetails.hb3 = x
testDetails.hb4 = hbEst
testDetails.age = DataHolder.age
testDetails.bloodGroup = DataHolder.bloodGroup
testDetails.led1Buffer = led1BufferForDevice
testDetails.led2Buffer = led2BufferForDevice
testDetails.led3Buffer = led3BufferForDevice
testDetails.led4Buffer = led4BufferForDevice
testDetails.led1Sample = led1SampleForDevice
testDetails.led2Sample = led2SampleForDevice
testDetails.led3Sample = led3SampleForDevice
testDetails.led4Sample = led4SampleForDevice
testDetails.led1Average = led1Average
testDetails.led2Average = led2Average
testDetails.led3Average = led3Average
testDetails.led4Average = led4Average
testDetails.testType = "HB Est"
testDetails.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
hBTestViewModel.uploadFirebaseQc(testDetails)
}
binding.btnBuffer.setOnClickListener {
binding.btnBuffer.visibility = View.GONE
binding.btnSample.isEnabled = false
binding.btnSample.isClickable = false
hBTestViewModel.messages.postValue("Buffer Started")
runBCommand()
}
binding.btnSample.setOnClickListener {
hBTestViewModel.messages.postValue("Sample Started")
binding.btnSample.visibility = View.GONE
binding.btnBuffer.visibility = View.GONE
runSCommand()
}
if (isBufferValueAvailable()) {
isUsingExistingBuffer = true
binding.btnBuffer.text = "Refresh Buffer"
binding.btnSample.isEnabled = true
binding.btnSample.isClickable = true
}else{
binding.btnBuffer.text = "Start Buffer"
binding.btnSample.isEnabled = false
binding.btnSample.isClickable = false
}
}
private fun observeViewModel() {
hBTestViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
hBTestViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it
}
hBTestViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Data uploaded successfully")
requireActivity().finish()
}
if (result == "Local") {
showToast("Data uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
}
private fun getDeviceId() {
hBTestViewModel.progressBar.postValue(true)
(activity as HBTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
//deviceId = stringData
hBTestViewModel.messages.postValue(stringData)
binding.tvSubtitle4.text = stringData
}
}
override fun onUsbError(e: Exception?) {
hBTestViewModel.progressBar.postValue(false)
}
})
}
private fun runBCommand() {
hBTestViewModel.progressBar.postValue(true)
(activity as HBTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.START_BUFFER_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
hBTestViewModel.progressBar.postValue(false)
}
})
}
private fun runSCommand() {
hBTestViewModel.progressBar.postValue(true)
(activity as HBTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.START_SAMPLE,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
hBTestViewModel.progressBar.postValue(false)
}
})
}
private fun runPCommand() {
hBTestViewModel.progressBar.postValue(true)
(activity as HBTestActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.PRINT_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
hBTestViewModel.progressBar.postValue(false)
}
})
}
fun extractV2HardwareId(input: String): String? {
val pattern = Regex("SNS\\s*(.*?)\\s*SNE")
val matchResult: MatchResult? = pattern.find(input)
return matchResult?.groups?.get(1)?.value
}
private fun listenToHemoCube() {
val fullReadOutput = StringBuilder()
startListening.postValue(true)
try {
(activity as HBTestActivity).mService.listenToHemoCube(object :
UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
fullReadOutput.append(stringData)
resultData += stringData
hBTestViewModel.messages.postValue(resultData)
// binding.tvSubtitle4.text = resultData
if (stringData.contains("SNE")) {
val slData = stringData.split(" ")
if (slData.size > 1) {
val hardwareId = slData[1].trim()
deviceId = extractV2HardwareId(resultData).toString()
hBTestViewModel.messages.postValue("Place buffer and click below button to start test")
// with(sharedPreferences.edit()) {
// putString(Constants.DEVICE_ID, hardwareId)
// apply()
// }
}
activity?.runOnUiThread {
binding.btnBuffer.visibility = View.VISIBLE
}
}
}
if (resultData.contains("#BC") && testStatusCode < 1.0) {
testStatusCode = 1.1
resultData += getString(R.string.buffer_completed)
hBTestViewModel.messages.postValue(resultData)
activity?.runOnUiThread {
binding.btnSample.visibility = View.VISIBLE
binding.btnSample.isEnabled = true
binding.btnSample.isClickable = true
}
}
if (resultData.contains("#SC") && testStatusCode < 1.3) {
testStatusCode = 1.4
resultData +=getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)
hBTestViewModel.messages.postValue(resultData)
activity?.runOnUiThread {
binding.btnSubmit.visibility = View.VISIBLE
runPCommand()
}
}
if (resultData.contains("REND") && testStatusCode < 1.5) {
testStatusCode = 1.6
runResult()
}
}
override fun onUsbError(e: Exception?) {
hBTestViewModel.progressBar.postValue(false)
}
})
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
}
}
private fun runResult() {
resultData += "\nFetching results...\n"
hBTestViewModel.messages.postValue(resultData)
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim()
led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[2].split(' ')[1].trim()
led2BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_2, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[3].split(' ')[1].trim()
led3BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_3, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
bufferIntensity = resultLines[4].split(' ')[1].trim()
led4BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_4, "")?.toDoubleOrNull()!!
} else {
bufferIntensity.toDoubleOrNull()!!
}
led1SampleForDevice = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2SampleForDevice = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4SampleForDevice = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
led1Average = log10(led1BufferForDevice.div(led1SampleForDevice))
led2Average = log10(led2BufferForDevice.div(led2SampleForDevice))
led3Average = log10(led3BufferForDevice.div(led3SampleForDevice))
led4Average = log10(led4BufferForDevice.div(led4SampleForDevice))
x = led1Average - led3Average
hbEst = (7.347 * x * x) + (12.704 * x) + 0.9033
resultData +="\n Result: HB EST: $hbEst"
if (!isUsingExistingBuffer) {
with(sharedPreferences.edit()) {
putString(Constants.BUFFER_VALUE_1, led1BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_2, led2BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_3, led3BufferForDevice.toString())
putString(Constants.BUFFER_VALUE_4, led4BufferForDevice.toString())
apply()
}
}
hBTestViewModel.messages.postValue(resultData)
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
private fun isBufferValueAvailable(): Boolean {
return try {
if (sharedPreferences.getString(
Constants.BUFFER_VALUE_1, ""
) != "" && sharedPreferences.getString(Constants.BUFFER_VALUE_2, "") != ""
&& sharedPreferences.getString(Constants.BUFFER_VALUE_3, "") != ""
&& sharedPreferences.getString(Constants.BUFFER_VALUE_4, "") != ""
) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")
?.toDouble()!! > 0.0 && sharedPreferences.getString(
Constants.BUFFER_VALUE_2,
""
)
?.toDouble()!! > 0.0 && sharedPreferences.getString(
Constants.BUFFER_VALUE_3,
""
)
?.toDouble()!! > 0.0 && sharedPreferences.getString(
Constants.BUFFER_VALUE_4,
""
)
?.toDouble()!! > 0.0
} else {
false
}
} catch (e: Exception) {
showToast("error_exist")
false
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
* // Notice: All information contained herein is, and remains
* // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
* // if any. The intellectual and technical concepts contained
* // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
* // and its suppliers and may be covered by Indian and Foreign Patents,
* // patents in process, and are protected by trade secret or copyright law.
* // Dissemination of this information or reproduction of this material
* // is strictly forbidden unless prior written permission is obtained
* // from ShanMukha Innovations Pvt. Ltd.
*/
package com.example.hpostesting.presentation.hb_test
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class HBTestViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao,
private val repository: Repository,
context: Context,
) : ViewModel() {
var isServiceConnected = false
val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>()
fun uploadFirebaseQc(testDetails: HemoCubeTestData){
viewModelScope.launch {
try {
when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> {
Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success")
testDetails.localFlag = true
hemoCubeDao.updateTest(testDetails)
}
is Response.Error -> {
Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
hemoCubeDao.updateTest(testDetails)
}
else -> {}
}
} catch (e: Exception) {
fireBaseUpload.postValue("Error")
}
}
}
fun addAutoDacDataToDb(data: DiagnosticsData) {
viewModelScope.launch {
try {
when (val response = repository.addDiagnostics(data)) {
is Response.Success -> {
fireBaseUpload.postValue("Success")
}
is Response.Error -> {
fireBaseUpload.postValue("Error")
}
}
} catch (e: Exception) {
fireBaseUpload.postValue("Error")
}
}
}
}

View File

@@ -57,7 +57,7 @@ class DigitalCardFragment : Fragment() {
binding.progressBar.visibility = View.VISIBLE binding.progressBar.visibility = View.VISIBLE
} }
Log.d("DigitalCardFragment", "Name: ${DataHolder.hemoCubeTestData?.name}") Log.d("DigitalCardFragment", "Name: ${DataHolder.hemoCubeTestData?.name}")
Log.d("DigitalCardFragment", "DOB: ${testDetails?.birthYear}") Log.d("DigitalCardFragment", "DOB: ${testDetails?.age}")
Log.d("DigitalCardFragment", "Gender: ${testDetails?.gender}") Log.d("DigitalCardFragment", "Gender: ${testDetails?.gender}")
Log.d("DigitalCardFragment", "State: ${testDetails?.state}") Log.d("DigitalCardFragment", "State: ${testDetails?.state}")
Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}") Log.d("DigitalCardFragment", "ABHA ID: ${testDetails?.abhaId}")
@@ -67,7 +67,7 @@ class DigitalCardFragment : Fragment() {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
binding.name.text = "Name: ${DataHolder.hemoCubeTestData?.name}" binding.name.text = "Name: ${DataHolder.hemoCubeTestData?.name}"
binding.dob.text = "DOB: ${testDetails?.birthYear}" binding.dob.text = "DOB: ${testDetails?.age}"
binding.gender.text = "Gender: ${testDetails?.gender}" binding.gender.text = "Gender: ${testDetails?.gender}"
binding.State.text = "State: ${testDetails?.state}" binding.State.text = "State: ${testDetails?.state}"
binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}" binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}"

View File

@@ -52,11 +52,45 @@ import kotlin.random.Random
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
class HemoCubeFragment : Fragment() { class HemoCubeFragment : Fragment() {
private var positiveBoderLine10mm1=Constants.positiveBoderLine10mm1
private var positiveBoderLine10mm2=Constants.positiveBoderLine10mm2
private var negativeBoderLine10mm1=Constants.negativeBoderLine10mm1
private var negativeBoderLine10mm2=Constants.negativeBoderLine10mm2
private var normalMin10mm=Constants.normalMin10mm
private var normalMax10mm=Constants.normalMax10mm
private var negativeBorderlineMin10mm=Constants.negativeBorderlineMin10mm
private var negativeBorderlineMax10mm=Constants.negativeBorderlineMax10mm
private var sickleCellTraitMin10mm=Constants.sickleCellTraitMin10mm
private var sickleCellTraitMax10mm=Constants.sickleCellTraitMax10mm
private var positiveForSickleCellMin10mm=Constants.positiveForSickleCellMin10mm
private var positiveForSickleCellMax10mm=Constants.positiveForSickleCellMax10mm
private var sickleCellDiseaseMin10mm=Constants.sickleCellDiseaseMin10mm
private var sickleCellDiseaseMax10mm=Constants.sickleCellDiseaseMax10mm
private var positiveBoderLine2mm1=Constants.positiveBoderLine2mm1
private var positiveBoderLine2mm2=Constants.positiveBoderLine2mm2
private var negativeBoderLine2mm1=Constants.negativeBoderLine2mm1
private var negativeBoderLine2mm2=Constants.negativeBoderLine2mm2
private var normalMin2mm=Constants.normalMin2mm
private var normalMax2mm=Constants.normalMax2mm
private var negativeBorderlineMin2mm=Constants.negativeBorderlineMin2mm
private var negativeBorderlineMax2mm=Constants.negativeBorderlineMax2mm
private var sickleCellTraitMin2mm=Constants.sickleCellTraitMin2mm
private var sickleCellTraitMax2mm=Constants.sickleCellTraitMax2mm
private var positiveForSickleCellMin2mm=Constants.positiveForSickleCellMin2mm
private var positiveForSickleCellMax2mm=Constants.positiveForSickleCellMax2mm
private var sickleCellDiseaseMin2mm=Constants.sickleCellDiseaseMin2mm
private var sickleCellDiseaseMax2mm=Constants.sickleCellDiseaseMax2mm
private var temperature="" private var temperature=""
private var cuvetteSize = "10mm" private var cuvetteSize = "10mm"
private var checkCuvette = false private var checkCuvette = false
private var checkRefreshCuvette = false
private var checkCuvetteSam = false private var checkCuvetteSam = false
private var checkSubmit = false
private var submitClick = false
private var sampleClick = false private var sampleClick = false
private var refreshClick = false
private lateinit var binding: FragmentHemoCubeReferenceBinding private lateinit var binding: FragmentHemoCubeReferenceBinding
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
@@ -100,6 +134,36 @@ class HemoCubeFragment : Fragment() {
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
cuvetteSize = sharedPreferences.getString(Constants.CUVETTE_SIZE,"10mm").toString() cuvetteSize = sharedPreferences.getString(Constants.CUVETTE_SIZE,"10mm").toString()
positiveBoderLine10mm1 = sharedPreferences.getString("positiveBoderLine10mm1", Constants.positiveBoderLine10mm1.toString())?.toDoubleOrNull() ?: Constants.positiveBoderLine10mm1
positiveBoderLine10mm2 = sharedPreferences.getString("positiveBoderLine10mm2", Constants.positiveBoderLine10mm2.toString())?.toDoubleOrNull() ?: Constants.positiveBoderLine10mm2
negativeBoderLine10mm1 = sharedPreferences.getString("negativeBoderLine10mm1", Constants.negativeBoderLine10mm1.toString())?.toDoubleOrNull() ?: Constants.negativeBoderLine10mm1
negativeBoderLine10mm2 = sharedPreferences.getString("negativeBoderLine10mm2", Constants.negativeBoderLine10mm2.toString())?.toDoubleOrNull() ?: Constants.negativeBoderLine10mm2
normalMin10mm = sharedPreferences.getString("normalMin10mm", Constants.normalMin10mm.toString())?.toDoubleOrNull() ?: Constants.normalMin10mm
normalMax10mm = sharedPreferences.getString("normalMax10mm", Constants.normalMax10mm.toString())?.toDoubleOrNull() ?: Constants.normalMax10mm
negativeBorderlineMin10mm = sharedPreferences.getString("negativeBorderlineMin10mm", Constants.negativeBorderlineMin10mm.toString())?.toDoubleOrNull() ?: Constants.negativeBorderlineMin10mm
negativeBorderlineMax10mm = sharedPreferences.getString("negativeBorderlineMax10mm", Constants.negativeBorderlineMax10mm.toString())?.toDoubleOrNull() ?: Constants.negativeBorderlineMax10mm
sickleCellTraitMin10mm = sharedPreferences.getString("sickleCellTraitMin10mm", Constants.sickleCellTraitMin10mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellTraitMin10mm
sickleCellTraitMax10mm = sharedPreferences.getString("sickleCellTraitMax10mm", Constants.sickleCellTraitMax10mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellTraitMax10mm
positiveForSickleCellMin10mm = sharedPreferences.getString("positiveForSickleCellMin10mm", Constants.positiveForSickleCellMin10mm.toString())?.toDoubleOrNull() ?: Constants.positiveForSickleCellMin10mm
positiveForSickleCellMax10mm = sharedPreferences.getString("positiveForSickleCellMax10mm", Constants.positiveForSickleCellMax10mm.toString())?.toDoubleOrNull() ?: Constants.positiveForSickleCellMax10mm
sickleCellDiseaseMin10mm = sharedPreferences.getString("sickleCellDiseaseMin10mm", Constants.sickleCellDiseaseMin10mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellDiseaseMin10mm
sickleCellDiseaseMax10mm = sharedPreferences.getString("sickleCellDiseaseMax10mm", Constants.sickleCellDiseaseMax10mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellDiseaseMax10mm
positiveBoderLine2mm1 = sharedPreferences.getString("positiveBoderLine2mm1", Constants.positiveBoderLine2mm1.toString())?.toDoubleOrNull() ?: Constants.positiveBoderLine2mm1
positiveBoderLine2mm2 = sharedPreferences.getString("positiveBoderLine2mm2", Constants.positiveBoderLine2mm2.toString())?.toDoubleOrNull() ?: Constants.positiveBoderLine2mm2
negativeBoderLine2mm1 = sharedPreferences.getString("negativeBoderLine2mm1", Constants.negativeBoderLine2mm1.toString())?.toDoubleOrNull() ?: Constants.negativeBoderLine2mm1
negativeBoderLine2mm2 = sharedPreferences.getString("negativeBoderLine2mm2", Constants.negativeBoderLine2mm2.toString())?.toDoubleOrNull() ?: Constants.negativeBoderLine2mm2
normalMin2mm = sharedPreferences.getString("normalMin2mm", Constants.normalMin2mm.toString())?.toDoubleOrNull() ?: Constants.normalMin2mm
normalMax2mm = sharedPreferences.getString("normalMax2mm", Constants.normalMax2mm.toString())?.toDoubleOrNull() ?: Constants.normalMax2mm
negativeBorderlineMin2mm = sharedPreferences.getString("negativeBorderlineMin2mm", Constants.negativeBorderlineMin2mm.toString())?.toDoubleOrNull() ?: Constants.negativeBorderlineMin2mm
negativeBorderlineMax2mm = sharedPreferences.getString("negativeBorderlineMax2mm", Constants.negativeBorderlineMax2mm.toString())?.toDoubleOrNull() ?: Constants.negativeBorderlineMax2mm
sickleCellTraitMin2mm = sharedPreferences.getString("sickleCellTraitMin2mm", Constants.sickleCellTraitMin2mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellTraitMin2mm
sickleCellTraitMax2mm = sharedPreferences.getString("sickleCellTraitMax2mm", Constants.sickleCellTraitMax2mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellTraitMax2mm
positiveForSickleCellMin2mm = sharedPreferences.getString("positiveForSickleCellMin2mm", Constants.positiveForSickleCellMin2mm.toString())?.toDoubleOrNull() ?: Constants.positiveForSickleCellMin2mm
positiveForSickleCellMax2mm = sharedPreferences.getString("positiveForSickleCellMax2mm", Constants.positiveForSickleCellMax2mm.toString())?.toDoubleOrNull() ?: Constants.positiveForSickleCellMax2mm
sickleCellDiseaseMin2mm = sharedPreferences.getString("sickleCellDiseaseMin2mm", Constants.sickleCellDiseaseMin2mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellDiseaseMin2mm
sickleCellDiseaseMax2mm = sharedPreferences.getString("sickleCellDiseaseMax2mm", Constants.sickleCellDiseaseMax2mm.toString())?.toDoubleOrNull() ?: Constants.sickleCellDiseaseMax2mm
testState = TestState( testState = TestState(
testDetails = DataHolder.selectedTest?.toHemoCubeTestData(), testDetails = DataHolder.selectedTest?.toHemoCubeTestData(),
) )
@@ -120,11 +184,29 @@ class HemoCubeFragment : Fragment() {
binding.tvSubtitle4.movementMethod = ScrollingMovementMethod() binding.tvSubtitle4.movementMethod = ScrollingMovementMethod()
binding.tvDeviceMessages.movementMethod = ScrollingMovementMethod() binding.tvDeviceMessages.movementMethod = ScrollingMovementMethod()
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
// with(sharedPreferences.edit()) {
// putBoolean(Constants.QUICK_CAPTURE, false)
// apply()
// }
// if(DataHolder.hemoCubeTestData!!.classificationResult != "Invalid"){
// DataHolder.sampleReadCounter++
// }
// binding.btnSubmit.isEnabled = false
// binding.btnSubmit.isClickable = false
// activity?.runOnUiThread {
// Log.d("HemoCubeFragment","Test Process completed, result saved")
// binding.progressBar.visibility = View.VISIBLE
// binding.btnSubmit.visibility = View.GONE
// }
submitClick = true
if(checkSubmit){
with(sharedPreferences.edit()) { with(sharedPreferences.edit()) {
putBoolean(Constants.QUICK_CAPTURE, false) putBoolean(Constants.QUICK_CAPTURE, false)
apply() apply()
} }
if(DataHolder.hemoCubeTestData!!.classificationResult != "Invalid"){
DataHolder.sampleReadCounter++ DataHolder.sampleReadCounter++
}
binding.btnSubmit.isEnabled = false binding.btnSubmit.isEnabled = false
binding.btnSubmit.isClickable = false binding.btnSubmit.isClickable = false
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -135,6 +217,11 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.uploadHemoCubeResultToDatabase( hemoCubeViewModel.uploadHemoCubeResultToDatabase(
isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, ""),quickCapture isOnline, true, sharedPreferences.getString(Constants.KIT_NUMBER, ""),quickCapture
) )
}else{
checkCuvettePresence()
binding.btnSubmit.isEnabled = true
binding.btnSubmit.isClickable = true
}
} }
binding.tvTitle2.visibility = View.GONE binding.tvTitle2.visibility = View.GONE
@@ -150,14 +237,19 @@ class HemoCubeFragment : Fragment() {
if (isBufferValueAvailable()){ if (isBufferValueAvailable()){
hemoCubeViewModel.messages.postValue("Ready to test") hemoCubeViewModel.messages.postValue("Ready to test")
binding.btnPlacebuffer.apply { isUsingExistingBuffer = true
setBackgroundColor(Color.GREEN) // Set button background color to green binding.btnPlaceRefreshbuffer.visibility = View.VISIBLE
text = "Refresh Buffer" // Change button text to "Buffer Exists" binding.btnPlacebuffer.visibility = View.GONE
} // binding.btnPlacebuffer.apply {
// setBackgroundColor(Color.GREEN) // Set button background color to green
// text = "Refresh Buffer" // Change button text to "Buffer Exists"
// }
binding.btnSamplestart.isClickable = true binding.btnSamplestart.isClickable = true
binding.btnSamplestart.isEnabled = true binding.btnSamplestart.isEnabled = true
}else{ }else{
hemoCubeViewModel.messages.postValue("Fresh Kit - Please take Buffer Blank reading") hemoCubeViewModel.messages.postValue("Fresh Kit - Please take Buffer Blank reading")
binding.btnPlacebuffer.visibility = View.VISIBLE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.apply { binding.btnPlacebuffer.apply {
setBackgroundColor(Color.RED) // Set button background color to green setBackgroundColor(Color.RED) // Set button background color to green
text = "Fresh Buffer" // Change button text to "Buffer Exists" text = "Fresh Buffer" // Change button text to "Buffer Exists"
@@ -188,6 +280,23 @@ class HemoCubeFragment : Fragment() {
Log.d("HemoCubeFragment","Retry Check Cuvette") Log.d("HemoCubeFragment","Retry Check Cuvette")
checkCuvettePresence() checkCuvettePresence()
} }
binding.btnPlaceRefreshbuffer.setOnClickListener {
activity?.runOnUiThread {
Log.d("HemoCubeFragment","Test Process started, reBuffer started")
binding.testing.visibility = View.VISIBLE
}
isUsingExistingBuffer = false
refreshClick = true
if(checkRefreshCuvette){
startBufferProcess()
activity?.runOnUiThread {
binding.tvSubtitle4.visibility = View.VISIBLE
}
}else{
checkCuvettePresence()
}
}
binding.btnPlacebuffer.setOnClickListener { binding.btnPlacebuffer.setOnClickListener {
activity?.runOnUiThread { activity?.runOnUiThread {
Log.d("HemoCubeFragment","Test Process started, Buffer started") Log.d("HemoCubeFragment","Test Process started, Buffer started")
@@ -393,7 +502,7 @@ class HemoCubeFragment : Fragment() {
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
binding.tvSubtitle4.text = getString(R.string.place_sample) binding.tvSubtitle4.text = getString(R.string.place_sample)
} }
isUsingExistingBuffer = true //isUsingExistingBuffer = true
} }
}) })
} }
@@ -495,7 +604,13 @@ class HemoCubeFragment : Fragment() {
//EPROM ADC Loaded //EPROM ADC Loaded
//checkCuvettePresence() //checkCuvettePresence()
activity?.runOnUiThread { activity?.runOnUiThread {
if(isBufferValueAvailable()){
binding.btnPlaceRefreshbuffer.visibility = View.VISIBLE
binding.btnPlacebuffer.visibility = View.GONE
}else{
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.VISIBLE binding.btnPlacebuffer.visibility = View.VISIBLE
}
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
} }
getTemp() getTemp()
@@ -512,6 +627,7 @@ class HemoCubeFragment : Fragment() {
checkCuvetteSam = true checkCuvetteSam = true
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.btnRetryCheckCuvette.visibility = View.GONE binding.btnRetryCheckCuvette.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
} }
@@ -524,7 +640,30 @@ class HemoCubeFragment : Fragment() {
} }
showRetryButtonForCuvette() showRetryButtonForCuvette()
} }
resultData.contains("#CIN") && refreshClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTR.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present))
this.testStatusCode = TestStatus.CUVETTE_PRESENTR.code
activity?.runOnUiThread {
checkRefreshCuvette = true
binding.testing.visibility = View.GONE
binding.btnRetryCheckCuvette.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.VISIBLE
binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = false
binding.btnSamplestart.isEnabled = false
}
}
resultData.contains("#AIN") && refreshClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTR.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_absent))
this.testStatusCode = TestStatus.CUVETTE_ABSENTR.code
activity?.runOnUiThread {
binding.testing.visibility = View.GONE
binding.btnSamplestart.isClickable = false
binding.btnSamplestart.isEnabled = false
}
showRetryButtonForCuvette()
}
resultData.contains("#CIN") && this.testStatusCode < TestStatus.CUVETTE_PRESENT.code -> { resultData.contains("#CIN") && this.testStatusCode < TestStatus.CUVETTE_PRESENT.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present)) hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_present))
this.testStatusCode = TestStatus.CUVETTE_PRESENT.code this.testStatusCode = TestStatus.CUVETTE_PRESENT.code
@@ -534,6 +673,8 @@ class HemoCubeFragment : Fragment() {
binding.btnRetryCheckCuvette.visibility = View.GONE binding.btnRetryCheckCuvette.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.VISIBLE binding.btnPlacebuffer.visibility = View.VISIBLE
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = false
binding.btnSamplestart.isEnabled = false
} }
} }
resultData.contains("#AIN") && this.testStatusCode <= TestStatus.CUVETTE_ABSENT.code -> { resultData.contains("#AIN") && this.testStatusCode <= TestStatus.CUVETTE_ABSENT.code -> {
@@ -541,14 +682,33 @@ class HemoCubeFragment : Fragment() {
this.testStatusCode = TestStatus.CUVETTE_ABSENT.code this.testStatusCode = TestStatus.CUVETTE_ABSENT.code
activity?.runOnUiThread { activity?.runOnUiThread {
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.btnSamplestart.isClickable = false
binding.btnSamplestart.isEnabled = false
} }
showRetryButtonForCuvette() showRetryButtonForCuvette()
} }
resultData.contains("#CIN") && this.submitClick && this.testStatusCode < TestStatus.CUVETTE_PRESENTT.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_presentt))
this.testStatusCode = TestStatus.CUVETTE_PRESENTT.code
activity?.runOnUiThread {
binding.testing.visibility = View.GONE
}
}
resultData.contains("#AIN") && this.submitClick && this.testStatusCode <= TestStatus.CUVETTE_ABSENTT.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.cuvette_absentt))
this.testStatusCode = TestStatus.CUVETTE_ABSENTT.code
activity?.runOnUiThread {
checkSubmit = true
binding.testing.visibility = View.GONE
}
}
resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> { resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started)) hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started))
this.testStatusCode = TestStatus.BUFFER_STARTED.code this.testStatusCode = TestStatus.BUFFER_STARTED.code
activity?.runOnUiThread { activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnSamplestart.isClickable = false binding.btnSamplestart.isClickable = false
binding.btnSamplestart.isEnabled = false binding.btnSamplestart.isEnabled = false
} }
@@ -557,14 +717,14 @@ class HemoCubeFragment : Fragment() {
resultData.contains("#BC") && this.testStatusCode < TestStatus.BUFFER_COMPLETED.code -> { resultData.contains("#BC") && this.testStatusCode < TestStatus.BUFFER_COMPLETED.code -> {
activity?.runOnUiThread { activity?.runOnUiThread {
resultData = "" resultData = ""
if(Constants.FLAGS_ENABLED){ if(Constants.BUFFER_FLAGS_ENABLED){
fetchResult() fetchResult()
}else{ }else{
Log.d("resultDataBC",resultData) Log.d("resultDataBC",resultData)
activity?.runOnUiThread { activity?.runOnUiThread {
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.tvSubtitle4.text = getString(R.string.buffer_completed) binding.tvSubtitle4.text = getString(R.string.buffer_completed)
// binding.btnSamplestart.visibility = View.VISIBLE binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true binding.btnSamplestart.isClickable = true
@@ -623,8 +783,8 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.messages.postValue( hemoCubeViewModel.messages.postValue(
getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data) getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)
) )
fetchResult()
currentResultData = "" currentResultData = ""
fetchResult()
} }
resultData.contains("ovf") -> { resultData.contains("ovf") -> {
@@ -791,11 +951,12 @@ class HemoCubeFragment : Fragment() {
val lb1Value = lb1Match!!.groupValues[1].toFloat() val lb1Value = lb1Match!!.groupValues[1].toFloat()
val lb2Value = lb2Match!!.groupValues[1].toFloat() val lb2Value = lb2Match!!.groupValues[1].toFloat()
val led1Min = 21000.00 // val led1Min = sharedPreferences.getString("bufferMinLed1", "21000.00")?.toDouble()
val led1Max = 23000.00 val led1Min = sharedPreferences.getString("bufferMinLed1", Constants.bufferMinLed1.toString())?.toDoubleOrNull() ?: Constants.bufferMinLed1
val led1Max = sharedPreferences.getString("bufferMaxLed1", Constants.bufferMaxLed1.toString())?.toDoubleOrNull() ?: Constants.bufferMaxLed1
val led2Min = 17000.00 val led2Min = sharedPreferences.getString("bufferMinLed2", Constants.bufferMinLed2.toString())?.toDoubleOrNull() ?: Constants.bufferMinLed2
val led2Max = 19000.00 val led2Max = sharedPreferences.getString("bufferMaxLed2", Constants.bufferMaxLed2.toString())?.toDoubleOrNull() ?: Constants.bufferMaxLed2
val isLb1InRange = lb1Value in led1Min..led1Max val isLb1InRange = lb1Value in led1Min..led1Max
val isLb2InRange = lb2Value in led2Min..led2Max val isLb2InRange = lb2Value in led2Min..led2Max
@@ -814,6 +975,7 @@ class HemoCubeFragment : Fragment() {
// binding.btnPlacebuffer.visibility = View.GONE // binding.btnPlacebuffer.visibility = View.GONE
binding.btnRetryCheckCuvette.visibility = View.VISIBLE binding.btnRetryCheckCuvette.visibility = View.VISIBLE
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.GONE binding.btnSamplestart.visibility = View.GONE
} }
} }
@@ -844,7 +1006,7 @@ class HemoCubeFragment : Fragment() {
getString(R.string.data_collected_processing_data) getString(R.string.data_collected_processing_data)
) )
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim() var bufferIntensity = resultLines[1].split(' ')[1].trim()
led1BufferForDevice = if (isUsingExistingBuffer) { led1BufferForDevice = if (isUsingExistingBuffer) {
sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()!! sharedPreferences.getString(Constants.BUFFER_VALUE_1, "")?.toDoubleOrNull()!!
@@ -997,7 +1159,20 @@ class HemoCubeFragment : Fragment() {
//used for latest trueheme and v1 //used for latest trueheme and v1
val deviceRatio = led2Average / led1Average val deviceRatio = led2Average / led1Average
val borderlineMetric = (led1Average - led2Average) / deviceRatio val borderlineMetric = (led1Average - led2Average) / deviceRatio
// activity?.runOnUiThread {
// Toast.makeText(requireContext(),"count: ${DataHolder.sampleReadCounter}",Toast.LENGTH_LONG).show()
// }
if(led1Average < 0 || led2Average < 0){
hemoCubeViewModel.messages.postValue("Negative Absorbance - Repeat test with reading Buffer first and sample second")
this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code
binding.testing.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true
binding.btnSamplestart.isEnabled = true
return
}
if(Constants.ABS_FLAGS_ENABLED){ if(Constants.ABS_FLAGS_ENABLED){
val inRange2mmLed1: Boolean val inRange2mmLed1: Boolean
val inRange2mmLed2: Boolean val inRange2mmLed2: Boolean
@@ -1015,6 +1190,7 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.messages.postValue("Negative Absorbance - Repeat test with reading Buffer first and sample second") hemoCubeViewModel.messages.postValue("Negative Absorbance - Repeat test with reading Buffer first and sample second")
this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true binding.btnSamplestart.isClickable = true
@@ -1028,6 +1204,7 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.messages.postValue("Absorbance out-of-Range - Repeat test with adequate blood volume and Incubation time") hemoCubeViewModel.messages.postValue("Absorbance out-of-Range - Repeat test with adequate blood volume and Incubation time")
this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true binding.btnSamplestart.isClickable = true
@@ -1041,6 +1218,7 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.messages.postValue("Absorbance out-of-Range - Repeat test with adequate blood volume and Incubation time") hemoCubeViewModel.messages.postValue("Absorbance out-of-Range - Repeat test with adequate blood volume and Incubation time")
this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code this.testStatusCode = TestStatus.BUFFER_PRINT_COMPLETED.code
binding.testing.visibility = View.GONE binding.testing.visibility = View.GONE
binding.btnPlaceRefreshbuffer.visibility = View.GONE
binding.btnPlacebuffer.visibility = View.GONE binding.btnPlacebuffer.visibility = View.GONE
binding.btnSamplestart.visibility = View.VISIBLE binding.btnSamplestart.visibility = View.VISIBLE
binding.btnSamplestart.isClickable = true binding.btnSamplestart.isClickable = true
@@ -1211,6 +1389,10 @@ class HemoCubeFragment : Fragment() {
"%.3f".format( "%.3f".format(
this.deviceRatio this.deviceRatio
) )
} : ${
"%.3f".format(
borderlineMetric
)
}" }"
) )
if (DataHolder.hemoCubeTestData?.testType == "HB") if (DataHolder.hemoCubeTestData?.testType == "HB")
@@ -1286,39 +1468,39 @@ class HemoCubeFragment : Fragment() {
if (deviceRatio != null && borderlineMetric != null) { if (deviceRatio != null && borderlineMetric != null) {
if(cuvetteSize == "10mm"){ if(cuvetteSize == "10mm"){
if (deviceRatioClass == "Negative Borderline") { if (deviceRatioClass == "Negative Borderline") {
if (borderlineMetric < Constants.negativeBoderLine10mm1){//1.34 if (borderlineMetric < negativeBoderLine10mm1){//2.0
return "Sickle Cell Trait" return "Sickle Cell Trait"
}else if(borderlineMetric > Constants.negativeBoderLine10mm2){ }else if(borderlineMetric > negativeBoderLine10mm1){
return "Normal" return "Normal"
}else if(borderlineMetric > Constants.negativeBoderLine10mm1 && borderlineMetric < Constants.negativeBoderLine10mm2){ }else if(borderlineMetric == negativeBoderLine10mm1){//borderlineMetric > negativeBoderLine10mm1 && borderlineMetric < negativeBoderLine10mm2
return "Negative borderline. Confirm with HPLC" return "Sickle Cell Trait"//"Negative borderline. Confirm with HPLC"
} }
} }
if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") { if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") {
if (borderlineMetric < Constants.positiveBoderLine10mm1){//1.34 if (borderlineMetric < positiveBoderLine10mm1){//1.3
return "Sickle Cell Disease" return "Sickle Cell Disease"
}else if(borderlineMetric > Constants.positiveBoderLine10mm2){ }else if(borderlineMetric > positiveBoderLine10mm1){
return "Sickle Cell Trait" return "Sickle Cell Trait"
}else if(borderlineMetric > Constants.positiveBoderLine10mm1 && borderlineMetric < Constants.positiveBoderLine10mm2){ }else if(borderlineMetric == positiveBoderLine10mm1){//borderlineMetric > positiveBoderLine10mm1 && borderlineMetric < positiveBoderLine10mm2
return "Positive for Sickle Cell. Confirm with HPLC" return "Sickle Cell Disease"//"Positive for Sickle Cell. Confirm with HPLC"
} }
} }
}else if(cuvetteSize == "2mm"){ }else if(cuvetteSize == "2mm"){
if (deviceRatioClass == "Negative Borderline") { if (deviceRatioClass == "Negative Borderline") {
if (borderlineMetric < Constants.negativeBoderLine2mm1){//1.34 if (borderlineMetric < negativeBoderLine2mm1){//1.34
return "Sickle Cell Trait" return "Sickle Cell Trait"
}else if(borderlineMetric > Constants.negativeBoderLine2mm2){ }else if(borderlineMetric > negativeBoderLine2mm2){
return "Normal" return "Normal"
}else if(borderlineMetric > Constants.negativeBoderLine2mm1 && borderlineMetric < Constants.negativeBoderLine2mm2){ }else if(borderlineMetric > negativeBoderLine2mm1 && borderlineMetric < negativeBoderLine2mm2){
return "Negative borderline. Confirm with HPLC" return "Negative borderline. Confirm with HPLC"
} }
} }
if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") { if (deviceRatioClass == "Positive for Sickle Cell. HPLC for Confirmation") {
if (borderlineMetric < Constants.positiveBoderLine2mm1){//1.34 if (borderlineMetric < positiveBoderLine2mm1){//1.34
return "Sickle Cell Disease" return "Sickle Cell Disease"
}else if(borderlineMetric > Constants.positiveBoderLine2mm2){ }else if(borderlineMetric > positiveBoderLine2mm2){
return "Sickle Cell Trait" return "Sickle Cell Trait"
}else if(borderlineMetric > Constants.positiveBoderLine2mm1 && borderlineMetric < Constants.positiveBoderLine2mm2){ }else if(borderlineMetric > positiveBoderLine2mm1 && borderlineMetric < positiveBoderLine2mm2){
return "Positive for Sickle Cell. Confirm with HPLC" return "Positive for Sickle Cell. Confirm with HPLC"
} }
} }
@@ -1361,37 +1543,37 @@ class HemoCubeFragment : Fragment() {
try { try {
if (ratio != null) { if (ratio != null) {
if(cuvetteSize == "10mm"){ if(cuvetteSize == "10mm"){
if (ratio in Constants.normalMin10mm..Constants.normalMax10mm) { if (ratio in normalMin10mm..normalMax10mm) {
// setSubtitleTextColor(R.color.green_2) // setSubtitleTextColor(R.color.green_2)
return "Normal" return "Normal"
} }
if (ratio in Constants.negativeBorderlineMin10mm..Constants.negativeBorderlineMax10mm){ if (ratio in negativeBorderlineMin10mm..negativeBorderlineMax10mm){
return "Negative Borderline" return "Negative Borderline"
} }
if (ratio in Constants.sickleCellTraitMin10mm..Constants.sickleCellTraitMax10mm){ if (ratio in sickleCellTraitMin10mm..sickleCellTraitMax10mm){
return "Sickle Cell Trait" return "Sickle Cell Trait"
} }
if (ratio in Constants.positiveForSickleCellMin10mm..Constants.positiveForSickleCellMax10mm){//0.36 if (ratio in positiveForSickleCellMin10mm..positiveForSickleCellMax10mm){//0.36
return "Positive for Sickle Cell. HPLC for Confirmation" return "Positive for Sickle Cell. HPLC for Confirmation"
} }
if (ratio in Constants.sickleCellDiseaseMin10mm..Constants.sickleCellDiseaseMax10mm){ if (ratio in sickleCellDiseaseMin10mm..sickleCellDiseaseMax10mm){
return "Sickle Cell Disease" return "Sickle Cell Disease"
} }
}else if(cuvetteSize == "2mm"){ }else if(cuvetteSize == "2mm"){
if (ratio in Constants.normalMin2mm..Constants.normalMax2mm) { if (ratio in normalMin2mm..normalMax2mm) {
// setSubtitleTextColor(R.color.green_2) // setSubtitleTextColor(R.color.green_2)
return "Normal" return "Normal"
} }
if (ratio in Constants.negativeBorderlineMin2mm..Constants.negativeBorderlineMax2mm){ if (ratio in negativeBorderlineMin2mm..negativeBorderlineMax2mm){
return "Negative Borderline" return "Negative Borderline"
} }
if (ratio in Constants.sickleCellTraitMin2mm..Constants.sickleCellTraitMax2mm){ if (ratio in sickleCellTraitMin2mm..sickleCellTraitMax2mm){
return "Sickle Cell Trait" return "Sickle Cell Trait"
} }
if (ratio in Constants.positiveForSickleCellMin2mm..Constants.positiveForSickleCellMax2mm){//0.36 if (ratio in positiveForSickleCellMin2mm..positiveForSickleCellMax2mm){//0.36
return "Positive for Sickle Cell. HPLC for Confirmation" return "Positive for Sickle Cell. HPLC for Confirmation"
} }
if (ratio in Constants.sickleCellDiseaseMin2mm..Constants.sickleCellDiseaseMax2mm){ if (ratio in sickleCellDiseaseMin2mm..sickleCellDiseaseMax2mm){
return "Sickle Cell Disease" return "Sickle Cell Disease"
} }
} }

View File

@@ -67,13 +67,14 @@ import javax.inject.Inject
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
@HiltViewModel @HiltViewModel
class HemoCubeViewModel @Inject constructor( class HemoCubeViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao, val hemoCubeDao: HemoCubeDao,
private val hemoCubeBufferDao: HemoCubeBufferDao, private val hemoCubeBufferDao: HemoCubeBufferDao,
private val repository: Repository, private val repository: Repository,
private val logFileManager: LogFileManager, private val logFileManager: LogFileManager,
private val localFileDataSource: LocalFileDataSource, private val localFileDataSource: LocalFileDataSource,
context: Context, context: Context,
) : ViewModel() { ) : ViewModel() {
private var testUpload: Boolean = false
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData() private val testDetails = DataHolder.selectedTest?.toHemoCubeTestData()
@@ -132,20 +133,84 @@ class HemoCubeViewModel @Inject constructor(
try { try {
if (isOnline) { if (isOnline) {
parseData() parseData()
//addResultTestToDb(quickCapture)
if(Constants.FIREBASE_INTEGRATION){
addResultTestToDb(quickCapture) addResultTestToDb(quickCapture)
}else{
uploadToMolbio()
}
} else { } else {
parseData() parseData()
addResultTestToDb(quickCapture) val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
// addResultTestToDb(quickCapture,isOnline)
testDetails?.testTime = SimpleDateFormat( testDetails?.testTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
testDetails?.localFlag = false
hemoCubeDao.updateTest(testDetails!!) hemoCubeDao.updateTest(testDetails!!)
fireBaseUpload.postValue("Local") fireBaseUpload.postValue("Local")
// parseData()
// addResultTestToDb(quickCapture)
// testDetails?.testTime = SimpleDateFormat(
// "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
// ).format(Calendar.getInstance().time)
// hemoCubeDao.updateTest(testDetails!!)
// fireBaseUpload.postValue("Local")
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e("Testdb", "Upload failed: ${e.message}") Log.e("Testdb", "Upload failed: ${e.message}")
} }
} }
fun uploadToMolbio(){
if (Constants.MOLBIO_INTEGRATION) {
testDetails!!.testStatus = true
testDetails.localFlag = true
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1))
apply()
}
fireBaseUpload.postValue("Success")
testDetails.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
// Sanitize testDetails before using it in the API call
val sanitizedTestDetails = sanitizeDoubleValues(testDetails)
// Now, use sanitizedTestDetails for the API call
uploadResult(
MolbioV2ResultRequest(
mutableListOf(
MolbioV2Result(
rawData = sanitizedTestDetails,
analysisId = sanitizedTestDetails._id,
analysisDate = currentTimeFormatted,
analysisStatus = sanitizedTestDetails.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[sanitizedTestDetails.deviceId]?.toString(),
interpretation = sanitizedTestDetails.classificationResult,
testId = sanitizedTestDetails._id,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted,
)
)
)
)
viewModelScope.launch {
hemoCubeDao.updateTest(testDetails)
}
}
}
fun login(loginRequest: LoginRequest) = viewModelScope.launch { fun login(loginRequest: LoginRequest) = viewModelScope.launch {
loginResponse.postValue(Result.Loading()) loginResponse.postValue(Result.Loading())
@@ -221,16 +286,20 @@ class HemoCubeViewModel @Inject constructor(
is Result.Success -> { is Result.Success -> {
it.data.data?.forEach { id -> it.data.data?.forEach { id ->
id.rawData?.let { it1 -> id.rawData?.let { it1 ->
updateLocalFlag(it1._id)
updateMolbioFlag( updateMolbioFlag(
it1._id it1._id
) )
} }
} }
fireBaseBulkUpload.postValue("Success")
} }
is Result.Error -> { is Result.Error -> {
fireBaseBulkUpload.postValue("Error")
Log.d("result","result upload error") Log.d("result","result upload error")
} }
else -> { else -> {
fireBaseBulkUpload.postValue("Error")
Log.d("result","result upload else") Log.d("result","result upload else")
} }
} }
@@ -248,7 +317,12 @@ class HemoCubeViewModel @Inject constructor(
} }
} }
} }
if(testUpload){
fireBaseBulkUpload.postValue("Success")
}
// else{
// fireBaseBulkUpload.postValue("Error")
// }
} }
@@ -399,7 +473,7 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString() testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString()
testDetails?.name = DataHolder.hemoCubeTestData?.name.toString() testDetails?.name = DataHolder.hemoCubeTestData?.name.toString()
testDetails?.birthYear = DataHolder.hemoCubeTestData?.birthYear.toString() testDetails?.age = DataHolder.hemoCubeTestData?.age.toString()
testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString() testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString()
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString() testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
@@ -422,12 +496,14 @@ class HemoCubeViewModel @Inject constructor(
testDetails?.centerName = sharedPreference.getString(Constants.CENTER_NAME, "").toString() testDetails?.centerName = sharedPreference.getString(Constants.CENTER_NAME, "").toString()
testDetails?.district = sharedPreference.getString(Constants.DISTRICT, "").toString() testDetails?.district = sharedPreference.getString(Constants.DISTRICT, "").toString()
testDetails?.ipAddress = sharedPreference.getString(Constants.IP_ADDRESS, "").toString() testDetails?.ipAddress = sharedPreference.getString(Constants.IP_ADDRESS, "").toString()
testDetails?.configUpdatedRecent = sharedPreference.getString(Constants.LAST_UPDATED, "NA").toString()
} }
private fun addResultTestToDb(quickCapture: Boolean) { private fun addResultTestToDb(quickCapture: Boolean) {
viewModelScope.launch { viewModelScope.launch {
try { try {
testDetails!!.quickCapture = quickCapture testDetails!!.quickCapture = quickCapture
testDetails.testStatus = true
testDetails.reportUploadTime = SimpleDateFormat( testDetails.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
@@ -460,6 +536,7 @@ class HemoCubeViewModel @Inject constructor(
}else{ }else{
when (val response = repository.addTestToDatabase(testDetails)) { when (val response = repository.addTestToDatabase(testDetails)) {
is Response.Success -> { is Response.Success -> {
testDetails.localFlag = true
val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0) val kitCount = sharedPreference.getInt(Constants.KIT_COUNT, 0)
with(sharedPreference.edit()) { with(sharedPreference.edit()) {
putInt(Constants.KIT_COUNT, kitCount.plus(1)) putInt(Constants.KIT_COUNT, kitCount.plus(1))
@@ -467,7 +544,7 @@ class HemoCubeViewModel @Inject constructor(
} }
Log.i("Testdb", "Data uploaded to Firestore successfully") Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
testDetails.localFlag = true
if (Constants.MOLBIO_INTEGRATION) { if (Constants.MOLBIO_INTEGRATION) {
// Sanitize testDetails before using it in the API call // Sanitize testDetails before using it in the API call
val sanitizedTestDetails = sanitizeDoubleValues(testDetails) val sanitizedTestDetails = sanitizeDoubleValues(testDetails)
@@ -519,13 +596,13 @@ class HemoCubeViewModel @Inject constructor(
).format(Calendar.getInstance().time) ).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) { when (repository.addTestToDatabase(userData)) {
is Response.Success -> { is Response.Success -> {
fireBaseBulkUpload.postValue("Success") testUpload = true
userData.localFlag = true userData.localFlag = true
updateLocalFlag(userData._id) updateLocalFlag(userData._id)
} }
else -> { else -> {
fireBaseBulkUpload.postValue("Error") testUpload = false
} }
} }
} }
@@ -590,6 +667,10 @@ class HemoCubeViewModel @Inject constructor(
viewModelScope.launch { viewModelScope.launch {
hemoCubeBufferDao.updateFieldById(id = bufferId, true) hemoCubeBufferDao.updateFieldById(id = bufferId, true)
} }
fun deleteByStatus() = viewModelScope.launch {
hemoCubeDao.deleteByStatus()
}
fun getLocalUserDataForCsv(context: Context): Boolean { fun getLocalUserDataForCsv(context: Context): Boolean {
val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll() val localUserDataLiveData: LiveData<List<HemoCubeTestData>> = hemoCubeDao.getAll()
@@ -605,7 +686,7 @@ class HemoCubeViewModel @Inject constructor(
userData._id, userData._id,
userData.name, userData.name,
userData.bloodGroup, userData.bloodGroup,
userData.birthYear, userData.age,
userData.classificationResult, userData.classificationResult,
userData.testTime.toString(), userData.testTime.toString(),
userData.userImageURL userData.userImageURL

View File

@@ -21,9 +21,11 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.ServiceConnection import android.content.ServiceConnection
import android.content.SharedPreferences
import android.hardware.usb.UsbDevice import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import android.icu.text.SimpleDateFormat
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
@@ -39,18 +41,25 @@ import com.example.hpostesting.data.constant.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.util.UsbService import com.example.hpostesting.util.UsbService
import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber import com.hoho.android.usbserial.driver.UsbSerialProber
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
import java.util.Calendar
import java.util.Locale
@AndroidEntryPoint @AndroidEntryPoint
open class HemocubeActivity : AppCompatActivity() { open class HemocubeActivity : AppCompatActivity() {
private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
private lateinit var binding: ActivityHemocubeBinding private lateinit var binding: ActivityHemocubeBinding
private val viewModel by viewModels<HemoCubeViewModel>() private val viewModel by viewModels<HemoCubeViewModel>()
private var myMenu: Menu? = null private var myMenu: Menu? = null
lateinit var sharedPreferences: SharedPreferences
private lateinit var mDriver: UsbSerialDriver private lateinit var mDriver: UsbSerialDriver
private var mConnection: UsbDeviceConnection? = null private var mConnection: UsbDeviceConnection? = null
lateinit var mService: UsbService lateinit var mService: UsbService
@@ -108,6 +117,95 @@ open class HemocubeActivity : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener() setupListener()
connectUsb(false) connectUsb(false)
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 10//3600
}
sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
remoteConfig.fetchAndActivate()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val normalMin2mm = remoteConfig.getDouble("normalMin2mm")
val normalMax2mm = remoteConfig.getDouble("normalMax2mm")
val negativeBorderlineMin2mm = remoteConfig.getDouble("negativeBorderlineMin2mm")
val negativeBorderlineMax2mm = remoteConfig.getDouble("negativeBorderlineMax2mm")
val positiveForSickleCellMin2mm = remoteConfig.getDouble("positiveForSickleCellMin2mm")
val positiveForSickleCellMax2mm = remoteConfig.getDouble("positiveForSickleCellMax2mm")
val sickleCellTraitMin2mm = remoteConfig.getDouble("sickleCellTraitMin2mm")
val sickleCellTraitMax2mm = remoteConfig.getDouble("sickleCellTraitMax2mm")
val sickleCellDiseaseMin2mm = remoteConfig.getDouble("sickleCellDiseaseMin2mm")
val sickleCellDiseaseMax2mm = remoteConfig.getDouble("sickleCellDiseaseMax2mm")
val positiveBoderLine2mm1 = remoteConfig.getDouble("positiveBoderLine2mm1")
val positiveBoderLine2mm2 = remoteConfig.getDouble("positiveBoderLine2mm2")
val negativeBoderLine2mm1 = remoteConfig.getDouble("negativeBoderLine2mm1")
val negativeBoderLine2mm2 = remoteConfig.getDouble("negativeBoderLine2mm2")
val normalMin10mm = remoteConfig.getDouble("normalMin10mm")
val normalMax10mm = remoteConfig.getDouble("normalMax10mm")
val negativeBorderlineMin10mm = remoteConfig.getDouble("negativeBorderlineMin10mm")
val negativeBorderlineMax10mm = remoteConfig.getDouble("negativeBorderlineMax10mm")
val positiveForSickleCellMin10mm = remoteConfig.getDouble("positiveForSickleCellMin10mm")
val positiveForSickleCellMax10mm = remoteConfig.getDouble("positiveForSickleCellMax10mm")
val sickleCellTraitMin10mm = remoteConfig.getDouble("sickleCellTraitMin10mm")
val sickleCellTraitMax10mm = remoteConfig.getDouble("sickleCellTraitMax10mm")
val sickleCellDiseaseMin10mm = remoteConfig.getDouble("sickleCellDiseaseMin10mm")
val sickleCellDiseaseMax10mm = remoteConfig.getDouble("sickleCellDiseaseMax10mm")
val positiveBoderLine10mm1 = remoteConfig.getDouble("positiveBoderLine10mm1")
val positiveBoderLine10mm2 = remoteConfig.getDouble("positiveBoderLine10mm2")
val negativeBoderLine10mm1 = remoteConfig.getDouble("negativeBoderLine10mm1")
val negativeBoderLine10mm2 = remoteConfig.getDouble("negativeBoderLine10mm2")
val bufferMinLed1 = remoteConfig.getDouble("bufferMinLed1")
val bufferMaxLed1 = remoteConfig.getDouble("bufferMaxLed1")
val bufferMinLed2 = remoteConfig.getDouble("bufferMinLed2")
val bufferMaxLed2 = remoteConfig.getDouble("bufferMaxLed2")
val time = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString()
with(sharedPreferences.edit()) {
putString(Constants.LAST_UPDATED, time)
putString("bufferMinLed1", bufferMinLed1.toString())
putString("bufferMaxLed1", bufferMaxLed1.toString())
putString("bufferMinLed2", bufferMinLed2.toString())
putString("bufferMaxLed2", bufferMaxLed2.toString())//buffer
putString("normalMin2mm", normalMin2mm.toString())//2mm
putString("normalMax2mm", normalMax2mm.toString())
putString("negativeBorderlineMin2mm", negativeBorderlineMin2mm.toString())
putString("negativeBorderlineMax2mm", negativeBorderlineMax2mm.toString())
putString("positiveForSickleCellMin2mm", positiveForSickleCellMin2mm.toString())
putString("positiveForSickleCellMax2mm", positiveForSickleCellMax2mm.toString())
putString("sickleCellTraitMin2mm", sickleCellTraitMin2mm.toString())
putString("sickleCellTraitMax2mm", sickleCellTraitMax2mm.toString())
putString("sickleCellDiseaseMin2mm", sickleCellDiseaseMin2mm.toString())
putString("sickleCellDiseaseMax2mm", sickleCellDiseaseMax2mm.toString())
putString("positiveBoderLine2mm1", positiveBoderLine2mm1.toString())
putString("positiveBoderLine2mm2", positiveBoderLine2mm2.toString())
putString("negativeBoderLine2mm1", negativeBoderLine2mm1.toString())
putString("negativeBoderLine2mm2", negativeBoderLine2mm2.toString())//2mm
putString("normalMin10mm", normalMin10mm.toString())//10mm
putString("normalMax10mm", normalMax10mm.toString())
putString("negativeBorderlineMin10mm", negativeBorderlineMin10mm.toString())
putString("negativeBorderlineMax10mm", negativeBorderlineMax10mm.toString())
putString("positiveForSickleCellMin10mm", positiveForSickleCellMin10mm.toString())
putString("positiveForSickleCellMax10mm", positiveForSickleCellMax10mm.toString())
putString("sickleCellTraitMin10mm", sickleCellTraitMin10mm.toString())
putString("sickleCellTraitMax10mm", sickleCellTraitMax10mm.toString())
putString("sickleCellDiseaseMin10mm", sickleCellDiseaseMin10mm.toString())
putString("sickleCellDiseaseMax10mm", sickleCellDiseaseMax10mm.toString())
putString("positiveBoderLine10mm1", positiveBoderLine10mm1.toString())
putString("positiveBoderLine10mm2", positiveBoderLine10mm2.toString())
putString("negativeBoderLine10mm1", negativeBoderLine10mm1.toString())
putString("negativeBoderLine10mm2", negativeBoderLine10mm2.toString())//10mm
apply()
}
Toast.makeText(this@HemocubeActivity, "Config params updated", Toast.LENGTH_SHORT).show()
Log.d(TAG, "Config params updated")
} else {
Log.d(TAG, "Config params Fetch failed")
}
}
} }
private fun setupListener() { private fun setupListener() {

View File

@@ -112,14 +112,14 @@ class TestRightResults : Fragment() {
} }
private fun updateResults() { private fun updateResults() {
if (viewModel.testDetails?.name == "" && viewModel.testDetails?.birthYear == "") { if (viewModel.testDetails?.name == "" && viewModel.testDetails?.age == "") {
binding.tvName.visibility = View.GONE binding.tvName.visibility = View.GONE
binding.tvAge.visibility = View.GONE binding.tvAge.visibility = View.GONE
} else { } else {
binding.tvName.text = getString(R.string.name_in_textview, viewModel.testDetails?.name) binding.tvName.text = getString(R.string.name_in_textview, viewModel.testDetails?.name)
binding.tvAge.text = getString( binding.tvAge.text = getString(
R.string.age_in_textview, R.string.age_in_textview,
viewModel.testDetails?.birthYear?.toInt()?.calculateAgeFromYOB().toString() viewModel.testDetails?.age?.toInt()?.calculateAgeFromYOB().toString()
) )
} }

View File

@@ -287,7 +287,7 @@ class TrueHemeViewModel @Inject constructor(
testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients
testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString() testDetails?.incubationTime = DataHolder.hemoCubeTestData?.incubationTime.toString()
testDetails?.name = DataHolder.hemoCubeTestData?.name.toString() testDetails?.name = DataHolder.hemoCubeTestData?.name.toString()
testDetails?.birthYear = DataHolder.hemoCubeTestData?.birthYear.toString() testDetails?.age = DataHolder.hemoCubeTestData?.age.toString()
testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString() testDetails?.userImageURL = DataHolder.hemoCubeTestData?.userImageURL.toString()
testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!!
testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString() testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString()
@@ -434,7 +434,7 @@ class TrueHemeViewModel @Inject constructor(
userData._id, userData._id,
userData.name, userData.name,
userData.bloodGroup, userData.bloodGroup,
userData.birthYear, userData.age,
userData.classificationResult, userData.classificationResult,
userData.testTime.toString(), userData.testTime.toString(),
userData.userImageURL userData.userImageURL

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM10,17l-3.5,-3.5 1.41,-1.41L10,14.17 15.18,9l1.41,1.41L10,17z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M21.5,14.98c-0.02,0 -0.03,0 -0.05,0.01C21.2,13.3 19.76,12 18,12c-1.4,0 -2.6,0.83 -3.16,2.02C13.26,14.1 12,15.4 12,17c0,1.66 1.34,3 3,3l6.5,-0.02c1.38,0 2.5,-1.12 2.5,-2.5S22.88,14.98 21.5,14.98zM10,4.26v2.09C7.67,7.18 6,9.39 6,12c0,1.77 0.78,3.34 2,4.44V14h2v6H4v-2h2.73C5.06,16.54 4,14.4 4,12C4,8.27 6.55,5.15 10,4.26zM20,6h-2.73c1.43,1.26 2.41,3.01 2.66,5l-2.02,0C17.68,9.64 16.98,8.45 16,7.56V10h-2V4h6V6z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z"/>
</vector>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="@+id/my_toolbar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="?attr/actionBarSize"-->
<!-- android:background="?attr/colorPrimary"-->
<!-- app:titleTextColor="#FFFFFF"-->
<!-- android:elevation="4dp"-->
<!-- app:menu="@menu/my_menu"-->
<!-- android:theme="@style/ToolbarTheme"-->
<!-- app:popupTheme="@style/ThemeOverlay.AppCompat.Light"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
<FrameLayout
android:id="@+id/fg_hb_test"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -45,6 +45,7 @@
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:text="@string/scan_qr_code_of_the_kit" android:text="@string/scan_qr_code_of_the_kit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/app_bar_layout" /> app:layout_constraintTop_toBottomOf="@id/app_bar_layout" />
@@ -58,6 +59,7 @@
android:textColor="@color/black" android:textColor="@color/black"
app:backgroundTint="@color/blue_app_light" app:backgroundTint="@color/blue_app_light"
app:cornerRadius="100dp" app:cornerRadius="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" /> app:layout_constraintTop_toBottomOf="@+id/tv_title" />

View File

@@ -133,6 +133,7 @@
android:id="@+id/cv_item3" android:id="@+id/cv_item3"
android:layout_width="128dp" android:layout_width="128dp"
android:layout_height="128dp" android:layout_height="128dp"
android:visibility="gone"
android:layout_marginTop="32dp" android:layout_marginTop="32dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
app:cardElevation="8dp" app:cardElevation="8dp"

View File

@@ -165,7 +165,7 @@
app:cornerRadius="16dp" app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_deviceProvision" /> app:layout_constraintTop_toBottomOf="@id/btn_reset_password" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_firefox" android:id="@+id/btn_firefox"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.autodac.AutoDacFragment">
<!-- <TextView-->
<!-- android:id="@+id/tv_title"-->
<!-- style="@style/title1"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginHorizontal="24dp"-->
<!-- android:text="@string/diagnostics"-->
<!-- android:layout_marginTop="16dp"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:textSize="22sp"
android:textStyle="bold"
android:text="HB Test"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_subtitle3"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<TextView
android:id="@+id/tv_subtitle4"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="320dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:scrollbars="vertical"
android:text="Start"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle3" />
<Button
android:id="@+id/btn_buffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Buffer Start"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle4" />
<Button
android:id="@+id/btn_sample"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="15dp"
android:clickable="false"
android:gravity="center"
android:visibility="visible"
android:text="Sample Start"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_buffer" />
<Button
android:id="@+id/btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:visibility="gone"
android:text="Submit"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_sample" />
<!-- <Button-->
<!-- android:id="@+id/btn_read"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/read"-->
<!-- android:layout_margin="16dp"-->
<!-- android:clickable="false"-->
<!-- app:layout_constraintTop_toBottomOf="@id/btn_set_reference"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
<!-- </androidx.constraintlayout.widget.ConstraintLayout>-->
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -20,7 +20,23 @@
android:id="@+id/cl_parent" android:id="@+id/cl_parent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<Button
android:id="@+id/btn_placeRefreshbuffer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_marginTop="3dp"
android:layout_marginEnd="3dp"
android:textSize="14sp"
android:visibility="gone"
android:clickable="false"
android:text="Refresh \nbuffer"
android:textColor="@color/white"
android:backgroundTint="@color/brightGreen"
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView <TextView
android:id="@+id/tv_title" android:id="@+id/tv_title"
style="@style/title1" style="@style/title1"

View File

@@ -101,6 +101,26 @@
android:inputType="textCapCharacters" android:inputType="textCapCharacters"
android:hint="@string/sample_id" /> android:hint="@string/sample_id" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_age"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginHorizontal="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_name">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="2"
android:inputType="number"
android:hint="@string/age" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
@@ -112,7 +132,7 @@
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/til_name"> app:layout_constraintTop_toBottomOf="@+id/til_age">
<AutoCompleteTextView <AutoCompleteTextView
android:id="@+id/et_blood_group" android:id="@+id/et_blood_group"
@@ -143,6 +163,7 @@
android:id="@+id/rv_order_offline" android:id="@+id/rv_order_offline"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@@ -76,6 +76,7 @@
android:textColor="@color/black" android:textColor="@color/black"
app:backgroundTint="@color/blue_app_light" app:backgroundTint="@color/blue_app_light"
app:cornerRadius="100dp" app:cornerRadius="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" /> app:layout_constraintTop_toBottomOf="@+id/tv_title" />
@@ -103,9 +104,9 @@
android:clickable="false" android:clickable="false"
android:gravity="center" android:gravity="center"
android:text="Refresh" android:text="Refresh"
android:visibility="visible"
android:textColor="@color/white" android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="@id/btn_scan_now" android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_scan_now" /> app:layout_constraintTop_toBottomOf="@id/btn_scan_now" />

View File

@@ -130,9 +130,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/district" android:hint="@string/district"
android:inputType="none" android:inputType="none"
android:text="Mysuru" />
android:labelFor="@id/til_district"
app:simpleItems="@array/district" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout

View File

@@ -53,6 +53,7 @@
android:textColor="@color/black" android:textColor="@color/black"
app:backgroundTint="@color/blue_app_light" app:backgroundTint="@color/blue_app_light"
app:cornerRadius="100dp" app:cornerRadius="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title2" /> app:layout_constraintTop_toBottomOf="@+id/tv_title2" />

View File

@@ -86,16 +86,26 @@
android:text="@string/add" android:text="@string/add"
app:cornerRadius="16dp" app:cornerRadius="16dp"
app:layout_constraintBottom_toBottomOf="@id/spinnerCuvette" app:layout_constraintBottom_toBottomOf="@id/spinnerCuvette"
app:layout_constraintStart_toEndOf="@id/spinnerCuvette" app:layout_constraintStart_toEndOf="@id/spinnerCuvette"
app:layout_constraintTop_toTopOf="@id/spinnerCuvette" /> app:layout_constraintTop_toTopOf="@id/spinnerCuvette" />
<TextView
android:id="@+id/last_updated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Last"
android:textColor="@color/black"
android:textSize="17sp"
app:layout_constraintTop_toBottomOf="@id/btn_add_size"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="10dp"
android:layout_marginStart="30dp"/>
<FrameLayout <FrameLayout
android:id="@+id/container" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/spinnerCuvette" app:layout_constraintTop_toBottomOf="@+id/last_updated"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="10dp"/> android:layout_marginTop="10dp"/>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- RadioGroup to select servers -->
<RadioGroup
android:id="@+id/radioGroupServers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical">
<!-- Radio Buttons for each server option -->
<RadioButton
android:id="@+id/radioButtonInternal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Internal" />
<RadioButton
android:id="@+id/radioButtonClinical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clinical" />
<RadioButton
android:id="@+id/radioButtonCustomer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Customer" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -305,4 +305,7 @@
<string name="quick_capture">Quick Capture</string> <string name="quick_capture">Quick Capture</string>
<string name="reset_password_for_this_device">Reset password for this device</string> <string name="reset_password_for_this_device">Reset password for this device</string>
<string name="calibrate_device">Calibrate the device</string> <string name="calibrate_device">Calibrate the device</string>
<string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string>
<string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string>
</resources> </resources>

View File

@@ -304,6 +304,9 @@
<string name="quick_capture">ತ್ವರಿತ ಕ್ಯಾಪ್ಚರ್</string> <string name="quick_capture">ತ್ವರಿತ ಕ್ಯಾಪ್ಚರ್</string>
<string name="reset_password_for_this_device">ಈ ಸಾಧನಕ್ಕಾಗಿ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಿ</string> <string name="reset_password_for_this_device">ಈ ಸಾಧನಕ್ಕಾಗಿ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಿ</string>
<string name="calibrate_device">ಸಾಧನವನ್ನು ಮಾಪನಾಂಕ ಮಾಡಿ</string> <string name="calibrate_device">ಸಾಧನವನ್ನು ಮಾಪನಾಂಕ ಮಾಡಿ</string>
<string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string>
<string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string>
<!-- Add translations for other strings --> <!-- Add translations for other strings -->
</resources> </resources>

View File

@@ -87,7 +87,7 @@
<string name="acquire">Acquire</string> <string name="acquire">Acquire</string>
<string name="enter_patient_details">Enter Patient Details</string> <string name="enter_patient_details">Enter Patient Details</string>
<string name="patient_name">Patient Name</string> <string name="patient_name">Patient Name</string>
<string name="age">Age in years</string> <string name="age">Age</string>
<string name="gender">Gender</string> <string name="gender">Gender</string>
<string name="name_error">Name can\'t be empty</string> <string name="name_error">Name can\'t be empty</string>
<string name="age_error">Age can\'t be empty</string> <string name="age_error">Age can\'t be empty</string>
@@ -204,7 +204,7 @@
<string name="user_id">User ID</string> <string name="user_id">User ID</string>
<string name="aadhar_id">Aadhar ID</string> <string name="aadhar_id">Aadhar ID</string>
<string name="internet_not_available_please_enter_the_user_id_manually">Internet not available, please enter the user ID and blood group manually</string> <string name="internet_not_available_please_enter_the_user_id_manually">Internet not available, please enter the user ID and blood group manually</string>
<string name="user_id_error_message">User ID should be 18 digits and please select the blood group</string> <string name="user_id_error_message">Sample ID Length should be greater then 5 and please select the blood group</string>
<string name="upload_db_registration_title">Upload DB Tests</string> <string name="upload_db_registration_title">Upload DB Tests</string>
<string name="upload_db_registration_message">Do you want to upload the local DB tests to the cloud?</string> <string name="upload_db_registration_message">Do you want to upload the local DB tests to the cloud?</string>
<string name="upload">Upload</string> <string name="upload">Upload</string>
@@ -305,4 +305,7 @@
<string name="quick_capture">Quick Capture</string> <string name="quick_capture">Quick Capture</string>
<string name="reset_password_for_this_device">Reset password for this device</string> <string name="reset_password_for_this_device">Reset password for this device</string>
<string name="calibrate_device">Calibrate Device</string> <string name="calibrate_device">Calibrate Device</string>
<string name="cuvette_presentt">Cuvette Present , Please Remove Cuvette And Try Again</string>
<string name="cuvette_absentt">Cuvette Absent,Now You Can Submit</string>
</resources> </resources>

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ // Copyright (c) 2024 ShanMukha Innovations Pvt. Ltd. All rights reserved.
~ // Notice: All information contained herein is, and remains
~ // the property of ShanMukha Innovations Pvt. Ltd. and its suppliers,
~ // if any. The intellectual and technical concepts contained
~ // herein are proprietary to ShanMukha Innovations Pvt. Ltd.
~ // and its suppliers and may be covered by Indian and Foreign Patents,
~ // patents in process, and are protected by trade secret or copyright law.
~ // Dissemination of this information or reproduction of this material
~ // is strictly forbidden unless prior written permission is obtained
~ // from ShanMukha Innovations Pvt. Ltd.
-->
<defaultsMap>
<entry>
<key>BUFFER_FLAGS_ENABLED</key>
<value>true</value>
</entry>
<entry>
<key>positiveBoderLine10mm1</key>
<value>1.3</value>
</entry>
<entry>
<key>positiveBoderLine10mm2</key>
<value>1.66</value>
</entry>
<entry>
<key>negativeBoderLine10mm1</key>
<value>2.0</value>
</entry>
<entry>
<key>negativeBoderLine10mm2</key>
<value>2.4</value>
</entry>
<entry>
<key>normalMin10mm</key>
<value>0.07</value>
</entry>
<entry>
<key>normalMax10mm</key>
<value>0.23</value>
</entry>
<entry>
<key>negativeBorderlineMin10mm</key>
<value>0.23</value>
</entry>
<entry>
<key>negativeBorderlineMax10mm</key>
<value>0.27</value>
</entry>
<entry>
<key>sickleCellTraitMin10mm</key>
<value>0.27</value>
</entry>
<entry>
<key>sickleCellTraitMax10mm</key>
<value>0.31</value>
</entry>
<entry>
<key>positiveForSickleCellMin10mm</key>
<value>0.31</value>
</entry>
<entry>
<key>positiveForSickleCellMax10mm</key>
<value>0.39</value>
</entry>
<entry>
<key>sickleCellDiseaseMin10mm</key>
<value>0.39</value>
</entry>
<entry>
<key>sickleCellDiseaseMax10mm</key>
<value>0.7</value>
</entry>
<entry>
<key>positiveBoderLine2mm1</key>
<value>0.8</value>
</entry>
<entry>
<key>positiveBoderLine2mm2</key>
<value>1.1</value>
</entry>
<entry>
<key>negativeBoderLine2mm1</key>
<value>1.5</value>
</entry>
<entry>
<key>negativeBoderLine2mm2</key>
<value>1.9</value>
</entry>
<entry>
<key>normalMin2mm</key>
<value>0.1</value>
</entry>
<entry>
<key>normalMax2mm</key>
<value>0.23</value>
</entry>
<entry>
<key>negativeBorderlineMin2mm</key>
<value>0.23</value>
</entry>
<entry>
<key>negativeBorderlineMax2mm</key>
<value>0.25</value>
</entry>
<entry>
<key>sickleCellTraitMin2mm</key>
<value>0.25</value>
</entry>
<entry>
<key>sickleCellTraitMax2mm</key>
<value>0.31</value>
</entry>
<entry>
<key>positiveForSickleCellMin2mm</key>
<value>0.31</value>
</entry>
<entry>
<key>positiveForSickleCellMax2mm</key>
<value>0.45</value>
</entry>
<entry>
<key>sickleCellDiseaseMin2mm</key>
<value>0.45</value>
</entry>
<entry>
<key>sickleCellDiseaseMax2mm</key>
<value>0.7</value>
</entry>
<entry>
<key>bufferMinLed1</key>
<value>21000.00</value>
</entry>
<entry>
<key>bufferMaxLed1</key>
<value>23000.00</value>
</entry>
<entry>
<key>bufferMinLed2</key>
<value>17000.00</value>
</entry>
<entry>
<key>bufferMaxLed2</key>
<value>19000.00</value>
</entry>
</defaultsMap>

View File

@@ -341,7 +341,7 @@ class HemoCubeFragmentTest {
fun testDeviceRatioClassificationSickleCellTraitLowerBound() { fun testDeviceRatioClassificationSickleCellTraitLowerBound() {
val ratio = 0.251 val ratio = 0.251
val result = hemoCubeFragment.deviceRatioClassification(ratio) val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Sickle Cell Trait", result) assertEquals("Negative Borderline", result)
} }
@Test @Test
@@ -362,7 +362,7 @@ class HemoCubeFragmentTest {
fun testDeviceRatioClassificationSickleCellDiseaseLowerBound() { fun testDeviceRatioClassificationSickleCellDiseaseLowerBound() {
val ratio = 0.391 val ratio = 0.391
val result = hemoCubeFragment.deviceRatioClassification(ratio) val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Positive for Sickle Cell. HPLC for Confirmation", result) assertEquals("Sickle Cell Disease", result)
} }
@Test @Test
@@ -390,7 +390,7 @@ class HemoCubeFragmentTest {
fun findResultWithAdditionalMethods_ValidInput_ReturnsBorderlineSickleCellTrait1() { fun findResultWithAdditionalMethods_ValidInput_ReturnsBorderlineSickleCellTrait1() {
val result = val result =
hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline", 2.2) hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline", 2.2)
assertEquals("Negative borderline. Confirm with HPLC", result) assertEquals("Normal", result)
} }
@Test @Test
@@ -400,7 +400,7 @@ class HemoCubeFragmentTest {
"Positive for Sickle Cell. HPLC for Confirmation", "Positive for Sickle Cell. HPLC for Confirmation",
1.4 1.4
) )
assertEquals("Positive for Sickle Cell. Confirm with HPLC", result) assertEquals("Sickle Cell Trait", result)
} }
@Test @Test
@@ -410,7 +410,7 @@ class HemoCubeFragmentTest {
"Positive for Sickle Cell. HPLC for Confirmation", "Positive for Sickle Cell. HPLC for Confirmation",
1.33 1.33
) )
assertEquals("Positive for Sickle Cell. Confirm with HPLC", result) assertEquals("Sickle Cell Trait", result)
} }
@Test @Test

View File

@@ -3,7 +3,7 @@ buildscript {
kotlin_version = '1.8.21' kotlin_version = '1.8.21'
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.2.2' classpath 'com.android.tools.build:gradle:8.4.0'
classpath 'com.google.gms:google-services:4.4.1' classpath 'com.google.gms:google-services:4.4.1'
classpath 'com.google.firebase:firebase-appdistribution-gradle:4.1.0' classpath 'com.google.firebase:firebase-appdistribution-gradle:4.1.0'
} }

View File

@@ -14,6 +14,6 @@
#Mon Mar 04 17:08:24 IST 2024 #Mon Mar 04 17:08:24 IST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists